wined3d: SRGB write correction emulation.
This commit is contained in:
parent
2b2c9199e8
commit
6313e0ffff
|
@ -154,6 +154,7 @@ void shader_arb_load_constants(
|
|||
if (usePixelShader) {
|
||||
|
||||
IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
|
||||
IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader;
|
||||
|
||||
/* Load DirectX 9 float constants for pixel shader */
|
||||
shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB,
|
||||
|
@ -165,10 +166,31 @@ void shader_arb_load_constants(
|
|||
* number of the constant to load the matrix into.
|
||||
* The state manager takes care that this function is always called if the bump env matrix changes
|
||||
*/
|
||||
IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader;
|
||||
float *data = (float *) &stateBlock->textureState[(int) psi->needsbumpmat][WINED3DTSS_BUMPENVMAT00];
|
||||
GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->bumpenvmatconst, data));
|
||||
}
|
||||
if(((IWineD3DPixelShaderImpl *) pshader)->srgb_enabled &&
|
||||
!((IWineD3DPixelShaderImpl *) pshader)->srgb_mode_hardcoded) {
|
||||
float comparison[4];
|
||||
float mul_low[4];
|
||||
|
||||
if(stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE]) {
|
||||
comparison[0] = srgb_cmp; comparison[1] = srgb_cmp;
|
||||
comparison[2] = srgb_cmp; comparison[3] = srgb_cmp;
|
||||
|
||||
mul_low[0] = srgb_mul_low; mul_low[1] = srgb_mul_low;
|
||||
mul_low[2] = srgb_mul_low; mul_low[3] = srgb_mul_low;
|
||||
} else {
|
||||
comparison[0] = 1.0 / 0.0; comparison[1] = 1.0 / 0.0;
|
||||
comparison[2] = 1.0 / 0.0; comparison[3] = 1.0 / 0.0;
|
||||
|
||||
mul_low[0] = 1.0; mul_low[1] = 1.0;
|
||||
mul_low[2] = 1.0; mul_low[3] = 1.0;
|
||||
}
|
||||
GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->srgb_cmp_const, comparison));
|
||||
GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->srgb_low_const, mul_low));
|
||||
checkGLcall("Load sRGB correction constants\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,10 +202,12 @@ void shader_generate_arb_declarations(
|
|||
WineD3D_GL_Info* gl_info) {
|
||||
|
||||
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
|
||||
IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device;
|
||||
DWORD i;
|
||||
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
|
||||
unsigned max_constantsF = min(This->baseShader.limits.constant_float,
|
||||
(pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF)));
|
||||
UINT extra_constants_needed = 0;
|
||||
|
||||
/* Temporary Output register */
|
||||
shader_addline(buffer, "TEMP TMP_OUT;\n");
|
||||
|
@ -220,6 +244,52 @@ void shader_generate_arb_declarations(
|
|||
} else {
|
||||
FIXME("No free constant found to load environemnt bump mapping matrix into the shader. texbem instruction will not apply bump mapping\n");
|
||||
}
|
||||
extra_constants_needed += 1;
|
||||
}
|
||||
if(device->stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE] && pshader) {
|
||||
IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This;
|
||||
/* If there are 2 constants left to use, use them to pass the sRGB correction values in. This way
|
||||
* srgb write correction can be turned on and off dynamically without recompilation. Otherwise
|
||||
* hardcode them. The drawback of hardcoding is that the shader needs recompilation to turn sRGB
|
||||
* off again
|
||||
*/
|
||||
if(max_constantsF + extra_constants_needed + 1 < GL_LIMITS(pshader_constantsF) && FALSE) {
|
||||
/* The idea is that if srgb is enabled, then disabled, the constant loading code
|
||||
* can effectively disabling sRGB correction by passing 1.0 and INF as the multiplication
|
||||
* and comparison constants. If it disables it that way, the shader won't be recompiled
|
||||
* and the code will stay in, so sRGB writing can be turned on again by setting the
|
||||
* constants from the spec
|
||||
*/
|
||||
ps_impl->srgb_mode_hardcoded = 0;
|
||||
ps_impl->srgb_low_const = GL_LIMITS(pshader_constantsF) - extra_constants_needed;
|
||||
ps_impl->srgb_cmp_const = GL_LIMITS(pshader_constantsF) - extra_constants_needed - 1;
|
||||
shader_addline(buffer, "PARAM srgb_mul_low = program.env[%d];\n", ps_impl->srgb_low_const);
|
||||
shader_addline(buffer, "PARAM srgb_comparison = program.env[%d];\n", ps_impl->srgb_cmp_const);
|
||||
} else {
|
||||
shader_addline(buffer, "PARAM srgb_mul_low = {%f, %f, %f, 1.0};\n",
|
||||
srgb_mul_low, srgb_mul_low, srgb_mul_low);
|
||||
shader_addline(buffer, "PARAM srgb_comparison = {%f, %f, %f, %f};\n",
|
||||
srgb_cmp, srgb_cmp, srgb_cmp, srgb_cmp);
|
||||
ps_impl->srgb_mode_hardcoded = 1;
|
||||
}
|
||||
/* These can be hardcoded, they do not cause any harm because no fragment will enter the high
|
||||
* path if the comparison value is set to INF
|
||||
*/
|
||||
shader_addline(buffer, "PARAM srgb_pow = {%f, %f, %f, 1.0};\n",
|
||||
srgb_pow, srgb_pow, srgb_pow);
|
||||
shader_addline(buffer, "PARAM srgb_mul_hi = {%f, %f, %f, 1.0};\n",
|
||||
srgb_mul_high, srgb_mul_high, srgb_mul_high);
|
||||
shader_addline(buffer, "PARAM srgb_sub_hi = {%f, %f, %f, 0.0};\n",
|
||||
srgb_sub_high, srgb_sub_high, srgb_sub_high);
|
||||
ps_impl->srgb_enabled = 1;
|
||||
} else if(pshader) {
|
||||
IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This;
|
||||
|
||||
/* Do not write any srgb fixup into the shader to save shader size and processing time.
|
||||
* As a consequence, we can't toggle srgb write on without recompilation
|
||||
*/
|
||||
ps_impl->srgb_enabled = 0;
|
||||
ps_impl->srgb_mode_hardcoded = 1;
|
||||
}
|
||||
|
||||
/* Need to PARAM the environment parameters (constants) so we can use relative addressing */
|
||||
|
|
|
@ -443,6 +443,31 @@ void shader_glsl_load_constants(
|
|||
GL_EXTCALL(glUniform1fvARB(pos, 1, offset));
|
||||
checkGLcall("glUniform1fvARB");
|
||||
}
|
||||
} else if(((IWineD3DPixelShaderImpl *) pshader)->srgb_enabled &&
|
||||
!((IWineD3DPixelShaderImpl *) pshader)->srgb_mode_hardcoded) {
|
||||
float comparison[4];
|
||||
float mul_low[4];
|
||||
|
||||
if(stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE]) {
|
||||
comparison[0] = srgb_cmp; comparison[1] = srgb_cmp;
|
||||
comparison[2] = srgb_cmp; comparison[3] = srgb_cmp;
|
||||
|
||||
mul_low[0] = srgb_mul_low; mul_low[1] = srgb_mul_low;
|
||||
mul_low[2] = srgb_mul_low; mul_low[3] = srgb_mul_low;
|
||||
} else {
|
||||
comparison[0] = 1.0 / 0.0; comparison[1] = 1.0 / 0.0;
|
||||
comparison[2] = 1.0 / 0.0; comparison[3] = 1.0 / 0.0;
|
||||
|
||||
mul_low[0] = 1.0; mul_low[1] = 1.0;
|
||||
mul_low[2] = 1.0; mul_low[3] = 1.0;
|
||||
}
|
||||
|
||||
pos = GL_EXTCALL(glGetUniformLocationARB(programId, "srgb_comparison"));
|
||||
checkGLcall("glGetUniformLocationARB");
|
||||
GL_EXTCALL(glUniform4fvARB(pos, 1, comparison));
|
||||
pos = GL_EXTCALL(glGetUniformLocationARB(programId, "srgb_mul_low"));
|
||||
checkGLcall("glGetUniformLocationARB");
|
||||
GL_EXTCALL(glUniform4fvARB(pos, 1, mul_low));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -455,7 +480,9 @@ void shader_generate_glsl_declarations(
|
|||
WineD3D_GL_Info* gl_info) {
|
||||
|
||||
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
|
||||
IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device;
|
||||
int i;
|
||||
unsigned int extra_constants_needed = 0;
|
||||
|
||||
/* There are some minor differences between pixel and vertex shaders */
|
||||
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
|
||||
|
@ -480,13 +507,42 @@ void shader_generate_glsl_declarations(
|
|||
if (This->baseShader.limits.constant_bool > 0)
|
||||
shader_addline(buffer, "uniform bool %cB[%u];\n", prefix, This->baseShader.limits.constant_bool);
|
||||
|
||||
if(!pshader)
|
||||
if(!pshader) {
|
||||
shader_addline(buffer, "uniform vec4 posFixup;\n");
|
||||
else if(reg_maps->bumpmat != -1) {
|
||||
shader_addline(buffer, "uniform mat2 bumpenvmat;\n");
|
||||
if(reg_maps->luminanceparams) {
|
||||
shader_addline(buffer, "uniform float luminancescale;\n");
|
||||
shader_addline(buffer, "uniform float luminanceoffset;\n");
|
||||
} else {
|
||||
IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This;
|
||||
|
||||
if(reg_maps->bumpmat != -1) {
|
||||
shader_addline(buffer, "uniform mat2 bumpenvmat;\n");
|
||||
if(reg_maps->luminanceparams) {
|
||||
shader_addline(buffer, "uniform float luminancescale;\n");
|
||||
shader_addline(buffer, "uniform float luminanceoffset;\n");
|
||||
extra_constants_needed++;
|
||||
}
|
||||
extra_constants_needed++;
|
||||
}
|
||||
|
||||
if(device->stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE]) {
|
||||
ps_impl->srgb_enabled = 1;
|
||||
if(This->baseShader.limits.constant_float + extra_constants_needed + 1 < GL_LIMITS(pshader_constantsF)) {
|
||||
shader_addline(buffer, "uniform vec4 srgb_mul_low;\n");
|
||||
shader_addline(buffer, "uniform vec4 srgb_comparison;\n");
|
||||
ps_impl->srgb_mode_hardcoded = 0;
|
||||
} else {
|
||||
ps_impl->srgb_mode_hardcoded = 1;
|
||||
shader_addline(buffer, "const vec4 srgb_mul_low = {%f, %f, %f, %f};\n",
|
||||
srgb_mul_low, srgb_mul_low, srgb_mul_low, srgb_mul_low);
|
||||
shader_addline(buffer, "const vec4 srgb_comparison = {%f, %f, %f, %f};\n",
|
||||
srgb_cmp, srgb_cmp, srgb_cmp, srgb_cmp);
|
||||
}
|
||||
} else {
|
||||
IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This;
|
||||
|
||||
/* Do not write any srgb fixup into the shader to save shader size and processing time.
|
||||
* As a consequence, we can't toggle srgb write on without recompilation
|
||||
*/
|
||||
ps_impl->srgb_enabled = 0;
|
||||
ps_impl->srgb_mode_hardcoded = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -399,6 +399,23 @@ static inline VOID IWineD3DPixelShaderImpl_GenerateShader(
|
|||
else
|
||||
shader_addline(&buffer, "gl_FragColor.xyz = mix(gl_Fog.color.xyz, gl_FragColor.xyz, Fog);\n");
|
||||
}
|
||||
if(This->srgb_enabled) {
|
||||
const char *fragcolor;
|
||||
|
||||
if(GL_SUPPORT(ARB_DRAW_BUFFERS)) {
|
||||
fragcolor = "gl_FragData[0]";
|
||||
} else {
|
||||
fragcolor = "gl_FragColor";
|
||||
}
|
||||
shader_addline(&buffer, "tmp0.xyz = pow(%s.xyz, vec3(%f, %f, %f)) * vec3(%f, %f, %f) - vec3(%f, %f, %f);\n",
|
||||
fragcolor, srgb_pow, srgb_pow, srgb_pow, srgb_mul_high, srgb_mul_high, srgb_mul_high,
|
||||
srgb_sub_high, srgb_sub_high, srgb_sub_high);
|
||||
shader_addline(&buffer, "tmp1.xyz = %s.xyz * srgb_mul_low.xyz;\n", fragcolor);
|
||||
shader_addline(&buffer, "%s.x = %s.x < srgb_comparison.x ? tmp1.x : tmp0.x;\n", fragcolor, fragcolor);
|
||||
shader_addline(&buffer, "%s.y = %s.y < srgb_comparison.y ? tmp1.y : tmp0.y;\n", fragcolor, fragcolor);
|
||||
shader_addline(&buffer, "%s.z = %s.z < srgb_comparison.z ? tmp1.z : tmp0.z;\n", fragcolor, fragcolor);
|
||||
shader_addline(&buffer, "%s = clamp(%s, 0.0, 1.0);\n", fragcolor, fragcolor);
|
||||
}
|
||||
|
||||
shader_addline(&buffer, "}\n");
|
||||
|
||||
|
@ -440,12 +457,41 @@ static inline VOID IWineD3DPixelShaderImpl_GenerateShader(
|
|||
* -1/(e-s) and e/(e-s) respectively.
|
||||
*/
|
||||
shader_addline(&buffer, "MAD_SAT TMP_FOG, fragment.fogcoord, state.fog.params.y, state.fog.params.z;\n");
|
||||
if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) {
|
||||
shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, R0, state.fog.color;\n");
|
||||
shader_addline(&buffer, "MOV result.color.a, R0.a;\n");
|
||||
|
||||
if(This->srgb_enabled) {
|
||||
if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) {
|
||||
shader_addline(&buffer, "LRP TMP_COLOR.rgb, TMP_FOG.x, R0, state.fog.color;\n");
|
||||
shader_addline(&buffer, "MOV result.color.a, R0.a;\n");
|
||||
} else {
|
||||
shader_addline(&buffer, "LRP TMP_COLOR.rgb, TMP_FOG.x, TMP_COLOR, state.fog.color;\n");
|
||||
shader_addline(&buffer, "MOV result.color.a, TMP_COLOR.a;\n");
|
||||
}
|
||||
/* Perform sRGB write correction. See GLX_EXT_framebuffer_sRGB */
|
||||
|
||||
/* Calculate the > 0.0031308 case */
|
||||
shader_addline(&buffer, "POW TMP.x, TMP_COLOR.x, srgb_pow.x;\n");
|
||||
shader_addline(&buffer, "POW TMP.y, TMP_COLOR.y, srgb_pow.y;\n");
|
||||
shader_addline(&buffer, "POW TMP.z, TMP_COLOR.z, srgb_pow.z;\n");
|
||||
shader_addline(&buffer, "MUL TMP, TMP, srgb_mul_hi;\n");
|
||||
shader_addline(&buffer, "SUB TMP, TMP, srgb_sub_hi;\n");
|
||||
/* Calculate the < case */
|
||||
shader_addline(&buffer, "MUL TMP2, srgb_mul_low, TMP_COLOR;\n");
|
||||
/* Get 1.0 / 0.0 masks for > 0.0031308 and < 0.0031308 */
|
||||
shader_addline(&buffer, "SLT TA, srgb_comparison, TMP_COLOR;\n");
|
||||
shader_addline(&buffer, "SGE TB, srgb_comparison, TMP_COLOR;\n");
|
||||
/* Store the components > 0.0031308 in the destination */
|
||||
shader_addline(&buffer, "MUL TMP_COLOR, TMP, TA;\n");
|
||||
/* Add the components that are < 0.0031308 */
|
||||
shader_addline(&buffer, "MAD result.color.xyz, TMP2, TB, TMP_COLOR;\n");
|
||||
/* [0.0;1.0] clamping. Not needed, this is done implicitly */
|
||||
} else {
|
||||
shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, TMP_COLOR, state.fog.color;\n");
|
||||
shader_addline(&buffer, "MOV result.color.a, TMP_COLOR.a;\n");
|
||||
if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) {
|
||||
shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, R0, state.fog.color;\n");
|
||||
shader_addline(&buffer, "MOV result.color.a, R0.a;\n");
|
||||
} else {
|
||||
shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, TMP_COLOR, state.fog.color;\n");
|
||||
shader_addline(&buffer, "MOV result.color.a, TMP_COLOR.a;\n");
|
||||
}
|
||||
}
|
||||
|
||||
shader_addline(&buffer, "END\n");
|
||||
|
@ -536,6 +582,7 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader
|
|||
* changed.
|
||||
*/
|
||||
if (This->baseShader.is_compiled) {
|
||||
char srgbenabled = deviceImpl->stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE] ? 1 : 0;
|
||||
for(i = 0; i < This->baseShader.num_sampled_samplers; i++) {
|
||||
sampler = This->baseShader.sampled_samplers[i];
|
||||
texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler];
|
||||
|
@ -551,6 +598,11 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader
|
|||
/* TODO: Check projected textures */
|
||||
/* TODO: Check texture types(2D, Cube, 3D) */
|
||||
|
||||
if(srgbenabled != This->srgb_enabled && This->srgb_mode_hardcoded) {
|
||||
WARN("Recompiling shader because srgb correction is different and hardcoded\n");
|
||||
goto recompile;
|
||||
}
|
||||
|
||||
return WINED3D_OK;
|
||||
|
||||
recompile:
|
||||
|
|
|
@ -1559,12 +1559,6 @@ static void state_tessellation(DWORD state, IWineD3DStateBlockImpl *stateblock,
|
|||
FIXME("(WINED3DRS_ENABLEADAPTIVETESSELLATION,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION]);
|
||||
}
|
||||
|
||||
|
||||
static void state_srgbwrite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
|
||||
if(stateblock->renderState[WINED3DRS_SRGBWRITEENABLE])
|
||||
FIXME("Render state WINED3DRS_SRGBWRITEENABLE not yet implemented\n");
|
||||
}
|
||||
|
||||
static void state_separateblend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
|
||||
TRACE("Stub\n");
|
||||
if(stateblock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE])
|
||||
|
@ -3827,7 +3821,7 @@ const struct StateEntry StateTable[] =
|
|||
{ /*191, WINED3DRS_COLORWRITEENABLE2 */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite },
|
||||
{ /*192, WINED3DRS_COLORWRITEENABLE3 */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite },
|
||||
{ /*193, WINED3DRS_BLENDFACTOR */ STATE_RENDER(WINED3DRS_BLENDFACTOR), state_blendfactor },
|
||||
{ /*194, WINED3DRS_SRGBWRITEENABLE */ STATE_RENDER(WINED3DRS_SRGBWRITEENABLE), state_srgbwrite },
|
||||
{ /*194, WINED3DRS_SRGBWRITEENABLE */ STATE_PIXELSHADER, pixelshader },
|
||||
{ /*195, WINED3DRS_DEPTHBIAS */ STATE_RENDER(WINED3DRS_DEPTHBIAS), state_depthbias },
|
||||
{ /*196, undefined */ 0, state_undefined },
|
||||
{ /*197, undefined */ 0, state_undefined },
|
||||
|
|
|
@ -2081,6 +2081,10 @@ typedef struct IWineD3DPixelShaderImpl {
|
|||
/* Some information about the shader behavior */
|
||||
char needsbumpmat;
|
||||
UINT bumpenvmatconst;
|
||||
char srgb_enabled;
|
||||
char srgb_mode_hardcoded;
|
||||
UINT srgb_low_const;
|
||||
UINT srgb_cmp_const;
|
||||
|
||||
#if 0 /* needs reworking */
|
||||
PSHADERINPUTDATA input;
|
||||
|
@ -2091,6 +2095,13 @@ typedef struct IWineD3DPixelShaderImpl {
|
|||
extern const SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[];
|
||||
extern const IWineD3DPixelShaderVtbl IWineD3DPixelShader_Vtbl;
|
||||
|
||||
/* sRGB correction constants */
|
||||
static const float srgb_cmp = 0.0031308;
|
||||
static const float srgb_mul_low = 12.92;
|
||||
static const float srgb_pow = 0.41666;
|
||||
static const float srgb_mul_high = 1.055;
|
||||
static const float srgb_sub_high = 0.055;
|
||||
|
||||
/*****************************************************************************
|
||||
* IWineD3DPalette implementation structure
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue