ปรับปรุงกราฟิกด้วยเนื้อหา Wide Color

Android 8.0 (API ระดับ 26) ได้เปิดตัวการรองรับการจัดการสีสำหรับพื้นที่สีเพิ่มเติมนอกเหนือจาก RGB มาตรฐาน (sRGB) สำหรับการเรนเดอร์กราฟิกในอุปกรณ์ที่มีจอแสดงผลที่เข้ากันได้ การรองรับนี้ช่วยให้แอปของคุณแสดงผลบิตแมปที่มีโปรไฟล์สีแบบกว้างที่ฝังไว้ซึ่งโหลดจากไฟล์ PNG, JPEG และ WebP ผ่าน Java หรือโค้ดเนทีฟได้ แอปที่ใช้ OpenGL หรือ Vulkan สามารถแสดงผลเนื้อหาแบบช่วงสีกว้างได้โดยตรง (โดยใช้ Display P3 และ scRGB) ความสามารถนี้มีประโยชน์ในการสร้างแอปที่เกี่ยวข้องกับการจำลองสีที่เหมือนจริง เช่น แอปแต่งรูปภาพและวิดีโอ

ทำความเข้าใจโหมด Wide Color gamut

โปรไฟล์สีแบบกว้างคือโปรไฟล์ ICC เช่น Adobe RGB, Pro Photo RGB และ DCI-P3 ซึ่งแสดงสีได้กว้างกว่า sRGB หน้าจอที่รองรับโปรไฟล์สีกว้าง สามารถแสดงรูปภาพที่มีสีหลักเข้มกว่า (สีแดง เขียว และน้ำเงิน) และสีรองที่เข้มขึ้น สีต่างๆ (เช่น ม่วงแดง ฟ้าเขียว และเหลือง)

ในอุปกรณ์ Android ที่ใช้ Android 8.0 (API ระดับ 26) ขึ้นไปที่รองรับ แอปของคุณจะเปิดใช้โหมดสีแบบสีกว้างสําหรับกิจกรรมได้ ซึ่งระบบจะจดจําและประมวลผลรูปภาพบิตแมปที่มีโปรไฟล์สีกว้างที่ฝังไว้ได้อย่างถูกต้อง คลาส ColorSpace.Named แจกแจงรายการบางส่วนของที่ใช้กันโดยทั่วไป พื้นที่สีที่ Android รองรับ

หมายเหตุ: เมื่อเปิดใช้โหมดขอบเขตสีแบบกว้าง กิจกรรม ใช้หน่วยความจำและการประมวลผล GPU มากขึ้นในการจัดองค์ประกอบหน้าจอ ก่อนเปิดใช้ขอบเขตสีแบบกว้าง คุณควรพิจารณาอย่างรอบคอบว่ากิจกรรมนั้นจะได้รับประโยชน์จริงๆ หรือไม่ ตัวอย่างเช่น กิจกรรมที่แสดงรูปภาพแบบเต็มหน้าจอเป็นตัวเลือกที่ดีสำหรับโหมดขอบเขตสีที่กว้าง แต่ กิจกรรมที่แสดงภาพขนาดย่อขนาดเล็กนั้นไม่ได้เป็นเช่นนั้น

เปิดใช้โหมดขอบเขตสีแบบกว้าง

ใช้แอตทริบิวต์ colorMode เพื่อขอให้กิจกรรมแสดงในโหมดสีกว้างในอุปกรณ์ที่เข้ากันได้ ในโหมดช่วงสีกว้าง หน้าต่างจะแสดงผลนอกช่วงสี sRGB เพื่อแสดงสีสันที่สดใสยิ่งขึ้น หากอุปกรณ์ไม่รองรับ Wide Color การแสดงผลแบบ Gamut แอตทริบิวต์นี้จะไม่มีผล หากแอปของคุณต้องกำหนดว่า การแสดงผลนั้นใช้ขอบเขตสีได้กว้าง isWideColorGamut() วิธี นอกจากนี้ แอปยังเรียกใช้ isScreenWideColorGamut() ได้ด้วย ซึ่งจะแสดงผลเป็น true เฉพาะในกรณีที่จอแสดงผลรองรับการแสดงผลแบบสีกว้างและอุปกรณ์รองรับการแสดงผลแบบสีกว้างเท่านั้น

