שיפור הגרפיקה באמצעות תוכן בצבע רחב

ב-Android 8.0 (רמת API 26) נוספה תמיכה בניהול צבעים, מרחבי צבעים RGB סטנדרטי (sRGB) לרינדור גרפיקה במכשירים עם מסכים תואמים. בעזרת התמיכה הזו, האפליקציה שלך יכולה לעבד מפות סיביות עם פרופילים מוטמעים של צבע רחב שנטענים מקובצי PNG , JPEG ו-WebP באמצעות Java או קוד נייטיב. אפליקציות שמשתמשות ב-OpenGL או ב-Vulkan יכולות להפיק ישירות פלט של תוכן של מטווח צבעים רחב (באמצעות Display P3 scRGB). היכולת הזו שימושי ליצירת אפליקציות שכוללות שחזור של צבעים באיכות גבוהה, כמו תמונות וסרטונים עריכת אפליקציות.

הסבר על מצב סולם צבעים רחב

פרופילים של צבעים רחבים הם פרופילים של ICC, כמו Adobe RGB, Pro Photos RGB, וגם DCI-P3, שיכול לייצג מגוון רחב יותר של צבעים מאשר sRGB. מסכים שתומכים בפרופילים של צבעים רחבים ניתן להציג תמונות בעלות צבעי יסוד עמוקים יותר (אדום, ירוק וכחול) וכן תמונות משניות עשירות יותר צבעים (כגון מג'נטה, ציאן וצהוב).

האפליקציה שלך יכולה להשתמש במכשירי Android עם Android 8.0 (רמת API 26) ואילך שתומכים בכך, להפעיל מצב צבעים רחבים (swide) בשביל פעילות שבה המערכת מזהה לעבד בצורה נכונה תמונות של מפת סיביות עם פרופילים מוטמעים של צבעים רחבים. כיתה ColorSpace.Named מסווגת רשימה חלקית של כלים נפוצים מרחבי צבעים שנתמכים ב-Android.

הערה: כשמצב 'סולם צבעים רחב' מופעל, החלון משתמש ביותר זיכרון ובעיבוד GPU להרכבת המסך. לפני שמפעילים סולם צבעים רחב כדאי לבדוק בקפידה אם הפעילות באמת מועילה. לדוגמה, פעילות שמציגה תמונות במסך מלא מתאימה למצב של סולם צבעים רחב, פעילות שמציגה תמונות ממוזערות קטנות היא לא פעילות.

הפעלת מצב 'טווח צבעים רחב'

אפשר להשתמש במאפיין colorMode כדי לבקש שהפעילות תוצג במצב של סולם צבעים רחב במכשירים תואמים. במצב של סולם צבעים רחב, חלון יכול לעבור רינדור מחוץ לטווח ה-sRGB כדי להציג צבעים עזים יותר. אם המכשיר לא תומך בצבע רחב עיבוד סולם, למאפיין הזה אין השפעה. אם האפליקציה שלך צריכה להחליט אם לתצוגה יש סולם צבעים רחב, אמצעי תשלום אחד (isWideColorGamut()). האפליקציה יכולה גם להתקשר isScreenWideColorGamut(), שמחזיר true רק אם המסך תומך בסולם צבעים רחב והמכשיר תומך במערך צבעים רחב. ורינדור.

יכול להיות שהמסך יהיה מוכן לטווח צבעים רחב אבל לא יהיה מנוהל על ידי צבעים. במקרה כזה, לא תעניק לאפליקציה את מצב 'לוח צבעים רחב'. כשהתצוגה לא מנוהלת לפי צבעים —כפי שהיה בכל הגרסאות של Android לפני 8.0 — המערכת תמפה מחדש את צבעים שהאפליקציה יצרה לסולם התצוגה.

כדי להפעיל את סולם הצבעים הרחב בפעילות, צריך להגדיר את colorMode ל-wideColorGamut בקובץ AndroidManifest.xml שלך. שלך צריך לעשות זאת בכל פעילות שעבורה רוצים להפעיל מצב צבע רחב.

android:colorMode="wideColorGamut"

תוכלו גם להגדיר את מצב הצבע באופן פרוגרמטי בפעילות על ידי קריאה ל שיטה אחת (setColorMode(int)) והעברה COLOR_MODE_WIDE_COLOR_GAMUT.

עיבוד תוכן של סולם צבעים רחב

איור 1. מרחבי צבעים של תצוגה P3 (כתום) לעומת sRGB (לבן)

כדי לעבד תוכן של מטווח צבעים רחב, האפליקציה צריכה לטעון מפת סיביות רחבה של צבעים, שמבוססת על מפת סיביות (bitmap) עם פרופיל צבעים שמכיל מרחב צבעים רחב יותר מ-sRGB. פרופילים נפוצים של צבעים רחבים כוללים Adobe RGB, DCI-P3 ו-Display P3.

האפליקציה יכולה לשלוח שאילתה על מרחב הצבעים של מפת סיביות באמצעות קריאה getColorSpace() כדי לקבוע אם המערכת מזהה לטווח צבעים ספציפי, להיות טווח רחב, אפשר לקרוא אמצעי תשלום אחד (isWideGamut()).

המחלקה Color מאפשרת לייצג צבע עם ארבעה רכיבים דחוסים בערך ארוך של 64 ביט, במקום הייצוג הנפוץ ביותר שמשתמש במספר שלם עם ערך מסוים. באמצעות ערכים ארוכים אפשר להגדיר צבעים עם מדויקים יותר מערכי מספרים שלמים. אם אתם צריכים ליצור או לקודד צבע כערך ארוך, אתם יכולים להשתמש אחת מה-methods pack() במחלקה Color.

כדי לוודא שהאפליקציה ביקשה באופן תקין את מצב סולם הצבעים הרחב, אפשר לבדוק הפונקציה getColorMode() מחזירה COLOR_MODE_WIDE_COLOR_GAMUT (השיטה הזו לא מציינת, עם זאת, האם מצב סולם הצבעים הרחב הוענק בפועל).

שימוש בערכת צבעים רחבה בקוד מקורי

בקטע הזה נסביר איך להפעיל מצב של סולם צבעים רחב באמצעות OpenGL ממשקי API של Vulkan אם האפליקציה שלכם משתמשת בקוד נייטיב.

OpenGL

כדי להשתמש במצב מטווח צבעים רחב ב-OpenGL, צריך לכלול באפליקציה את ספריית EGL 1.4 עם אחד מהתוספים הבאים:

כדי להפעיל את התכונה, קודם צריך ליצור הקשר GL דרך eglChooseConfig, עם אחת מתוך ה-3 הנתמכות של מאגר נתונים זמני של צבעים רחבים במאפיינים. הפורמט של מאגר הנתונים הזמני של צבעים לרוחב הצבע חייב להיות אחד מהקבוצות הבאות של ערכי RGBA:

  • 8, 8, 8, 8
  • 10, 10, 10, 2
  • FP16, FP16, FP16, FP16

לאחר מכן, מבקשים את תוסף מרחב הצבעים P3 כשיוצרים את לעבד יעדים, כפי שמוצג בקטע הקוד הבא:

std::vector<EGLint> attributes;
attributes.push_back(EGL_GL_COLORSPACE_KHR);
attributes.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
attributes.push_back(EGL_NONE);
engine->surface_ = eglCreateWindowSurface(
    engine->display_, config, engine->app->window, attributes.data());

וולקן

התמיכה של Vulkan במערך צבעים רחב מסופקת באמצעות התוסף VK_EXT_swapchain_colorspace.

לפני שמפעילים תמיכה בצבעים רחבים בקוד Vulkan, צריך לוודא יש תמיכה בתוסף דרך vkEnumerateInstanceExtensionProperties אם התוסף זמין, צריך להפעיל אותו במהלך vkCreateInstance לפני שיוצרים תמונות מוחלפות להשתמש במרחבי הצבע הנוספים שהתוסף מגדיר.

לפני יצירת ההחלפה, עליך לבחור את מרחב הצבעים הרצוי, ואז לעבור על את הפלטפורמות הזמינות של מכשירים פיזיים ולבחור עבורם פורמט צבע תקין מרחב צבעים.

במכשירי Android, ב-Vulkan יש תמיכה במערך צבעים רחב עם מרחבי הצבעים הבאים וגם VkSurfaceFormatKHR פורמטים של צבעים:

  • מרחבי צבעים רחבים של Vulkan עם סולם צבעים:
    • VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
    • VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
  • פורמטים של צבעי Vulkan עם תמיכה במערך צבעים רחב:
    • VK_FORMAT_R16G16B16A16_SFLOAT
    • VK_FORMAT_A2R10G10B10_UNORM_PACK32
    • VK_FORMAT_R8G8B8A8_UNORM

קטע הקוד הבא מראה איך אפשר לבדוק אם המכשיר תומך בטכנולוגיית Display P3 מרחב צבעים:

uint32_t formatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(
       vkPhysicalDev,
       vkSurface,
       &formatCount,
       nullptr);
VkSurfaceFormatKHR *formats = new VkSurfaceFormatKHR[formatCount];
vkGetPhysicalDeviceSurfaceFormatsKHR(
       vkPhysicalDev,
       vkSurface,
       &formatCount,
       formats);

uint32_t displayP3Index = formatCount;
for (uint32_t idx = 0; idx < formatCount; idx++) {
 if (formats[idx].format == requiredSwapChainFmt &&
     formats[idx].colorSpace==VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT)
 {
   displayP3Index = idx;
   break;
 }
}
if (displayP3Index == formatCount) {
    // Display P3 is not supported on the platform
    // choose other format
}

קטע הקוד הבא מראה איך לבקש החלפה של Vulkan עם VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:

uint32_t queueFamily = 0;
VkSwapchainCreateInfoKHR swapchainCreate {
   .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
   .pNext = nullptr,
   .surface = AndroidVkSurface_,
   .minImageCount = surfaceCapabilities.minImageCount,
   .imageFormat = requiredSwapChainFmt,
   .imageColorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT,
   .imageExtent = surfaceCapabilities.currentExtent,
   .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
   .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
   .imageArrayLayers = 1,
   .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
   .queueFamilyIndexCount = 1,
   .pQueueFamilyIndices = &queueFamily,
   .presentMode = VK_PRESENT_MODE_FIFO_KHR,
   .oldSwapchain = VK_NULL_HANDLE,
   .clipped = VK_FALSE,
};
VkRresult status = vkCreateSwapchainKHR(
                       vkDevice,
                       &swapchainCreate,
                       nullptr,
                       &vkSwapchain);
if (status != VK_SUCCESS) {
    // Display P3 is not supported
    return false;
}