Added the Chrome HDR tonemap operator

Also added support for the SDL_PIXELFORMAT_XBGR2101010 pixel format to the D3D12, D3D11, and Metal renderers.
This commit is contained in:
Sam Lantinga
2024-02-21 09:03:03 -08:00
parent 4ba6aeee9d
commit 54c2ba6afd
50 changed files with 15111 additions and 21123 deletions

View File

@@ -75,21 +75,41 @@ typedef struct
Float4X4 projectionAndView;
} VertexShaderConstants;
/* These should mirror the definitions in D3D11_PixelShader_Common.incl */
//static const float TONEMAP_NONE = 0;
//static const float TONEMAP_LINEAR = 1;
static const float TONEMAP_CHROME = 2;
//static const float TEXTURETYPE_NONE = 0;
static const float TEXTURETYPE_RGB = 1;
static const float TEXTURETYPE_NV12 = 2;
static const float TEXTURETYPE_NV21 = 3;
static const float TEXTURETYPE_YUV = 4;
static const float INPUTTYPE_UNSPECIFIED = 0;
static const float INPUTTYPE_SRGB = 1;
static const float INPUTTYPE_SCRGB = 2;
static const float INPUTTYPE_HDR10 = 3;
typedef struct
{
float scRGB_output;
float texture_type;
float input_type;
float color_scale;
float unused1;
float unused2;
float tonemap_method;
float tonemap_factor1;
float tonemap_factor2;
float sdr_white_point;
float YCbCr_matrix[16];
} PixelShaderConstants;
typedef struct
{
ID3D11Buffer *constants;
SDL_bool scRGB_output;
float color_scale;
const float *shader_params;
PixelShaderConstants shader_constants;
} PixelShaderState;
/* Per-vertex data */
@@ -112,7 +132,7 @@ typedef struct
int lockedTexturePositionY;
D3D11_FILTER scaleMode;
D3D11_Shader shader;
const float *shader_params;
const float *YCbCr_matrix;
#if SDL_HAVE_YUV
/* YV12 texture support */
SDL_bool yuv;
@@ -245,6 +265,8 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 color
switch (format) {
case SDL_PIXELFORMAT_RGBA64_FLOAT:
return DXGI_FORMAT_R16G16B16A16_FLOAT;
case SDL_PIXELFORMAT_XBGR2101010:
return DXGI_FORMAT_R10G10B10A2_UNORM;
case SDL_PIXELFORMAT_ARGB8888:
if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
@@ -263,8 +285,6 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 color
return DXGI_FORMAT_NV12;
case SDL_PIXELFORMAT_P010:
return DXGI_FORMAT_P010;
case SDL_PIXELFORMAT_P016:
return DXGI_FORMAT_P016;
default:
return DXGI_FORMAT_UNKNOWN;
}
@@ -275,6 +295,8 @@ static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uin
switch (format) {
case SDL_PIXELFORMAT_RGBA64_FLOAT:
return DXGI_FORMAT_R16G16B16A16_FLOAT;
case SDL_PIXELFORMAT_XBGR2101010:
return DXGI_FORMAT_R10G10B10A2_UNORM;
case SDL_PIXELFORMAT_ARGB8888:
if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
@@ -291,7 +313,6 @@ static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uin
case SDL_PIXELFORMAT_NV21: /* For the Y texture */
return DXGI_FORMAT_R8_UNORM;
case SDL_PIXELFORMAT_P010: /* For the Y texture */
case SDL_PIXELFORMAT_P016: /* For the Y texture */
return DXGI_FORMAT_R16_UNORM;
default:
return DXGI_FORMAT_UNKNOWN;
@@ -1267,14 +1288,17 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
/* NV12 textures must have even width and height */
if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21 ||
texture->format == SDL_PIXELFORMAT_P010 ||
texture->format == SDL_PIXELFORMAT_P016) {
texture->format == SDL_PIXELFORMAT_P010) {
textureDesc.Width = (textureDesc.Width + 1) & ~1;
textureDesc.Height = (textureDesc.Height + 1) & ~1;
}
textureData->w = (int)textureDesc.Width;
textureData->h = (int)textureDesc.Height;
textureData->shader = SHADER_RGB;
if (SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_SRGB) {
textureData->shader = SHADER_RGB;
} else {
textureData->shader = SHADER_ADVANCED;
}
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
@@ -1339,53 +1363,28 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
}
SDL_SetProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_V_POINTER, textureData->mainTextureV);
textureData->shader = SHADER_YUV;
textureData->shader_params = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8);
if (!textureData->shader_params) {
textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8);
if (!textureData->YCbCr_matrix) {
return SDL_SetError("Unsupported YUV colorspace");
}
}
if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21 ||
texture->format == SDL_PIXELFORMAT_P010 ||
texture->format == SDL_PIXELFORMAT_P016) {
texture->format == SDL_PIXELFORMAT_P010) {
int bits_per_pixel;
textureData->nv12 = SDL_TRUE;
switch (texture->format) {
case SDL_PIXELFORMAT_NV12:
textureData->shader = SHADER_NV12;
break;
case SDL_PIXELFORMAT_NV21:
textureData->shader = SHADER_NV21;
break;
case SDL_PIXELFORMAT_P010:
case SDL_PIXELFORMAT_P016:
if(SDL_COLORSPACEPRIMARIES(texture->colorspace) == SDL_COLOR_PRIMARIES_BT2020 &&
SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) {
textureData->shader = SHADER_HDR10;
} else {
return SDL_SetError("Unsupported YUV colorspace");
}
break;
default:
/* This should never happen because of the check above */
return SDL_SetError("Unsupported YUV colorspace");
}
switch (texture->format) {
case SDL_PIXELFORMAT_P010:
bits_per_pixel = 10;
break;
case SDL_PIXELFORMAT_P016:
bits_per_pixel = 16;
break;
default:
bits_per_pixel = 8;
break;
}
textureData->shader_params = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel);
if (!textureData->shader_params) {
textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel);
if (!textureData->YCbCr_matrix) {
return SDL_SetError("Unsupported YUV colorspace");
}
}
@@ -1425,7 +1424,7 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
if (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21) {
nvResourceViewDesc.Format = DXGI_FORMAT_R8G8_UNORM;
} else if (texture->format == SDL_PIXELFORMAT_P010 || texture->format == SDL_PIXELFORMAT_P016) {
} else if (texture->format == SDL_PIXELFORMAT_P010) {
nvResourceViewDesc.Format = DXGI_FORMAT_R16G16_UNORM;
}
@@ -1503,8 +1502,7 @@ static int D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Tex
stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
if (stagingTextureDesc.Format == DXGI_FORMAT_NV12 ||
stagingTextureDesc.Format == DXGI_FORMAT_P010 ||
stagingTextureDesc.Format == DXGI_FORMAT_P016) {
stagingTextureDesc.Format == DXGI_FORMAT_P010) {
stagingTextureDesc.Width = (stagingTextureDesc.Width + 1) & ~1;
stagingTextureDesc.Height = (stagingTextureDesc.Height + 1) & ~1;
}
@@ -1548,8 +1546,7 @@ static int D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Tex
}
if (stagingTextureDesc.Format == DXGI_FORMAT_NV12 ||
stagingTextureDesc.Format == DXGI_FORMAT_P010 ||
stagingTextureDesc.Format == DXGI_FORMAT_P016) {
stagingTextureDesc.Format == DXGI_FORMAT_P010) {
/* Copy the UV plane as well */
h = (h + 1) / 2;
length = (length + 1) & ~1;
@@ -2170,8 +2167,71 @@ static ID3D11RenderTargetView *D3D11_GetCurrentRenderTargetView(SDL_Renderer *re
}
}
static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Texture *texture, PixelShaderConstants *constants)
{
float output_headroom;
SDL_zerop(constants);
constants->scRGB_output = (float)SDL_RenderingLinearSpace(renderer);
constants->color_scale = cmd->data.draw.color_scale;
if (texture) {
D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata;
switch (texture->format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
constants->texture_type = TEXTURETYPE_YUV;
constants->input_type = INPUTTYPE_SRGB;
break;
case SDL_PIXELFORMAT_NV12:
constants->texture_type = TEXTURETYPE_NV12;
constants->input_type = INPUTTYPE_SRGB;
break;
case SDL_PIXELFORMAT_NV21:
constants->texture_type = TEXTURETYPE_NV21;
constants->input_type = INPUTTYPE_SRGB;
break;
case SDL_PIXELFORMAT_P010:
constants->texture_type = TEXTURETYPE_NV12;
constants->input_type = INPUTTYPE_HDR10;
break;
default:
constants->texture_type = TEXTURETYPE_RGB;
if (texture->colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
constants->input_type = INPUTTYPE_SCRGB;
} else if (SDL_COLORSPACEPRIMARIES(texture->colorspace) == SDL_COLOR_PRIMARIES_BT2020 &&
SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) {
constants->input_type = INPUTTYPE_HDR10;
} else {
constants->input_type = INPUTTYPE_UNSPECIFIED;
}
break;
}
constants->sdr_white_point = texture->SDR_white_point;
if (renderer->target) {
output_headroom = renderer->target->HDR_headroom;
} else {
output_headroom = renderer->HDR_headroom;
}
if (texture->HDR_headroom > output_headroom) {
constants->tonemap_method = TONEMAP_CHROME;
constants->tonemap_factor1 = (output_headroom / (texture->HDR_headroom * texture->HDR_headroom));
constants->tonemap_factor2 = (1.0f / output_headroom);
}
if (textureData->YCbCr_matrix) {
SDL_memcpy(constants->YCbCr_matrix, textureData->YCbCr_matrix, sizeof(constants->YCbCr_matrix));
}
}
}
static int D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd,
D3D11_Shader shader, const float *shader_params,
D3D11_Shader shader, const PixelShaderConstants *shader_constants,
const int numShaderResources, ID3D11ShaderResourceView **shaderResources,
ID3D11SamplerState *sampler, const Float4X4 *matrix)
@@ -2184,9 +2244,8 @@ static int D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *c
const SDL_BlendMode blendMode = cmd->data.draw.blend;
ID3D11BlendState *blendState = NULL;
SDL_bool updateSubresource = SDL_FALSE;
SDL_bool scRGB_output = SDL_RenderingLinearSpace(renderer);
float color_scale = cmd->data.draw.color_scale;
PixelShaderState *shader_state = &rendererData->currentShaderState[shader];
PixelShaderConstants solid_constants;
if (numShaderResources > 0) {
shaderResource = shaderResources[0];
@@ -2260,37 +2319,31 @@ static int D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *c
rendererData->currentBlendState = blendState;
}
if (!shader_state->constants ||
scRGB_output != shader_state->scRGB_output ||
color_scale != shader_state->color_scale ||
shader_params != shader_state->shader_params) {
SAFE_RELEASE(shader_state->constants);
if (!shader_constants) {
D3D11_SetupShaderConstants(renderer, cmd, NULL, &solid_constants);
shader_constants = &solid_constants;
}
PixelShaderConstants constants;
constants.scRGB_output = (float)scRGB_output;
constants.color_scale = color_scale;
if (shader_params) {
SDL_memcpy(constants.YCbCr_matrix, shader_params, sizeof(constants.YCbCr_matrix));
}
if (!shader_state->constants ||
SDL_memcmp(shader_constants, &shader_state->shader_constants, sizeof(*shader_constants)) != 0) {
SAFE_RELEASE(shader_state->constants);
D3D11_BUFFER_DESC desc;
SDL_zero(desc);
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ByteWidth = sizeof(constants);
desc.ByteWidth = sizeof(*shader_constants);
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
D3D11_SUBRESOURCE_DATA data;
SDL_zero(data);
data.pSysMem = &constants;
data.pSysMem = shader_constants;
HRESULT result = ID3D11Device_CreateBuffer(rendererData->d3dDevice, &desc, &data, &shader_state->constants);
if (FAILED(result)) {
WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device::CreateBuffer [create shader constants]"), result);
return -1;
}
shader_state->scRGB_output = scRGB_output;
shader_state->color_scale = color_scale;
shader_state->shader_params = shader_params;
SDL_memcpy(&shader_state->shader_constants, shader_constants, sizeof(*shader_constants));
/* Force the shader parameters to be re-set */
rendererData->currentShader = SHADER_NONE;
@@ -2302,8 +2355,8 @@ static int D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *c
}
}
ID3D11DeviceContext_PSSetShader(rendererData->d3dContext, rendererData->pixelShaders[shader], NULL, 0);
if (rendererData->currentShaderState[shader].constants) {
ID3D11DeviceContext_PSSetConstantBuffers(rendererData->d3dContext, 0, 1, &rendererData->currentShaderState[shader].constants);
if (shader_state->constants) {
ID3D11DeviceContext_PSSetConstantBuffers(rendererData->d3dContext, 0, 1, &shader_state->constants);
}
rendererData->currentShader = shader;
}
@@ -2336,6 +2389,9 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata;
ID3D11SamplerState *textureSampler;
PixelShaderConstants constants;
D3D11_SetupShaderConstants(renderer, cmd, texture, &constants);
switch (textureData->scaleMode) {
case D3D11_FILTER_MIN_MAG_MIP_POINT:
@@ -2355,7 +2411,7 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
shaderResources[1] = textureData->mainTextureResourceViewU;
shaderResources[2] = textureData->mainTextureResourceViewV;
return D3D11_SetDrawState(renderer, cmd, textureData->shader, textureData->shader_params,
return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants,
SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
} else if (textureData->nv12) {
@@ -2364,11 +2420,11 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
shaderResources[0] = textureData->mainTextureResourceView;
shaderResources[1] = textureData->mainTextureResourceViewNV;
return D3D11_SetDrawState(renderer, cmd, textureData->shader, textureData->shader_params,
return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants,
SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
}
#endif /* SDL_HAVE_YUV */
return D3D11_SetDrawState(renderer, cmd, textureData->shader, textureData->shader_params,
return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants,
1, &textureData->mainTextureResourceView, textureSampler, matrix);
}
@@ -2791,13 +2847,13 @@ SDL_RenderDriver D3D11_RenderDriver = {
{ /* texture_formats */
SDL_PIXELFORMAT_ARGB8888,
SDL_PIXELFORMAT_XRGB8888,
SDL_PIXELFORMAT_XBGR2101010,
SDL_PIXELFORMAT_RGBA64_FLOAT,
SDL_PIXELFORMAT_YV12,
SDL_PIXELFORMAT_IYUV,
SDL_PIXELFORMAT_NV12,
SDL_PIXELFORMAT_NV21,
SDL_PIXELFORMAT_P010,
SDL_PIXELFORMAT_P016 },
SDL_PIXELFORMAT_P010 },
0, /* max_texture_width: will be filled in later */
0 /* max_texture_height: will be filled in later */
}