libobs: Add dormant SRGB format support
GS_RGBA, GS_BGRX, and GS_BGRA now use TYPELESS DXGI formats, so we can alias them between UNORM and UNORM_SRGB as necessary. GS_RGBA_UNORM, GS_BGRX_UNORM, and GS_BGRA_UNORM have been added to support straight UNORM types, which Windows requires for sharing textures from D3D9 and OpenGL. The D3D path aliases via views, and GL aliases via GL_EXT_texture_sRGB_decode/GL_FRAMEBUFFER_SRGB. A significant amount of code has changed in the D3D/GL backends, but the concepts are simple. On the D3D side, we need separate SRVs and RTVs to support nonlinear/linear reads and writes. On the GL side, we need to set the proper GL parameters to emulate the same. Add gs_enable_framebuffer_srgb/gs_framebuffer_srgb_enabled to set/get the framebuffer as SRGB or not. Add gs_linear_srgb_active/gs_set_linear_srgb to instruct sources that they should render as SRGB. Legacy sources can ignore this setting without regression. Update obs_source_draw to use linear SRGB as needed. Update render_filter_tex to use linear SRGB as needed. Add gs_effect_set_texture_srgb next to gs_effect_set_texture to set texture with SRGB view instead. Add SRGB helpers for vec4 struct. Create GDI-compatible textures without SRGB support. Doesn't seem to work with SRGB formats.
This commit is contained in:
parent
7427272062
commit
66259560e0
@ -33,24 +33,37 @@ void gs_index_buffer::Rebuild(ID3D11Device *dev)
|
||||
|
||||
void gs_texture_2d::RebuildSharedTextureFallback()
|
||||
{
|
||||
static const gs_color_format format = GS_BGRA;
|
||||
static const DXGI_FORMAT dxgi_format_resource =
|
||||
ConvertGSTextureFormatResource(format);
|
||||
static const DXGI_FORMAT dxgi_format_view =
|
||||
ConvertGSTextureFormatView(format);
|
||||
static const DXGI_FORMAT dxgi_format_view_linear =
|
||||
ConvertGSTextureFormatViewLinear(format);
|
||||
|
||||
td = {};
|
||||
td.Width = 2;
|
||||
td.Height = 2;
|
||||
td.MipLevels = 1;
|
||||
td.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
td.Format = dxgi_format_resource;
|
||||
td.ArraySize = 1;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
width = td.Width;
|
||||
height = td.Height;
|
||||
dxgiFormat = td.Format;
|
||||
dxgiFormatResource = dxgi_format_resource;
|
||||
dxgiFormatView = dxgi_format_view;
|
||||
dxgiFormatViewLinear = dxgi_format_view_linear;
|
||||
levels = 1;
|
||||
|
||||
resourceDesc = {};
|
||||
resourceDesc.Format = td.Format;
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceDesc.Texture2D.MipLevels = 1;
|
||||
viewDesc = {};
|
||||
viewDesc.Format = dxgi_format_view;
|
||||
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
viewDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
viewDescLinear = viewDesc;
|
||||
viewDescLinear.Format = dxgi_format_view_linear;
|
||||
|
||||
isShared = false;
|
||||
}
|
||||
@ -77,9 +90,18 @@ void gs_texture_2d::Rebuild(ID3D11Device *dev)
|
||||
throw HRError("Failed to create 2D texture", hr);
|
||||
}
|
||||
|
||||
hr = dev->CreateShaderResourceView(texture, &resourceDesc, &shaderRes);
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDesc, &shaderRes);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
throw HRError("Failed to create SRV", hr);
|
||||
|
||||
if (viewDesc.Format == viewDescLinear.Format) {
|
||||
shaderResLinear = shaderRes;
|
||||
} else {
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDescLinear,
|
||||
&shaderResLinear);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear SRV", hr);
|
||||
}
|
||||
|
||||
if (isRenderTarget)
|
||||
InitRenderTargets();
|
||||
@ -110,9 +132,18 @@ void gs_texture_2d::RebuildNV12_Y(ID3D11Device *dev)
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create 2D texture", hr);
|
||||
|
||||
hr = dev->CreateShaderResourceView(texture, &resourceDesc, &shaderRes);
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDesc, &shaderRes);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
throw HRError("Failed to create Y SRV", hr);
|
||||
|
||||
if (viewDesc.Format == viewDescLinear.Format) {
|
||||
shaderResLinear = shaderRes;
|
||||
} else {
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDescLinear,
|
||||
&shaderResLinear);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear Y SRV", hr);
|
||||
}
|
||||
|
||||
if (isRenderTarget)
|
||||
InitRenderTargets();
|
||||
@ -136,9 +167,18 @@ void gs_texture_2d::RebuildNV12_UV(ID3D11Device *dev)
|
||||
|
||||
texture = tex_y->texture;
|
||||
|
||||
hr = dev->CreateShaderResourceView(texture, &resourceDesc, &shaderRes);
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDesc, &shaderRes);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
throw HRError("Failed to create UV SRV", hr);
|
||||
|
||||
if (viewDesc.Format == viewDescLinear.Format) {
|
||||
shaderResLinear = shaderRes;
|
||||
} else {
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDescLinear,
|
||||
&shaderResLinear);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear UV SRV", hr);
|
||||
}
|
||||
|
||||
if (isRenderTarget)
|
||||
InitRenderTargets();
|
||||
@ -253,25 +293,38 @@ void gs_timer_range::Rebuild(ID3D11Device *dev)
|
||||
|
||||
void gs_texture_3d::RebuildSharedTextureFallback()
|
||||
{
|
||||
static const gs_color_format format = GS_BGRA;
|
||||
static const DXGI_FORMAT dxgi_format_resource =
|
||||
ConvertGSTextureFormatResource(format);
|
||||
static const DXGI_FORMAT dxgi_format_view =
|
||||
ConvertGSTextureFormatView(format);
|
||||
static const DXGI_FORMAT dxgi_format_view_linear =
|
||||
ConvertGSTextureFormatViewLinear(format);
|
||||
|
||||
td = {};
|
||||
td.Width = 2;
|
||||
td.Height = 2;
|
||||
td.Depth = 2;
|
||||
td.MipLevels = 1;
|
||||
td.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
td.Format = dxgi_format_resource;
|
||||
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
width = td.Width;
|
||||
height = td.Height;
|
||||
depth = td.Depth;
|
||||
dxgiFormat = td.Format;
|
||||
dxgiFormatResource = dxgi_format_resource;
|
||||
dxgiFormatView = dxgi_format_view;
|
||||
dxgiFormatViewLinear = dxgi_format_view_linear;
|
||||
levels = 1;
|
||||
|
||||
resourceDesc = {};
|
||||
resourceDesc.Format = td.Format;
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
resourceDesc.Texture3D.MostDetailedMip = 0;
|
||||
resourceDesc.Texture3D.MipLevels = 1;
|
||||
viewDesc = {};
|
||||
viewDesc.Format = dxgi_format_view;
|
||||
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
viewDesc.Texture3D.MostDetailedMip = 0;
|
||||
viewDesc.Texture3D.MipLevels = 1;
|
||||
|
||||
viewDescLinear = viewDesc;
|
||||
viewDescLinear.Format = dxgi_format_view_linear;
|
||||
|
||||
isShared = false;
|
||||
}
|
||||
@ -298,9 +351,18 @@ void gs_texture_3d::Rebuild(ID3D11Device *dev)
|
||||
throw HRError("Failed to create 3D texture", hr);
|
||||
}
|
||||
|
||||
hr = dev->CreateShaderResourceView(texture, &resourceDesc, &shaderRes);
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDesc, &shaderRes);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
throw HRError("Failed to create 3D SRV", hr);
|
||||
|
||||
if (viewDesc.Format == viewDescLinear.Format) {
|
||||
shaderResLinear = shaderRes;
|
||||
} else {
|
||||
hr = dev->CreateShaderResourceView(texture, &viewDescLinear,
|
||||
&shaderResLinear);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear 3D SRV", hr);
|
||||
}
|
||||
|
||||
acquired = false;
|
||||
|
||||
|
@ -262,10 +262,15 @@ inline void gs_shader::UpdateParam(vector<uint8_t> &constData,
|
||||
param.changed = false;
|
||||
}
|
||||
|
||||
} else if (param.curValue.size() == sizeof(gs_texture_t *)) {
|
||||
gs_texture_t *tex;
|
||||
memcpy(&tex, param.curValue.data(), sizeof(gs_texture_t *));
|
||||
device_load_texture(device, tex, param.textureID);
|
||||
} else if (param.curValue.size() == sizeof(struct gs_shader_texture)) {
|
||||
struct gs_shader_texture shader_tex;
|
||||
memcpy(&shader_tex, param.curValue.data(), sizeof(shader_tex));
|
||||
if (shader_tex.srgb)
|
||||
device_load_texture_srgb(device, shader_tex.tex,
|
||||
param.textureID);
|
||||
else
|
||||
device_load_texture(device, shader_tex.tex,
|
||||
param.textureID);
|
||||
|
||||
if (param.nextSampler) {
|
||||
ID3D11SamplerState *state = param.nextSampler->state;
|
||||
|
@ -23,7 +23,7 @@ gs_stage_surface::gs_stage_surface(gs_device_t *device, uint32_t width,
|
||||
width(width),
|
||||
height(height),
|
||||
format(colorFormat),
|
||||
dxgiFormat(ConvertGSTextureFormat(colorFormat))
|
||||
dxgiFormat(ConvertGSTextureFormatView(colorFormat))
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
|
@ -78,7 +78,7 @@ static inline void make_swap_desc(DXGI_SWAP_CHAIN_DESC &desc,
|
||||
{
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.BufferCount = data->num_backbuffers;
|
||||
desc.BufferDesc.Format = ConvertGSTextureFormat(data->format);
|
||||
desc.BufferDesc.Format = ConvertGSTextureFormatView(data->format);
|
||||
desc.BufferDesc.Width = data->cx;
|
||||
desc.BufferDesc.Height = data->cy;
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
@ -99,10 +99,24 @@ void gs_swap_chain::InitTarget(uint32_t cx, uint32_t cy)
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to get swap buffer texture", hr);
|
||||
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv;
|
||||
rtv.Format = target.dxgiFormatView;
|
||||
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
rtv.Texture2D.MipSlice = 0;
|
||||
hr = device->device->CreateRenderTargetView(
|
||||
target.texture, NULL, target.renderTarget[0].Assign());
|
||||
target.texture, &rtv, target.renderTarget[0].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create swap render target view", hr);
|
||||
throw HRError("Failed to create swap RTV", hr);
|
||||
if (target.dxgiFormatView == target.dxgiFormatViewLinear) {
|
||||
target.renderTargetLinear[0] = target.renderTarget[0];
|
||||
} else {
|
||||
rtv.Format = target.dxgiFormatViewLinear;
|
||||
hr = device->device->CreateRenderTargetView(
|
||||
target.texture, &rtv,
|
||||
target.renderTargetLinear[0].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear swap RTV", hr);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_swap_chain::InitZStencilBuffer(uint32_t cx, uint32_t cy)
|
||||
@ -125,6 +139,7 @@ void gs_swap_chain::Resize(uint32_t cx, uint32_t cy)
|
||||
|
||||
target.texture.Clear();
|
||||
target.renderTarget[0].Clear();
|
||||
target.renderTargetLinear[0].Clear();
|
||||
zs.texture.Clear();
|
||||
zs.view.Clear();
|
||||
|
||||
@ -139,7 +154,7 @@ void gs_swap_chain::Resize(uint32_t cx, uint32_t cy)
|
||||
cy = clientRect.bottom;
|
||||
}
|
||||
|
||||
hr = swap->ResizeBuffers(numBuffers, cx, cy, target.dxgiFormat, 0);
|
||||
hr = swap->ResizeBuffers(numBuffers, cx, cy, DXGI_FORMAT_UNKNOWN, 0);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to resize swap buffers", hr);
|
||||
|
||||
@ -152,7 +167,11 @@ void gs_swap_chain::Init()
|
||||
target.device = device;
|
||||
target.isRenderTarget = true;
|
||||
target.format = initData.format;
|
||||
target.dxgiFormat = ConvertGSTextureFormat(initData.format);
|
||||
target.dxgiFormatResource =
|
||||
ConvertGSTextureFormatResource(initData.format);
|
||||
target.dxgiFormatView = ConvertGSTextureFormatView(initData.format);
|
||||
target.dxgiFormatViewLinear =
|
||||
ConvertGSTextureFormatViewLinear(initData.format);
|
||||
InitTarget(initData.cx, initData.cy);
|
||||
|
||||
zs.device = device;
|
||||
@ -310,6 +329,7 @@ try {
|
||||
UpdateBlendState();
|
||||
UpdateRasterState();
|
||||
UpdateZStencilState();
|
||||
FlushOutputViews();
|
||||
context->Draw(4, 0);
|
||||
|
||||
device_set_viewport(this, 0, 0, NV12_CX / 2, NV12_CY / 2);
|
||||
@ -318,6 +338,7 @@ try {
|
||||
UpdateBlendState();
|
||||
UpdateRasterState();
|
||||
UpdateZStencilState();
|
||||
FlushOutputViews();
|
||||
context->Draw(4, 0);
|
||||
|
||||
device_load_pixelshader(this, nullptr);
|
||||
@ -727,6 +748,30 @@ void gs_device::UpdateViewProjMatrix()
|
||||
&curViewProjMatrix);
|
||||
}
|
||||
|
||||
void gs_device::FlushOutputViews()
|
||||
{
|
||||
if (curFramebufferInvalidate) {
|
||||
ID3D11RenderTargetView *rtv = nullptr;
|
||||
if (curRenderTarget) {
|
||||
const int i = curRenderSide;
|
||||
rtv = curFramebufferSrgb
|
||||
? curRenderTarget->renderTargetLinear[i]
|
||||
.Get()
|
||||
: curRenderTarget->renderTarget[i].Get();
|
||||
if (!rtv) {
|
||||
blog(LOG_ERROR,
|
||||
"device_draw (D3D11): texture is not a render target");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ID3D11DepthStencilView *dsv = nullptr;
|
||||
if (curZStencilBuffer)
|
||||
dsv = curZStencilBuffer->view;
|
||||
context->OMSetRenderTargets(1, &rtv, dsv);
|
||||
curFramebufferInvalidate = false;
|
||||
}
|
||||
}
|
||||
|
||||
gs_device::gs_device(uint32_t adapterIdx)
|
||||
: curToplogy(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED)
|
||||
{
|
||||
@ -1045,18 +1090,9 @@ void device_resize(gs_device_t *device, uint32_t cx, uint32_t cy)
|
||||
|
||||
try {
|
||||
ID3D11RenderTargetView *renderView = NULL;
|
||||
ID3D11DepthStencilView *depthView = NULL;
|
||||
int i = device->curRenderSide;
|
||||
|
||||
device->context->OMSetRenderTargets(1, &renderView, depthView);
|
||||
device->context->OMSetRenderTargets(1, &renderView, NULL);
|
||||
device->curSwapChain->Resize(cx, cy);
|
||||
|
||||
if (device->curRenderTarget)
|
||||
renderView = device->curRenderTarget->renderTarget[i];
|
||||
if (device->curZStencilBuffer)
|
||||
depthView = device->curZStencilBuffer->view;
|
||||
device->context->OMSetRenderTargets(1, &renderView, depthView);
|
||||
|
||||
device->curFramebufferInvalidate = true;
|
||||
} catch (const HRError &error) {
|
||||
blog(LOG_ERROR, "device_resize (D3D11): %s (%08lX)", error.str,
|
||||
error.hr);
|
||||
@ -1419,20 +1455,29 @@ void device_load_indexbuffer(gs_device_t *device, gs_indexbuffer_t *indexbuffer)
|
||||
device->context->IASetIndexBuffer(buffer, format, 0);
|
||||
}
|
||||
|
||||
void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
|
||||
static void device_load_texture_internal(gs_device_t *device, gs_texture_t *tex,
|
||||
int unit,
|
||||
ID3D11ShaderResourceView *view)
|
||||
{
|
||||
ID3D11ShaderResourceView *view = NULL;
|
||||
|
||||
if (device->curTextures[unit] == tex)
|
||||
return;
|
||||
|
||||
if (tex)
|
||||
view = tex->shaderRes;
|
||||
|
||||
device->curTextures[unit] = tex;
|
||||
device->context->PSSetShaderResources(unit, 1, &view);
|
||||
}
|
||||
|
||||
void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
|
||||
{
|
||||
ID3D11ShaderResourceView *view = tex ? tex->shaderRes : NULL;
|
||||
return device_load_texture_internal(device, tex, unit, view);
|
||||
}
|
||||
|
||||
void device_load_texture_srgb(gs_device_t *device, gs_texture_t *tex, int unit)
|
||||
{
|
||||
ID3D11ShaderResourceView *view = tex ? tex->shaderResLinear : NULL;
|
||||
return device_load_texture_internal(device, tex, unit, view);
|
||||
}
|
||||
|
||||
void device_load_samplerstate(gs_device_t *device,
|
||||
gs_samplerstate_t *samplerstate, int unit)
|
||||
{
|
||||
@ -1574,26 +1619,19 @@ void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
return;
|
||||
|
||||
if (tex && tex->type != GS_TEXTURE_2D) {
|
||||
blog(LOG_ERROR, "device_set_render_target (D3D11): "
|
||||
"texture is not a 2D texture");
|
||||
blog(LOG_ERROR,
|
||||
"device_set_render_target (D3D11): texture is not a 2D texture");
|
||||
return;
|
||||
}
|
||||
|
||||
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
||||
if (tex2d && !tex2d->renderTarget[0]) {
|
||||
blog(LOG_ERROR, "device_set_render_target (D3D11): "
|
||||
"texture is not a render target");
|
||||
return;
|
||||
gs_texture_2d *const tex2d = static_cast<gs_texture_2d *>(tex);
|
||||
if (device->curRenderTarget != tex2d || device->curRenderSide != 0 ||
|
||||
device->curZStencilBuffer != zstencil) {
|
||||
device->curRenderTarget = tex2d;
|
||||
device->curRenderSide = 0;
|
||||
device->curZStencilBuffer = zstencil;
|
||||
device->curFramebufferInvalidate = true;
|
||||
}
|
||||
|
||||
ID3D11RenderTargetView *rt = tex2d ? tex2d->renderTarget[0].Get()
|
||||
: nullptr;
|
||||
|
||||
device->curRenderTarget = tex2d;
|
||||
device->curRenderSide = 0;
|
||||
device->curZStencilBuffer = zstencil;
|
||||
device->context->OMSetRenderTargets(
|
||||
1, &rt, zstencil ? zstencil->view : nullptr);
|
||||
}
|
||||
|
||||
void device_set_cube_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
@ -1619,19 +1657,27 @@ void device_set_cube_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
return;
|
||||
}
|
||||
|
||||
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
||||
if (!tex2d->renderTarget[side]) {
|
||||
blog(LOG_ERROR, "device_set_cube_render_target (D3D11): "
|
||||
"texture is not a render target");
|
||||
return;
|
||||
gs_texture_2d *const tex2d = static_cast<gs_texture_2d *>(tex);
|
||||
if (device->curRenderTarget != tex2d || device->curRenderSide != side ||
|
||||
device->curZStencilBuffer != zstencil) {
|
||||
device->curRenderTarget = tex2d;
|
||||
device->curRenderSide = side;
|
||||
device->curZStencilBuffer = zstencil;
|
||||
device->curFramebufferInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11RenderTargetView *rt = tex2d->renderTarget[0];
|
||||
void device_enable_framebuffer_srgb(gs_device_t *device, bool enable)
|
||||
{
|
||||
if (device->curFramebufferSrgb != enable) {
|
||||
device->curFramebufferSrgb = enable;
|
||||
device->curFramebufferInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
device->curRenderTarget = tex2d;
|
||||
device->curRenderSide = side;
|
||||
device->curZStencilBuffer = zstencil;
|
||||
device->context->OMSetRenderTargets(1, &rt, zstencil->view);
|
||||
bool device_framebuffer_srgb_enabled(gs_device_t *device)
|
||||
{
|
||||
return device->curFramebufferSrgb;
|
||||
}
|
||||
|
||||
inline void gs_device::CopyTex(ID3D11Texture2D *dst, uint32_t dst_x,
|
||||
@ -1780,6 +1826,8 @@ void device_draw(gs_device_t *device, enum gs_draw_mode draw_mode,
|
||||
if (!device->curSwapChain && !device->curRenderTarget)
|
||||
throw "No render target or swap chain to render to";
|
||||
|
||||
device->FlushOutputViews();
|
||||
|
||||
gs_effect_t *effect = gs_get_effect();
|
||||
if (effect)
|
||||
gs_effect_update_params(effect);
|
||||
@ -2589,9 +2637,10 @@ device_texture_create_gdi(gs_device_t *device, uint32_t width, uint32_t height)
|
||||
{
|
||||
gs_texture *texture = nullptr;
|
||||
try {
|
||||
texture = new gs_texture_2d(device, width, height, GS_BGRA, 1,
|
||||
nullptr, GS_RENDER_TARGET,
|
||||
GS_TEXTURE_2D, true);
|
||||
texture = new gs_texture_2d(device, width, height,
|
||||
GS_BGRA_UNORM, 1, nullptr,
|
||||
GS_RENDER_TARGET, GS_TEXTURE_2D,
|
||||
true);
|
||||
} catch (const HRError &error) {
|
||||
blog(LOG_ERROR, "device_texture_create_gdi (D3D11): %s (%08lX)",
|
||||
error.str, error.hr);
|
||||
|
@ -59,7 +59,7 @@ static inline uint32_t GetWinVer()
|
||||
return (ver.major << 8) | ver.minor;
|
||||
}
|
||||
|
||||
static inline DXGI_FORMAT ConvertGSTextureFormat(gs_color_format format)
|
||||
static inline DXGI_FORMAT ConvertGSTextureFormatResource(gs_color_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_UNKNOWN:
|
||||
@ -69,11 +69,11 @@ static inline DXGI_FORMAT ConvertGSTextureFormat(gs_color_format format)
|
||||
case GS_R8:
|
||||
return DXGI_FORMAT_R8_UNORM;
|
||||
case GS_RGBA:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
return DXGI_FORMAT_R8G8B8A8_TYPELESS;
|
||||
case GS_BGRX:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||
return DXGI_FORMAT_B8G8R8X8_TYPELESS;
|
||||
case GS_BGRA:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
return DXGI_FORMAT_B8G8R8A8_TYPELESS;
|
||||
case GS_R10G10B10A2:
|
||||
return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case GS_RGBA16:
|
||||
@ -100,11 +100,46 @@ static inline DXGI_FORMAT ConvertGSTextureFormat(gs_color_format format)
|
||||
return DXGI_FORMAT_BC3_UNORM;
|
||||
case GS_R8G8:
|
||||
return DXGI_FORMAT_R8G8_UNORM;
|
||||
case GS_RGBA_UNORM:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GS_BGRX_UNORM:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||
case GS_BGRA_UNORM:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
}
|
||||
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline DXGI_FORMAT ConvertGSTextureFormatView(gs_color_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_RGBA:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GS_BGRX:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||
case GS_BGRA:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
default:
|
||||
return ConvertGSTextureFormatResource(format);
|
||||
}
|
||||
}
|
||||
|
||||
static inline DXGI_FORMAT
|
||||
ConvertGSTextureFormatViewLinear(gs_color_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_RGBA:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
||||
case GS_BGRX:
|
||||
return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
|
||||
case GS_BGRA:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
|
||||
default:
|
||||
return ConvertGSTextureFormatResource(format);
|
||||
}
|
||||
}
|
||||
|
||||
static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format)
|
||||
{
|
||||
switch ((unsigned long)format) {
|
||||
@ -115,12 +150,9 @@ static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format)
|
||||
case DXGI_FORMAT_R8G8_UNORM:
|
||||
return GS_R8G8;
|
||||
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
return GS_RGBA;
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
|
||||
return GS_BGRX;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
|
||||
return GS_BGRA;
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
||||
@ -147,6 +179,12 @@ static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format)
|
||||
return GS_DXT3;
|
||||
case DXGI_FORMAT_BC3_UNORM:
|
||||
return GS_DXT5;
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
return GS_RGBA_UNORM;
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
||||
return GS_BGRX_UNORM;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
return GS_BGRA_UNORM;
|
||||
}
|
||||
|
||||
return GS_UNKNOWN;
|
||||
@ -410,7 +448,9 @@ struct gs_texture : gs_obj {
|
||||
gs_color_format format;
|
||||
|
||||
ComPtr<ID3D11ShaderResourceView> shaderRes;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC resourceDesc = {};
|
||||
ComPtr<ID3D11ShaderResourceView> shaderResLinear;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{};
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC viewDescLinear{};
|
||||
|
||||
void Rebuild(ID3D11Device *dev);
|
||||
|
||||
@ -440,11 +480,14 @@ struct gs_texture : gs_obj {
|
||||
struct gs_texture_2d : gs_texture {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11RenderTargetView> renderTarget[6];
|
||||
ComPtr<ID3D11RenderTargetView> renderTargetLinear[6];
|
||||
ComPtr<IDXGISurface1> gdiSurface;
|
||||
|
||||
uint32_t width = 0, height = 0;
|
||||
uint32_t flags = 0;
|
||||
DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dxgiFormatResource = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dxgiFormatView = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dxgiFormatViewLinear = DXGI_FORMAT_UNKNOWN;
|
||||
bool isRenderTarget = false;
|
||||
bool isGDICompatible = false;
|
||||
bool isDynamic = false;
|
||||
@ -476,10 +519,13 @@ struct gs_texture_2d : gs_texture {
|
||||
inline void Release()
|
||||
{
|
||||
texture.Release();
|
||||
for (auto &rt : renderTarget)
|
||||
for (ComPtr<ID3D11RenderTargetView> &rt : renderTarget)
|
||||
rt.Release();
|
||||
for (ComPtr<ID3D11RenderTargetView> &rt : renderTargetLinear)
|
||||
rt.Release();
|
||||
gdiSurface.Release();
|
||||
shaderRes.Release();
|
||||
shaderResLinear.Release();
|
||||
}
|
||||
|
||||
inline gs_texture_2d() : gs_texture(GS_TEXTURE_2D, 0, GS_UNKNOWN) {}
|
||||
@ -501,7 +547,9 @@ struct gs_texture_3d : gs_texture {
|
||||
|
||||
uint32_t width = 0, height = 0, depth = 0;
|
||||
uint32_t flags = 0;
|
||||
DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dxgiFormatResource = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dxgiFormatView = DXGI_FORMAT_UNKNOWN;
|
||||
DXGI_FORMAT dxgiFormatViewLinear = DXGI_FORMAT_UNKNOWN;
|
||||
bool isDynamic = false;
|
||||
bool isShared = false;
|
||||
bool genMipmaps = false;
|
||||
@ -912,6 +960,8 @@ struct gs_device {
|
||||
gs_texture_2d *curRenderTarget = nullptr;
|
||||
gs_zstencil_buffer *curZStencilBuffer = nullptr;
|
||||
int curRenderSide = 0;
|
||||
bool curFramebufferSrgb = false;
|
||||
bool curFramebufferInvalidate = false;
|
||||
gs_texture *curTextures[GS_MAX_TEXTURES];
|
||||
gs_sampler_state *curSamplers[GS_MAX_TEXTURES];
|
||||
gs_vertex_buffer *curVertexBuffer = nullptr;
|
||||
@ -972,6 +1022,8 @@ struct gs_device {
|
||||
|
||||
void UpdateViewProjMatrix();
|
||||
|
||||
void FlushOutputViews();
|
||||
|
||||
void RebuildDevice();
|
||||
|
||||
bool HasBadNV12Output();
|
||||
|
@ -98,7 +98,7 @@ void gs_texture_2d::InitTexture(const uint8_t *const *data)
|
||||
td.Height = height;
|
||||
td.MipLevels = genMipmaps ? 0 : levels;
|
||||
td.ArraySize = type == GS_TEXTURE_CUBE ? 6 : 1;
|
||||
td.Format = nv12 ? DXGI_FORMAT_NV12 : dxgiFormat;
|
||||
td.Format = nv12 ? DXGI_FORMAT_NV12 : dxgiFormatResource;
|
||||
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.CPUAccessFlags = isDynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
@ -172,23 +172,35 @@ void gs_texture_2d::InitResourceView()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.Format = dxgiFormat;
|
||||
memset(&viewDesc, 0, sizeof(viewDesc));
|
||||
viewDesc.Format = dxgiFormatView;
|
||||
|
||||
if (type == GS_TEXTURE_CUBE) {
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
||||
resourceDesc.TextureCube.MipLevels =
|
||||
genMipmaps || !levels ? -1 : levels;
|
||||
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
||||
viewDesc.TextureCube.MipLevels = genMipmaps || !levels ? -1
|
||||
: levels;
|
||||
} else {
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceDesc.Texture2D.MipLevels =
|
||||
genMipmaps || !levels ? -1 : levels;
|
||||
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
viewDesc.Texture2D.MipLevels = genMipmaps || !levels ? -1
|
||||
: levels;
|
||||
}
|
||||
|
||||
hr = device->device->CreateShaderResourceView(texture, &resourceDesc,
|
||||
hr = device->device->CreateShaderResourceView(texture, &viewDesc,
|
||||
shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
throw HRError("Failed to create SRV", hr);
|
||||
|
||||
viewDescLinear = viewDesc;
|
||||
viewDescLinear.Format = dxgiFormatViewLinear;
|
||||
|
||||
if (dxgiFormatView == dxgiFormatViewLinear) {
|
||||
shaderResLinear = shaderRes;
|
||||
} else {
|
||||
hr = device->device->CreateShaderResourceView(
|
||||
texture, &viewDescLinear, shaderResLinear.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear SRV", hr);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitRenderTargets()
|
||||
@ -196,18 +208,27 @@ void gs_texture_2d::InitRenderTargets()
|
||||
HRESULT hr;
|
||||
if (type == GS_TEXTURE_2D) {
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv;
|
||||
rtv.Format = dxgiFormat;
|
||||
rtv.Format = dxgiFormatView;
|
||||
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
rtv.Texture2D.MipSlice = 0;
|
||||
|
||||
hr = device->device->CreateRenderTargetView(
|
||||
texture, &rtv, renderTarget[0].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create render target view",
|
||||
hr);
|
||||
throw HRError("Failed to create RTV", hr);
|
||||
if (dxgiFormatView == dxgiFormatViewLinear) {
|
||||
renderTargetLinear[0] = renderTarget[0];
|
||||
} else {
|
||||
rtv.Format = dxgiFormatViewLinear;
|
||||
hr = device->device->CreateRenderTargetView(
|
||||
texture, &rtv, renderTargetLinear[0].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear RTV",
|
||||
hr);
|
||||
}
|
||||
} else {
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv;
|
||||
rtv.Format = dxgiFormat;
|
||||
rtv.Format = dxgiFormatView;
|
||||
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
rtv.Texture2DArray.MipSlice = 0;
|
||||
rtv.Texture2DArray.ArraySize = 1;
|
||||
@ -217,9 +238,19 @@ void gs_texture_2d::InitRenderTargets()
|
||||
hr = device->device->CreateRenderTargetView(
|
||||
texture, &rtv, renderTarget[i].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create cube render "
|
||||
"target view",
|
||||
hr);
|
||||
throw HRError("Failed to create cube RTV", hr);
|
||||
if (dxgiFormatView == dxgiFormatViewLinear) {
|
||||
renderTargetLinear[i] = renderTarget[i];
|
||||
} else {
|
||||
rtv.Format = dxgiFormatViewLinear;
|
||||
hr = device->device->CreateRenderTargetView(
|
||||
texture, &rtv,
|
||||
renderTargetLinear[i].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError(
|
||||
"Failed to create linear cube RTV",
|
||||
hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -235,7 +266,9 @@ gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t width,
|
||||
width(width),
|
||||
height(height),
|
||||
flags(flags_),
|
||||
dxgiFormat(ConvertGSTextureFormat(format)),
|
||||
dxgiFormatResource(ConvertGSTextureFormatResource(format)),
|
||||
dxgiFormatView(ConvertGSTextureFormatView(format)),
|
||||
dxgiFormatViewLinear(ConvertGSTextureFormatViewLinear(format)),
|
||||
isRenderTarget((flags_ & GS_RENDER_TARGET) != 0),
|
||||
isGDICompatible(gdiCompatible),
|
||||
isDynamic((flags_ & GS_DYNAMIC) != 0),
|
||||
@ -271,7 +304,9 @@ gs_texture_2d::gs_texture_2d(gs_device_t *device, ID3D11Texture2D *nv12tex,
|
||||
this->chroma = true;
|
||||
this->width = td.Width / 2;
|
||||
this->height = td.Height / 2;
|
||||
this->dxgiFormat = DXGI_FORMAT_R8G8_UNORM;
|
||||
this->dxgiFormatResource = DXGI_FORMAT_R8G8_UNORM;
|
||||
this->dxgiFormatView = DXGI_FORMAT_R8G8_UNORM;
|
||||
this->dxgiFormatViewLinear = DXGI_FORMAT_R8G8_UNORM;
|
||||
|
||||
InitResourceView();
|
||||
if (isRenderTarget)
|
||||
@ -292,24 +327,20 @@ gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t handle)
|
||||
|
||||
texture->GetDesc(&td);
|
||||
|
||||
const gs_color_format format = ConvertDXGITextureFormat(td.Format);
|
||||
|
||||
this->type = GS_TEXTURE_2D;
|
||||
this->format = ConvertDXGITextureFormat(td.Format);
|
||||
this->format = format;
|
||||
this->levels = 1;
|
||||
this->device = device;
|
||||
|
||||
this->width = td.Width;
|
||||
this->height = td.Height;
|
||||
this->dxgiFormat = td.Format;
|
||||
this->dxgiFormatResource = ConvertGSTextureFormatResource(format);
|
||||
this->dxgiFormatView = ConvertGSTextureFormatView(format);
|
||||
this->dxgiFormatViewLinear = ConvertGSTextureFormatViewLinear(format);
|
||||
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.Format = ConvertGSTextureFormat(this->format);
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
hr = device->device->CreateShaderResourceView(texture, &resourceDesc,
|
||||
shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create shader resource view", hr);
|
||||
InitResourceView();
|
||||
}
|
||||
|
||||
gs_texture_2d::gs_texture_2d(gs_device_t *device, ID3D11Texture2D *obj)
|
||||
@ -319,22 +350,18 @@ gs_texture_2d::gs_texture_2d(gs_device_t *device, ID3D11Texture2D *obj)
|
||||
|
||||
texture->GetDesc(&td);
|
||||
|
||||
const gs_color_format format = ConvertDXGITextureFormat(td.Format);
|
||||
|
||||
this->type = GS_TEXTURE_2D;
|
||||
this->format = ConvertDXGITextureFormat(td.Format);
|
||||
this->format = format;
|
||||
this->levels = 1;
|
||||
this->device = device;
|
||||
|
||||
this->width = td.Width;
|
||||
this->height = td.Height;
|
||||
this->dxgiFormat = td.Format;
|
||||
this->dxgiFormatResource = ConvertGSTextureFormatResource(format);
|
||||
this->dxgiFormatView = ConvertGSTextureFormatView(format);
|
||||
this->dxgiFormatViewLinear = ConvertGSTextureFormatViewLinear(format);
|
||||
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.Format = ConvertGSTextureFormat(this->format);
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
HRESULT hr = device->device->CreateShaderResourceView(
|
||||
texture, &resourceDesc, shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create shader resource view", hr);
|
||||
InitResourceView();
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void gs_texture_3d::InitTexture(const uint8_t *const *data)
|
||||
td.Height = height;
|
||||
td.Depth = depth;
|
||||
td.MipLevels = genMipmaps ? 0 : levels;
|
||||
td.Format = dxgiFormat;
|
||||
td.Format = dxgiFormatResource;
|
||||
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
td.CPUAccessFlags = isDynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
td.Usage = isDynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
|
||||
@ -155,17 +155,29 @@ void gs_texture_3d::InitResourceView()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.Format = dxgiFormat;
|
||||
memset(&viewDesc, 0, sizeof(viewDesc));
|
||||
viewDesc.Format = dxgiFormatView;
|
||||
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
resourceDesc.Texture3D.MostDetailedMip = 0;
|
||||
resourceDesc.Texture3D.MipLevels = genMipmaps || !levels ? -1 : levels;
|
||||
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
viewDesc.Texture3D.MostDetailedMip = 0;
|
||||
viewDesc.Texture3D.MipLevels = genMipmaps || !levels ? -1 : levels;
|
||||
|
||||
hr = device->device->CreateShaderResourceView(texture, &resourceDesc,
|
||||
hr = device->device->CreateShaderResourceView(texture, &viewDesc,
|
||||
shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
throw HRError("Failed to create 3D SRV", hr);
|
||||
|
||||
viewDescLinear = viewDesc;
|
||||
viewDescLinear.Format = dxgiFormatViewLinear;
|
||||
|
||||
if (dxgiFormatView == dxgiFormatViewLinear) {
|
||||
shaderResLinear = shaderRes;
|
||||
} else {
|
||||
hr = device->device->CreateShaderResourceView(
|
||||
texture, &viewDescLinear, shaderResLinear.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create linear 3D SRV", hr);
|
||||
}
|
||||
}
|
||||
|
||||
#define SHARED_FLAGS (GS_SHARED_TEX | GS_SHARED_KM_TEX)
|
||||
@ -180,7 +192,9 @@ gs_texture_3d::gs_texture_3d(gs_device_t *device, uint32_t width,
|
||||
height(height),
|
||||
depth(depth),
|
||||
flags(flags_),
|
||||
dxgiFormat(ConvertGSTextureFormat(format)),
|
||||
dxgiFormatResource(ConvertGSTextureFormatResource(format)),
|
||||
dxgiFormatView(ConvertGSTextureFormatView(format)),
|
||||
dxgiFormatViewLinear(ConvertGSTextureFormatViewLinear(format)),
|
||||
isDynamic((flags_ & GS_DYNAMIC) != 0),
|
||||
isShared((flags_ & SHARED_FLAGS) != 0),
|
||||
genMipmaps((flags_ & GS_BUILD_MIPMAPS) != 0),
|
||||
@ -203,24 +217,19 @@ gs_texture_3d::gs_texture_3d(gs_device_t *device, uint32_t handle)
|
||||
|
||||
texture->GetDesc(&td);
|
||||
|
||||
const gs_color_format format = ConvertDXGITextureFormat(td.Format);
|
||||
|
||||
this->type = GS_TEXTURE_3D;
|
||||
this->format = ConvertDXGITextureFormat(td.Format);
|
||||
this->format = format;
|
||||
this->levels = 1;
|
||||
this->device = device;
|
||||
|
||||
this->width = td.Width;
|
||||
this->height = td.Height;
|
||||
this->depth = td.Depth;
|
||||
this->dxgiFormat = td.Format;
|
||||
this->dxgiFormatResource = ConvertGSTextureFormatResource(format);
|
||||
this->dxgiFormatView = ConvertGSTextureFormatView(format);
|
||||
this->dxgiFormatViewLinear = ConvertGSTextureFormatViewLinear(format);
|
||||
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.Format = td.Format;
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
resourceDesc.Texture3D.MostDetailedMip = 0;
|
||||
resourceDesc.Texture3D.MipLevels = 1;
|
||||
|
||||
hr = device->device->CreateShaderResourceView(texture, &resourceDesc,
|
||||
shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create shader resource view", hr);
|
||||
InitResourceView();
|
||||
}
|
||||
|
@ -525,8 +525,13 @@ static void program_set_param_data(struct gs_program *program,
|
||||
}
|
||||
|
||||
glUniform1i(pp->obj, pp->param->texture_id);
|
||||
device_load_texture(program->device, pp->param->texture,
|
||||
pp->param->texture_id);
|
||||
if (pp->param->srgb)
|
||||
device_load_texture_srgb(program->device,
|
||||
pp->param->texture,
|
||||
pp->param->texture_id);
|
||||
else
|
||||
device_load_texture(program->device, pp->param->texture,
|
||||
pp->param->texture_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,7 +762,7 @@ void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
|
||||
expected_size = sizeof(float) * 4 * 4;
|
||||
break;
|
||||
case GS_SHADER_PARAM_TEXTURE:
|
||||
expected_size = sizeof(void *);
|
||||
expected_size = sizeof(struct gs_shader_texture);
|
||||
break;
|
||||
default:
|
||||
expected_size = 0;
|
||||
@ -773,10 +778,14 @@ void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
|
||||
return;
|
||||
}
|
||||
|
||||
if (param->type == GS_SHADER_PARAM_TEXTURE)
|
||||
gs_shader_set_texture(param, *(gs_texture_t **)val);
|
||||
else
|
||||
if (param->type == GS_SHADER_PARAM_TEXTURE) {
|
||||
struct gs_shader_texture shader_tex;
|
||||
memcpy(&shader_tex, val, sizeof(shader_tex));
|
||||
gs_shader_set_texture(param, shader_tex.tex);
|
||||
param->srgb = shader_tex.srgb;
|
||||
} else {
|
||||
da_copy_array(param->cur_value, val, size);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_shader_set_default(gs_sparam_t *param)
|
||||
|
@ -138,6 +138,12 @@ static bool gl_init_extensions(struct gs_device *device)
|
||||
|
||||
gl_enable_debug();
|
||||
|
||||
if (!GLAD_GL_EXT_texture_sRGB_decode) {
|
||||
blog(LOG_ERROR, "OpenGL extension EXT_texture_sRGB_decode "
|
||||
"is required.");
|
||||
return false;
|
||||
}
|
||||
|
||||
gl_enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
if (GLAD_GL_VERSION_4_3 || GLAD_GL_ARB_copy_image)
|
||||
@ -492,7 +498,8 @@ static inline struct gs_shader_param *get_texture_param(gs_device_t *device,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
|
||||
static void device_load_texture_internal(gs_device_t *device, gs_texture_t *tex,
|
||||
int unit, GLint decode)
|
||||
{
|
||||
struct gs_shader_param *param;
|
||||
struct gs_sampler_state *sampler;
|
||||
@ -530,6 +537,10 @@ void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
|
||||
|
||||
if (!gl_bind_texture(tex->gl_target, tex->texture))
|
||||
goto fail;
|
||||
|
||||
if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_SRGB_DECODE_EXT, decode))
|
||||
goto fail;
|
||||
|
||||
if (sampler && !load_texture_sampler(tex, sampler))
|
||||
goto fail;
|
||||
|
||||
@ -539,6 +550,16 @@ fail:
|
||||
blog(LOG_ERROR, "device_load_texture (GL) failed");
|
||||
}
|
||||
|
||||
void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
|
||||
{
|
||||
device_load_texture_internal(device, tex, unit, GL_SKIP_DECODE_EXT);
|
||||
}
|
||||
|
||||
void device_load_texture_srgb(gs_device_t *device, gs_texture_t *tex, int unit)
|
||||
{
|
||||
device_load_texture_internal(device, tex, unit, GL_DECODE_EXT);
|
||||
}
|
||||
|
||||
static bool load_sampler_on_textures(gs_device_t *device, gs_samplerstate_t *ss,
|
||||
int sampler_unit)
|
||||
{
|
||||
@ -863,6 +884,21 @@ fail:
|
||||
blog(LOG_ERROR, "device_set_cube_render_target (GL) failed");
|
||||
}
|
||||
|
||||
void device_enable_framebuffer_srgb(gs_device_t *device, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
gl_enable(GL_FRAMEBUFFER_SRGB);
|
||||
else
|
||||
gl_disable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
|
||||
bool device_framebuffer_srgb_enabled(gs_device_t *device)
|
||||
{
|
||||
const GLboolean enabled = glIsEnabled(GL_FRAMEBUFFER_SRGB);
|
||||
gl_success("glIsEnabled");
|
||||
return enabled == GL_TRUE;
|
||||
}
|
||||
|
||||
void device_copy_texture_region(gs_device_t *device, gs_texture_t *dst,
|
||||
uint32_t dst_x, uint32_t dst_y,
|
||||
gs_texture_t *src, uint32_t src_x,
|
||||
|
@ -71,6 +71,12 @@ static inline GLenum convert_gs_format(enum gs_color_format format)
|
||||
return GL_RGBA;
|
||||
case GS_DXT5:
|
||||
return GL_RGBA;
|
||||
case GS_RGBA_UNORM:
|
||||
return GL_RGBA;
|
||||
case GS_BGRX_UNORM:
|
||||
return GL_BGRA;
|
||||
case GS_BGRA_UNORM:
|
||||
return GL_BGRA;
|
||||
case GS_UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
@ -86,11 +92,11 @@ static inline GLenum convert_gs_internal_format(enum gs_color_format format)
|
||||
case GS_R8:
|
||||
return GL_R8;
|
||||
case GS_RGBA:
|
||||
return GL_RGBA;
|
||||
return GL_SRGB8_ALPHA8;
|
||||
case GS_BGRX:
|
||||
return GL_RGB;
|
||||
return GL_SRGB8;
|
||||
case GS_BGRA:
|
||||
return GL_RGBA;
|
||||
return GL_SRGB8_ALPHA8;
|
||||
case GS_R10G10B10A2:
|
||||
return GL_RGB10_A2;
|
||||
case GS_RGBA16:
|
||||
@ -117,6 +123,12 @@ static inline GLenum convert_gs_internal_format(enum gs_color_format format)
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
case GS_DXT5:
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
case GS_RGBA_UNORM:
|
||||
return GL_RGBA;
|
||||
case GS_BGRX_UNORM:
|
||||
return GL_RGB;
|
||||
case GS_BGRA_UNORM:
|
||||
return GL_RGBA;
|
||||
case GS_UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
@ -163,6 +175,12 @@ static inline GLenum get_gl_format_type(enum gs_color_format format)
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case GS_DXT5:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case GS_RGBA_UNORM:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case GS_BGRX_UNORM:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case GS_BGRA_UNORM:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case GS_UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
@ -411,6 +429,7 @@ struct gs_shader_param {
|
||||
int array_count;
|
||||
|
||||
struct gs_texture *texture;
|
||||
bool srgb;
|
||||
|
||||
DARRAY(uint8_t) cur_value;
|
||||
DARRAY(uint8_t) def_value;
|
||||
|
@ -88,6 +88,8 @@ EXPORT void device_load_indexbuffer(gs_device_t *device,
|
||||
gs_indexbuffer_t *indexbuffer);
|
||||
EXPORT void device_load_texture(gs_device_t *device, gs_texture_t *tex,
|
||||
int unit);
|
||||
EXPORT void device_load_texture_srgb(gs_device_t *device, gs_texture_t *tex,
|
||||
int unit);
|
||||
EXPORT void device_load_samplerstate(gs_device_t *device,
|
||||
gs_samplerstate_t *samplerstate, int unit);
|
||||
EXPORT void device_load_vertexshader(gs_device_t *device,
|
||||
@ -105,6 +107,8 @@ EXPORT void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
||||
EXPORT void device_set_cube_render_target(gs_device_t *device,
|
||||
gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
EXPORT void device_enable_framebuffer_srgb(gs_device_t *device, bool enable);
|
||||
EXPORT bool device_framebuffer_srgb_enabled(gs_device_t *device);
|
||||
EXPORT void device_copy_texture(gs_device_t *device, gs_texture_t *dst,
|
||||
gs_texture_t *src);
|
||||
EXPORT void device_copy_texture_region(gs_device_t *device, gs_texture_t *dst,
|
||||
|
@ -486,7 +486,18 @@ void gs_effect_set_color(gs_eparam_t *param, uint32_t argb)
|
||||
|
||||
void gs_effect_set_texture(gs_eparam_t *param, gs_texture_t *val)
|
||||
{
|
||||
effect_setval_inline(param, &val, sizeof(gs_texture_t *));
|
||||
struct gs_shader_texture shader_tex;
|
||||
shader_tex.tex = val;
|
||||
shader_tex.srgb = false;
|
||||
effect_setval_inline(param, &shader_tex, sizeof(shader_tex));
|
||||
}
|
||||
|
||||
void gs_effect_set_texture_srgb(gs_eparam_t *param, gs_texture_t *val)
|
||||
{
|
||||
struct gs_shader_texture shader_tex;
|
||||
shader_tex.tex = val;
|
||||
shader_tex.srgb = true;
|
||||
effect_setval_inline(param, &shader_tex, sizeof(shader_tex));
|
||||
}
|
||||
|
||||
void gs_effect_set_val(gs_eparam_t *param, const void *val, size_t size)
|
||||
|
@ -82,6 +82,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
|
||||
GRAPHICS_IMPORT(device_get_zstencil_target);
|
||||
GRAPHICS_IMPORT(device_set_render_target);
|
||||
GRAPHICS_IMPORT(device_set_cube_render_target);
|
||||
GRAPHICS_IMPORT(device_enable_framebuffer_srgb);
|
||||
GRAPHICS_IMPORT(device_framebuffer_srgb_enabled);
|
||||
GRAPHICS_IMPORT(device_copy_texture_region);
|
||||
GRAPHICS_IMPORT(device_copy_texture);
|
||||
GRAPHICS_IMPORT(device_stage_texture);
|
||||
|
@ -106,6 +106,9 @@ struct gs_exports {
|
||||
void (*device_set_cube_render_target)(gs_device_t *device,
|
||||
gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
void (*device_enable_framebuffer_srgb)(gs_device_t *device,
|
||||
bool enable);
|
||||
bool (*device_framebuffer_srgb_enabled)(gs_device_t *device);
|
||||
void (*device_copy_texture)(gs_device_t *device, gs_texture_t *dst,
|
||||
gs_texture_t *src);
|
||||
void (*device_copy_texture_region)(gs_device_t *device,
|
||||
@ -362,4 +365,6 @@ struct graphics_subsystem {
|
||||
|
||||
struct blend_state cur_blend_state;
|
||||
DARRAY(struct blend_state) blend_state_stack;
|
||||
|
||||
bool linear_srgb;
|
||||
};
|
||||
|
@ -1708,6 +1708,50 @@ void gs_set_cube_render_target(gs_texture_t *cubetex, int side,
|
||||
graphics->device, cubetex, side, zstencil);
|
||||
}
|
||||
|
||||
void gs_enable_framebuffer_srgb(bool enable)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
||||
if (!gs_valid("gs_enable_framebuffer_srgb"))
|
||||
return;
|
||||
|
||||
graphics->exports.device_enable_framebuffer_srgb(graphics->device,
|
||||
enable);
|
||||
}
|
||||
|
||||
bool gs_framebuffer_srgb_enabled(void)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
||||
if (!gs_valid("gs_framebuffer_srgb_enabled"))
|
||||
return false;
|
||||
|
||||
return graphics->exports.device_framebuffer_srgb_enabled(
|
||||
graphics->device);
|
||||
}
|
||||
|
||||
bool gs_get_linear_srgb(void)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
||||
if (!gs_valid("gs_get_linear_srgb"))
|
||||
return false;
|
||||
|
||||
return graphics->linear_srgb;
|
||||
}
|
||||
|
||||
bool gs_set_linear_srgb(bool linear_srgb)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
||||
if (!gs_valid("gs_set_linear_srgb"))
|
||||
return false;
|
||||
|
||||
const bool previous = graphics->linear_srgb;
|
||||
graphics->linear_srgb = linear_srgb;
|
||||
return previous;
|
||||
}
|
||||
|
||||
void gs_copy_texture(gs_texture_t *dst, gs_texture_t *src)
|
||||
{
|
||||
graphics_t *graphics = thread_graphics;
|
||||
|
@ -73,6 +73,9 @@ enum gs_color_format {
|
||||
GS_DXT3,
|
||||
GS_DXT5,
|
||||
GS_R8G8,
|
||||
GS_RGBA_UNORM,
|
||||
GS_BGRX_UNORM,
|
||||
GS_BGRA_UNORM,
|
||||
};
|
||||
|
||||
enum gs_zstencil_format {
|
||||
@ -302,6 +305,11 @@ enum gs_shader_param_type {
|
||||
GS_SHADER_PARAM_TEXTURE,
|
||||
};
|
||||
|
||||
struct gs_shader_texture {
|
||||
gs_texture_t *tex;
|
||||
bool srgb;
|
||||
};
|
||||
|
||||
#ifndef SWIG
|
||||
struct gs_shader_param_info {
|
||||
enum gs_shader_param_type type;
|
||||
@ -423,6 +431,7 @@ EXPORT void gs_effect_set_vec2(gs_eparam_t *param, const struct vec2 *val);
|
||||
EXPORT void gs_effect_set_vec3(gs_eparam_t *param, const struct vec3 *val);
|
||||
EXPORT void gs_effect_set_vec4(gs_eparam_t *param, const struct vec4 *val);
|
||||
EXPORT void gs_effect_set_texture(gs_eparam_t *param, gs_texture_t *val);
|
||||
EXPORT void gs_effect_set_texture_srgb(gs_eparam_t *param, gs_texture_t *val);
|
||||
EXPORT void gs_effect_set_val(gs_eparam_t *param, const void *val, size_t size);
|
||||
EXPORT void gs_effect_set_default(gs_eparam_t *param);
|
||||
EXPORT size_t gs_effect_get_val_size(gs_eparam_t *param);
|
||||
@ -667,6 +676,12 @@ EXPORT void gs_set_render_target(gs_texture_t *tex, gs_zstencil_t *zstencil);
|
||||
EXPORT void gs_set_cube_render_target(gs_texture_t *cubetex, int side,
|
||||
gs_zstencil_t *zstencil);
|
||||
|
||||
EXPORT void gs_enable_framebuffer_srgb(bool enable);
|
||||
EXPORT bool gs_framebuffer_srgb_enabled(void);
|
||||
|
||||
EXPORT bool gs_get_linear_srgb(void);
|
||||
EXPORT bool gs_set_linear_srgb(bool linear_srgb);
|
||||
|
||||
EXPORT void gs_copy_texture(gs_texture_t *dst, gs_texture_t *src);
|
||||
EXPORT void gs_copy_texture_region(gs_texture_t *dst, uint32_t dst_x,
|
||||
uint32_t dst_y, gs_texture_t *src,
|
||||
@ -939,6 +954,12 @@ static inline uint32_t gs_get_format_bpp(enum gs_color_format format)
|
||||
return 8;
|
||||
case GS_R8G8:
|
||||
return 16;
|
||||
case GS_RGBA_UNORM:
|
||||
return 32;
|
||||
case GS_BGRX_UNORM:
|
||||
return 32;
|
||||
case GS_BGRA_UNORM:
|
||||
return 32;
|
||||
case GS_UNKNOWN:
|
||||
return 0;
|
||||
}
|
||||
@ -951,6 +972,18 @@ static inline bool gs_is_compressed_format(enum gs_color_format format)
|
||||
return (format == GS_DXT1 || format == GS_DXT3 || format == GS_DXT5);
|
||||
}
|
||||
|
||||
static inline bool gs_is_srgb_format(enum gs_color_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_RGBA:
|
||||
case GS_BGRX:
|
||||
case GS_BGRA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t gs_get_total_levels(uint32_t width, uint32_t height,
|
||||
uint32_t depth)
|
||||
{
|
||||
|
@ -199,43 +199,126 @@ static inline void vec4_ceil(struct vec4 *dst, const struct vec4 *v)
|
||||
static inline uint32_t vec4_to_rgba(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((double)src->x * 255.0);
|
||||
val |= (uint32_t)((double)src->y * 255.0) << 8;
|
||||
val |= (uint32_t)((double)src->z * 255.0) << 16;
|
||||
val |= (uint32_t)((double)src->w * 255.0) << 24;
|
||||
val = (uint32_t)((src->x * 255.0f) + 0.5f);
|
||||
val |= (uint32_t)((src->y * 255.0f) + 0.5f) << 8;
|
||||
val |= (uint32_t)((src->z * 255.0f) + 0.5f) << 16;
|
||||
val |= (uint32_t)((src->w * 255.0f) + 0.5f) << 24;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline uint32_t vec4_to_bgra(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((double)src->z * 255.0);
|
||||
val |= (uint32_t)((double)src->y * 255.0) << 8;
|
||||
val |= (uint32_t)((double)src->x * 255.0) << 16;
|
||||
val |= (uint32_t)((double)src->w * 255.0) << 24;
|
||||
val = (uint32_t)((src->z * 255.0f) + 0.5f);
|
||||
val |= (uint32_t)((src->y * 255.0f) + 0.5f) << 8;
|
||||
val |= (uint32_t)((src->x * 255.0f) + 0.5f) << 16;
|
||||
val |= (uint32_t)((src->w * 255.0f) + 0.5f) << 24;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void vec4_from_rgba(struct vec4 *dst, uint32_t rgba)
|
||||
{
|
||||
dst->x = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
dst->x = (float)(rgba & 0xFF) / 255.0f;
|
||||
rgba >>= 8;
|
||||
dst->y = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
dst->y = (float)(rgba & 0xFF) / 255.0f;
|
||||
rgba >>= 8;
|
||||
dst->z = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
dst->z = (float)(rgba & 0xFF) / 255.0f;
|
||||
rgba >>= 8;
|
||||
dst->w = (float)((double)(rgba & 0xFF) * (1.0 / 255.0));
|
||||
dst->w = (float)rgba / 255.0f;
|
||||
}
|
||||
|
||||
static inline void vec4_from_bgra(struct vec4 *dst, uint32_t bgra)
|
||||
{
|
||||
dst->z = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
dst->z = (float)(bgra & 0xFF) / 255.0f;
|
||||
bgra >>= 8;
|
||||
dst->y = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
dst->y = (float)(bgra & 0xFF) / 255.0f;
|
||||
bgra >>= 8;
|
||||
dst->x = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
dst->x = (float)(bgra & 0xFF) / 255.0f;
|
||||
bgra >>= 8;
|
||||
dst->w = (float)((double)(bgra & 0xFF) * (1.0 / 255.0));
|
||||
dst->w = (float)bgra / 255.0f;
|
||||
}
|
||||
|
||||
static inline float srgb_nonlinear_to_linear(float u)
|
||||
{
|
||||
return (u <= 0.04045f) ? (u / 12.92f)
|
||||
: powf((u + 0.055f) / 1.055f, 2.4f);
|
||||
}
|
||||
|
||||
static inline void vec4_from_rgba_srgb(struct vec4 *dst, uint32_t rgba)
|
||||
{
|
||||
dst->x = srgb_nonlinear_to_linear((float)(rgba & 0xFF) / 255.0f);
|
||||
rgba >>= 8;
|
||||
dst->y = srgb_nonlinear_to_linear((float)(rgba & 0xFF) / 255.0f);
|
||||
rgba >>= 8;
|
||||
dst->z = srgb_nonlinear_to_linear((float)(rgba & 0xFF) / 255.0f);
|
||||
rgba >>= 8;
|
||||
dst->w = (float)rgba / 255.0f;
|
||||
}
|
||||
|
||||
static inline void vec4_from_bgra_srgb(struct vec4 *dst, uint32_t bgra)
|
||||
{
|
||||
dst->z = srgb_nonlinear_to_linear((float)(bgra & 0xFF) / 255.0f);
|
||||
bgra >>= 8;
|
||||
dst->y = srgb_nonlinear_to_linear((float)(bgra & 0xFF) / 255.0f);
|
||||
bgra >>= 8;
|
||||
dst->x = srgb_nonlinear_to_linear((float)(bgra & 0xFF) / 255.0f);
|
||||
bgra >>= 8;
|
||||
dst->w = (float)bgra / 255.0f;
|
||||
}
|
||||
|
||||
static inline void vec4_from_rgba_srgb_premultiply(struct vec4 *dst,
|
||||
uint32_t rgba)
|
||||
{
|
||||
vec4_from_rgba_srgb(dst, rgba);
|
||||
dst->x *= dst->w;
|
||||
dst->y *= dst->w;
|
||||
dst->z *= dst->w;
|
||||
}
|
||||
|
||||
static inline void vec4_from_bgra_srgb_premultiply(struct vec4 *dst,
|
||||
uint32_t bgra)
|
||||
{
|
||||
vec4_from_bgra_srgb(dst, bgra);
|
||||
dst->x *= dst->w;
|
||||
dst->y *= dst->w;
|
||||
dst->z *= dst->w;
|
||||
}
|
||||
|
||||
static inline float srgb_linear_to_nonlinear(float u)
|
||||
{
|
||||
return (u <= 0.0031308f) ? (12.92f * u)
|
||||
: ((1.055f * powf(u, 1.0f / 2.4f)) - 0.055f);
|
||||
}
|
||||
|
||||
static inline uint32_t vec4_to_rgba_srgb(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((srgb_linear_to_nonlinear(src->x) * 255.0f) + 0.5f);
|
||||
val |= (uint32_t)((srgb_linear_to_nonlinear(src->y) * 255.0f) + 0.5f)
|
||||
<< 8;
|
||||
val |= (uint32_t)((srgb_linear_to_nonlinear(src->z) * 255.0f) + 0.5f)
|
||||
<< 16;
|
||||
val |= (uint32_t)((src->w * 255.0f) + 0.5f) << 24;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline uint32_t vec4_to_bgra_srgb(const struct vec4 *src)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (uint32_t)((srgb_linear_to_nonlinear(src->z) * 255.0f) + 0.5f);
|
||||
val |= (uint32_t)((srgb_linear_to_nonlinear(src->y) * 255.0f) + 0.5f)
|
||||
<< 8;
|
||||
val |= (uint32_t)((srgb_linear_to_nonlinear(src->x) * 255.0f) + 0.5f)
|
||||
<< 16;
|
||||
val |= (uint32_t)((src->w * 255.0f) + 0.5f) << 24;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void vec4_srgb_linear_to_nonlinear(struct vec4 *dst)
|
||||
{
|
||||
dst->x = srgb_linear_to_nonlinear(dst->x);
|
||||
dst->y = srgb_linear_to_nonlinear(dst->y);
|
||||
dst->y = srgb_linear_to_nonlinear(dst->y);
|
||||
}
|
||||
|
||||
EXPORT void vec4_transform(struct vec4 *dst, const struct vec4 *v,
|
||||
|
@ -2012,9 +2012,21 @@ static inline void obs_source_draw_texture(struct obs_source *source,
|
||||
tex = gs_texrender_get_texture(source->async_texrender);
|
||||
|
||||
param = gs_effect_get_param_by_name(effect, "image");
|
||||
gs_effect_set_texture(param, tex);
|
||||
|
||||
const bool linear_srgb = gs_get_linear_srgb();
|
||||
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
gs_enable_framebuffer_srgb(linear_srgb);
|
||||
|
||||
if (linear_srgb) {
|
||||
gs_effect_set_texture_srgb(param, tex);
|
||||
} else {
|
||||
gs_effect_set_texture(param, tex);
|
||||
}
|
||||
|
||||
gs_draw_sprite(tex, source->async_flip ? GS_FLIP_V : 0, 0, 0);
|
||||
|
||||
gs_enable_framebuffer_srgb(previous);
|
||||
}
|
||||
|
||||
static void obs_source_draw_async_texture(struct obs_source *source)
|
||||
@ -3588,7 +3600,15 @@ static inline void render_filter_tex(gs_texture_t *tex, gs_effect_t *effect,
|
||||
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
||||
size_t passes, i;
|
||||
|
||||
gs_effect_set_texture(image, tex);
|
||||
const bool linear_srgb = gs_get_linear_srgb();
|
||||
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
gs_enable_framebuffer_srgb(linear_srgb);
|
||||
|
||||
if (linear_srgb)
|
||||
gs_effect_set_texture_srgb(image, tex);
|
||||
else
|
||||
gs_effect_set_texture(image, tex);
|
||||
|
||||
passes = gs_technique_begin(tech);
|
||||
for (i = 0; i < passes; i++) {
|
||||
@ -3597,6 +3617,8 @@ static inline void render_filter_tex(gs_texture_t *tex, gs_effect_t *effect,
|
||||
gs_technique_end_pass(tech);
|
||||
}
|
||||
gs_technique_end(tech);
|
||||
|
||||
gs_enable_framebuffer_srgb(previous);
|
||||
}
|
||||
|
||||
static inline bool can_bypass(obs_source_t *target, obs_source_t *parent,
|
||||
@ -4164,21 +4186,27 @@ void obs_source_draw_set_color_matrix(const struct matrix4 *color_matrix,
|
||||
void obs_source_draw(gs_texture_t *texture, int x, int y, uint32_t cx,
|
||||
uint32_t cy, bool flip)
|
||||
{
|
||||
gs_effect_t *effect = gs_get_effect();
|
||||
bool change_pos = (x != 0 || y != 0);
|
||||
gs_eparam_t *image;
|
||||
if (!obs_ptr_valid(texture, "obs_source_draw"))
|
||||
return;
|
||||
|
||||
gs_effect_t *effect = gs_get_effect();
|
||||
if (!effect) {
|
||||
blog(LOG_WARNING, "obs_source_draw: no active effect!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obs_ptr_valid(texture, "obs_source_draw"))
|
||||
return;
|
||||
const bool linear_srgb = gs_get_linear_srgb();
|
||||
|
||||
image = gs_effect_get_param_by_name(effect, "image");
|
||||
gs_effect_set_texture(image, texture);
|
||||
const bool previous = gs_framebuffer_srgb_enabled();
|
||||
gs_enable_framebuffer_srgb(linear_srgb);
|
||||
|
||||
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
|
||||
if (linear_srgb)
|
||||
gs_effect_set_texture_srgb(image, texture);
|
||||
else
|
||||
gs_effect_set_texture(image, texture);
|
||||
|
||||
const bool change_pos = (x != 0 || y != 0);
|
||||
if (change_pos) {
|
||||
gs_matrix_push();
|
||||
gs_matrix_translate3f((float)x, (float)y, 0.0f);
|
||||
@ -4188,6 +4216,8 @@ void obs_source_draw(gs_texture_t *texture, int x, int y, uint32_t cx,
|
||||
|
||||
if (change_pos)
|
||||
gs_matrix_pop();
|
||||
|
||||
gs_enable_framebuffer_srgb(previous);
|
||||
}
|
||||
|
||||
void obs_source_inc_showing(obs_source_t *source)
|
||||
|
Loading…
x
Reference in New Issue
Block a user