feat: gamma functionality on windows64

This commit is contained in:
2026-09-12 00:23:31 +01:00
parent acee40a506
commit d0f99a6d28
6 changed files with 327 additions and 6 deletions
+2 -1
View File
@@ -36,4 +36,5 @@ SOFTWARE.
#include "PS_TextureProjection.h"
#include "PS_ForceLOD.h"
#include "PS_ScreenSpace.h"
#include "PS_ScreenClear.h"
#include "PS_ScreenClear.h"
#include "PS_ScreenGamma.h"
+201
View File
@@ -0,0 +1,201 @@
#if 0
//
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
//
//
// Buffer Definitions:
//
// cbuffer gammaBuff
// {
//
// float4 gammaParams; // Offset: 0 Size: 16
//
// }
//
//
// Resource Bindings:
//
// Name Type Format Dim HLSL Bind Count
// ------------------------------ ---------- ------- ----------- -------------- ------
// screen_sampler_s sampler NA NA s0 1
// screen_texture texture float4 2d t0 1
// gammaBuff cbuffer NA NA cb6 1
//
//
//
// Input signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_POSITION 0 xyzw 0 POS float
// TEXCOORD 0 xy 1 NONE float xy
//
//
// Output signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_TARGET 0 xyzw 0 TARGET float xyzw
//
ps_4_0
dcl_constantbuffer CB6[1], immediateIndexed
dcl_sampler s0, mode_default
dcl_resource_texture2d (float,float,float,float) t0
dcl_input_ps linear v1.xy
dcl_output o0.xyzw
dcl_temps 1
sample r0.xyzw, v1.xyxx, t0.xyzw, s0
mov_sat r0.xyz, r0.xyzx
mov o0.w, r0.w
log r0.xyz, r0.xyzx
mul r0.xyz, r0.xyzx, cb6[0].xxxx
exp o0.xyz, r0.xyzx
ret
// Approximately 7 instruction slots used
#endif
const BYTE g_main_PS_ScreenGamma[] =
{
68, 88, 66, 67, 53, 209,
160, 253, 213, 124, 231, 96,
156, 17, 77, 217, 140, 64,
219, 192, 1, 0, 0, 0,
84, 3, 0, 0, 5, 0,
0, 0, 52, 0, 0, 0,
88, 1, 0, 0, 176, 1,
0, 0, 228, 1, 0, 0,
216, 2, 0, 0, 82, 68,
69, 70, 28, 1, 0, 0,
1, 0, 0, 0, 168, 0,
0, 0, 3, 0, 0, 0,
28, 0, 0, 0, 0, 4,
255, 255, 0, 129, 0, 0,
244, 0, 0, 0, 124, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0,
141, 0, 0, 0, 2, 0,
0, 0, 5, 0, 0, 0,
4, 0, 0, 0, 255, 255,
255, 255, 0, 0, 0, 0,
1, 0, 0, 0, 13, 0,
0, 0, 156, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 6, 0,
0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 115, 99,
114, 101, 101, 110, 95, 115,
97, 109, 112, 108, 101, 114,
95, 115, 0, 115, 99, 114,
101, 101, 110, 95, 116, 101,
120, 116, 117, 114, 101, 0,
103, 97, 109, 109, 97, 66,
117, 102, 102, 0, 171, 171,
156, 0, 0, 0, 1, 0,
0, 0, 192, 0, 0, 0,
16, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
216, 0, 0, 0, 0, 0,
0, 0, 16, 0, 0, 0,
2, 0, 0, 0, 228, 0,
0, 0, 0, 0, 0, 0,
103, 97, 109, 109, 97, 80,
97, 114, 97, 109, 115, 0,
1, 0, 3, 0, 1, 0,
4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 77, 105,
99, 114, 111, 115, 111, 102,
116, 32, 40, 82, 41, 32,
72, 76, 83, 76, 32, 83,
104, 97, 100, 101, 114, 32,
67, 111, 109, 112, 105, 108,
101, 114, 32, 49, 48, 46,
49, 0, 73, 83, 71, 78,
80, 0, 0, 0, 2, 0,
0, 0, 8, 0, 0, 0,
56, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
3, 0, 0, 0, 0, 0,
0, 0, 15, 0, 0, 0,
68, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 1, 0,
0, 0, 3, 3, 0, 0,
83, 86, 95, 80, 79, 83,
73, 84, 73, 79, 78, 0,
84, 69, 88, 67, 79, 79,
82, 68, 0, 171, 171, 171,
79, 83, 71, 78, 44, 0,
0, 0, 1, 0, 0, 0,
8, 0, 0, 0, 32, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
15, 0, 0, 0, 83, 86,
95, 84, 65, 82, 71, 69,
84, 0, 171, 171, 83, 72,
68, 82, 236, 0, 0, 0,
64, 0, 0, 0, 59, 0,
0, 0, 89, 0, 0, 4,
70, 142, 32, 0, 6, 0,
0, 0, 1, 0, 0, 0,
90, 0, 0, 3, 0, 96,
16, 0, 0, 0, 0, 0,
88, 24, 0, 4, 0, 112,
16, 0, 0, 0, 0, 0,
85, 85, 0, 0, 98, 16,
0, 3, 50, 16, 16, 0,
1, 0, 0, 0, 101, 0,
0, 3, 242, 32, 16, 0,
0, 0, 0, 0, 104, 0,
0, 2, 1, 0, 0, 0,
69, 0, 0, 9, 242, 0,
16, 0, 0, 0, 0, 0,
70, 16, 16, 0, 1, 0,
0, 0, 70, 126, 16, 0,
0, 0, 0, 0, 0, 96,
16, 0, 0, 0, 0, 0,
54, 32, 0, 5, 114, 0,
16, 0, 0, 0, 0, 0,
70, 2, 16, 0, 0, 0,
0, 0, 54, 0, 0, 5,
130, 32, 16, 0, 0, 0,
0, 0, 58, 0, 16, 0,
0, 0, 0, 0, 47, 0,
0, 5, 114, 0, 16, 0,
0, 0, 0, 0, 70, 2,
16, 0, 0, 0, 0, 0,
56, 0, 0, 8, 114, 0,
16, 0, 0, 0, 0, 0,
70, 2, 16, 0, 0, 0,
0, 0, 6, 128, 32, 0,
6, 0, 0, 0, 0, 0,
0, 0, 25, 0, 0, 5,
114, 32, 16, 0, 0, 0,
0, 0, 70, 2, 16, 0,
0, 0, 0, 0, 62, 0,
0, 1, 83, 84, 65, 84,
116, 0, 0, 0, 7, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 2, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0
};
+8 -1
View File
@@ -61,6 +61,7 @@ public:
int kScreenHeight;
int kScreenWidth;
void SetGamma(float gamma);
void UpdateGamma(unsigned short usGamma);
void MatrixMode(int type);
void MatrixSetIdentity();
@@ -415,6 +416,7 @@ public:
ID3D11Buffer *m_alphaTestBuffer;
ID3D11Buffer *m_clearColorBuffer;
ID3D11Buffer *m_forcedLODBuffer;
ID3D11Buffer *m_gammaRenderBuffer;
uint64_t dynamicVertexBase;
DWORD dynamicVertexOffset;
ID3D11Buffer *dynamicVertexBuffer;
@@ -456,6 +458,7 @@ public:
ID3D11PixelShader **pixelShaderTable;
ID3D11PixelShader *screenSpacePixelShader;
ID3D11PixelShader *screenClearPixelShader;
ID3D11PixelShader *screenGammaPixelShader;
unsigned int *vertexStrideTable;
ID3D11InputLayout **inputLayoutTable;
ID3D11Buffer *quadIndexBuffer;
@@ -492,7 +495,11 @@ public:
std::unordered_map<int, ID3D11RasterizerState *> managedRasterizerStates;
bool m_bShouldScreenGrabNextFrame;
bool m_bSuspended;
unsigned short m_usPreviousGamma;
float m_usGamma;
ID3D11SamplerState *m_gammaSamplerState;
ID3D11Buffer *m_gammaFullscreenBoundsBuffer;
// @Patoke add
ID3D11Texture2D *m_backBufferTexture;
};
+101 -3
View File
@@ -99,6 +99,7 @@ Renderer::Context::Context(ID3D11Device* device, ID3D11DeviceContext* deviceCont
, m_alphaTestBuffer(NULL)
, m_clearColorBuffer(NULL)
, m_forcedLODBuffer(NULL)
, m_gammaRenderBuffer(NULL)
, dynamicVertexBase(0)
, dynamicVertexOffset(0)
, dynamicVertexBuffer(NULL)
@@ -226,6 +227,10 @@ Renderer::Context::Context(ID3D11Device* device, ID3D11DeviceContext* deviceCont
device->CreateBuffer(&cbDesc, &cbData, &m_clearColorBuffer);
device->CreateBuffer(&cbDesc, &cbData, &m_forcedLODBuffer);
cbDesc.ByteWidth = sizeof(zero4);
cbData.pSysMem = zero4;
device->CreateBuffer(&cbDesc, &cbData, &m_gammaRenderBuffer);
deviceContext->VSSetConstantBuffers(0, 10, &m_modelViewMatrix);
deviceContext->PSSetConstantBuffers(0, 6, &m_tintColorBuffer);
@@ -411,7 +416,6 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut)
c.m_pDeviceContext->VSSetShader(screenSpaceVertexShader, NULL, 0);
c.m_pDeviceContext->IASetInputLayout(NULL);
c.m_pDeviceContext->PSSetShader(screenSpacePixelShader, NULL, 0);
c.m_pDeviceContext->OMSetBlendState(blendState, NULL, -1);
c.m_pDeviceContext->OMSetDepthStencilState(depthState, 0);
c.m_pDeviceContext->RSSetState(rasterizerState);
@@ -836,7 +840,26 @@ void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain)
m_pDevice->CreateBuffer(&fanIndexDesc, &fanIndexData, &fanIndexBuffer);
delete[] fanIndices;
InitializeCriticalSection(&Renderer::totalAllocCS);
D3D11_SAMPLER_DESC gammaSamplerDesc = {};
gammaSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
gammaSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
gammaSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
gammaSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
gammaSamplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
m_pDevice->CreateSamplerState(&gammaSamplerDesc, &m_gammaSamplerState);
const float fullscreenBounds[4] = { 0.0f, 0.0f, 2.0f, 2.0f };
D3D11_BUFFER_DESC boundsDesc = {};
boundsDesc.ByteWidth = sizeof(fullscreenBounds);
boundsDesc.Usage = D3D11_USAGE_IMMUTABLE;
boundsDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
D3D11_SUBRESOURCE_DATA boundsData = { fullscreenBounds };
m_pDevice->CreateBuffer(&boundsDesc, &boundsData, &m_gammaFullscreenBoundsBuffer);
m_usPreviousGamma = 0xFFFF;
m_usGamma = 1.0f;
InitializeCriticalSection(&Renderer::totalAllocCS);
}
ID3D11DeviceContext *Renderer::InitialiseContext(bool fromPresent)
@@ -877,6 +900,70 @@ bool Renderer::IsWidescreen()
return (aspectRatio >= 1.56f);
}
// PIEBOT: Inspired by CaptureThumbnail
void Renderer::SetGamma(float gamma)
{
Renderer::Context &c = getContext();
// @Patoke fix: bind render target to a proper backbuffer texture
ID3D11Resource *actualBackBuffer = NULL;
mainRenderTargetView->GetResource(&actualBackBuffer);
// copy the backbuffer contents
c.m_pDeviceContext->CopyResource(m_backBufferTexture, actualBackBuffer);
actualBackBuffer->Release();
D3D11_MAPPED_SUBRESOURCE mapped = {};
if (SUCCEEDED(c.m_pDeviceContext->Map(c.m_gammaRenderBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)))
{
*reinterpret_cast<DirectX::XMFLOAT4 *>(mapped.pData) = DirectX::XMFLOAT4(gamma, 0.0f, 0.0f, 0.0f);
c.m_pDeviceContext->Unmap(c.m_gammaRenderBuffer, 0);
}
ID3D11BlendState *blendState = NULL;
ID3D11RasterizerState *rasterizerState = NULL;
D3D11_BLEND_DESC blendDesc = {};
blendDesc.RenderTarget[0].BlendEnable = false;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
m_pDevice->CreateBlendState(&blendDesc, &blendState);
D3D11_RASTERIZER_DESC rasterDesc = {};
rasterDesc.FillMode = D3D11_FILL_SOLID;
rasterDesc.CullMode = D3D11_CULL_NONE;
rasterDesc.DepthClipEnable = true;
rasterDesc.MultisampleEnable = true;
m_pDevice->CreateRasterizerState(&rasterDesc, &rasterizerState);
c.m_pDeviceContext->VSSetShader(screenSpaceVertexShader, NULL, 0);
c.m_pDeviceContext->PSSetShader(screenGammaPixelShader, NULL, 0);
c.m_pDeviceContext->IASetInputLayout(NULL);
c.m_pDeviceContext->IASetVertexBuffers(0, 0, NULL, NULL, NULL);
c.m_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
c.m_pDeviceContext->OMSetBlendState(blendState, NULL, 0xFFFFFFFF);
c.m_pDeviceContext->RSSetState(rasterizerState);
blendState->Release();
rasterizerState->Release();
D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (float)backBufferWidth, (float)backBufferHeight, 0.0f, 1.0f };
c.m_pDeviceContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL);
c.m_pDeviceContext->RSSetViewports(1, &viewport);
c.m_pDeviceContext->PSSetShaderResources(0, 1, &mainShaderResourceView);
c.m_pDeviceContext->PSSetSamplers(0, 1, &m_gammaSamplerState);
c.m_pDeviceContext->VSSetConstantBuffers(9, 1, &m_gammaFullscreenBoundsBuffer);
c.m_pDeviceContext->PSSetConstantBuffers(6, 1, &c.m_gammaRenderBuffer);
c.m_pDeviceContext->Draw(4, 0);
}
void Renderer::Present()
{
PROFILER_SCOPE("Renderer::Present", "Present", MP_MAGENTA);
@@ -948,6 +1035,8 @@ void Renderer::Present()
m_bShouldScreenGrabNextFrame = false;
}
SetGamma(m_usGamma);
m_pSwapChain->Present(C4JRender::GetVSync(), 0);
++presentCount;
}
@@ -993,6 +1082,7 @@ void Renderer::SetupShaders()
m_pDevice->CreatePixelShader(g_main_PS_ForceLOD, sizeof(g_main_PS_ForceLOD), NULL, &pixelShaderTable[C4JRender::PIXEL_SHADER_TYPE_FORCELOD]);
m_pDevice->CreatePixelShader(g_main_PS_ScreenSpace, sizeof(g_main_PS_ScreenSpace), NULL, &screenSpacePixelShader);
m_pDevice->CreatePixelShader(g_main_PS_ScreenClear, sizeof(g_main_PS_ScreenClear), NULL, &screenClearPixelShader);
m_pDevice->CreatePixelShader(g_main_PS_ScreenGamma, sizeof(g_main_PS_ScreenGamma), NULL, &screenGammaPixelShader);
m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1, 5, g_main_VS_PF3_TF2_CB4_NB4_XW1, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1), &inputLayoutTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1]);
m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_Compressed, 2, g_main_VS_Compressed, sizeof(g_main_VS_Compressed), &inputLayoutTable[C4JRender::VERTEX_TYPE_COMPRESSED]);
@@ -1053,7 +1143,15 @@ bool Renderer::Suspended()
return m_bSuspended;
}
void Renderer::UpdateGamma(unsigned short) {}
void Renderer::UpdateGamma(unsigned short usGamma)
{
if (usGamma != m_usPreviousGamma)
{
m_usPreviousGamma = usGamma;
m_usGamma = 1.0f / (0.5f + (usGamma / 32768.0f) * 1.5f);
}
}
Renderer::Context &Renderer::getContext()
{
+2 -1
View File
@@ -21,4 +21,5 @@ if not exist %OUT% mkdir %OUT%
%FXC% %OPT% /T ps_4_0 /E main /D TEXTURE_PROJECTION /Fh %OUT%/PS_TextureProjection.h /Vn g_main_PS_TextureProjection main_PS.hlsl
%FXC% %OPT% /T ps_4_0 /E main /D FORCE_LOD /Fh %OUT%/PS_ForceLOD.h /Vn g_main_PS_ForceLOD main_PS.hlsl
%FXC% %OPT% /T ps_4_0 /E PS_ScreenSpace /Fh %OUT%/PS_ScreenSpace.h /Vn g_main_PS_ScreenSpace screen_PS.hlsl
%FXC% %OPT% /T ps_4_0 /E PS_ScreenClear /Fh %OUT%/PS_ScreenClear.h /Vn g_main_PS_ScreenClear screen_PS.hlsl
%FXC% %OPT% /T ps_4_0 /E PS_ScreenClear /Fh %OUT%/PS_ScreenClear.h /Vn g_main_PS_ScreenClear screen_PS.hlsl
%FXC% %OPT% /T ps_4_0 /E PS_ScreenGamma /Fh %OUT%/PS_ScreenGamma.h /Vn g_main_PS_ScreenGamma screen_PS.hlsl
@@ -26,6 +26,11 @@ cbuffer cbuff : register(b4)
float4 clearColour;
};
cbuffer gammaBuff : register(b6)
{
float4 gammaParams;
};
SamplerState screen_sampler_s : register(s0);
Texture2D<float4> screen_texture : register(t0);
@@ -37,4 +42,12 @@ float4 PS_ScreenSpace(float4 position : SV_POSITION, float2 texcoord : TEXCOORD0
float4 PS_ScreenClear(float4 position : SV_POSITION) : SV_TARGET
{
return clearColour;
}
float4 PS_ScreenGamma(float4 position : SV_POSITION, float2 texcoord : TEXCOORD0) : SV_TARGET
{
float4 colour = screen_texture.Sample(screen_sampler_s, texcoord);
float invGamma = gammaParams.x;
colour.rgb = pow(saturate(colour.rgb), invGamma);
return colour;
}