ปรับปรุงกราฟิกด้วยเนื้อหา 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 บิตแทนการแสดงทั่วไปที่ใช้จำนวนเต็ม เมื่อใช้ค่าที่ยาว คุณสามารถกำหนดสีได้ด้วย แม่นยำกว่าค่าจำนวนเต็ม หากต้องการสร้างหรือเข้ารหัสสีเป็นค่าแบบยาว ให้ใช้ หนึ่งในเมธอด pack() ในชั้นเรียน Color

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

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

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

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

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