mirror of
https://github.com/obsproject/obs-studio
synced 2024-10-23 08:01:43 +00:00
libobs/graphics: Add color space support
This commit is contained in:
parent
99afbc687e
commit
abddfead2f
|
@ -47,6 +47,14 @@ Graphics Enumerations
|
|||
- GS_BGRA_UNORM - BGRA, 8 bits per channel, no SRGB aliasing
|
||||
- GS_RG16 - RG, 16 bits per channel
|
||||
|
||||
.. type:: enum gs_color_space
|
||||
|
||||
Color space. Can be one of the following values:
|
||||
|
||||
- GS_CS_SRGB - sRGB
|
||||
- GS_CS_709_EXTENDED - Canvas, Mac EDR (HDR)
|
||||
- GS_CS_709_SCRGB - 1.0 = 80 nits, Windows/Linux HDR
|
||||
|
||||
.. type:: enum gs_zstencil_format
|
||||
|
||||
Z-Stencil buffer format. Can be one of the following values:
|
||||
|
@ -542,6 +550,13 @@ Swap Chains
|
|||
|
||||
---------------------
|
||||
|
||||
.. function:: void gs_update_color_space(void)
|
||||
|
||||
Updates the color space of the swap chain based on the HDR status of
|
||||
the nearest monitor
|
||||
|
||||
---------------------
|
||||
|
||||
.. function:: void gs_get_size(uint32_t *cx, uint32_t *cy)
|
||||
|
||||
Gets the size of the currently active swap chain
|
||||
|
@ -613,6 +628,12 @@ Resource Loading
|
|||
Draw Functions
|
||||
--------------
|
||||
|
||||
.. function:: enum gs_color_space gs_get_color_space(void)
|
||||
|
||||
:return: The currently active color space
|
||||
|
||||
---------------------
|
||||
|
||||
.. function:: gs_texture_t *gs_get_render_target(void)
|
||||
|
||||
:return: The currently active render target
|
||||
|
@ -627,13 +648,23 @@ Draw Functions
|
|||
|
||||
.. function:: void gs_set_render_target(gs_texture_t *tex, gs_zstencil_t *zstencil)
|
||||
|
||||
Sets the active render target
|
||||
Sets the active render target with implicit GS_CS_SRGB color space
|
||||
|
||||
:param tex: Texture to set as the active render target
|
||||
:param zstencil: Z-stencil to use as the active render target
|
||||
|
||||
---------------------
|
||||
|
||||
.. function:: void gs_set_render_target_with_color_space(gs_texture_t *tex, gs_zstencil_t *zstencil, enum gs_color_space space)
|
||||
|
||||
Sets the active render target along with color space
|
||||
|
||||
:param tex: Texture to set as the active render target
|
||||
:param zstencil: Z-stencil to use as the active render target
|
||||
:param space: Color space of the render target
|
||||
|
||||
---------------------
|
||||
|
||||
.. function:: void gs_set_cube_render_target(gs_texture_t *cubetex, int side, gs_zstencil_t *zstencil)
|
||||
|
||||
Sets a cubemap side as the active render target
|
||||
|
|
|
@ -66,21 +66,78 @@ gs_obj::~gs_obj()
|
|||
next->prev_next = prev_next;
|
||||
}
|
||||
|
||||
static inline void make_swap_desc(DXGI_SWAP_CHAIN_DESC &desc,
|
||||
const gs_init_data *data,
|
||||
DXGI_SWAP_EFFECT effect, UINT flags)
|
||||
static bool screen_supports_hdr(gs_device_t *device, HMONITOR hMonitor)
|
||||
{
|
||||
IDXGIFactory1 *factory1 = device->factory;
|
||||
if (!factory1->IsCurrent()) {
|
||||
device->InitFactory();
|
||||
factory1 = device->factory;
|
||||
}
|
||||
|
||||
ComPtr<IDXGIAdapter> adapter;
|
||||
ComPtr<IDXGIOutput> output;
|
||||
ComPtr<IDXGIOutput6> output6;
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(factory1->EnumAdapters(adapterIndex, &adapter));
|
||||
++adapterIndex) {
|
||||
for (UINT outputIndex = 0;
|
||||
SUCCEEDED(adapter->EnumOutputs(outputIndex, &output));
|
||||
++outputIndex) {
|
||||
if (SUCCEEDED(output->QueryInterface(&output6))) {
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
if (SUCCEEDED(output6->GetDesc1(&desc1)) &&
|
||||
desc1.Monitor == hMonitor) {
|
||||
return desc1.ColorSpace ==
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum gs_color_space get_next_space(gs_device_t *device, HWND hwnd)
|
||||
{
|
||||
enum gs_color_space next_space = GS_CS_SRGB;
|
||||
const HMONITOR hMonitor =
|
||||
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (hMonitor) {
|
||||
if (screen_supports_hdr(device, hMonitor))
|
||||
next_space = GS_CS_709_SCRGB;
|
||||
}
|
||||
|
||||
return next_space;
|
||||
}
|
||||
|
||||
static enum gs_color_format
|
||||
get_swap_format_from_space(gs_color_space space, gs_color_format sdr_format)
|
||||
{
|
||||
return (space == GS_CS_709_SCRGB) ? GS_RGBA16F : sdr_format;
|
||||
}
|
||||
|
||||
static inline enum gs_color_space
|
||||
make_swap_desc(gs_device *device, DXGI_SWAP_CHAIN_DESC &desc,
|
||||
const gs_init_data *data, DXGI_SWAP_EFFECT effect, UINT flags)
|
||||
{
|
||||
const HWND hwnd = (HWND)data->window.hwnd;
|
||||
const enum gs_color_space space = get_next_space(device, hwnd);
|
||||
const gs_color_format format =
|
||||
get_swap_format_from_space(space, data->format);
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.BufferDesc.Width = data->cx;
|
||||
desc.BufferDesc.Height = data->cy;
|
||||
desc.BufferDesc.Format = ConvertGSTextureFormatView(data->format);
|
||||
desc.BufferDesc.Format = ConvertGSTextureFormatView(format);
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc.BufferCount = data->num_backbuffers;
|
||||
desc.OutputWindow = (HWND)data->window.hwnd;
|
||||
desc.OutputWindow = hwnd;
|
||||
desc.Windowed = TRUE;
|
||||
desc.SwapEffect = effect;
|
||||
desc.Flags = flags;
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
void gs_swap_chain::InitTarget(uint32_t cx, uint32_t cy)
|
||||
|
@ -128,7 +185,7 @@ void gs_swap_chain::InitZStencilBuffer(uint32_t cx, uint32_t cy)
|
|||
}
|
||||
}
|
||||
|
||||
void gs_swap_chain::Resize(uint32_t cx, uint32_t cy)
|
||||
void gs_swap_chain::Resize(uint32_t cx, uint32_t cy, gs_color_format format)
|
||||
{
|
||||
RECT clientRect;
|
||||
HRESULT hr;
|
||||
|
@ -150,25 +207,40 @@ void gs_swap_chain::Resize(uint32_t cx, uint32_t cy)
|
|||
cy = clientRect.bottom;
|
||||
}
|
||||
|
||||
hr = swap->ResizeBuffers(swapDesc.BufferCount, cx, cy,
|
||||
DXGI_FORMAT_UNKNOWN, swapDesc.Flags);
|
||||
const DXGI_FORMAT dxgi_format = ConvertGSTextureFormatView(format);
|
||||
hr = swap->ResizeBuffers(swapDesc.BufferCount, cx, cy, dxgi_format,
|
||||
swapDesc.Flags);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to resize swap buffers", hr);
|
||||
ComQIPtr<IDXGISwapChain3> swap3 = swap;
|
||||
if (swap3) {
|
||||
const DXGI_COLOR_SPACE_TYPE dxgi_space =
|
||||
(format == GS_RGBA16F)
|
||||
? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
|
||||
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
hr = swap3->SetColorSpace1(dxgi_space);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to set color space", hr);
|
||||
}
|
||||
|
||||
target.dxgiFormatResource = ConvertGSTextureFormatResource(format);
|
||||
target.dxgiFormatView = dxgi_format;
|
||||
target.dxgiFormatViewLinear = ConvertGSTextureFormatViewLinear(format);
|
||||
InitTarget(cx, cy);
|
||||
InitZStencilBuffer(cx, cy);
|
||||
}
|
||||
|
||||
void gs_swap_chain::Init()
|
||||
{
|
||||
const gs_color_format format = get_swap_format_from_space(
|
||||
get_next_space(device, hwnd), initData.format);
|
||||
|
||||
target.device = device;
|
||||
target.isRenderTarget = true;
|
||||
target.format = initData.format;
|
||||
target.dxgiFormatResource =
|
||||
ConvertGSTextureFormatResource(initData.format);
|
||||
target.dxgiFormatView = ConvertGSTextureFormatView(initData.format);
|
||||
target.dxgiFormatViewLinear =
|
||||
ConvertGSTextureFormatViewLinear(initData.format);
|
||||
target.dxgiFormatResource = ConvertGSTextureFormatResource(format);
|
||||
target.dxgiFormatView = ConvertGSTextureFormatView(format);
|
||||
target.dxgiFormatViewLinear = ConvertGSTextureFormatViewLinear(format);
|
||||
InitTarget(initData.cx, initData.cy);
|
||||
|
||||
zs.device = device;
|
||||
|
@ -180,7 +252,8 @@ void gs_swap_chain::Init()
|
|||
gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data)
|
||||
: gs_obj(device, gs_type::gs_swap_chain),
|
||||
hwnd((HWND)data->window.hwnd),
|
||||
initData(*data)
|
||||
initData(*data),
|
||||
space(GS_CS_SRGB)
|
||||
{
|
||||
DXGI_SWAP_EFFECT effect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
UINT flags = 0;
|
||||
|
@ -203,7 +276,7 @@ gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data)
|
|||
}
|
||||
}
|
||||
|
||||
make_swap_desc(swapDesc, &initData, effect, flags);
|
||||
space = make_swap_desc(device, swapDesc, &initData, effect, flags);
|
||||
HRESULT hr = device->factory->CreateSwapChain(device->device, &swapDesc,
|
||||
swap.Assign());
|
||||
if (FAILED(hr))
|
||||
|
@ -1340,6 +1413,24 @@ gs_swapchain_t *device_swapchain_create(gs_device_t *device,
|
|||
return swap;
|
||||
}
|
||||
|
||||
static void device_resize_internal(gs_device_t *device, uint32_t cx,
|
||||
uint32_t cy, gs_color_space space)
|
||||
{
|
||||
try {
|
||||
const gs_color_format format = get_swap_format_from_space(
|
||||
space, device->curSwapChain->initData.format);
|
||||
|
||||
device->context->OMSetRenderTargets(0, NULL, NULL);
|
||||
device->curSwapChain->Resize(cx, cy, format);
|
||||
device->curSwapChain->space = space;
|
||||
device->curFramebufferInvalidate = true;
|
||||
} catch (const HRError &error) {
|
||||
blog(LOG_ERROR, "device_resize_internal (D3D11): %s (%08lX)",
|
||||
error.str, error.hr);
|
||||
LogD3D11ErrorDetails(error, device);
|
||||
}
|
||||
}
|
||||
|
||||
void device_resize(gs_device_t *device, uint32_t cx, uint32_t cy)
|
||||
{
|
||||
if (!device->curSwapChain) {
|
||||
|
@ -1347,14 +1438,26 @@ void device_resize(gs_device_t *device, uint32_t cx, uint32_t cy)
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
device->context->OMSetRenderTargets(0, NULL, NULL);
|
||||
device->curSwapChain->Resize(cx, cy);
|
||||
device->curFramebufferInvalidate = true;
|
||||
} catch (const HRError &error) {
|
||||
blog(LOG_ERROR, "device_resize (D3D11): %s (%08lX)", error.str,
|
||||
error.hr);
|
||||
LogD3D11ErrorDetails(error, device);
|
||||
const enum gs_color_space next_space =
|
||||
get_next_space(device, device->curSwapChain->hwnd);
|
||||
device_resize_internal(device, cx, cy, next_space);
|
||||
}
|
||||
|
||||
enum gs_color_space device_get_color_space(gs_device_t *device)
|
||||
{
|
||||
return device->curColorSpace;
|
||||
}
|
||||
|
||||
void device_update_color_space(gs_device_t *device)
|
||||
{
|
||||
if (device->curSwapChain) {
|
||||
const enum gs_color_space next_space =
|
||||
get_next_space(device, device->curSwapChain->hwnd);
|
||||
if (device->curSwapChain->space != next_space)
|
||||
device_resize_internal(device, 0, 0, next_space);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"device_update_color_space (D3D11): No active swap");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1874,8 +1977,10 @@ gs_zstencil_t *device_get_zstencil_target(const gs_device_t *device)
|
|||
return device->curZStencilBuffer;
|
||||
}
|
||||
|
||||
void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil)
|
||||
static void device_set_render_target_internal(gs_device_t *device,
|
||||
gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil,
|
||||
enum gs_color_space space)
|
||||
{
|
||||
if (device->curSwapChain) {
|
||||
if (!tex)
|
||||
|
@ -1885,12 +1990,13 @@ void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
|||
}
|
||||
|
||||
if (device->curRenderTarget == tex &&
|
||||
device->curZStencilBuffer == zstencil)
|
||||
return;
|
||||
device->curZStencilBuffer == zstencil) {
|
||||
device->curColorSpace = space;
|
||||
}
|
||||
|
||||
if (tex && tex->type != GS_TEXTURE_2D) {
|
||||
blog(LOG_ERROR,
|
||||
"device_set_render_target (D3D11): texture is not a 2D texture");
|
||||
"device_set_render_target_internal (D3D11): texture is not a 2D texture");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1898,12 +2004,27 @@ void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
|||
if (device->curRenderTarget != tex2d || device->curRenderSide != 0 ||
|
||||
device->curZStencilBuffer != zstencil) {
|
||||
device->curRenderTarget = tex2d;
|
||||
device->curRenderSide = 0;
|
||||
device->curZStencilBuffer = zstencil;
|
||||
device->curRenderSide = 0;
|
||||
device->curColorSpace = space;
|
||||
device->curFramebufferInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil)
|
||||
{
|
||||
device_set_render_target_internal(device, tex, zstencil, GS_CS_SRGB);
|
||||
}
|
||||
|
||||
void device_set_render_target_with_color_space(gs_device_t *device,
|
||||
gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil,
|
||||
enum gs_color_space space)
|
||||
{
|
||||
device_set_render_target_internal(device, tex, zstencil, space);
|
||||
}
|
||||
|
||||
void device_set_cube_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
int side, gs_zstencil_t *zstencil)
|
||||
{
|
||||
|
@ -1931,8 +2052,9 @@ void device_set_cube_render_target(gs_device_t *device, gs_texture_t *tex,
|
|||
if (device->curRenderTarget != tex2d || device->curRenderSide != side ||
|
||||
device->curZStencilBuffer != zstencil) {
|
||||
device->curRenderTarget = tex2d;
|
||||
device->curRenderSide = side;
|
||||
device->curZStencilBuffer = zstencil;
|
||||
device->curRenderSide = side;
|
||||
device->curColorSpace = GS_CS_SRGB;
|
||||
device->curFramebufferInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
@ -2177,11 +2299,14 @@ void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swapchain)
|
|||
|
||||
device->curSwapChain = swapchain;
|
||||
|
||||
if (is_cube)
|
||||
if (is_cube) {
|
||||
device_set_cube_render_target(device, target,
|
||||
device->curRenderSide, zs);
|
||||
else
|
||||
device_set_render_target(device, target, zs);
|
||||
} else {
|
||||
const enum gs_color_space space = swapchain ? swapchain->space
|
||||
: GS_CS_SRGB;
|
||||
device_set_render_target_internal(device, target, zs, space);
|
||||
}
|
||||
}
|
||||
|
||||
void device_clear(gs_device_t *device, uint32_t clear_flags,
|
||||
|
|
|
@ -820,6 +820,7 @@ struct gs_swap_chain : gs_obj {
|
|||
HWND hwnd;
|
||||
gs_init_data initData;
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc = {};
|
||||
gs_color_space space;
|
||||
UINT presentFlags = 0;
|
||||
|
||||
gs_texture_2d target;
|
||||
|
@ -829,7 +830,7 @@ struct gs_swap_chain : gs_obj {
|
|||
|
||||
void InitTarget(uint32_t cx, uint32_t cy);
|
||||
void InitZStencilBuffer(uint32_t cx, uint32_t cy);
|
||||
void Resize(uint32_t cx, uint32_t cy);
|
||||
void Resize(uint32_t cx, uint32_t cy, gs_color_format format);
|
||||
void Init();
|
||||
|
||||
void Rebuild(ID3D11Device *dev);
|
||||
|
@ -991,6 +992,7 @@ struct gs_device {
|
|||
gs_texture_2d *curRenderTarget = nullptr;
|
||||
gs_zstencil_buffer *curZStencilBuffer = nullptr;
|
||||
int curRenderSide = 0;
|
||||
enum gs_color_space curColorSpace = GS_CS_SRGB;
|
||||
bool curFramebufferSrgb = false;
|
||||
bool curFramebufferInvalidate = false;
|
||||
gs_texture *curTextures[GS_MAX_TEXTURES];
|
||||
|
|
|
@ -340,6 +340,17 @@ void device_resize(gs_device_t *device, uint32_t cx, uint32_t cy)
|
|||
gl_update(device);
|
||||
}
|
||||
|
||||
enum gs_color_space device_get_color_space(gs_device_t *device)
|
||||
{
|
||||
return device->cur_color_space;
|
||||
}
|
||||
|
||||
void device_update_color_space(gs_device_t *device)
|
||||
{
|
||||
if (!device->cur_swap)
|
||||
blog(LOG_WARNING, "device_display_change (GL): No active swap");
|
||||
}
|
||||
|
||||
void device_get_size(const gs_device_t *device, uint32_t *cx, uint32_t *cy)
|
||||
{
|
||||
if (device->cur_swap) {
|
||||
|
@ -819,9 +830,9 @@ static bool attach_zstencil(struct fbo_info *fbo, gs_zstencil_t *zs)
|
|||
}
|
||||
|
||||
static bool set_target(gs_device_t *device, gs_texture_t *tex, int side,
|
||||
gs_zstencil_t *zs)
|
||||
gs_zstencil_t *zs, enum gs_color_space space)
|
||||
{
|
||||
struct fbo_info *fbo;
|
||||
device->cur_color_space = space;
|
||||
|
||||
if (device->cur_render_target == tex &&
|
||||
device->cur_zstencil_buffer == zs &&
|
||||
|
@ -835,7 +846,7 @@ static bool set_target(gs_device_t *device, gs_texture_t *tex, int side,
|
|||
if (!tex)
|
||||
return set_current_fbo(device, NULL);
|
||||
|
||||
fbo = get_fbo_by_tex(tex);
|
||||
struct fbo_info *const fbo = get_fbo_by_tex(tex);
|
||||
if (!fbo)
|
||||
return false;
|
||||
|
||||
|
@ -864,7 +875,7 @@ void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
|||
}
|
||||
}
|
||||
|
||||
if (!set_target(device, tex, 0, zstencil))
|
||||
if (!set_target(device, tex, 0, zstencil, GS_CS_SRGB))
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
|
@ -873,6 +884,33 @@ fail:
|
|||
blog(LOG_ERROR, "device_set_render_target (GL) failed");
|
||||
}
|
||||
|
||||
void device_set_render_target_with_color_space(gs_device_t *device,
|
||||
gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil,
|
||||
enum gs_color_space space)
|
||||
{
|
||||
if (tex) {
|
||||
if (tex->type != GS_TEXTURE_2D) {
|
||||
blog(LOG_ERROR, "Texture is not a 2D texture");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!tex->is_render_target) {
|
||||
blog(LOG_ERROR, "Texture is not a render target");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!set_target(device, tex, 0, zstencil, space))
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
blog(LOG_ERROR,
|
||||
"device_set_render_target_with_color_space (GL) failed");
|
||||
}
|
||||
|
||||
void device_set_cube_render_target(gs_device_t *device, gs_texture_t *cubetex,
|
||||
int side, gs_zstencil_t *zstencil)
|
||||
{
|
||||
|
@ -888,7 +926,7 @@ void device_set_cube_render_target(gs_device_t *device, gs_texture_t *cubetex,
|
|||
}
|
||||
}
|
||||
|
||||
if (!set_target(device, cubetex, side, zstencil))
|
||||
if (!set_target(device, cubetex, side, zstencil, GS_CS_SRGB))
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
|
|
|
@ -653,6 +653,7 @@ struct gs_device {
|
|||
gs_shader_t *cur_pixel_shader;
|
||||
gs_swapchain_t *cur_swap;
|
||||
struct gs_program *cur_program;
|
||||
enum gs_color_space cur_color_space;
|
||||
|
||||
struct gs_program *first_program;
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ EXPORT void *device_get_device_obj(gs_device_t *device);
|
|||
EXPORT gs_swapchain_t *device_swapchain_create(gs_device_t *device,
|
||||
const struct gs_init_data *data);
|
||||
EXPORT void device_resize(gs_device_t *device, uint32_t x, uint32_t y);
|
||||
EXPORT enum gs_color_space device_get_color_space(gs_device_t *device);
|
||||
EXPORT void device_update_color_space(gs_device_t *device);
|
||||
EXPORT void device_get_size(const gs_device_t *device, uint32_t *x,
|
||||
uint32_t *y);
|
||||
EXPORT uint32_t device_get_width(const gs_device_t *device);
|
||||
|
@ -104,6 +106,9 @@ EXPORT gs_texture_t *device_get_render_target(const gs_device_t *device);
|
|||
EXPORT gs_zstencil_t *device_get_zstencil_target(const gs_device_t *device);
|
||||
EXPORT void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil);
|
||||
EXPORT void device_set_render_target_with_color_space(
|
||||
gs_device_t *device, gs_texture_t *tex, gs_zstencil_t *zstencil,
|
||||
enum gs_color_space space);
|
||||
EXPORT void device_set_cube_render_target(gs_device_t *device,
|
||||
gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
|
|
|
@ -53,6 +53,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
|||
GRAPHICS_IMPORT(device_get_device_obj);
|
||||
GRAPHICS_IMPORT(device_swapchain_create);
|
||||
GRAPHICS_IMPORT(device_resize);
|
||||
GRAPHICS_IMPORT(device_get_color_space);
|
||||
GRAPHICS_IMPORT(device_update_color_space);
|
||||
GRAPHICS_IMPORT(device_get_size);
|
||||
GRAPHICS_IMPORT(device_get_width);
|
||||
GRAPHICS_IMPORT(device_get_height);
|
||||
|
@ -81,6 +83,7 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
|||
GRAPHICS_IMPORT(device_get_render_target);
|
||||
GRAPHICS_IMPORT(device_get_zstencil_target);
|
||||
GRAPHICS_IMPORT(device_set_render_target);
|
||||
GRAPHICS_IMPORT(device_set_render_target_with_color_space);
|
||||
GRAPHICS_IMPORT(device_set_cube_render_target);
|
||||
GRAPHICS_IMPORT(device_enable_framebuffer_srgb);
|
||||
GRAPHICS_IMPORT(device_framebuffer_srgb_enabled);
|
||||
|
|
|
@ -38,6 +38,8 @@ struct gs_exports {
|
|||
gs_swapchain_t *(*device_swapchain_create)(
|
||||
gs_device_t *device, const struct gs_init_data *data);
|
||||
void (*device_resize)(gs_device_t *device, uint32_t x, uint32_t y);
|
||||
enum gs_color_space (*device_get_color_space)(gs_device_t *device);
|
||||
void (*device_update_color_space)(gs_device_t *device);
|
||||
void (*device_get_size)(const gs_device_t *device, uint32_t *x,
|
||||
uint32_t *y);
|
||||
uint32_t (*device_get_width)(const gs_device_t *device);
|
||||
|
@ -103,6 +105,9 @@ struct gs_exports {
|
|||
gs_zstencil_t *(*device_get_zstencil_target)(const gs_device_t *device);
|
||||
void (*device_set_render_target)(gs_device_t *device, gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil);
|
||||
void (*device_set_render_target_with_color_space)(
|
||||
gs_device_t *device, gs_texture_t *tex, gs_zstencil_t *zstencil,
|
||||
enum gs_color_space space);
|
||||
void (*device_set_cube_render_target)(gs_device_t *device,
|
||||
gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
|
|
|
@ -1308,6 +1308,16 @@ void gs_resize(uint32_t x, uint32_t y)
|
|||
graphics->exports.device_resize(graphics->device, x, y);
|
||||
}
|
||||
|
||||
void gs_update_color_space(void)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
||||
if (!gs_valid("gs_update_color_space"))
|
||||
return;
|
||||
|
||||
graphics->exports.device_update_color_space(graphics->device);
|
||||
}
|
||||
|
||||
void gs_get_size(uint32_t *x, uint32_t *y)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
@ -1715,6 +1725,16 @@ gs_shader_t *gs_get_pixel_shader(void)
|
|||
return graphics->exports.device_get_pixel_shader(graphics->device);
|
||||
}
|
||||
|
||||
enum gs_color_space gs_get_color_space(void)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
||||
if (!gs_valid("gs_get_color_space"))
|
||||
return GS_CS_SRGB;
|
||||
|
||||
return graphics->exports.device_get_color_space(graphics->device);
|
||||
}
|
||||
|
||||
gs_texture_t *gs_get_render_target(void)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
@ -1746,6 +1766,19 @@ void gs_set_render_target(gs_texture_t *tex, gs_zstencil_t *zstencil)
|
|||
zstencil);
|
||||
}
|
||||
|
||||
void gs_set_render_target_with_color_space(gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil,
|
||||
enum gs_color_space space)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
||||
if (!gs_valid("gs_set_render_target_with_color_space"))
|
||||
return;
|
||||
|
||||
graphics->exports.device_set_render_target_with_color_space(
|
||||
graphics->device, tex, zstencil, space);
|
||||
}
|
||||
|
||||
void gs_set_cube_render_target(gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil)
|
||||
{
|
||||
|
|
|
@ -79,6 +79,12 @@ enum gs_color_format {
|
|||
GS_RG16,
|
||||
};
|
||||
|
||||
enum gs_color_space {
|
||||
GS_CS_SRGB, /* SDR */
|
||||
GS_CS_709_EXTENDED, /* Canvas, Mac EDR (HDR) */
|
||||
GS_CS_709_SCRGB, /* 1.0 = 80 nits, Windows/Linux HDR */
|
||||
};
|
||||
|
||||
enum gs_zstencil_format {
|
||||
GS_ZS_NONE,
|
||||
GS_Z16,
|
||||
|
@ -461,6 +467,9 @@ EXPORT gs_texrender_t *gs_texrender_create(enum gs_color_format format,
|
|||
EXPORT void gs_texrender_destroy(gs_texrender_t *texrender);
|
||||
EXPORT bool gs_texrender_begin(gs_texrender_t *texrender, uint32_t cx,
|
||||
uint32_t cy);
|
||||
EXPORT bool gs_texrender_begin_with_color_space(gs_texrender_t *texrender,
|
||||
uint32_t cx, uint32_t cy,
|
||||
enum gs_color_space space);
|
||||
EXPORT void gs_texrender_end(gs_texrender_t *texrender);
|
||||
EXPORT void gs_texrender_reset(gs_texrender_t *texrender);
|
||||
EXPORT gs_texture_t *gs_texrender_get_texture(const gs_texrender_t *texrender);
|
||||
|
@ -634,6 +643,7 @@ EXPORT void gs_reset_blend_state(void);
|
|||
EXPORT gs_swapchain_t *gs_swapchain_create(const struct gs_init_data *data);
|
||||
|
||||
EXPORT void gs_resize(uint32_t x, uint32_t y);
|
||||
EXPORT void gs_update_color_space(void);
|
||||
EXPORT void gs_get_size(uint32_t *x, uint32_t *y);
|
||||
EXPORT uint32_t gs_get_width(void);
|
||||
EXPORT uint32_t gs_get_height(void);
|
||||
|
@ -689,10 +699,14 @@ EXPORT void gs_load_default_samplerstate(bool b_3d, int unit);
|
|||
EXPORT gs_shader_t *gs_get_vertex_shader(void);
|
||||
EXPORT gs_shader_t *gs_get_pixel_shader(void);
|
||||
|
||||
EXPORT enum gs_color_space gs_get_color_space(void);
|
||||
EXPORT gs_texture_t *gs_get_render_target(void);
|
||||
EXPORT gs_zstencil_t *gs_get_zstencil_target(void);
|
||||
|
||||
EXPORT void gs_set_render_target(gs_texture_t *tex, gs_zstencil_t *zstencil);
|
||||
EXPORT void gs_set_render_target_with_color_space(gs_texture_t *tex,
|
||||
gs_zstencil_t *zstencil,
|
||||
enum gs_color_space space);
|
||||
EXPORT void gs_set_cube_render_target(gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
|
||||
|
@ -1039,6 +1053,20 @@ gs_generalize_format(enum gs_color_format format)
|
|||
}
|
||||
}
|
||||
|
||||
static inline enum gs_color_format
|
||||
gs_get_format_from_space(enum gs_color_space space)
|
||||
{
|
||||
switch (space) {
|
||||
case GS_CS_SRGB:
|
||||
break;
|
||||
case GS_CS_709_EXTENDED:
|
||||
case GS_CS_709_SCRGB:
|
||||
return GS_RGBA16F;
|
||||
}
|
||||
|
||||
return GS_RGBA;
|
||||
}
|
||||
|
||||
static inline uint32_t gs_get_total_levels(uint32_t width, uint32_t height,
|
||||
uint32_t depth)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
struct gs_texture_render {
|
||||
gs_texture_t *target, *prev_target;
|
||||
gs_zstencil_t *zs, *prev_zs;
|
||||
enum gs_color_space prev_space;
|
||||
|
||||
uint32_t cx, cy;
|
||||
|
||||
|
@ -88,6 +89,13 @@ static bool texrender_resetbuffer(gs_texrender_t *texrender, uint32_t cx,
|
|||
}
|
||||
|
||||
bool gs_texrender_begin(gs_texrender_t *texrender, uint32_t cx, uint32_t cy)
|
||||
{
|
||||
return gs_texrender_begin_with_color_space(texrender, cx, cy,
|
||||
GS_CS_SRGB);
|
||||
}
|
||||
|
||||
bool gs_texrender_begin_with_color_space(gs_texrender_t *texrender, uint32_t cx,
|
||||
uint32_t cy, enum gs_color_space space)
|
||||
{
|
||||
if (!texrender || texrender->rendered)
|
||||
return false;
|
||||
|
@ -109,7 +117,9 @@ bool gs_texrender_begin(gs_texrender_t *texrender, uint32_t cx, uint32_t cy)
|
|||
|
||||
texrender->prev_target = gs_get_render_target();
|
||||
texrender->prev_zs = gs_get_zstencil_target();
|
||||
gs_set_render_target(texrender->target, texrender->zs);
|
||||
texrender->prev_space = gs_get_color_space();
|
||||
gs_set_render_target_with_color_space(texrender->target, texrender->zs,
|
||||
space);
|
||||
|
||||
gs_set_viewport(0, 0, texrender->cx, texrender->cy);
|
||||
|
||||
|
@ -121,7 +131,9 @@ void gs_texrender_end(gs_texrender_t *texrender)
|
|||
if (!texrender)
|
||||
return;
|
||||
|
||||
gs_set_render_target(texrender->prev_target, texrender->prev_zs);
|
||||
gs_set_render_target_with_color_space(texrender->prev_target,
|
||||
texrender->prev_zs,
|
||||
texrender->prev_space);
|
||||
|
||||
gs_matrix_pop();
|
||||
gs_projection_pop();
|
||||
|
|
Loading…
Reference in a new issue