จอแสดงผลอาจรองรับขอบเขตสีที่กว้างแต่ไม่ได้จัดการสี ในกรณีนี้ ระบบจะไม่อนุญาตให้แอปใช้โหมดขอบเขตสีที่กว้าง เมื่อจอแสดงผลไม่มีการจัดการสี เช่นเดียวกับกรณีของ Android ทุกเวอร์ชันก่อน 8.0 ระบบจะแมป ที่แอปวาดในช่วงขอบเขตของจอแสดงผล

หากต้องการเปิดใช้ขอบเขตสีแบบกว้างในกิจกรรม ให้ตั้งค่า colorMode เป็น wideColorGamut ในไฟล์ AndroidManifest.xml ของคุณ คุณ สำหรับแต่ละกิจกรรมที่ต้องการเปิดใช้โหมด Wide Color

android:colorMode="wideColorGamut"

คุณยังสามารถตั้งค่าโหมดสีแบบเป็นโปรแกรมในกิจกรรมได้ด้วยการเรียกใช้ setColorMode(int) เมธอดและการส่งใน COLOR_MODE_WIDE_COLOR_GAMUT

แสดงผลเนื้อหา Wide Color gamut

รูปที่ 1 พื้นที่สี Display P3 (สีส้ม) เทียบกับ sRGB (สีขาว)

ในการแสดงผลเนื้อหา Wide Color gamut แอปของคุณต้องโหลดบิตแมป แบบกว้าง ซึ่งเป็นบิตแมปที่มี โปรไฟล์สีที่มีพื้นที่สีที่กว้างกว่า sRGB โปรไฟล์สีกว้างที่ใช้กันโดยทั่วไป ได้แก่ Adobe RGB, DCI-P3 และ Display P3

แอปสามารถค้นหาพื้นที่สีของบิตแมปได้โดยเรียกใช้ getColorSpace() เพื่อดูว่าระบบรู้จัก พื้นที่สีที่เจาะจงให้ขอบเขตกว้าง คุณสามารถเรียกใช้ isWideGamut() วิธี

คลาส Color ให้คุณแสดงสีที่มีส่วนประกอบ 4 รายการ เป็นค่ายาว 64 บิตแทนการแสดงทั่วไปที่ใช้จำนวนเต็ม เมื่อใช้ค่าที่ยาว คุณสามารถกำหนดสีได้ด้วย แม่นยำกว่าค่าจำนวนเต็ม หากต้องการสร้างหรือเข้ารหัสสีเป็นค่าแบบ Long ให้ใช้เมธอด pack() อย่างใดอย่างหนึ่งในคลาส Color

คุณสามารถตรวจสอบว่าแอปขอโหมดสีกว้างอย่างถูกต้องหรือไม่โดยดูว่าเมธอด getColorMode() แสดงผลเป็น COLOR_MODE_WIDE_COLOR_GAMUT หรือไม่ (อย่างไรก็ตาม เมธอดนี้ไม่ได้ระบุว่าระบบให้โหมดสีกว้างจริงหรือไม่)

ใช้การรองรับขอบเขตสีที่กว้างในโค้ดเนทีฟ

ส่วนนี้จะอธิบายวิธีเปิดใช้โหมดสีกว้างด้วย API ของ OpenGL และ Vulkan หากแอปของคุณใช้โค้ดเนทีฟ

OpenGL

หากต้องการใช้โหมดช่วงสีกว้างใน OpenGL แอปของคุณต้องมีไลบรารี EGL 1.4 ที่มีส่วนขยายอย่างใดอย่างหนึ่งต่อไปนี้

หากต้องการเปิดใช้ฟีเจอร์นี้ ก่อนอื่นคุณต้องสร้างบริบท GL ผ่าน eglChooseConfig โดยใช้รูปแบบบัฟเฟอร์สีที่รองรับ 1 ใน 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

ก่อนที่จะเปิดใช้งานการสนับสนุน Wide Color ในโค้ด Vulkan ก่อนอื่นให้ตรวจสอบว่า ส่วนขยายได้รับการสนับสนุนผ่าน vkEnumerateInstanceExtensionProperties หากส่วนขยายพร้อมใช้งาน คุณต้องเปิดใช้ระหว่างvkCreateInstanceก่อนสร้างรูปภาพ Swapchain ที่ใช้พื้นที่สีเพิ่มเติมที่ส่วนขยายกำหนด

ก่อนที่จะสร้าง Swapchain คุณต้องเลือกพื้นที่สีที่ต้องการ จากนั้นวนซ้ำ พื้นผิวจริงของอุปกรณ์ที่พร้อมจำหน่ายและเลือกรูปแบบสีที่ถูกต้องสำหรับรูปแบบสีดังกล่าว พื้นที่สี

ในอุปกรณ์ 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;
}