Added support for HDR10 video on Apple platforms

This commit is contained in:
Sam Lantinga 2024-02-06 15:25:05 -08:00
parent 2039c46d2c
commit 8afba41aef
9 changed files with 12433 additions and 10240 deletions

View File

@ -76,7 +76,9 @@ static const size_t CONSTANTS_OFFSET_DECODE_BT601_LIMITED = ALIGN_CONSTANTS(16,
static const size_t CONSTANTS_OFFSET_DECODE_BT601_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT601_LIMITED + sizeof(float) * 4 * 4);
static const size_t CONSTANTS_OFFSET_DECODE_BT709_LIMITED = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT601_FULL + sizeof(float) * 4 * 4);
static const size_t CONSTANTS_OFFSET_DECODE_BT709_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT709_LIMITED + sizeof(float) * 4 * 4);
static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT709_FULL + sizeof(float) * 4 * 4;
static const size_t CONSTANTS_OFFSET_DECODE_BT2020_LIMITED = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT709_FULL + sizeof(float) * 4 * 4);
static const size_t CONSTANTS_OFFSET_DECODE_BT2020_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT2020_LIMITED + sizeof(float) * 4 * 4);
static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT2020_FULL + sizeof(float) * 4 * 4;
typedef enum SDL_MetalVertexFunction
{
@ -91,6 +93,7 @@ typedef enum SDL_MetalFragmentFunction
SDL_METAL_FRAGMENT_YUV,
SDL_METAL_FRAGMENT_NV12,
SDL_METAL_FRAGMENT_NV21,
SDL_METAL_FRAGMENT_HDR10,
SDL_METAL_FRAGMENT_COUNT,
} SDL_MetalFragmentFunction;
@ -248,6 +251,8 @@ static NSString *GetFragmentFunctionName(SDL_MetalFragmentFunction function)
return @"SDL_NV12_fragment";
case SDL_METAL_FRAGMENT_NV21:
return @"SDL_NV21_fragment";
case SDL_METAL_FRAGMENT_HDR10:
return @"SDL_HDR10_fragment";
default:
return nil;
}
@ -387,6 +392,7 @@ void MakeShaderPipelines(METAL_RenderData *data, METAL_ShaderPipelines *pipeline
MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_YUV], "SDL YUV pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_YUV);
MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_NV12], "SDL NV12 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV12);
MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_NV21], "SDL NV21 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV21);
MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_HDR10], "SDL HDR10 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_HDR10);
}
static METAL_ShaderPipelines *ChooseShaderPipelines(METAL_RenderData *data, MTLPixelFormat rtformat)
@ -551,10 +557,8 @@ size_t GetBT601ConversionMatrix( SDL_Colorspace colorspace )
case SDL_COLOR_RANGE_LIMITED:
case SDL_COLOR_RANGE_UNKNOWN:
return CONSTANTS_OFFSET_DECODE_BT601_LIMITED;
break;
case SDL_COLOR_RANGE_FULL:
return CONSTANTS_OFFSET_DECODE_BT601_FULL;
break;
default:
break;
}
@ -567,10 +571,8 @@ size_t GetBT709ConversionMatrix(SDL_Colorspace colorspace)
case SDL_COLOR_RANGE_LIMITED:
case SDL_COLOR_RANGE_UNKNOWN:
return CONSTANTS_OFFSET_DECODE_BT709_LIMITED;
break;
case SDL_COLOR_RANGE_FULL:
return CONSTANTS_OFFSET_DECODE_BT709_FULL;
break;
default:
break;
}
@ -582,11 +584,9 @@ size_t GetBT2020ConversionMatrix(SDL_Colorspace colorspace)
switch (SDL_COLORSPACERANGE(colorspace)) {
case SDL_COLOR_RANGE_LIMITED:
case SDL_COLOR_RANGE_UNKNOWN:
return 0;
break;
return CONSTANTS_OFFSET_DECODE_BT2020_LIMITED;
case SDL_COLOR_RANGE_FULL:
return 0;
break;
return CONSTANTS_OFFSET_DECODE_BT2020_FULL;
default:
break;
}
@ -671,6 +671,9 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
case SDL_PIXELFORMAT_NV21:
pixfmt = MTLPixelFormatR8Unorm;
break;
case SDL_PIXELFORMAT_P010:
pixfmt = MTLPixelFormatR16Unorm;
break;
case SDL_PIXELFORMAT_RGBA64_FLOAT:
pixfmt = MTLPixelFormatRGBA16Float;
break;
@ -706,8 +709,8 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
mtltextureUv = nil;
#if SDL_HAVE_YUV
yuv = (texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12);
nv12 = (texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21);
yuv = (texture->format == SDL_PIXELFORMAT_IYUV || texture->format == SDL_PIXELFORMAT_YV12);
nv12 = (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21 || texture->format == SDL_PIXELFORMAT_P010);
if (yuv) {
mtltexdesc.pixelFormat = MTLPixelFormatR8Unorm;
@ -715,6 +718,10 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
mtltexdesc.height = (texture->h + 1) / 2;
mtltexdesc.textureType = MTLTextureType2DArray;
mtltexdesc.arrayLength = 2;
} else if (texture->format == SDL_PIXELFORMAT_P010) {
mtltexdesc.pixelFormat = MTLPixelFormatRG16Unorm;
mtltexdesc.width = (texture->w + 1) / 2;
mtltexdesc.height = (texture->h + 1) / 2;
} else if (nv12) {
mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
mtltexdesc.width = (texture->w + 1) / 2;
@ -750,6 +757,8 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12;
} else if (texture->format == SDL_PIXELFORMAT_NV21) {
texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21;
} else if (texture->format == SDL_PIXELFORMAT_P010) {
texturedata.fragmentFunction = SDL_METAL_FRAGMENT_HDR10;
} else
#endif
{
@ -2011,6 +2020,8 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601_FULL, SDL_GetYCbCRtoRGBConversionMatrix(SDL_COLORSPACE_BT601_FULL, 0, 0, 8), YCbCr_shader_matrix_size);
SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709_LIMITED, SDL_GetYCbCRtoRGBConversionMatrix(SDL_COLORSPACE_BT709_LIMITED, 0, 0, 8), YCbCr_shader_matrix_size);
SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709_FULL, SDL_GetYCbCRtoRGBConversionMatrix(SDL_COLORSPACE_BT709_FULL, 0, 0, 8), YCbCr_shader_matrix_size);
SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT2020_LIMITED, SDL_GetYCbCRtoRGBConversionMatrix(SDL_COLORSPACE_BT2020_LIMITED, 0, 0, 10), YCbCr_shader_matrix_size);
SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT2020_FULL, SDL_GetYCbCRtoRGBConversionMatrix(SDL_COLORSPACE_BT2020_FULL, 0, 0, 10), YCbCr_shader_matrix_size);
mtlbufquadindicesstaging = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModeShared];
@ -2139,7 +2150,7 @@ SDL_RenderDriver METAL_RenderDriver = {
{
"metal",
(SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
8,
9,
{ SDL_PIXELFORMAT_ARGB8888,
SDL_PIXELFORMAT_ABGR8888,
SDL_PIXELFORMAT_RGBA64_FLOAT,
@ -2147,7 +2158,8 @@ SDL_RenderDriver METAL_RenderDriver = {
SDL_PIXELFORMAT_YV12,
SDL_PIXELFORMAT_IYUV,
SDL_PIXELFORMAT_NV12,
SDL_PIXELFORMAT_NV21 },
SDL_PIXELFORMAT_NV21,
SDL_PIXELFORMAT_P010 },
0,
0,
}

View File

@ -34,6 +34,19 @@ float sRGBfromLinear(float v)
return v;
}
float3 PQtoNits(float3 v)
{
const float c1 = 0.8359375;
const float c2 = 18.8515625;
const float c3 = 18.6875;
const float oo_m1 = 1.0 / 0.1593017578125;
const float oo_m2 = 1.0 / 78.84375;
float3 num = max(pow(abs(v), oo_m2) - c1, 0.0);
float3 den = c2 - c3 * pow(abs(v), oo_m2);
return 10000.0 * pow(abs(num / den), oo_m1);
}
float4 GetOutputColor(float4 rgba, float color_scale)
{
float4 output;
@ -215,3 +228,35 @@ fragment float4 SDL_NV21_fragment(CopyVertexOutput vert [[stage_in]],
return GetOutputColorFromSRGB(rgb, c.scRGB_output, c.color_scale) * vert.color;
}
fragment float4 SDL_HDR10_fragment(CopyVertexOutput vert [[stage_in]],
constant ShaderConstants &c [[buffer(0)]],
constant YUVDecode &decode [[buffer(1)]],
texture2d<float> texY [[texture(0)]],
texture2d<float> texUV [[texture(1)]],
sampler s [[sampler(0)]])
{
const float3x3 mat2020to709 = {
{ 1.660496, -0.587656, -0.072840 },
{ -0.124547, 1.132895, -0.008348 },
{ -0.018154, -0.100597, 1.118751 }
};
float3 yuv;
yuv.x = texY.sample(s, vert.texcoord).r;
yuv.yz = texUV.sample(s, vert.texcoord).rg;
float3 rgb;
yuv += decode.offset;
rgb.r = dot(yuv, decode.Rcoeff);
rgb.g = dot(yuv, decode.Gcoeff);
rgb.b = dot(yuv, decode.Bcoeff);
rgb = PQtoNits(rgb);
rgb = rgb * mat2020to709;
rgb = scRGBfromNits(rgb);
return GetOutputColorFromSCRGB(rgb, c.scRGB_output, c.color_scale) * vert.color;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -815,10 +815,8 @@ static const float *SDL_GetBT601ConversionMatrix( SDL_Colorspace colorspace )
case SDL_COLOR_RANGE_LIMITED:
case SDL_COLOR_RANGE_UNKNOWN:
return mat_BT601_Limited_8bit;
break;
case SDL_COLOR_RANGE_FULL:
return mat_BT601_Full_8bit;
break;
default:
break;
}
@ -831,10 +829,8 @@ static const float *SDL_GetBT709ConversionMatrix(SDL_Colorspace colorspace)
case SDL_COLOR_RANGE_LIMITED:
case SDL_COLOR_RANGE_UNKNOWN:
return mat_BT709_Limited_8bit;
break;
case SDL_COLOR_RANGE_FULL:
return mat_BT709_Full_8bit;
break;
default:
break;
}
@ -847,10 +843,8 @@ static const float *SDL_GetBT2020ConversionMatrix(SDL_Colorspace colorspace)
case SDL_COLOR_RANGE_LIMITED:
case SDL_COLOR_RANGE_UNKNOWN:
return mat_BT2020_Limited_10bit;
break;
case SDL_COLOR_RANGE_FULL:
return mat_BT2020_Full_10bit;
break;
default:
break;
}

View File

@ -759,6 +759,11 @@ static SDL_bool GetTextureForVideoToolboxFrame(AVFrame *frame, SDL_Texture **tex
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
format = SDL_PIXELFORMAT_NV12;
break;
case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
format = SDL_PIXELFORMAT_P010;
HDR_video = SDL_TRUE;
break;
default:
SDL_SetError("Unsupported texture format %c%c%c%c",
(char)((nPixelBufferType >> 24) & 0xFF),