【HDR学习】苹果EDR技术洞察(二)
?
-
綜述
蘋果用 EDR 這個詞是為了跟 HDR 區分開,因為 HDR 在不同的場景可能對應著不同的理解:
而 EDR(Extended Dynamic Range)是蘋果推出的一套渲染管線技術,以支持在不同的屏幕上同時正確顯示 SDR 和 HDR 內容。當顯示 HDR 的內容時,EDR 并不會直接將 HDR 區域變得更亮,而是識別到 HDR 內容后提高整體屏幕亮度的同時,降低非 HDR 區域的白點值,使得其看起來沒有那么亮。
-
EDR 的技術方案
SDR 的像素浮點數表示范圍為?[0.0, 1.0],其中 0.0 表示黑色,1.0 表示白色。在 EDR 的像素浮點數表示中,SDR 的部分映射到?[0.0, 1.0],而大于 1.0 的部分就是比 SDR 更亮的 HDR 部分。
不像其他的 HDR 格式那樣,EDR 不會做 Tone Mapping 將像素值都映射到?[0.0, 1.0]?的范圍。這就意味著在渲染時,它有一套新的機制。當渲染時,像素浮點值范圍為?[0.0, 1.0]?的 SDR 內容是始終會正常渲染的。(1.0, EDR headroom]?范圍的 HDR 內容也是可以渲染的。但是,超過了 EDR headroom 的部分就會被丟掉。
EDR headroom 的存在支持了亮度更高的 HDR 內容,但是它具體是多少呢?其實,EDR headroom 是動態的,它的值受到多種因素的影響,比如:設備的顯示技術、當前的顯示亮度等等。
我們通??梢允褂孟旅孢@個公式粗略估計 EDR headroom:
Headroom ≈ Display Peak / SDRPro Display XDR顯示器可手動/自動調節的最大亮度等級是500nits(用于光線好的環境),所以把它作為1.0EDR預設值,這個范圍就是SDR的范圍,EDR值=1600nits/500nits=3.2;如果昏暗環境,手動/自動把顯示器亮度調到4nits, EDR值就是1600nits/4nits=400。
-
代碼講解
1. 以首選的EDR框架CAMetalLayer為示范。首先看以下4個步驟:選擇使用EDR-》設置擴展范圍色域-》將metaLayer的像素格式調整為浮點格式,如RGBA16Float-》實際生成EDR像素
前三個步驟代碼示例如下:
有關第四個步驟,我們用ImageIO導入HDR靜態圖像內容,并將其渲染成EDR紋理,這個過程可以概括為: 先通過HDR圖片建立CGImage-》繪制浮點bitmap-》創建浮點紋理-》將EDR位圖導入到texture中-》將texture渲染成EDR可用的metal管線
1)讀取HDR原圖片,保存成CGImageRef格式。
CGImageRef ,這個結構用來創建像素位圖,可以通過操作存儲的像素位來編輯圖片。其參數解釋如下:
sizt_t是定義的一個可移植性的單位,在64位機器中為8字節,32位位4字節。 width:圖片寬度像素 height:圖片高度像素 bitsPerComponent:每個顏色的比特數,例如在rgba-32模式下為8 bitsPerPixel:每個像素的總比特數 bytesPerRow:每一行占用的字節數,注意這里的單位是字節 space:顏色空間模式,例如const CFStringRef kCGColorSpaceGenericRGB 這個函數可以返回一個顏色空間對象。 bitmapInfo:位圖像素布局,這是個枚舉 provider:數據源提供者 decode[]:解碼渲染數組 shouldInterpolate:是否抗鋸齒 intent:圖片相關參數2)繪制浮點位圖
先讀取像素位圖的寬度、高度,再根據位圖組成信息和色彩空間(之前設置過的Display-P3),調用CGBitmapContextCreate創建繪圖上下文(相當于一個畫布),然后調用CGContextDrawImage方法在當前上下文畫圖。
CGContextRef?(Quartz?2D繪圖的核心API是CGContextRef,該API專門用于繪制各種圖形。)
CGContextRef CGBitmapContextCreate ( void *data, size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow, CGColorSpaceRef colorspace, CGBitmapInfo bitmapInfo ); /** 參數: data 指向要渲染的繪制內存的地址。這個內存塊的大小至少是(bytesPerRow*height)個字節。使用時可填NULL或unsigned char類型的指針。 width bitmap的寬度,單位為像素 height bitmap的高度,單位為像素 bitsPerComponent 內存中像素的每個組件的位數.例如,對于32位像素格式和RGB 顏色空間,你應該將這個值設為8。 bytesPerRow bitmap的每一行在內存所占的比特數,一個像素一個byte。 colorspace bitmap上下文使用的顏色空間。 bitmapInfo 指定bitmap是否包含alpha通道,像素中alpha通道的相對位置,像素組件是整形還是浮點型等信息的字符串。 */- CGBitmapInfo講解
CGBitmapInfo由兩部分取或運算組成,一部分是指定 cpu使用的大小端模式,另一部分指定的是顏色空間中每個 bule green red alpha 的排列順序。
typedef CF_ENUM(uint32_t, CGImageByteOrderInfo) {kCGImageByteOrderMask = 0x7000,kCGImageByteOrderDefault = (0 << 12),kCGImageByteOrder16Little = (1 << 12),kCGImageByteOrder32Little = (2 << 12),kCGImageByteOrder16Big = (3 << 12),kCGImageByteOrder32Big = (4 << 12) } CG_AVAILABLE_STARTING(10.0, 2.0);typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {kCGImageAlphaNone, /* For example, RGB. */kCGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */kCGImageAlphaLast, /* For example, non-premultiplied RGBA */kCGImageAlphaFirst, /* For example, non-premultiplied ARGB */kCGImageAlphaNoneSkipLast, /* For example, RBGX. */kCGImageAlphaNoneSkipFirst, /* For example, XRGB. */kCGImageAlphaOnly /* No color data, alpha data only */ };typedef CF_OPTIONS(uint32_t, CGBitmapInfo) {kCGBitmapAlphaInfoMask = 0x1F,kCGBitmapFloatInfoMask = 0xF00, kCGBitmapFloatComponents = (1 << 8), // 浮點型表示kCGBitmapByteOrderMask = kCGImageByteOrderMask,kCGBitmapByteOrderDefault = kCGImageByteOrderDefault, // 默認kCGBitmapByteOrder16Little = kCGImageByteOrder16Little, // 16 位小端kCGBitmapByteOrder32Little = kCGImageByteOrder32Little, // 32 位小端kCGBitmapByteOrder16Big = kCGImageByteOrder16Big, // 16 位大端kCGBitmapByteOrder32Big = kCGImageByteOrder32Big // 32 位大端 } CG_AVAILABLE_STARTING(10.0, 2.0); // Big、Little 大端和小端分別 // 大端表示低字節放在高地址,高字節放在低地址 // 小端表示高字節放在高地址,低字節放在低地址顏色空間的格式 RGB肯定要連續排序,唯一可能的變化是A的存放位置,A存放位置有兩種可能:
情況一:A放在RGB之后RGBA 對應iOS的CGImageAlphaInfo為AlphaLast.
(對于32位圖像,4個字節表示一個像素,每8位表示一個顏色。)
情況二:A放在RGB前面ARGB 對應iOS的CGImageAlphaInfo為AlphaFirst
?再聯系上大小端,那么
對于情況一:A放在RGB之后RGBA?
對于大端對齊的cpu其像素存儲格式是 0xRGBA?
對于小端對齊的cpu其像素存儲格式是 0xABGR
對于情況二:A放在RGB前面ARGB
對于大端對齊的cpu其像素存儲格式是 0xARGB
對于小端對齊的cpu其像素存儲格式是 0xBGRA
另外:Alpha通道的作用
?IOS是小端序,所以kCGBitmapByteOrder16Host就是?kCGBitmapByteOrder16Little。
3)創建RGBA16Float類型的紋理對象(MTLTexture)
通過newTextureWithDescriptor方法使用一塊新的用于存放texture image data的內存來創建 MTLTexture紋理對象,該api中通過 MTLTextureDescriptor 來描述texture的屬性
創建 MTLTexture的時候 MTLTextureDescriptor 被用于定義屬性,包括圖像尺寸(寬、高、深度)、pixel format、arrangement(array、cubemap)以及mipmap的數量。MTLTextureDescriptor 值在創建 MTLTexture 的時候有用,當創建完畢后, 改變 MTLTextureDescriptor 的屬性將對已經創建的 texture 沒有任何影響。也就是說,當紋理對象創建完成后,它的大多數屬性,比如大小,新類型,像素格式都是不能改變的,但是紋理的像素數據是可以改變。
- 創建一個包含 texture 屬性的 MTLTextureDescriptor :
- textureType 表示 texture的dimensionality 和 arrangement(array or cube)
- width、height、depth用于表明 texture base level mipmap中每一個dimension的pixel size
- pixelFormat表明 texture中的像素存儲方式
- arrayLength 表明 MTLTextureType1DArray or MTLTextureType2DArray 類型 texture的數組元素的數量
- mipmapLevelCount 表明texture mipmap的數量
- sampleCount 表明每個pixel的對應的sample數量
- resourceOptions 表明內存分配的方式
- 通過 MTLDevice 的 newTextureWithDescriptor: 方法根據 MTLTextureDescriptor 創建一個texture。創建完畢后,如果要復制內存的像素數據到紋理中,調用 replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:?方法來加載texture image data
?4)將EDR的像素數據加到紋理中。
利用CGBitmapContextGetData獲取EDR圖像數據,并用replaceRegion設置EDR紋理。
5)使用metal管線渲染EDR
?【相關鏈接】
bilibili講解的文字版描述:?WWDC 2022 音視頻相關 Session 概覽(EDR 相關)丨音視頻工程示例 - 掘金
bilibili講解:【中文字幕】Apple:EDR是如何工作的?HDR渲染之道 | Explore HDR rendering with EDR_嗶哩嗶哩_bilibili
w3講解EDR:http://3ms.huawei.com/hi/group/1004055/wiki_6221842.html
Apple’s “EDR” Brings High Dynamic Range to Non-HDR Displays — Prolost
微信公眾號講解:?https://mp.weixin.qq.com/s/EgJkGimBs5AF1n3O4KqYog
總結
以上是生活随笔為你收集整理的【HDR学习】苹果EDR技术洞察(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件测试工作的感想怎么写,软件测试工作中
- 下一篇: 广东技术师范大学一行来访虹科并进行“见习