diff --git a/include/SDL3/SDL_pixels.h b/include/SDL3/SDL_pixels.h index ecbc129f6d..f53cd7f644 100644 --- a/include/SDL3/SDL_pixels.h +++ b/include/SDL3/SDL_pixels.h @@ -558,6 +558,8 @@ typedef enum typedef enum { SDL_COLORSPACE_UNKNOWN, + + /* sRGB is a gamma corrected colorspace, and the default colorspace for SDL rendering and 8-bit RGB surfaces */ SDL_COLORSPACE_SRGB = /**< Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 */ SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_RGB, SDL_COLOR_RANGE_FULL, @@ -565,6 +567,8 @@ typedef enum SDL_TRANSFER_CHARACTERISTICS_SRGB, SDL_MATRIX_COEFFICIENTS_UNSPECIFIED, SDL_CHROMA_LOCATION_NONE), + + /* scRGB is a linear colorspace and the default colorspace for floating point surfaces */ SDL_COLORSPACE_SCRGB = /**< Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 */ SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_RGB, SDL_COLOR_RANGE_FULL, @@ -572,6 +576,8 @@ typedef enum SDL_TRANSFER_CHARACTERISTICS_LINEAR, SDL_MATRIX_COEFFICIENTS_UNSPECIFIED, SDL_CHROMA_LOCATION_NONE), + + /* HDR10 is a non-linear HDR colorspace and the default colorspace for 10-bit surfaces */ SDL_COLORSPACE_HDR10 = /**< Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 */ SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_RGB, SDL_COLOR_RANGE_FULL, @@ -579,6 +585,7 @@ typedef enum SDL_TRANSFER_CHARACTERISTICS_PQ, SDL_MATRIX_COEFFICIENTS_UNSPECIFIED, SDL_CHROMA_LOCATION_NONE), + SDL_COLORSPACE_BT601_LIMITED = /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 */ SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, SDL_COLOR_RANGE_LIMITED, @@ -586,6 +593,7 @@ typedef enum SDL_TRANSFER_CHARACTERISTICS_BT601, SDL_MATRIX_COEFFICIENTS_BT601, SDL_CHROMA_LOCATION_LEFT), + SDL_COLORSPACE_BT601_FULL = /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 */ SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, SDL_COLOR_RANGE_FULL, @@ -593,6 +601,7 @@ typedef enum SDL_TRANSFER_CHARACTERISTICS_BT601, SDL_MATRIX_COEFFICIENTS_BT601, SDL_CHROMA_LOCATION_LEFT), + SDL_COLORSPACE_BT709_LIMITED = /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 */ SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, SDL_COLOR_RANGE_LIMITED, @@ -600,6 +609,7 @@ typedef enum SDL_TRANSFER_CHARACTERISTICS_BT709, SDL_MATRIX_COEFFICIENTS_BT709, SDL_CHROMA_LOCATION_LEFT), + SDL_COLORSPACE_BT709_FULL = /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 */ SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR, SDL_COLOR_RANGE_FULL, diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index 5ad57210cb..4b04982801 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -240,15 +240,9 @@ extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window, co * is displayed, if you want a software renderer without a window * - `SDL_PROP_RENDERER_CREATE_NAME_STRING`: the name of the rendering driver * to use, if a specific one is desired - * - `SDL_PROP_RENDERER_CREATE_INPUT_COLORSPACE_NUMBER`: an SDL_ColorSpace - * value describing the colorspace for input colors, defaults to - * SDL_COLORSPACE_SRGB * - `SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER`: an SDL_ColorSpace * value describing the colorspace for output to the display, defaults to - * SDL_COLORSPACE_SRGB - * - `SDL_PROP_RENDERER_CREATE_COLORSPACE_CONVERSION_BOOLEAN`: true if you - * want conversion between the input colorspace and the output colorspace, - * defaults to SDL_TRUE + * SDL_COLORSPACE_SRGB. The direct3d11 and direct3d12 renderers support SDL_COLORSPACE_SCRGB, which is a linear color space and supports HDR output. * - `SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_BOOLEAN`: true if you want * present synchronized with the refresh rate * @@ -273,9 +267,7 @@ extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_Prop #define SDL_PROP_RENDERER_CREATE_WINDOW_POINTER "window" #define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER "surface" #define SDL_PROP_RENDERER_CREATE_NAME_STRING "name" -#define SDL_PROP_RENDERER_CREATE_INPUT_COLORSPACE_NUMBER "input_colorspace" #define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER "output_colorspace" -#define SDL_PROP_RENDERER_CREATE_COLORSPACE_CONVERSION_BOOLEAN "colorspace_conversion" #define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_BOOLEAN "present_vsync" /** @@ -1360,44 +1352,6 @@ extern DECLSPEC int SDLCALL SDL_SetRenderScale(SDL_Renderer *renderer, float sca */ extern DECLSPEC int SDLCALL SDL_GetRenderScale(SDL_Renderer *renderer, float *scaleX, float *scaleY); -/** - * Set the colorspace used for drawing operations - * - * The default colorspace for drawing operations is SDL_COLORSPACE_SRGB, but - * you can change it to other colorspaces such as SDL_COLORSPACE_SCRGB for HDR - * rendering. - * - * This does not affect the colorspace of textures, which is specified via - * properties when the texture is created and does not change. - * - * \param renderer the rendering context - * \param colorspace an SDL_ColorSpace value describing the colorspace for - * drawing operations - * \returns 0 on success or a negative error code on failure; call - * SDL_GetError() for more information. - * - * \since This function is available since SDL 3.0.0. - * - * \sa SDL_GetRenderDrawColorspace - */ -extern DECLSPEC int SDLCALL SDL_SetRenderDrawColorspace(SDL_Renderer *renderer, SDL_Colorspace colorspace); - -/** - * Get the colorspace used for drawing operations - * - * \param renderer the rendering context - * \param colorspace a pointer filled in with an SDL_ColorSpace value - * describing the colorspace for drawing operations - * \returns 0 on success or a negative error code on failure; call - * SDL_GetError() for more information. - * - * \since This function is available since SDL 3.0.0. - * - * \sa SDL_SetRenderDrawColorspace - */ -extern DECLSPEC int SDLCALL SDL_GetRenderDrawColorspace(SDL_Renderer *renderer, SDL_Colorspace *colorspace); - - /** * Set the color used for drawing operations. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index c9d6cceebd..1dc5a5405e 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -969,8 +969,6 @@ SDL3_0.0.0 { SDL_SetSurfaceColorspace; SDL_GetSurfaceColorspace; SDL_ConvertSurfaceFormatAndColorspace; - SDL_SetRenderDrawColorspace; - SDL_GetRenderDrawColorspace; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 51530f6701..42a2e4846f 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -994,5 +994,3 @@ #define SDL_SetSurfaceColorspace SDL_SetSurfaceColorspace_REAL #define SDL_GetSurfaceColorspace SDL_GetSurfaceColorspace_REAL #define SDL_ConvertSurfaceFormatAndColorspace SDL_ConvertSurfaceFormatAndColorspace_REAL -#define SDL_SetRenderDrawColorspace SDL_SetRenderDrawColorspace_REAL -#define SDL_GetRenderDrawColorspace SDL_GetRenderDrawColorspace_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 8eb2f14d98..b6221bb51d 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1019,5 +1019,3 @@ SDL_DYNAPI_PROC(int,SDL_ConvertPixelsAndColorspace,(int a, int b, Uint32 c, SDL_ SDL_DYNAPI_PROC(int,SDL_SetSurfaceColorspace,(SDL_Surface *a, SDL_Colorspace b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_GetSurfaceColorspace,(SDL_Surface *a, SDL_Colorspace *b),(a,b),return) SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurfaceFormatAndColorspace,(SDL_Surface *a, Uint32 b, SDL_Colorspace c),(a,b,c),return) -SDL_DYNAPI_PROC(int,SDL_SetRenderDrawColorspace,(SDL_Renderer *a, SDL_Colorspace b),(a,b),return) -SDL_DYNAPI_PROC(int,SDL_GetRenderDrawColorspace,(SDL_Renderer *a, SDL_Colorspace *b),(a,b),return) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 2fc35c15aa..491e102bdc 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -128,9 +128,7 @@ char SDL_texture_magic; void SDL_SetupRendererColorspace(SDL_Renderer *renderer, SDL_PropertiesID props) { - renderer->input_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_INPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB); renderer->output_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB); - renderer->colorspace_conversion = SDL_GetBooleanProperty(props, SDL_PROP_RENDERER_CREATE_COLORSPACE_CONVERSION_BOOLEAN, SDL_TRUE); } static float sRGBtoLinear(float v) @@ -143,46 +141,33 @@ static float sRGBfromLinear(float v) return v <= 0.0031308f ? (v * 12.92f) : (SDL_powf(v, 1.0f / 2.4f) * 1.055f - 0.055f); } -void SDL_ConvertToLinear(SDL_Renderer *renderer, SDL_FColor *color) +SDL_bool SDL_RenderingLinearSpace(SDL_Renderer *renderer) { - if (!renderer->colorspace_conversion) { - return; - } + SDL_Colorspace colorspace; - switch (SDL_COLORSPACETRANSFER(renderer->input_colorspace)) { - case SDL_TRANSFER_CHARACTERISTICS_SRGB: - color->r = sRGBtoLinear(color->r); - color->g = sRGBtoLinear(color->g); - color->b = sRGBtoLinear(color->b); - break; - case SDL_TRANSFER_CHARACTERISTICS_LINEAR: - /* No conversion needed */ - break; - default: - /* Unsupported */ - break; + if (renderer->target) { + colorspace = renderer->target->colorspace; + } else { + colorspace = renderer->output_colorspace; } + if (colorspace == SDL_COLORSPACE_SCRGB) { + return SDL_TRUE; + } + return SDL_FALSE; } -void SDL_ConvertFromLinear(SDL_Renderer *renderer, SDL_FColor *color) +void SDL_ConvertToLinear(SDL_FColor *color) { - if (!renderer->colorspace_conversion) { - return; - } + color->r = sRGBtoLinear(color->r); + color->g = sRGBtoLinear(color->g); + color->b = sRGBtoLinear(color->b); +} - switch (SDL_COLORSPACETRANSFER(renderer->input_colorspace)) { - case SDL_TRANSFER_CHARACTERISTICS_SRGB: - color->r = sRGBfromLinear(color->r); - color->g = sRGBfromLinear(color->g); - color->b = sRGBfromLinear(color->b); - break; - case SDL_TRANSFER_CHARACTERISTICS_LINEAR: - /* No conversion needed */ - break; - default: - /* Unsupported */ - break; - } +void SDL_ConvertFromLinear(SDL_FColor *color) +{ + color->r = sRGBfromLinear(color->r); + color->g = sRGBfromLinear(color->g); + color->b = sRGBfromLinear(color->b); } static SDL_INLINE void DebugLogRenderCommands(const SDL_RenderCommand *cmd) @@ -1549,7 +1534,6 @@ int SDL_SetTextureColorModFloat(SDL_Texture *texture, float r, float g, float b) texture->color.r = r; texture->color.g = g; texture->color.b = b; - SDL_ConvertToLinear(texture->renderer, &texture->color); if (texture->native) { return SDL_SetTextureColorModFloat(texture->native, r, g, b); } @@ -1583,7 +1567,6 @@ int SDL_GetTextureColorModFloat(SDL_Texture *texture, float *r, float *g, float CHECK_TEXTURE_MAGIC(texture, -1); color = texture->color; - SDL_ConvertFromLinear(texture->renderer, &color); if (r) { *r = color.r; @@ -2785,30 +2768,6 @@ int SDL_GetRenderScale(SDL_Renderer *renderer, float *scaleX, float *scaleY) return 0; } -int SDL_SetRenderDrawColorspace(SDL_Renderer *renderer, SDL_Colorspace colorspace) -{ - CHECK_RENDERER_MAGIC(renderer, -1); - - if (colorspace != SDL_COLORSPACE_SRGB && - colorspace != SDL_COLORSPACE_SCRGB) { - return SDL_SetError("Unsupported colorspace"); - } - - renderer->input_colorspace = colorspace; - return 0; -} - -int SDL_GetRenderDrawColorspace(SDL_Renderer *renderer, SDL_Colorspace *colorspace) -{ - CHECK_RENDERER_MAGIC(renderer, -1); - - if (colorspace) { - *colorspace = renderer->input_colorspace; - } - return 0; -} - - int SDL_SetRenderDrawColor(SDL_Renderer *renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a) { const float fR = (float)r / 255.0f; @@ -2827,7 +2786,6 @@ int SDL_SetRenderDrawColorFloat(SDL_Renderer *renderer, float r, float g, float renderer->color.g = g; renderer->color.b = b; renderer->color.a = a; - SDL_ConvertToLinear(renderer, &renderer->color); return 0; } @@ -2861,7 +2819,6 @@ int SDL_GetRenderDrawColorFloat(SDL_Renderer *renderer, float *r, float *g, floa CHECK_RENDERER_MAGIC(renderer, -1); color = renderer->color; - SDL_ConvertFromLinear(renderer, &color); if (r) { *r = color.r; @@ -4163,24 +4120,6 @@ int SDL_RenderGeometryRaw(SDL_Renderer *renderer, indices, num_indices, size_indices); } - /* Transform the colors if necessary */ - if (renderer->colorspace_conversion && - SDL_COLORSPACETRANSFER(renderer->input_colorspace) == SDL_TRANSFER_CHARACTERISTICS_SRGB) { - int num_colors = (color_stride > 0) ? num_vertices : 1; - updated_colors = SDL_small_alloc(SDL_FColor, num_colors, &isstack); - if (!updated_colors) { - return -1; - } - for (i = 0; i < num_colors; ++i) { - updated_colors[i] = *(const SDL_FColor *)(((const Uint8 *)color) + i * color_stride); - SDL_ConvertToLinear(renderer, &updated_colors[i]); - } - color = updated_colors; - if (color_stride > 0) { - color_stride = sizeof(SDL_FColor); - } - } - retval = QueueCmdGeometry(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 58536876f3..0894fd3db4 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -250,9 +250,7 @@ struct SDL_Renderer SDL_Texture *target; SDL_Mutex *target_mutex; - SDL_Colorspace input_colorspace; SDL_Colorspace output_colorspace; - SDL_bool colorspace_conversion; SDL_FColor color; /**< Color for drawing operations values */ SDL_BlendMode blendMode; /**< The drawing blend mode */ @@ -303,8 +301,9 @@ extern SDL_RenderDriver VITA_GXM_RenderDriver; extern void SDL_SetupRendererColorspace(SDL_Renderer *renderer, SDL_PropertiesID props); /* Colorspace conversion functions */ -extern void SDL_ConvertToLinear(SDL_Renderer *renderer, SDL_FColor *color); -extern void SDL_ConvertFromLinear(SDL_Renderer *renderer, SDL_FColor *color); +extern SDL_bool SDL_RenderingLinearSpace(SDL_Renderer *renderer); +extern void SDL_ConvertToLinear(SDL_FColor *color); +extern void SDL_ConvertFromLinear(SDL_FColor *color); /* Blend mode functions */ extern SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode); diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index c5f103835e..3c61a192e3 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -214,18 +214,18 @@ Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) } } -static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 colorspace, SDL_bool colorspace_conversion) +static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 colorspace) { switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; case SDL_PIXELFORMAT_ARGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8X8_UNORM; @@ -240,18 +240,18 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 color } } -static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uint32 colorspace, SDL_bool colorspace_conversion) +static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uint32 colorspace) { switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; case SDL_PIXELFORMAT_ARGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8X8_UNORM; @@ -523,6 +523,7 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D11_DEBUG, SDL_FALSE)) { creationFlags |= D3D11_CREATE_DEVICE_DEBUG; } + creationFlags |= D3D11_CREATE_DEVICE_DEBUG; /* Create a single-threaded device unless the app requests otherwise. */ if (!SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) { @@ -893,23 +894,31 @@ static HRESULT D3D11_CreateSwapChain(SDL_Renderer *renderer, int w, int h) IDXGISwapChain3 *swapChain3 = NULL; if (SUCCEEDED(IDXGISwapChain1_QueryInterface(data->swapChain, &SDL_IID_IDXGISwapChain2, (void **)&swapChain3))) { - DXGI_COLOR_SPACE_TYPE ColorSpace; + UINT colorspace_support = 0; + DXGI_COLOR_SPACE_TYPE colorspace; switch (renderer->output_colorspace) { case SDL_COLORSPACE_SCRGB: - ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; break; case SDL_COLORSPACE_HDR10: - ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; break; default: /* sRGB */ - ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; break; } - result = IDXGISwapChain3_SetColorSpace1(swapChain3, ColorSpace); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain3::SetColorSpace1"), result); - goto done; + if (SUCCEEDED(IDXGISwapChain3_CheckColorSpaceSupport(swapChain3, colorspace, &colorspace_support)) && + (colorspace_support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { + result = IDXGISwapChain3_SetColorSpace1(swapChain3, colorspace); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain3::SetColorSpace1"), result); + goto done; + } + } else if (colorspace != DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709) { + /* Not the default, we're not going to be able to present in this colorspace */ + SDL_SetError("Unsupported output colorspace"); + result = DXGI_ERROR_UNSUPPORTED; } } @@ -1050,27 +1059,9 @@ static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) } /* Create a render target view of the swap chain back buffer. */ - D3D11_RENDER_TARGET_VIEW_DESC desc; - SDL_zero(desc); - switch (renderer->output_colorspace) { - case SDL_COLORSPACE_SCRGB: - desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - break; - case SDL_COLORSPACE_HDR10: - desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; - break; - default: - if (renderer->colorspace_conversion && renderer->output_colorspace == SDL_COLORSPACE_SRGB) { - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; - } else { - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - } - break; - } - desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; result = ID3D11Device_CreateRenderTargetView(data->d3dDevice, (ID3D11Resource *)backBuffer, - &desc, + NULL, &data->mainRenderTargetView); if (FAILED(result)) { WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device::CreateRenderTargetView"), result); @@ -1163,7 +1154,7 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata; D3D11_TextureData *textureData; HRESULT result; - DXGI_FORMAT textureFormat = SDLPixelFormatToDXGITextureFormat(texture->format, texture->colorspace, renderer->colorspace_conversion); + DXGI_FORMAT textureFormat = SDLPixelFormatToDXGITextureFormat(texture->format, renderer->output_colorspace); D3D11_TEXTURE2D_DESC textureDesc; D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; @@ -1262,7 +1253,7 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL } #endif /* SDL_HAVE_YUV */ SDL_zero(resourceViewDesc); - resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(texture->format, texture->colorspace, renderer->colorspace_conversion); + resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(texture->format, renderer->output_colorspace); resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; resourceViewDesc.Texture2D.MostDetailedMip = 0; resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; @@ -1774,6 +1765,7 @@ static int D3D11_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, { VertexPositionColor *verts = (VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertexPositionColor), 0, &cmd->data.draw.first); int i; + SDL_bool convert_color = SDL_RenderingLinearSpace(renderer); if (!verts) { return -1; @@ -1787,6 +1779,9 @@ static int D3D11_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, verts->tex.x = 0.0f; verts->tex.y = 0.0f; verts->color = cmd->data.draw.color; + if (convert_color) { + SDL_ConvertToLinear(&verts->color); + } verts++; } @@ -1801,6 +1796,7 @@ static int D3D11_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, S int i; int count = indices ? num_indices : num_vertices; VertexPositionColor *verts = (VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertexPositionColor), 0, &cmd->data.draw.first); + SDL_bool convert_color = SDL_RenderingLinearSpace(renderer); if (!verts) { return -1; @@ -1827,6 +1823,9 @@ static int D3D11_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, S verts->pos.x = xy_[0] * scale_x; verts->pos.y = xy_[1] * scale_y; verts->color = *(SDL_FColor *)((char *)color + j * color_stride); + if (convert_color) { + SDL_ConvertToLinear(&verts->color); + } if (texture) { float *uv_ = (float *)((char *)uv + j * uv_stride); @@ -2270,7 +2269,12 @@ static int D3D11_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, case SDL_RENDERCMD_CLEAR: { - ID3D11DeviceContext_ClearRenderTargetView(rendererData->d3dContext, D3D11_GetCurrentRenderTargetView(renderer), &cmd->data.color.color.r); + SDL_bool convert_color = SDL_RenderingLinearSpace(renderer); + SDL_FColor color = cmd->data.color.color; + if (convert_color) { + SDL_ConvertToLinear(&color); + } + ID3D11DeviceContext_ClearRenderTargetView(rendererData->d3dContext, D3D11_GetCurrentRenderTargetView(renderer), &color.r); break; } @@ -2419,7 +2423,7 @@ static int D3D11_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, textureMemory.pData, textureMemory.RowPitch, format, - renderer->input_colorspace, + SDL_COLORSPACE_SRGB, pixels, pitch); diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c index bfd5da1abf..0d6c405901 100644 --- a/src/render/direct3d12/SDL_render_d3d12.c +++ b/src/render/direct3d12/SDL_render_d3d12.c @@ -288,18 +288,18 @@ Uint32 D3D12_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) } } -static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 colorspace, SDL_bool colorspace_conversion) +static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 colorspace) { switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; case SDL_PIXELFORMAT_ARGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8X8_UNORM; @@ -314,18 +314,18 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 color } } -static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uint32 colorspace, SDL_bool colorspace_conversion) +static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uint32 colorspace) { switch (format) { case SDL_PIXELFORMAT_RGBA64_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; case SDL_PIXELFORMAT_ARGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8A8_UNORM; case SDL_PIXELFORMAT_XRGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { + if (colorspace == SDL_COLORSPACE_SCRGB) { return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; } return DXGI_FORMAT_B8G8R8X8_UNORM; @@ -1200,11 +1200,7 @@ static HRESULT D3D12_CreateSwapChain(SDL_Renderer *renderer, int w, int h) break; default: swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; /* This is the most common swap chain format. */ - if (renderer->colorspace_conversion && renderer->output_colorspace == SDL_COLORSPACE_SRGB) { - data->renderTargetFormat = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; - } else { - data->renderTargetFormat = DXGI_FORMAT_B8G8R8A8_UNORM; - } + data->renderTargetFormat = DXGI_FORMAT_B8G8R8A8_UNORM; break; } swapChainDesc.Stereo = FALSE; @@ -1255,23 +1251,31 @@ static HRESULT D3D12_CreateSwapChain(SDL_Renderer *renderer, int w, int h) data->swapEffect = swapChainDesc.SwapEffect; data->swapFlags = swapChainDesc.Flags; - DXGI_COLOR_SPACE_TYPE ColorSpace; + UINT colorspace_support = 0; + DXGI_COLOR_SPACE_TYPE colorspace; switch (renderer->output_colorspace) { case SDL_COLORSPACE_SCRGB: - ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; break; case SDL_COLORSPACE_HDR10: - ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; break; default: /* sRGB */ - ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; break; } - result = D3D_CALL(data->swapChain, SetColorSpace1, ColorSpace); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain3::SetColorSpace1"), result); - goto done; + if (SUCCEEDED(D3D_CALL(data->swapChain, CheckColorSpaceSupport, colorspace, &colorspace_support)) && + (colorspace_support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { + result = D3D_CALL(data->swapChain, SetColorSpace1, colorspace); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain3::SetColorSpace1"), result); + goto done; + } + } else { + /* Not the default, we're not going to be able to present in this colorspace */ + SDL_SetError("Unsupported output colorspace"); + result = DXGI_ERROR_UNSUPPORTED; } done: @@ -1511,7 +1515,7 @@ static int D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL D3D12_RenderData *rendererData = (D3D12_RenderData *)renderer->driverdata; D3D12_TextureData *textureData; HRESULT result; - DXGI_FORMAT textureFormat = SDLPixelFormatToDXGITextureFormat(texture->format, texture->colorspace, renderer->colorspace_conversion); + DXGI_FORMAT textureFormat = SDLPixelFormatToDXGITextureFormat(texture->format, renderer->output_colorspace); D3D12_RESOURCE_DESC textureDesc; D3D12_HEAP_PROPERTIES heapProps; D3D12_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; @@ -1624,7 +1628,7 @@ static int D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL #endif /* SDL_HAVE_YUV */ SDL_zero(resourceViewDesc); resourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(texture->format, texture->colorspace, renderer->colorspace_conversion); + resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(texture->format, renderer->output_colorspace); resourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; @@ -2200,6 +2204,7 @@ static int D3D12_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, { VertexPositionColor *verts = (VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertexPositionColor), 0, &cmd->data.draw.first); int i; + SDL_bool convert_color = SDL_RenderingLinearSpace(renderer); if (!verts) { return -1; @@ -2213,6 +2218,9 @@ static int D3D12_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, verts->tex.x = 0.0f; verts->tex.y = 0.0f; verts->color = cmd->data.draw.color; + if (convert_color) { + SDL_ConvertToLinear(&verts->color); + } verts++; } @@ -2227,6 +2235,7 @@ static int D3D12_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, S int i; int count = indices ? num_indices : num_vertices; VertexPositionColor *verts = (VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertexPositionColor), 0, &cmd->data.draw.first); + SDL_bool convert_color = SDL_RenderingLinearSpace(renderer); if (!verts) { return -1; @@ -2253,6 +2262,9 @@ static int D3D12_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, S verts->pos.x = xy_[0] * scale_x; verts->pos.y = xy_[1] * scale_y; verts->color = *(SDL_FColor *)((char *)color + j * color_stride); + if (convert_color) { + SDL_ConvertToLinear(&verts->color); + } if (texture) { float *uv_ = (float *)((char *)uv + j * uv_stride); @@ -2716,7 +2728,12 @@ static int D3D12_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, case SDL_RENDERCMD_CLEAR: { D3D12_CPU_DESCRIPTOR_HANDLE rtvDescriptor = D3D12_GetCurrentRenderTargetView(renderer); - D3D_CALL(rendererData->commandList, ClearRenderTargetView, rtvDescriptor, &cmd->data.color.color.r, 0, NULL); + SDL_bool convert_color = SDL_RenderingLinearSpace(renderer); + SDL_FColor color = cmd->data.color.color; + if (convert_color) { + SDL_ConvertToLinear(&color); + } + D3D_CALL(rendererData->commandList, ClearRenderTargetView, rtvDescriptor, &color.r, 0, NULL); break; } @@ -2927,7 +2944,7 @@ static int D3D12_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, textureMemory, pitchedDesc.RowPitch, format, - renderer->input_colorspace, + SDL_COLORSPACE_SRGB, pixels, pitch); diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 22553053cf..e758e0de04 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -401,27 +401,18 @@ static SDL_bool GL_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blend return SDL_TRUE; } -static SDL_bool convert_format(Uint32 pixel_format, Uint32 colorspace, SDL_bool colorspace_conversion, - GLint *internalFormat, GLenum *format, GLenum *type) +static SDL_bool convert_format(Uint32 pixel_format, GLint *internalFormat, GLenum *format, GLenum *type) { switch (pixel_format) { case SDL_PIXELFORMAT_ARGB8888: case SDL_PIXELFORMAT_XRGB8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { - *internalFormat = GL_SRGB8_ALPHA8; - } else { - *internalFormat = GL_RGBA8; - } + *internalFormat = GL_RGBA8; *format = GL_BGRA; *type = GL_UNSIGNED_INT_8_8_8_8_REV; break; case SDL_PIXELFORMAT_ABGR8888: case SDL_PIXELFORMAT_XBGR8888: - if (colorspace_conversion && colorspace == SDL_COLORSPACE_SRGB) { - *internalFormat = GL_SRGB8_ALPHA8; - } else { - *internalFormat = GL_RGBA8; - } + *internalFormat = GL_RGBA8; *format = GL_RGBA; *type = GL_UNSIGNED_INT_8_8_8_8_REV; break; @@ -466,8 +457,7 @@ static int GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr return SDL_SetError("Render targets not supported by OpenGL"); } - if (!convert_format(texture->format, texture->colorspace, renderer->colorspace_conversion, - &internalFormat, &format, &type)) { + if (!convert_format(texture->format, &internalFormat, &format, &type)) { return SDL_SetError("Texture format %s not supported by OpenGL", SDL_GetPixelFormatName(texture->format)); } @@ -1481,8 +1471,7 @@ static int GL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, GL_ActivateRenderer(renderer); - if (!convert_format(temp_format, renderer->input_colorspace, renderer->colorspace_conversion, - &internalFormat, &format, &type)) { + if (!convert_format(temp_format, &internalFormat, &format, &type)) { return SDL_SetError("Texture format %s not supported by OpenGL", SDL_GetPixelFormatName(temp_format)); } @@ -1925,9 +1914,6 @@ static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea data->glDisable(data->textype); data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - if (renderer->colorspace_conversion && renderer->output_colorspace == SDL_COLORSPACE_SRGB) { - data->glEnable(GL_FRAMEBUFFER_SRGB); - } /* This ended up causing video discrepancies between OpenGL and Direct3D */ /* data->glEnable(GL_LINE_SMOOTH); */ diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c index d814b54431..a4832af70a 100644 --- a/src/render/software/SDL_render_sw.c +++ b/src/render/software/SDL_render_sw.c @@ -1176,6 +1176,7 @@ SDL_Renderer *SW_CreateRendererForSurface(SDL_Surface *surface) static SDL_Renderer *SW_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_props) { + SDL_Renderer *renderer; const char *hint; SDL_Surface *surface; SDL_bool no_hint_set; @@ -1206,7 +1207,21 @@ static SDL_Renderer *SW_CreateRenderer(SDL_Window *window, SDL_PropertiesID crea if (!surface) { return NULL; } - return SW_CreateRendererForSurface(surface); + + renderer = SW_CreateRendererForSurface(surface); + if (!renderer) { + return NULL; + } + + SDL_SetupRendererColorspace(renderer, create_props); + + if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { + SDL_SetError("Unsupported output colorspace"); + SW_DestroyRenderer(renderer); + return NULL; + } + + return renderer; } SDL_RenderDriver SW_RenderDriver = { diff --git a/test/testcolorspace.c b/test/testcolorspace.c index 2116364089..9763bf72c8 100644 --- a/test/testcolorspace.c +++ b/test/testcolorspace.c @@ -51,9 +51,7 @@ static void CreateRenderer(void) props = SDL_CreateProperties(); SDL_SetProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window); SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, SDL_GetRenderDriver(renderer_index)); - SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_INPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB); SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER, colorspace); - SDL_SetBooleanProperty(props, SDL_PROP_RENDERER_CREATE_COLORSPACE_CONVERSION_BOOLEAN, SDL_TRUE); renderer = SDL_CreateRendererWithProperties(props); SDL_DestroyProperties(props); if (!renderer) { @@ -254,13 +252,13 @@ static void RenderBlendDrawing(void) float y = TEXT_START_Y; DrawText(x, y, "%s %s", renderer_name, colorspace_name); y += TEXT_LINE_ADVANCE; - DrawText(x, y, "Test: Draw Linear Blending"); + DrawText(x, y, "Test: Draw Blending"); y += TEXT_LINE_ADVANCE; if (cr.r == 199 && cr.g == 193 && cr.b == 121) { - DrawText(x, y, "Correct blend color in linear space"); + DrawText(x, y, "Correct blend color, blending in linear space"); } else if ((cr.r == 192 && cr.g == 163 && cr.b == 83) || (cr.r == 191 && cr.g == 162 && cr.b == 82)) { - DrawText(x, y, "Incorrect blend color, blending in sRGB space"); + DrawText(x, y, "Correct blend color, blending in sRGB space"); } else if (cr.r == 214 && cr.g == 156 && cr.b == 113) { DrawText(x, y, "Incorrect blend color, blending in PQ space"); } else { @@ -314,13 +312,13 @@ static void RenderBlendTexture(void) float y = TEXT_START_Y; DrawText(x, y, "%s %s", renderer_name, colorspace_name); y += TEXT_LINE_ADVANCE; - DrawText(x, y, "Test: Texture Linear Blending"); + DrawText(x, y, "Test: Texture Blending"); y += TEXT_LINE_ADVANCE; if (cr.r == 199 && cr.g == 193 && cr.b == 121) { - DrawText(x, y, "Correct blend color in linear space"); + DrawText(x, y, "Correct blend color, blending in linear space"); } else if ((cr.r == 192 && cr.g == 163 && cr.b == 83) || (cr.r == 191 && cr.g == 162 && cr.b == 82)) { - DrawText(x, y, "Incorrect blend color, blending in sRGB space"); + DrawText(x, y, "Correct blend color, blending in sRGB space"); } else { DrawText(x, y, "Incorrect blend color, unknown reason"); } @@ -351,13 +349,10 @@ static void DrawGradient(float x, float y, float width, float height, float star xy[0] = minx; xy[1] = miny; - xy[2] = maxx; xy[3] = miny; - xy[4] = maxx; xy[5] = maxy; - xy[6] = minx; xy[7] = maxy; @@ -369,6 +364,36 @@ static void DrawGradient(float x, float y, float width, float height, float star SDL_RenderGeometryRaw(renderer, NULL, xy, xy_stride, color, color_stride, NULL, 0, num_vertices, indices, num_indices, size_indices); } +static float scRGBfromNits(float v) +{ + return v / 80.0f; +} + +static float sRGBtoLinear(float v) +{ + if (v <= 0.04045f) { + v = (v / 12.92f); + } else { + v = SDL_powf(((v + 0.055f) / 1.055f), 2.4f); + } + return v; +} + +static float sRGBFromLinear(float v) +{ + if (v <= 0.0031308f) { + v = (v * 12.92f); + } else { + v = (SDL_powf(v, 1.0f / 2.4f) * 1.055f - 0.055f); + } + return v; +} + +static float sRGBfromNits(float v) +{ + return sRGBFromLinear(scRGBfromNits(v)); +} + static void RenderGradientDrawing(void) { SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); @@ -383,29 +408,25 @@ static void RenderGradientDrawing(void) y += TEXT_LINE_ADVANCE; - DrawTextWhite(x, y, "SDR mathematically linear gradient (%d nits)", 80); + DrawTextWhite(x, y, "SDR gradient (%d nits)", 80); y += TEXT_LINE_ADVANCE; - DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 1.0f); + DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(80.0f)); y += 64.0f; y += TEXT_LINE_ADVANCE; y += TEXT_LINE_ADVANCE; - DrawTextWhite(x, y, "HDR mathematically linear gradient (%d nits)", 400); + DrawTextWhite(x, y, "HDR gradient (%d nits)", 400); y += TEXT_LINE_ADVANCE; - SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SCRGB); - DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 5.0f); - SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SRGB); + DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(400.0f)); y += 64.0f; y += TEXT_LINE_ADVANCE; y += TEXT_LINE_ADVANCE; - DrawTextWhite(x, y, "HDR mathematically linear gradient (%d nits)", 1000); + DrawTextWhite(x, y, "HDR gradient (%d nits)", 1000); y += TEXT_LINE_ADVANCE; - SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SCRGB); - DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 12.5f); - SDL_SetRenderDrawColorspace(renderer, SDL_COLORSPACE_SRGB); + DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(1000)); y += 64.0f; } @@ -414,19 +435,27 @@ static SDL_Texture *CreateGradientTexture(int width, float start, float end) SDL_Texture *texture; float *pixels; + /* Floating point textures are in the scRGB colorspace by default */ texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA128_FLOAT, SDL_TEXTUREACCESS_STATIC, width, 1); if (!texture) { return NULL; } + if (colorspace == SDL_COLORSPACE_SCRGB) { + /* The input values are in the sRGB colorspace, but we're blending in linear space */ + start = sRGBtoLinear(start); + end = sRGBtoLinear(end); + } else if (colorspace == SDL_COLORSPACE_SRGB) { + /* The input values are in the sRGB colorspace, and we're blending in sRGB space */ + } + pixels = (float *)SDL_malloc(width * sizeof(float) * 4); if (pixels) { int i; float length = (end - start); for (i = 0; i < width; ++i) { - /* Use a 2.4 gamma function to create a perceptually linear gradient */ - float v = SDL_powf(start + (length * i) / width, 2.4f); + float v = (start + (length * i) / width); pixels[i * 4 + 0] = v; pixels[i * 4 + 1] = v; pixels[i * 4 + 2] = v; @@ -455,30 +484,30 @@ static void RenderGradientTexture(void) float y = TEXT_START_Y; DrawTextWhite(x, y, "%s %s", renderer_name, colorspace_name); y += TEXT_LINE_ADVANCE; - DrawTextWhite(x, y, "Test: Draw SDR and HDR gradients"); + DrawTextWhite(x, y, "Test: Texture SDR and HDR gradients"); y += TEXT_LINE_ADVANCE; y += TEXT_LINE_ADVANCE; - DrawTextWhite(x, y, "SDR perceptually linear gradient (%d nits)", 80); + DrawTextWhite(x, y, "SDR gradient (%d nits)", 80); y += TEXT_LINE_ADVANCE; - DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 1.0f); + DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(80)); y += 64.0f; y += TEXT_LINE_ADVANCE; y += TEXT_LINE_ADVANCE; - DrawTextWhite(x, y, "HDR perceptually linear gradient (%d nits)", 400); + DrawTextWhite(x, y, "HDR gradient (%d nits)", 400); y += TEXT_LINE_ADVANCE; - DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 5.0f); + DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(400)); y += 64.0f; y += TEXT_LINE_ADVANCE; y += TEXT_LINE_ADVANCE; - DrawTextWhite(x, y, "HDR perceptually linear gradient (%d nits)", 1000); + DrawTextWhite(x, y, "HDR gradient (%d nits)", 1000); y += TEXT_LINE_ADVANCE; - DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, 12.5f); + DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(1000)); y += 64.0f; }