mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-15 17:28:28 +00:00
Added HDR display properties and related event
Also added an HDR calibration stage to testcolorspace
This commit is contained in:
parent
d4caef5b89
commit
30e176d6ba
11 changed files with 510 additions and 57 deletions
|
@ -97,8 +97,9 @@ typedef enum
|
||||||
SDL_EVENT_DISPLAY_REMOVED, /**< Display has been removed from the system */
|
SDL_EVENT_DISPLAY_REMOVED, /**< Display has been removed from the system */
|
||||||
SDL_EVENT_DISPLAY_MOVED, /**< Display has changed position */
|
SDL_EVENT_DISPLAY_MOVED, /**< Display has changed position */
|
||||||
SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed content scale */
|
SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, /**< Display has changed content scale */
|
||||||
|
SDL_EVENT_DISPLAY_HDR_STATE_CHANGED, /**< Display HDR properties have changed */
|
||||||
SDL_EVENT_DISPLAY_FIRST = SDL_EVENT_DISPLAY_ORIENTATION,
|
SDL_EVENT_DISPLAY_FIRST = SDL_EVENT_DISPLAY_ORIENTATION,
|
||||||
SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED,
|
SDL_EVENT_DISPLAY_LAST = SDL_EVENT_DISPLAY_HDR_STATE_CHANGED,
|
||||||
|
|
||||||
/* Window events */
|
/* Window events */
|
||||||
/* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */
|
/* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */
|
||||||
|
|
|
@ -234,12 +234,12 @@ extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window, co
|
||||||
*
|
*
|
||||||
* These are the supported properties:
|
* These are the supported properties:
|
||||||
*
|
*
|
||||||
* - `SDL_PROP_RENDERER_CREATE_WINDOW_POINTER`: the window where rendering is
|
|
||||||
* displayed
|
|
||||||
* - `SDL_PROP_RENDERER_CREATE_SURFACE_POINTER`: the surface where rendering
|
|
||||||
* is displayed, if you want a software renderer without a window
|
|
||||||
* - `SDL_PROP_RENDERER_CREATE_NAME_STRING`: the name of the rendering driver
|
* - `SDL_PROP_RENDERER_CREATE_NAME_STRING`: the name of the rendering driver
|
||||||
* to use, if a specific one is desired
|
* to use, if a specific one is desired
|
||||||
|
* - `SDL_PROP_RENDERER_CREATE_WINDOW_POINTER`: the window where rendering is
|
||||||
|
* displayed, required if this isn't a software renderer using a surface
|
||||||
|
* - `SDL_PROP_RENDERER_CREATE_SURFACE_POINTER`: the surface where rendering
|
||||||
|
* is displayed, if you want a software renderer without a window
|
||||||
* - `SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER`: an SDL_ColorSpace
|
* - `SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER`: an SDL_ColorSpace
|
||||||
* value describing the colorspace for output to the display, defaults to
|
* value describing the colorspace for output to the display, defaults to
|
||||||
* SDL_COLORSPACE_SRGB. The direct3d11 and direct3d12 renderers support
|
* SDL_COLORSPACE_SRGB. The direct3d11 and direct3d12 renderers support
|
||||||
|
@ -263,9 +263,9 @@ extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window, co
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_PropertiesID props);
|
extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_PropertiesID props);
|
||||||
|
|
||||||
|
#define SDL_PROP_RENDERER_CREATE_NAME_STRING "name"
|
||||||
#define SDL_PROP_RENDERER_CREATE_WINDOW_POINTER "window"
|
#define SDL_PROP_RENDERER_CREATE_WINDOW_POINTER "window"
|
||||||
#define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER "surface"
|
#define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER "surface"
|
||||||
#define SDL_PROP_RENDERER_CREATE_NAME_STRING "name"
|
|
||||||
#define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER "output_colorspace"
|
#define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER "output_colorspace"
|
||||||
#define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_BOOLEAN "present_vsync"
|
#define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_BOOLEAN "present_vsync"
|
||||||
|
|
||||||
|
@ -334,6 +334,10 @@ extern DECLSPEC int SDLCALL SDL_GetRendererInfo(SDL_Renderer *renderer, SDL_Rend
|
||||||
*
|
*
|
||||||
* The following read-only properties are provided by SDL:
|
* The following read-only properties are provided by SDL:
|
||||||
*
|
*
|
||||||
|
* - `SDL_PROP_RENDERER_NAME_STRING`: the name of the rendering driver
|
||||||
|
* - `SDL_PROP_RENDERER_WINDOW_POINTER`: the window where rendering is displayed, if any
|
||||||
|
* - `SDL_PROP_RENDERER_SURFACE_POINTER`: the surface where rendering is displayed, if this is a software renderer without a window
|
||||||
|
* - `SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER`: an SDL_ColorSpace value describing the colorspace for output to the display, defaults to SDL_COLORSPACE_SRGB.
|
||||||
* - `SDL_PROP_RENDERER_D3D9_DEVICE_POINTER`: the IDirect3DDevice9 associated
|
* - `SDL_PROP_RENDERER_D3D9_DEVICE_POINTER`: the IDirect3DDevice9 associated
|
||||||
* with the renderer
|
* with the renderer
|
||||||
* - `SDL_PROP_RENDERER_D3D11_DEVICE_POINTER`: the ID3D11Device associated
|
* - `SDL_PROP_RENDERER_D3D11_DEVICE_POINTER`: the ID3D11Device associated
|
||||||
|
@ -354,6 +358,10 @@ extern DECLSPEC int SDLCALL SDL_GetRendererInfo(SDL_Renderer *renderer, SDL_Rend
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetRendererProperties(SDL_Renderer *renderer);
|
extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetRendererProperties(SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
#define SDL_PROP_RENDERER_NAME_STRING "SDL.renderer.name"
|
||||||
|
#define SDL_PROP_RENDERER_WINDOW_POINTER "SDL.renderer.window"
|
||||||
|
#define SDL_PROP_RENDERER_SURFACE_POINTER "SDL.renderer.surface"
|
||||||
|
#define SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER "SDL.renderer.output_colorspace"
|
||||||
#define SDL_PROP_RENDERER_D3D9_DEVICE_POINTER "SDL.renderer.d3d9.device"
|
#define SDL_PROP_RENDERER_D3D9_DEVICE_POINTER "SDL.renderer.d3d9.device"
|
||||||
#define SDL_PROP_RENDERER_D3D11_DEVICE_POINTER "SDL.renderer.d3d11.device"
|
#define SDL_PROP_RENDERER_D3D11_DEVICE_POINTER "SDL.renderer.d3d11.device"
|
||||||
#define SDL_PROP_RENDERER_D3D12_DEVICE_POINTER "SDL.renderer.d3d12.device"
|
#define SDL_PROP_RENDERER_D3D12_DEVICE_POINTER "SDL.renderer.d3d12.device"
|
||||||
|
|
|
@ -353,6 +353,11 @@ extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetPrimaryDisplay(void);
|
||||||
/**
|
/**
|
||||||
* Get the properties associated with a display.
|
* Get the properties associated with a display.
|
||||||
*
|
*
|
||||||
|
* The following read-only properties are provided by SDL:
|
||||||
|
*
|
||||||
|
* - `SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN`: true if the display has High Dynamic Range enabled
|
||||||
|
* - `SDL_PROP_DISPLAY_SDR_WHITE_LEVEL_FLOAT`: the luminance, in nits, that SDR white is rendered on this display. If this value is not set or is zero, the value 200 is a reasonable default when HDR is enabled.
|
||||||
|
*
|
||||||
* \param displayID the instance ID of the display to query
|
* \param displayID the instance ID of the display to query
|
||||||
* \returns a valid property ID on success or 0 on failure; call
|
* \returns a valid property ID on success or 0 on failure; call
|
||||||
* SDL_GetError() for more information.
|
* SDL_GetError() for more information.
|
||||||
|
@ -364,6 +369,9 @@ extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetPrimaryDisplay(void);
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetDisplayProperties(SDL_DisplayID displayID);
|
extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetDisplayProperties(SDL_DisplayID displayID);
|
||||||
|
|
||||||
|
#define SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN "SDL.display.HDR_enabled"
|
||||||
|
#define SDL_PROP_DISPLAY_SDR_WHITE_LEVEL_FLOAT "SDL.display.SDR_white_level"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of a display in UTF-8 encoding.
|
* Get the name of a display in UTF-8 encoding.
|
||||||
*
|
*
|
||||||
|
|
|
@ -282,6 +282,7 @@ static void SDL_LogEvent(const SDL_Event *event)
|
||||||
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_REMOVED);
|
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_REMOVED);
|
||||||
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_MOVED);
|
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_MOVED);
|
||||||
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
|
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
|
||||||
|
SDL_DISPLAYEVENT_CASE(SDL_EVENT_DISPLAY_HDR_STATE_CHANGED);
|
||||||
#undef SDL_DISPLAYEVENT_CASE
|
#undef SDL_DISPLAYEVENT_CASE
|
||||||
|
|
||||||
#define SDL_WINDOWEVENT_CASE(x) \
|
#define SDL_WINDOWEVENT_CASE(x) \
|
||||||
|
|
|
@ -854,6 +854,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
||||||
const int n = SDL_GetNumRenderDrivers();
|
const int n = SDL_GetNumRenderDrivers();
|
||||||
const char *hint;
|
const char *hint;
|
||||||
int i, attempted = 0;
|
int i, attempted = 0;
|
||||||
|
SDL_PropertiesID new_props;
|
||||||
|
|
||||||
if (!window && surface) {
|
if (!window && surface) {
|
||||||
return SDL_CreateSoftwareRenderer(surface);
|
return SDL_CreateSoftwareRenderer(surface);
|
||||||
|
@ -964,6 +965,16 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
||||||
renderer->hidden = SDL_FALSE;
|
renderer->hidden = SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_props = SDL_GetRendererProperties(renderer);
|
||||||
|
SDL_SetStringProperty(new_props, SDL_PROP_RENDERER_NAME_STRING, renderer->info.name);
|
||||||
|
if (window) {
|
||||||
|
SDL_SetProperty(new_props, SDL_PROP_RENDERER_WINDOW_POINTER, window);
|
||||||
|
}
|
||||||
|
if (surface) {
|
||||||
|
SDL_SetProperty(new_props, SDL_PROP_RENDERER_SURFACE_POINTER, surface);
|
||||||
|
}
|
||||||
|
SDL_SetNumberProperty(new_props, SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER, renderer->output_colorspace);
|
||||||
|
|
||||||
SDL_SetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_RENDERER, renderer);
|
SDL_SetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_RENDERER, renderer);
|
||||||
|
|
||||||
SDL_SetRenderViewport(renderer, NULL);
|
SDL_SetRenderViewport(renderer, NULL);
|
||||||
|
|
|
@ -1666,6 +1666,12 @@ static void SDLTest_PrintEvent(const SDL_Event *event)
|
||||||
event->display.displayID, (int)(scale * 100.0f));
|
event->display.displayID, (int)(scale * 100.0f));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SDL_EVENT_DISPLAY_HDR_STATE_CHANGED:
|
||||||
|
{
|
||||||
|
SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " HDR %s",
|
||||||
|
event->display.displayID, event->display.data1 ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SDL_EVENT_DISPLAY_MOVED:
|
case SDL_EVENT_DISPLAY_MOVED:
|
||||||
SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed position",
|
SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " changed position",
|
||||||
event->display.displayID);
|
event->display.displayID);
|
||||||
|
|
|
@ -117,6 +117,12 @@ struct SDL_Window
|
||||||
#define SDL_WINDOW_IS_POPUP(W) \
|
#define SDL_WINDOW_IS_POPUP(W) \
|
||||||
(((W)->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) != 0)
|
(((W)->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) != 0)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SDL_bool enabled;
|
||||||
|
float SDR_whitelevel;
|
||||||
|
} SDL_HDRDisplayProperties;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define the SDL display structure.
|
* Define the SDL display structure.
|
||||||
* This corresponds to physical monitors attached to the system.
|
* This corresponds to physical monitors attached to the system.
|
||||||
|
@ -133,6 +139,7 @@ struct SDL_VideoDisplay
|
||||||
SDL_DisplayOrientation natural_orientation;
|
SDL_DisplayOrientation natural_orientation;
|
||||||
SDL_DisplayOrientation current_orientation;
|
SDL_DisplayOrientation current_orientation;
|
||||||
float content_scale;
|
float content_scale;
|
||||||
|
SDL_HDRDisplayProperties HDR;
|
||||||
|
|
||||||
SDL_Window *fullscreen_window;
|
SDL_Window *fullscreen_window;
|
||||||
|
|
||||||
|
@ -489,6 +496,7 @@ extern void SDL_ResetFullscreenDisplayModes(SDL_VideoDisplay *display);
|
||||||
extern void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
|
extern void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
|
||||||
extern void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
|
extern void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
|
||||||
extern void SDL_SetDisplayContentScale(SDL_VideoDisplay *display, float scale);
|
extern void SDL_SetDisplayContentScale(SDL_VideoDisplay *display, float scale);
|
||||||
|
extern void SDL_SetDisplayHDRProperties(SDL_VideoDisplay *display, const SDL_HDRDisplayProperties *HDR);
|
||||||
extern int SDL_SetDisplayModeForDisplay(SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
extern int SDL_SetDisplayModeForDisplay(SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
||||||
extern SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID display);
|
extern SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID display);
|
||||||
extern SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window);
|
extern SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window);
|
||||||
|
|
|
@ -671,6 +671,7 @@ SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send
|
||||||
{
|
{
|
||||||
SDL_VideoDisplay **displays, *new_display;
|
SDL_VideoDisplay **displays, *new_display;
|
||||||
SDL_DisplayID id;
|
SDL_DisplayID id;
|
||||||
|
SDL_PropertiesID props;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
new_display = (SDL_VideoDisplay *)SDL_malloc(sizeof(*new_display));
|
new_display = (SDL_VideoDisplay *)SDL_malloc(sizeof(*new_display));
|
||||||
|
@ -710,9 +711,15 @@ SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send
|
||||||
new_display->fullscreen_modes[i].displayID = id;
|
new_display->fullscreen_modes[i].displayID = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_event) {
|
props = SDL_GetDisplayProperties(id);
|
||||||
SDL_SendDisplayEvent(new_display, SDL_EVENT_DISPLAY_ADDED, 0);
|
|
||||||
|
if (display->HDR.enabled) {
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN, SDL_TRUE);
|
||||||
}
|
}
|
||||||
|
if (display->HDR.SDR_whitelevel != 0.0f) {
|
||||||
|
SDL_SetFloatProperty(props, SDL_PROP_DISPLAY_SDR_WHITE_LEVEL_FLOAT, display->HDR.SDR_whitelevel);
|
||||||
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -976,6 +983,26 @@ float SDL_GetDisplayContentScale(SDL_DisplayID displayID)
|
||||||
return display->content_scale;
|
return display->content_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDL_SetDisplayHDRProperties(SDL_VideoDisplay *display, const SDL_HDRDisplayProperties *HDR)
|
||||||
|
{
|
||||||
|
SDL_PropertiesID props = SDL_GetDisplayProperties(display->id);
|
||||||
|
SDL_bool changed = SDL_FALSE;
|
||||||
|
|
||||||
|
if (HDR->enabled != display->HDR.enabled) {
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN, HDR->enabled);
|
||||||
|
changed = SDL_TRUE;
|
||||||
|
}
|
||||||
|
if (HDR->SDR_whitelevel != display->HDR.SDR_whitelevel) {
|
||||||
|
SDL_SetFloatProperty(props, SDL_PROP_DISPLAY_SDR_WHITE_LEVEL_FLOAT, HDR->SDR_whitelevel);
|
||||||
|
changed = SDL_TRUE;
|
||||||
|
}
|
||||||
|
SDL_copyp(&display->HDR, HDR);
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_HDR_STATE_CHANGED, HDR->enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const SDL_DisplayMode *SDL_GetFullscreenModeMatch(const SDL_DisplayMode *mode)
|
static const SDL_DisplayMode *SDL_GetFullscreenModeMatch(const SDL_DisplayMode *mode)
|
||||||
{
|
{
|
||||||
const SDL_DisplayMode **modes;
|
const SDL_DisplayMode **modes;
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#include "SDL_windowsvideo.h"
|
#include "SDL_windowsvideo.h"
|
||||||
#include "../../events/SDL_displayevents_c.h"
|
#include "../../events/SDL_displayevents_c.h"
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
#include <dxgi1_6.h>
|
||||||
|
|
||||||
/* Windows CE compatibility */
|
/* Windows CE compatibility */
|
||||||
#ifndef CDS_FULLSCREEN
|
#ifndef CDS_FULLSCREEN
|
||||||
#define CDS_FULLSCREEN 0
|
#define CDS_FULLSCREEN 0
|
||||||
|
@ -334,6 +337,162 @@ WIN_GetDisplayNameVista_failed:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_bool WIN_GetMonitorDESC1(HMONITOR hMonitor, DXGI_OUTPUT_DESC1 *desc)
|
||||||
|
{
|
||||||
|
typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
|
||||||
|
PFN_CREATE_DXGI_FACTORY CreateDXGIFactoryFunc = NULL;
|
||||||
|
void *hDXGIMod = NULL;
|
||||||
|
SDL_bool found = SDL_FALSE;
|
||||||
|
|
||||||
|
#ifdef SDL_PLATFORM_WINRT
|
||||||
|
CreateDXGIFactoryFunc = CreateDXGIFactory1;
|
||||||
|
#else
|
||||||
|
hDXGIMod = SDL_LoadObject("dxgi.dll");
|
||||||
|
if (hDXGIMod) {
|
||||||
|
CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY)SDL_LoadFunction(hDXGIMod, "CreateDXGIFactory");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (CreateDXGIFactoryFunc) {
|
||||||
|
static const GUID SDL_IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
|
||||||
|
static const GUID SDL_IID_IDXGIOutput6 = { 0x068346e8, 0xaaec, 0x4b84, { 0xad, 0xd7, 0x13, 0x7f, 0x51, 0x3f, 0x77, 0xa1 } };
|
||||||
|
IDXGIFactory2 *dxgiFactory;
|
||||||
|
|
||||||
|
if (SUCCEEDED(CreateDXGIFactoryFunc(&SDL_IID_IDXGIFactory2, (void **)&dxgiFactory))) {
|
||||||
|
IDXGIAdapter1 *dxgiAdapter;
|
||||||
|
UINT adapter = 0;
|
||||||
|
while (!found && SUCCEEDED(IDXGIFactory2_EnumAdapters1(dxgiFactory, adapter, &dxgiAdapter))) {
|
||||||
|
IDXGIOutput *dxgiOutput;
|
||||||
|
UINT output = 0;
|
||||||
|
while (!found && SUCCEEDED(IDXGIAdapter1_EnumOutputs(dxgiAdapter, output, &dxgiOutput))) {
|
||||||
|
IDXGIOutput6 *dxgiOutput6;
|
||||||
|
if (SUCCEEDED(IDXGIOutput_QueryInterface(dxgiOutput, &SDL_IID_IDXGIOutput6, (void **)&dxgiOutput6))) {
|
||||||
|
if (SUCCEEDED(IDXGIOutput6_GetDesc1(dxgiOutput6, desc))) {
|
||||||
|
if (desc->Monitor == hMonitor) {
|
||||||
|
found = SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDXGIOutput6_Release(dxgiOutput6);
|
||||||
|
}
|
||||||
|
IDXGIOutput_Release(dxgiOutput);
|
||||||
|
++output;
|
||||||
|
}
|
||||||
|
IDXGIAdapter1_Release(dxgiAdapter);
|
||||||
|
++adapter;
|
||||||
|
}
|
||||||
|
IDXGIFactory2_Release(dxgiFactory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hDXGIMod) {
|
||||||
|
SDL_UnloadObject(hDXGIMod);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_bool WIN_GetMonitorPathInfo(HMONITOR hMonitor, DISPLAYCONFIG_PATH_INFO *path_info)
|
||||||
|
{
|
||||||
|
LONG result;
|
||||||
|
MONITORINFOEXW view_info;
|
||||||
|
UINT32 i;
|
||||||
|
UINT32 num_path_array_elements = 0;
|
||||||
|
UINT32 num_mode_info_array_elements = 0;
|
||||||
|
DISPLAYCONFIG_PATH_INFO *path_infos = NULL, *new_path_infos;
|
||||||
|
DISPLAYCONFIG_MODE_INFO *mode_infos = NULL, *new_mode_infos;
|
||||||
|
SDL_bool found = SDL_FALSE;
|
||||||
|
|
||||||
|
SDL_zero(view_info);
|
||||||
|
view_info.cbSize = sizeof(view_info);
|
||||||
|
if (!GetMonitorInfoW(hMonitor, (MONITORINFO *)&view_info)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &num_path_array_elements, &num_mode_info_array_elements) != ERROR_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_path_infos = (DISPLAYCONFIG_PATH_INFO *)SDL_realloc(path_infos, num_path_array_elements * sizeof(*path_infos));
|
||||||
|
if (!new_path_infos) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
path_infos = new_path_infos;
|
||||||
|
|
||||||
|
new_mode_infos = (DISPLAYCONFIG_MODE_INFO *)SDL_realloc(mode_infos, num_mode_info_array_elements * sizeof(*mode_infos));
|
||||||
|
if (!new_mode_infos) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mode_infos = new_mode_infos;
|
||||||
|
|
||||||
|
result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &num_path_array_elements, path_infos, &num_mode_info_array_elements, mode_infos, NULL);
|
||||||
|
|
||||||
|
} while (result == ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
|
||||||
|
if (result == ERROR_SUCCESS) {
|
||||||
|
for (i = 0; i < num_path_array_elements; ++i) {
|
||||||
|
DISPLAYCONFIG_SOURCE_DEVICE_NAME device_name;
|
||||||
|
|
||||||
|
SDL_zero(device_name);
|
||||||
|
device_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
|
||||||
|
device_name.header.size = sizeof(device_name);
|
||||||
|
device_name.header.adapterId = path_infos[i].sourceInfo.adapterId;
|
||||||
|
device_name.header.id = path_infos[i].sourceInfo.id;
|
||||||
|
if (DisplayConfigGetDeviceInfo(&device_name.header) == ERROR_SUCCESS) {
|
||||||
|
if (SDL_wcscmp(view_info.szDevice, device_name.viewGdiDeviceName) == 0) {
|
||||||
|
SDL_copyp(path_info, &path_infos[i]);
|
||||||
|
found = SDL_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
SDL_free(path_infos);
|
||||||
|
SDL_free(mode_infos);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float WIN_GetSDRWhiteLevel(HMONITOR hMonitor)
|
||||||
|
{
|
||||||
|
DISPLAYCONFIG_PATH_INFO path_info;
|
||||||
|
float SDR_whitelevel = 200.0f;
|
||||||
|
|
||||||
|
if (WIN_GetMonitorPathInfo(hMonitor, &path_info)) {
|
||||||
|
DISPLAYCONFIG_SDR_WHITE_LEVEL white_level;
|
||||||
|
|
||||||
|
SDL_zero(white_level);
|
||||||
|
white_level.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
|
||||||
|
white_level.header.size = sizeof(white_level);
|
||||||
|
white_level.header.adapterId = path_info.targetInfo.adapterId;
|
||||||
|
white_level.header.id = path_info.targetInfo.id;
|
||||||
|
if (DisplayConfigGetDeviceInfo(&white_level.header) == ERROR_SUCCESS) {
|
||||||
|
SDR_whitelevel = (white_level.SDRWhiteLevel / 1000.0f) * 80.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SDR_whitelevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WIN_GetHDRProperties(SDL_VideoDevice *_this, HMONITOR hMonitor, SDL_HDRDisplayProperties *HDR)
|
||||||
|
{
|
||||||
|
DXGI_OUTPUT_DESC1 desc;
|
||||||
|
|
||||||
|
SDL_zerop(HDR);
|
||||||
|
|
||||||
|
if (WIN_GetMonitorDESC1(hMonitor, &desc)) {
|
||||||
|
if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
|
||||||
|
HDR->enabled = SDL_TRUE;
|
||||||
|
HDR->SDR_whitelevel = WIN_GetSDRWhiteLevel(hMonitor);
|
||||||
|
|
||||||
|
/* In theory you can get the maximum luminence from desc.MaxLuminance, but this value is 80
|
||||||
|
* on my system regardless of whether HDR is enabled. Because the value isn't reliable games
|
||||||
|
* will typically have a calibration step where they show you a white image at high luminence
|
||||||
|
* and slowly lower the brightness until you can see it as distinct from the background and
|
||||||
|
* then use that as the calibrated maximum luminence. The value 400 is a reasonable default.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONITORINFOEXW *info, int *display_index)
|
static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONITORINFOEXW *info, int *display_index)
|
||||||
{
|
{
|
||||||
int i, index = *display_index;
|
int i, index = *display_index;
|
||||||
|
@ -386,6 +545,7 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI
|
||||||
if (!_this->setting_display_mode) {
|
if (!_this->setting_display_mode) {
|
||||||
SDL_VideoDisplay *existing_display = _this->displays[i];
|
SDL_VideoDisplay *existing_display = _this->displays[i];
|
||||||
SDL_Rect bounds;
|
SDL_Rect bounds;
|
||||||
|
SDL_HDRDisplayProperties HDR;
|
||||||
|
|
||||||
SDL_ResetFullscreenDisplayModes(existing_display);
|
SDL_ResetFullscreenDisplayModes(existing_display);
|
||||||
SDL_SetDesktopDisplayMode(existing_display, &mode);
|
SDL_SetDesktopDisplayMode(existing_display, &mode);
|
||||||
|
@ -399,6 +559,8 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI
|
||||||
}
|
}
|
||||||
SDL_SendDisplayEvent(existing_display, SDL_EVENT_DISPLAY_ORIENTATION, current_orientation);
|
SDL_SendDisplayEvent(existing_display, SDL_EVENT_DISPLAY_ORIENTATION, current_orientation);
|
||||||
SDL_SetDisplayContentScale(existing_display, content_scale);
|
SDL_SetDisplayContentScale(existing_display, content_scale);
|
||||||
|
WIN_GetHDRProperties(_this, hMonitor, &HDR);
|
||||||
|
SDL_SetDisplayHDRProperties(existing_display, &HDR);
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -430,6 +592,7 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI
|
||||||
display.device = _this;
|
display.device = _this;
|
||||||
display.driverdata = displaydata;
|
display.driverdata = displaydata;
|
||||||
WIN_GetDisplayBounds(_this, &display, &displaydata->bounds);
|
WIN_GetDisplayBounds(_this, &display, &displaydata->bounds);
|
||||||
|
WIN_GetHDRProperties(_this, hMonitor, &display.HDR);
|
||||||
SDL_AddVideoDisplay(&display, SDL_FALSE);
|
SDL_AddVideoDisplay(&display, SDL_FALSE);
|
||||||
SDL_free(display.name);
|
SDL_free(display.name);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,18 @@
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The value for the SDR white level on an SDR display, scRGB 1.0 */
|
||||||
|
#define SDR_DISPLAY_WHITE_LEVEL 80.0f
|
||||||
|
|
||||||
|
/* The default value for the SDR white level on an HDR display */
|
||||||
|
#define DEFAULT_SDR_WHITE_LEVEL 200.0f
|
||||||
|
|
||||||
|
/* The default value for the HDR white level on an HDR display */
|
||||||
|
#define DEFAULT_HDR_WHITE_LEVEL 400.0f
|
||||||
|
|
||||||
|
/* The maximum value for the HDR white level on an HDR display */
|
||||||
|
#define MAXIMUM_HDR_WHITE_LEVEL 1000.0f
|
||||||
|
|
||||||
#define WINDOW_WIDTH 640
|
#define WINDOW_WIDTH 640
|
||||||
#define WINDOW_HEIGHT 480
|
#define WINDOW_HEIGHT 480
|
||||||
|
|
||||||
|
@ -32,11 +44,27 @@ static SDL_Colorspace colorspace = SDL_COLORSPACE_SRGB;
|
||||||
static const char *colorspace_name = "sRGB";
|
static const char *colorspace_name = "sRGB";
|
||||||
static int renderer_count = 0;
|
static int renderer_count = 0;
|
||||||
static int renderer_index = 0;
|
static int renderer_index = 0;
|
||||||
static int stage_count = 6;
|
|
||||||
static int stage_index = 0;
|
static int stage_index = 0;
|
||||||
static int done;
|
static int done;
|
||||||
|
static SDL_bool HDR_enabled = SDL_FALSE;
|
||||||
|
static float SDR_white_level = SDR_DISPLAY_WHITE_LEVEL;
|
||||||
static float SDR_color_scale = 1.0f;
|
static float SDR_color_scale = 1.0f;
|
||||||
static float HDR_color_scale = 1.0f;
|
static SDL_FRect SDR_calibration_rect;
|
||||||
|
static float HDR_white_level = DEFAULT_HDR_WHITE_LEVEL;
|
||||||
|
static float HDR_color_scale = DEFAULT_HDR_WHITE_LEVEL / SDR_DISPLAY_WHITE_LEVEL;
|
||||||
|
static SDL_FRect HDR_calibration_rect;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
StageClearBackground,
|
||||||
|
StageDrawBackground,
|
||||||
|
StageBlendDrawing,
|
||||||
|
StageBlendTexture,
|
||||||
|
StageHDRCalibration,
|
||||||
|
StageGradientDrawing,
|
||||||
|
StageGradientTexture,
|
||||||
|
StageCount
|
||||||
|
};
|
||||||
|
|
||||||
static void FreeRenderer(void)
|
static void FreeRenderer(void)
|
||||||
{
|
{
|
||||||
|
@ -45,11 +73,61 @@ static void FreeRenderer(void)
|
||||||
renderer = NULL;
|
renderer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float GetDisplaySDRWhiteLevel(void)
|
||||||
|
{
|
||||||
|
SDL_PropertiesID props;
|
||||||
|
|
||||||
|
HDR_enabled = SDL_FALSE;
|
||||||
|
|
||||||
|
props = SDL_GetRendererProperties(renderer);
|
||||||
|
if (SDL_GetNumberProperty(props, SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB) != SDL_COLORSPACE_SCRGB) {
|
||||||
|
/* We're not displaying in HDR, use the SDR white level */
|
||||||
|
return SDR_DISPLAY_WHITE_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
props = SDL_GetDisplayProperties(SDL_GetDisplayForWindow(window));
|
||||||
|
if (!SDL_GetBooleanProperty(props, SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN, SDL_FALSE)) {
|
||||||
|
/* HDR is not enabled on the display */
|
||||||
|
return SDR_DISPLAY_WHITE_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDR_enabled = SDL_TRUE;
|
||||||
|
|
||||||
|
return SDL_GetFloatProperty(props, SDL_PROP_DISPLAY_SDR_WHITE_LEVEL_FLOAT, DEFAULT_SDR_WHITE_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetSDRWhiteLevel(float value)
|
||||||
|
{
|
||||||
|
if (value == SDR_white_level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Log("SDR white level set to %g nits\n", value);
|
||||||
|
SDR_white_level = value;
|
||||||
|
SDR_color_scale = SDR_white_level / SDR_DISPLAY_WHITE_LEVEL;
|
||||||
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UpdateSDRWhiteLevel(void)
|
||||||
|
{
|
||||||
|
SetSDRWhiteLevel(GetDisplaySDRWhiteLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetHDRWhiteLevel(float value)
|
||||||
|
{
|
||||||
|
if (value == HDR_white_level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Log("HDR white level set to %g nits\n", value);
|
||||||
|
HDR_white_level = value;
|
||||||
|
HDR_color_scale = HDR_white_level / SDR_DISPLAY_WHITE_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
static void CreateRenderer(void)
|
static void CreateRenderer(void)
|
||||||
{
|
{
|
||||||
SDL_PropertiesID props;
|
SDL_PropertiesID props;
|
||||||
SDL_RendererInfo info;
|
SDL_RendererInfo info;
|
||||||
float SDR_white_level;
|
|
||||||
|
|
||||||
props = SDL_CreateProperties();
|
props = SDL_CreateProperties();
|
||||||
SDL_SetProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window);
|
SDL_SetProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window);
|
||||||
|
@ -66,15 +144,7 @@ static void CreateRenderer(void)
|
||||||
SDL_Log("Created renderer %s\n", info.name);
|
SDL_Log("Created renderer %s\n", info.name);
|
||||||
renderer_name = info.name;
|
renderer_name = info.name;
|
||||||
|
|
||||||
/* If HDR is enabled... */
|
UpdateSDRWhiteLevel();
|
||||||
if (colorspace == SDL_COLORSPACE_SCRGB) {
|
|
||||||
SDR_white_level = 200.0f;
|
|
||||||
} else {
|
|
||||||
SDR_white_level = 80.0f;
|
|
||||||
}
|
|
||||||
SDR_color_scale = SDR_white_level / 80.0f;
|
|
||||||
|
|
||||||
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NextRenderer( void )
|
static void NextRenderer( void )
|
||||||
|
@ -107,12 +177,12 @@ static void PrevRenderer(void)
|
||||||
|
|
||||||
static void NextStage(void)
|
static void NextStage(void)
|
||||||
{
|
{
|
||||||
if (stage_count <= 0) {
|
if (StageCount <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
++stage_index;
|
++stage_index;
|
||||||
if (stage_index == stage_count) {
|
if (stage_index == StageCount) {
|
||||||
stage_index = 0;
|
stage_index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +191,7 @@ static void PrevStage(void)
|
||||||
{
|
{
|
||||||
--stage_index;
|
--stage_index;
|
||||||
if (stage_index == -1) {
|
if (stage_index == -1) {
|
||||||
stage_index += stage_count;
|
stage_index += StageCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,6 +458,11 @@ 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);
|
SDL_RenderGeometryRaw(renderer, NULL, xy, xy_stride, color, color_stride, NULL, 0, num_vertices, indices, num_indices, size_indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float scRGBtoNits(float v)
|
||||||
|
{
|
||||||
|
return v * 80.0f;
|
||||||
|
}
|
||||||
|
|
||||||
static float scRGBfromNits(float v)
|
static float scRGBfromNits(float v)
|
||||||
{
|
{
|
||||||
return v / 80.0f;
|
return v / 80.0f;
|
||||||
|
@ -413,6 +488,11 @@ static float sRGBFromLinear(float v)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float sRGBtoNits(float v)
|
||||||
|
{
|
||||||
|
return scRGBtoNits(sRGBtoLinear(v));
|
||||||
|
}
|
||||||
|
|
||||||
static float sRGBfromNits(float v)
|
static float sRGBfromNits(float v)
|
||||||
{
|
{
|
||||||
return sRGBFromLinear(scRGBfromNits(v));
|
return sRGBFromLinear(scRGBfromNits(v));
|
||||||
|
@ -432,28 +512,30 @@ static void RenderGradientDrawing(void)
|
||||||
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
DrawTextWhite(x, y, "SDR gradient (%d nits)", 80);
|
DrawTextWhite(x, y, "SDR gradient (%g nits)", SDR_white_level);
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(80.0f));
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
||||||
y += 64.0f;
|
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(SDR_white_level));
|
||||||
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
|
||||||
|
|
||||||
DrawTextWhite(x, y, "HDR gradient (%d nits)", 400);
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
|
||||||
SDL_SetRenderColorScale(renderer, HDR_color_scale);
|
|
||||||
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(400.0f));
|
|
||||||
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
y += 64.0f;
|
y += 64.0f;
|
||||||
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
DrawTextWhite(x, y, "HDR gradient (%d nits)", 1000);
|
DrawTextWhite(x, y, "HDR gradient (%g nits)", HDR_white_level);
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
SDL_SetRenderColorScale(renderer, HDR_color_scale);
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
||||||
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(1000));
|
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(HDR_white_level));
|
||||||
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
|
y += 64.0f;
|
||||||
|
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
|
DrawTextWhite(x, y, "HDR gradient (%g nits)", MAXIMUM_HDR_WHITE_LEVEL);
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
||||||
|
DrawGradient(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(MAXIMUM_HDR_WHITE_LEVEL));
|
||||||
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
y += 64.0f;
|
y += 64.0f;
|
||||||
}
|
}
|
||||||
|
@ -517,28 +599,119 @@ static void RenderGradientTexture(void)
|
||||||
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
DrawTextWhite(x, y, "SDR gradient (%d nits)", 80);
|
DrawTextWhite(x, y, "SDR gradient (%g nits)", SDR_white_level);
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(80));
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
||||||
|
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(SDR_white_level));
|
||||||
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
y += 64.0f;
|
y += 64.0f;
|
||||||
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
DrawTextWhite(x, y, "HDR gradient (%d nits)", 400);
|
DrawTextWhite(x, y, "HDR gradient (%g nits)", HDR_white_level);
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(400));
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
||||||
|
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(HDR_white_level));
|
||||||
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
y += 64.0f;
|
y += 64.0f;
|
||||||
|
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
DrawTextWhite(x, y, "HDR gradient (%d nits)", 1000);
|
DrawTextWhite(x, y, "HDR gradient (%g nits)", MAXIMUM_HDR_WHITE_LEVEL);
|
||||||
y += TEXT_LINE_ADVANCE;
|
y += TEXT_LINE_ADVANCE;
|
||||||
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(1000));
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
||||||
|
DrawGradientTexture(x, y, WINDOW_WIDTH - 2 * x, 64.0f, 0.0f, sRGBfromNits(MAXIMUM_HDR_WHITE_LEVEL));
|
||||||
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
y += 64.0f;
|
y += 64.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RenderHDRCalibration(void)
|
||||||
|
{
|
||||||
|
SDL_FRect rect;
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
float x = TEXT_START_X;
|
||||||
|
float y = TEXT_START_Y;
|
||||||
|
DrawTextWhite(x, y, "%s %s", renderer_name, colorspace_name);
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
DrawTextWhite(x, y, "Test: HDR calibration");
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
|
if (!HDR_enabled) {
|
||||||
|
DrawTextWhite(x, y, "HDR not enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTextWhite(x, y, "Select HDR maximum brightness (%g nits)", HDR_white_level);
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
DrawTextWhite(x, y, "The square in the middle should just barely be visible");
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
HDR_calibration_rect.x = x;
|
||||||
|
HDR_calibration_rect.y = y;
|
||||||
|
HDR_calibration_rect.w = WINDOW_WIDTH - 2 * x;
|
||||||
|
HDR_calibration_rect.h = 64.0f;
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||||
|
SDL_SetRenderColorScale(renderer, MAXIMUM_HDR_WHITE_LEVEL / SDR_DISPLAY_WHITE_LEVEL);
|
||||||
|
SDL_RenderFillRect(renderer, &HDR_calibration_rect);
|
||||||
|
SDL_SetRenderColorScale(renderer, HDR_color_scale);
|
||||||
|
rect = HDR_calibration_rect;
|
||||||
|
rect.h -= 4.0f;
|
||||||
|
rect.w = 60.0f;
|
||||||
|
rect.x = (WINDOW_WIDTH - rect.w) / 2.0f;
|
||||||
|
rect.y += 2.0f;
|
||||||
|
SDL_RenderFillRect(renderer, &rect);
|
||||||
|
SDL_SetRenderColorScale(renderer, SDR_color_scale);
|
||||||
|
y += 64.0f;
|
||||||
|
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
|
||||||
|
DrawTextWhite(x, y, "Select SDR maximum brightness (%g nits)", SDR_white_level);
|
||||||
|
y += TEXT_LINE_ADVANCE;
|
||||||
|
SDR_calibration_rect.x = x;
|
||||||
|
SDR_calibration_rect.y = y;
|
||||||
|
SDR_calibration_rect.w = WINDOW_WIDTH - 2 * x;
|
||||||
|
SDR_calibration_rect.h = 64.0f;
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||||
|
SDL_RenderFillRect(renderer, &SDR_calibration_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnHDRCalibrationMouseHeld(float x, float y)
|
||||||
|
{
|
||||||
|
SDL_FPoint mouse = { x, y };
|
||||||
|
|
||||||
|
if (SDL_PointInRectFloat(&mouse, &HDR_calibration_rect)) {
|
||||||
|
float v = (x - HDR_calibration_rect.x) / HDR_calibration_rect.w;
|
||||||
|
v *= (sRGBfromNits(MAXIMUM_HDR_WHITE_LEVEL) - 1.0f);
|
||||||
|
v += 1.0f;
|
||||||
|
v = sRGBtoNits(v);
|
||||||
|
SetHDRWhiteLevel(v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_PointInRectFloat(&mouse, &SDR_calibration_rect)) {
|
||||||
|
float v = (x - SDR_calibration_rect.x) / SDR_calibration_rect.w;
|
||||||
|
v *= (sRGBfromNits(MAXIMUM_HDR_WHITE_LEVEL) - 1.0f);
|
||||||
|
v += 1.0f;
|
||||||
|
v = sRGBtoNits(v);
|
||||||
|
SetSDRWhiteLevel(v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnMouseHeld(float x, float y)
|
||||||
|
{
|
||||||
|
if (stage_index == StageHDRCalibration) {
|
||||||
|
OnHDRCalibrationMouseHeld(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void loop(void)
|
static void loop(void)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
@ -565,6 +738,14 @@ static void loop(void)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
||||||
|
OnMouseHeld(event.button.x, event.button.y);
|
||||||
|
} else if (event.type == SDL_EVENT_MOUSE_MOTION) {
|
||||||
|
if (event.motion.state) {
|
||||||
|
OnMouseHeld(event.button.x, event.button.y);
|
||||||
|
}
|
||||||
|
} else if (event.type == SDL_EVENT_DISPLAY_HDR_STATE_CHANGED) {
|
||||||
|
UpdateSDRWhiteLevel();
|
||||||
} else if (event.type == SDL_EVENT_QUIT) {
|
} else if (event.type == SDL_EVENT_QUIT) {
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
|
@ -575,22 +756,25 @@ static void loop(void)
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
switch (stage_index) {
|
switch (stage_index) {
|
||||||
case 0:
|
case StageClearBackground:
|
||||||
RenderClearBackground();
|
RenderClearBackground();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case StageDrawBackground:
|
||||||
RenderDrawBackground();
|
RenderDrawBackground();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case StageBlendDrawing:
|
||||||
RenderBlendDrawing();
|
RenderBlendDrawing();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case StageBlendTexture:
|
||||||
RenderBlendTexture();
|
RenderBlendTexture();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case StageHDRCalibration:
|
||||||
|
RenderHDRCalibration();
|
||||||
|
break;
|
||||||
|
case StageGradientDrawing:
|
||||||
RenderGradientDrawing();
|
RenderGradientDrawing();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case StageGradientTexture:
|
||||||
RenderGradientTexture();
|
RenderGradientTexture();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,16 @@
|
||||||
|
|
||||||
#include "icon.h"
|
#include "icon.h"
|
||||||
|
|
||||||
|
/* The value for the SDR white level on an SDR display, scRGB 1.0 */
|
||||||
|
#define SDR_DISPLAY_WHITE_LEVEL 80.0f
|
||||||
|
|
||||||
|
/* The default value for the SDR white level on an HDR display */
|
||||||
|
#define DEFAULT_SDR_WHITE_LEVEL 200.0f
|
||||||
|
|
||||||
|
/* The default value for the HDR white level on an HDR display */
|
||||||
|
#define DEFAULT_HDR_WHITE_LEVEL 400.0f
|
||||||
|
|
||||||
|
|
||||||
static SDL_Texture *sprite;
|
static SDL_Texture *sprite;
|
||||||
static SDL_FRect *positions;
|
static SDL_FRect *positions;
|
||||||
static SDL_FRect *velocities;
|
static SDL_FRect *velocities;
|
||||||
|
@ -90,6 +100,33 @@ struct SwsContextContainer
|
||||||
static const char *SWS_CONTEXT_CONTAINER_PROPERTY = "SWS_CONTEXT_CONTAINER";
|
static const char *SWS_CONTEXT_CONTAINER_PROPERTY = "SWS_CONTEXT_CONTAINER";
|
||||||
static int done;
|
static int done;
|
||||||
|
|
||||||
|
/* This function isn't Windows specific, but we haven't hooked up HDR video support on other platforms yet */
|
||||||
|
#ifdef SDL_PLATFORM_WIN32
|
||||||
|
static void GetDisplayHDRProperties(SDL_bool *HDR_display, float *SDR_white_level)
|
||||||
|
{
|
||||||
|
SDL_PropertiesID props;
|
||||||
|
|
||||||
|
props = SDL_GetRendererProperties(renderer);
|
||||||
|
if (SDL_GetNumberProperty(props, SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB) != SDL_COLORSPACE_SCRGB) {
|
||||||
|
/* We're not displaying in HDR, use the SDR white level */
|
||||||
|
*HDR_display = SDL_FALSE;
|
||||||
|
*SDR_white_level = SDR_DISPLAY_WHITE_LEVEL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
props = SDL_GetDisplayProperties(SDL_GetDisplayForWindow(window));
|
||||||
|
if (!SDL_GetBooleanProperty(props, SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN, SDL_FALSE)) {
|
||||||
|
/* HDR is not enabled on the display */
|
||||||
|
*HDR_display = SDL_FALSE;
|
||||||
|
*SDR_white_level = SDR_DISPLAY_WHITE_LEVEL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*HDR_display = SDL_TRUE;
|
||||||
|
*SDR_white_level = SDL_GetFloatProperty(props, SDL_PROP_DISPLAY_SDR_WHITE_LEVEL_FLOAT, DEFAULT_SDR_WHITE_LEVEL);
|
||||||
|
}
|
||||||
|
#endif /* SDL_PLATFORM_WIN32 */
|
||||||
|
|
||||||
static SDL_bool CreateWindowAndRenderer(Uint32 window_flags, const char *driver)
|
static SDL_bool CreateWindowAndRenderer(Uint32 window_flags, const char *driver)
|
||||||
{
|
{
|
||||||
SDL_PropertiesID props;
|
SDL_PropertiesID props;
|
||||||
|
@ -646,14 +683,16 @@ static SDL_bool GetTextureForD3D11Frame(AVFrame *frame, SDL_Texture **texture)
|
||||||
SDL_QueryTexture(*texture, NULL, NULL, &texture_width, &texture_height);
|
SDL_QueryTexture(*texture, NULL, NULL, &texture_width, &texture_height);
|
||||||
}
|
}
|
||||||
if (!*texture || (UINT)texture_width != desc.Width || (UINT)texture_height != desc.Height) {
|
if (!*texture || (UINT)texture_width != desc.Width || (UINT)texture_height != desc.Height) {
|
||||||
SDL_bool HDR_display = SDL_TRUE;
|
float SDR_white_level, video_white_level;
|
||||||
|
SDL_bool HDR_display = SDL_FALSE;
|
||||||
SDL_bool HDR_video = SDL_FALSE;
|
SDL_bool HDR_video = SDL_FALSE;
|
||||||
float display_white_level, video_white_level;
|
|
||||||
|
|
||||||
if (*texture) {
|
if (*texture) {
|
||||||
SDL_DestroyTexture(*texture);
|
SDL_DestroyTexture(*texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetDisplayHDRProperties(&HDR_display, &SDR_white_level);
|
||||||
|
|
||||||
SDL_PropertiesID props = SDL_CreateProperties();
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, GetFrameColorspace(frame));
|
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, GetFrameColorspace(frame));
|
||||||
switch (desc.Format) {
|
switch (desc.Format) {
|
||||||
|
@ -683,15 +722,12 @@ static SDL_bool GetTextureForD3D11Frame(AVFrame *frame, SDL_Texture **texture)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HDR_video != HDR_display) {
|
if (HDR_video != HDR_display) {
|
||||||
/* Use some reasonable assumptions for white levels */
|
|
||||||
if (HDR_display) {
|
if (HDR_display) {
|
||||||
display_white_level = 200.0f; /* SDR white level */
|
video_white_level = SDR_DISPLAY_WHITE_LEVEL;
|
||||||
video_white_level = 80.0f;
|
|
||||||
} else {
|
} else {
|
||||||
display_white_level = 80.0f;
|
video_white_level = DEFAULT_HDR_WHITE_LEVEL;
|
||||||
video_white_level = 400.0f;
|
|
||||||
}
|
}
|
||||||
SDL_SetRenderColorScale(renderer, display_white_level / video_white_level);
|
SDL_SetRenderColorScale(renderer, SDR_white_level / video_white_level);
|
||||||
} else {
|
} else {
|
||||||
SDL_SetRenderColorScale(renderer, 1.0f);
|
SDL_SetRenderColorScale(renderer, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue