wined3d: Move shader generation into the shader backend.
Generating the shader ID and parts of the shader prolog and epilog was done by the common vertexshader.c / pixelshader.c, which is ugly. This patch doesn't get rid of all the uglyness, somewhen we'll still have to sort out the relationship of [arb|glsl]_generate_shader and [arb|glsl]_generate_declarations.
This commit is contained in:
parent
84258723f9
commit
a66fb40d83
|
@ -1873,6 +1873,175 @@ static BOOL shader_arb_dirty_const(IWineD3DDevice *iface) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void shader_arb_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer) {
|
||||
IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface;
|
||||
shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
|
||||
CONST DWORD *function = This->baseShader.function;
|
||||
const char *fragcolor;
|
||||
WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info;
|
||||
|
||||
/* Create the hw ARB shader */
|
||||
shader_addline(buffer, "!!ARBfp1.0\n");
|
||||
|
||||
shader_addline(buffer, "TEMP TMP;\n"); /* Used in matrix ops */
|
||||
shader_addline(buffer, "TEMP TMP2;\n"); /* Used in matrix ops */
|
||||
shader_addline(buffer, "TEMP TA;\n"); /* Used for modifiers */
|
||||
shader_addline(buffer, "TEMP TB;\n"); /* Used for modifiers */
|
||||
shader_addline(buffer, "TEMP TC;\n"); /* Used for modifiers */
|
||||
shader_addline(buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
|
||||
shader_addline(buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n");
|
||||
shader_addline(buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* We need two variables for fog blending */
|
||||
shader_addline(buffer, "TEMP TMP_FOG;\n");
|
||||
if (This->baseShader.hex_version >= WINED3DPS_VERSION(2,0)) {
|
||||
shader_addline(buffer, "TEMP TMP_COLOR;\n");
|
||||
}
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, buffer, reg_maps, function);
|
||||
|
||||
/* calculate fog and blend it
|
||||
* NOTE: state.fog.params.y and state.fog.params.z don't hold fog start s and end e but
|
||||
* -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)) {
|
||||
fragcolor = "R0";
|
||||
} else {
|
||||
fragcolor = "TMP_COLOR";
|
||||
}
|
||||
if(This->srgb_enabled) {
|
||||
/* Perform sRGB write correction. See GLX_EXT_framebuffer_sRGB */
|
||||
|
||||
/* Calculate the > 0.0031308 case */
|
||||
shader_addline(buffer, "POW TMP.x, %s.x, srgb_pow.x;\n", fragcolor);
|
||||
shader_addline(buffer, "POW TMP.y, %s.y, srgb_pow.y;\n", fragcolor);
|
||||
shader_addline(buffer, "POW TMP.z, %s.z, srgb_pow.z;\n", fragcolor);
|
||||
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, %s;\n", fragcolor);
|
||||
/* Get 1.0 / 0.0 masks for > 0.0031308 and < 0.0031308 */
|
||||
shader_addline(buffer, "SLT TA, srgb_comparison, %s;\n", fragcolor);
|
||||
shader_addline(buffer, "SGE TB, srgb_comparison, %s;\n", fragcolor);
|
||||
/* Store the components > 0.0031308 in the destination */
|
||||
shader_addline(buffer, "MUL %s, TMP, TA;\n", fragcolor);
|
||||
/* Add the components that are < 0.0031308 */
|
||||
shader_addline(buffer, "MAD result.color.xyz, TMP2, TB, %s;\n", fragcolor);
|
||||
/* [0.0;1.0] clamping. Not needed, this is done implicitly */
|
||||
}
|
||||
if (This->baseShader.hex_version < WINED3DPS_VERSION(3,0)) {
|
||||
shader_addline(buffer, "LRP result.color.rgb, TMP_FOG.x, %s, state.fog.color;\n", fragcolor);
|
||||
shader_addline(buffer, "MOV result.color.a, %s.a;\n", fragcolor);
|
||||
}
|
||||
|
||||
shader_addline(buffer, "END\n");
|
||||
|
||||
/* TODO: change to resource.glObjectHandle or something like that */
|
||||
GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
|
||||
|
||||
TRACE("Creating a hw pixel shader, prg=%d\n", This->baseShader.prgId);
|
||||
GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, This->baseShader.prgId));
|
||||
|
||||
TRACE("Created hw pixel shader, prg=%d\n", This->baseShader.prgId);
|
||||
/* Create the program and check for errors */
|
||||
GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
|
||||
buffer->bsize, buffer->buffer));
|
||||
|
||||
if (glGetError() == GL_INVALID_OPERATION) {
|
||||
GLint errPos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
|
||||
FIXME("HW PixelShader Error at position %d: %s\n",
|
||||
errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
|
||||
This->baseShader.prgId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) {
|
||||
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
|
||||
shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
|
||||
CONST DWORD *function = This->baseShader.function;
|
||||
WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info;
|
||||
|
||||
/* Create the hw ARB shader */
|
||||
shader_addline(buffer, "!!ARBvp1.0\n");
|
||||
shader_addline(buffer, "PARAM helper_const = { 2.0, -1.0, %d.0, 0.0 };\n", This->rel_offset);
|
||||
|
||||
/* Mesa supports only 95 constants */
|
||||
if (GL_VEND(MESA) || GL_VEND(WINE))
|
||||
This->baseShader.limits.constant_float =
|
||||
min(95, This->baseShader.limits.constant_float);
|
||||
|
||||
shader_addline(buffer, "TEMP TMP;\n");
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* We need a constant to fixup the final position */
|
||||
shader_addline(buffer, "PARAM posFixup = program.env[%d];\n", ARB_SHADER_PRIVCONST_POS);
|
||||
|
||||
if((GLINFO_LOCATION).set_texcoord_w) {
|
||||
int i;
|
||||
for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
|
||||
if(This->baseShader.reg_maps.texcoord_mask[i] != 0 &&
|
||||
This->baseShader.reg_maps.texcoord_mask[i] != WINED3DSP_WRITEMASK_ALL) {
|
||||
shader_addline(buffer, "MOV result.texcoord[%u].w, -helper_const.y;\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, buffer, reg_maps, function);
|
||||
|
||||
/* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
|
||||
if (!reg_maps->fog)
|
||||
shader_addline(buffer, "MOV result.fogcoord, TMP_OUT.z;\n");
|
||||
|
||||
/* Write the final position.
|
||||
*
|
||||
* OpenGL coordinates specify the center of the pixel while d3d coords specify
|
||||
* the corner. The offsets are stored in z and w in posFixup. posFixup.y contains
|
||||
* 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x
|
||||
* contains 1.0 to allow a mad, but arb vs swizzles are too restricted for that.
|
||||
*/
|
||||
shader_addline(buffer, "MUL TMP, posFixup, TMP_OUT.w;\n");
|
||||
shader_addline(buffer, "ADD TMP_OUT.x, TMP_OUT.x, TMP.z;\n");
|
||||
shader_addline(buffer, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, TMP.w;\n");
|
||||
|
||||
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
|
||||
* and the glsl equivalent
|
||||
*/
|
||||
shader_addline(buffer, "MAD TMP_OUT.z, TMP_OUT.z, helper_const.x, -TMP_OUT.w;\n");
|
||||
|
||||
shader_addline(buffer, "MOV result.position, TMP_OUT;\n");
|
||||
|
||||
shader_addline(buffer, "END\n");
|
||||
|
||||
/* TODO: change to resource.glObjectHandle or something like that */
|
||||
GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
|
||||
|
||||
TRACE("Creating a hw vertex shader, prg=%d\n", This->baseShader.prgId);
|
||||
GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->baseShader.prgId));
|
||||
|
||||
TRACE("Created hw vertex shader, prg=%d\n", This->baseShader.prgId);
|
||||
/* Create the program and check for errors */
|
||||
GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
|
||||
buffer->bsize, buffer->buffer));
|
||||
|
||||
if (glGetError() == GL_INVALID_OPERATION) {
|
||||
GLint errPos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
|
||||
FIXME("HW VertexShader Error at position %d: %s\n",
|
||||
errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
|
||||
This->baseShader.prgId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
const shader_backend_t arb_program_shader_backend = {
|
||||
&shader_arb_select,
|
||||
&shader_arb_select_depth_blt,
|
||||
|
@ -1884,5 +2053,7 @@ const shader_backend_t arb_program_shader_backend = {
|
|||
&shader_arb_alloc,
|
||||
&shader_arb_free,
|
||||
&shader_arb_dirty_const,
|
||||
&shader_arb_generate_pshader,
|
||||
&shader_arb_generate_vshader,
|
||||
FFPStateTable
|
||||
};
|
||||
|
|
|
@ -1098,6 +1098,12 @@ static void shader_none_destroy(IWineD3DBaseShader *iface) {}
|
|||
static HRESULT shader_none_alloc(IWineD3DDevice *iface) {return WINED3D_OK;}
|
||||
static void shader_none_free(IWineD3DDevice *iface) {}
|
||||
static BOOL shader_none_dirty_const(IWineD3DDevice *iface) {return FALSE;}
|
||||
static void shader_none_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer) {
|
||||
FIXME("NONE shader backend asked to generate a pixel shader\n");
|
||||
}
|
||||
static void shader_none_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) {
|
||||
FIXME("NONE shader backend asked to generate a vertex shader\n");
|
||||
}
|
||||
|
||||
const shader_backend_t none_shader_backend = {
|
||||
&shader_none_select,
|
||||
|
@ -1110,6 +1116,8 @@ const shader_backend_t none_shader_backend = {
|
|||
&shader_none_alloc,
|
||||
&shader_none_free,
|
||||
&shader_none_dirty_const,
|
||||
&shader_none_generate_pshader,
|
||||
&shader_none_generate_vshader,
|
||||
FFPStateTable
|
||||
};
|
||||
|
||||
|
|
|
@ -3362,6 +3362,147 @@ static BOOL shader_glsl_dirty_const(IWineD3DDevice *iface) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static void shader_glsl_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer) {
|
||||
IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface;
|
||||
shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
|
||||
CONST DWORD *function = This->baseShader.function;
|
||||
const char *fragcolor;
|
||||
WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info;
|
||||
|
||||
/* Create the hw GLSL shader object and assign it as the baseShader.prgId */
|
||||
GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB));
|
||||
|
||||
if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
|
||||
shader_addline(buffer, "#extension GL_ARB_draw_buffers : enable\n");
|
||||
}
|
||||
if (GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
|
||||
/* The spec says that it doesn't have to be explicitly enabled, but the nvidia
|
||||
* drivers write a warning if we don't do so
|
||||
*/
|
||||
shader_addline(buffer, "#extension GL_ARB_texture_rectangle : enable\n");
|
||||
}
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* Pack 3.0 inputs */
|
||||
if (This->baseShader.hex_version >= WINED3DPS_VERSION(3,0)) {
|
||||
|
||||
if(((IWineD3DDeviceImpl *) This->baseShader.device)->strided_streams.u.s.position_transformed) {
|
||||
This->vertexprocessing = pretransformed;
|
||||
pshader_glsl_input_pack(buffer, This->semantics_in, iface);
|
||||
} else if(!use_vs((IWineD3DDeviceImpl *) This->baseShader.device)) {
|
||||
This->vertexprocessing = fixedfunction;
|
||||
pshader_glsl_input_pack(buffer, This->semantics_in, iface);
|
||||
} else {
|
||||
This->vertexprocessing = vertexshader;
|
||||
}
|
||||
}
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, buffer, reg_maps, function);
|
||||
|
||||
/* Pixel shaders < 2.0 place the resulting color in R0 implicitly */
|
||||
if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) {
|
||||
/* Some older cards like GeforceFX ones don't support multiple buffers, so also not gl_FragData */
|
||||
if(GL_SUPPORT(ARB_DRAW_BUFFERS))
|
||||
shader_addline(buffer, "gl_FragData[0] = R0;\n");
|
||||
else
|
||||
shader_addline(buffer, "gl_FragColor = R0;\n");
|
||||
}
|
||||
|
||||
if(GL_SUPPORT(ARB_DRAW_BUFFERS)) {
|
||||
fragcolor = "gl_FragData[0]";
|
||||
} else {
|
||||
fragcolor = "gl_FragColor";
|
||||
}
|
||||
if(This->srgb_enabled) {
|
||||
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);
|
||||
}
|
||||
/* Pixel shader < 3.0 do not replace the fog stage.
|
||||
* This implements linear fog computation and blending.
|
||||
* TODO: non linear fog
|
||||
* NOTE: gl_Fog.start and gl_Fog.end don't hold fog start s and end e but
|
||||
* -1/(e-s) and e/(e-s) respectively.
|
||||
*/
|
||||
if(This->baseShader.hex_version < WINED3DPS_VERSION(3,0)) {
|
||||
shader_addline(buffer, "float Fog = clamp(gl_FogFragCoord * gl_Fog.start + gl_Fog.end, 0.0, 1.0);\n");
|
||||
shader_addline(buffer, "%s.xyz = mix(gl_Fog.color.xyz, %s.xyz, Fog);\n", fragcolor, fragcolor);
|
||||
}
|
||||
|
||||
shader_addline(buffer, "}\n");
|
||||
|
||||
TRACE("Compiling shader object %u\n", shader_obj);
|
||||
GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer->buffer, NULL));
|
||||
GL_EXTCALL(glCompileShaderARB(shader_obj));
|
||||
print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
|
||||
|
||||
/* Store the shader object */
|
||||
This->baseShader.prgId = shader_obj;
|
||||
}
|
||||
|
||||
static void shader_glsl_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) {
|
||||
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
|
||||
shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
|
||||
CONST DWORD *function = This->baseShader.function;
|
||||
WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info;
|
||||
|
||||
/* Create the hw GLSL shader program and assign it as the baseShader.prgId */
|
||||
GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, buffer, reg_maps, function);
|
||||
|
||||
/* Unpack 3.0 outputs */
|
||||
if (This->baseShader.hex_version >= WINED3DVS_VERSION(3,0)) {
|
||||
shader_addline(buffer, "order_ps_input(OUT);\n");
|
||||
} else {
|
||||
shader_addline(buffer, "order_ps_input();\n");
|
||||
}
|
||||
|
||||
/* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
|
||||
if (!reg_maps->fog)
|
||||
shader_addline(buffer, "gl_FogFragCoord = gl_Position.z;\n");
|
||||
|
||||
/* Write the final position.
|
||||
*
|
||||
* OpenGL coordinates specify the center of the pixel while d3d coords specify
|
||||
* the corner. The offsets are stored in z and w in posFixup. posFixup.y contains
|
||||
* 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x
|
||||
* contains 1.0 to allow a mad.
|
||||
*/
|
||||
shader_addline(buffer, "gl_Position.y = gl_Position.y * posFixup.y;\n");
|
||||
shader_addline(buffer, "gl_Position.xy += posFixup.zw * gl_Position.ww;\n");
|
||||
|
||||
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
|
||||
*
|
||||
* Basically we want (in homogeneous coordinates) z = z * 2 - 1. However, shaders are run
|
||||
* before the homogeneous divide, so we have to take the w into account: z = ((z / w) * 2 - 1) * w,
|
||||
* which is the same as z = z / 2 - w.
|
||||
*/
|
||||
shader_addline(buffer, "gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n");
|
||||
|
||||
shader_addline(buffer, "}\n");
|
||||
|
||||
TRACE("Compiling shader object %u\n", shader_obj);
|
||||
GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer->buffer, NULL));
|
||||
GL_EXTCALL(glCompileShaderARB(shader_obj));
|
||||
print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
|
||||
|
||||
/* Store the shader object */
|
||||
This->baseShader.prgId = shader_obj;
|
||||
}
|
||||
|
||||
const shader_backend_t glsl_shader_backend = {
|
||||
&shader_glsl_select,
|
||||
&shader_glsl_select_depth_blt,
|
||||
|
@ -3373,5 +3514,7 @@ const shader_backend_t glsl_shader_backend = {
|
|||
&shader_glsl_alloc,
|
||||
&shader_glsl_free,
|
||||
&shader_glsl_dirty_const,
|
||||
&shader_glsl_generate_pshader,
|
||||
&shader_glsl_generate_vshader,
|
||||
FFPStateTable
|
||||
};
|
||||
|
|
|
@ -280,13 +280,9 @@ static void pshader_set_limits(
|
|||
/** Generate a pixel shader string using either GL_FRAGMENT_PROGRAM_ARB
|
||||
or GLSL and send it to the card */
|
||||
static inline VOID IWineD3DPixelShaderImpl_GenerateShader(
|
||||
IWineD3DPixelShader *iface,
|
||||
shader_reg_maps* reg_maps,
|
||||
CONST DWORD *pFunction) {
|
||||
|
||||
IWineD3DPixelShader *iface) {
|
||||
IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface;
|
||||
SHADER_BUFFER buffer;
|
||||
const char *fragcolor;
|
||||
|
||||
#if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders
|
||||
it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */
|
||||
|
@ -304,168 +300,7 @@ static inline VOID IWineD3DPixelShaderImpl_GenerateShader(
|
|||
buffer.lineNo = 0;
|
||||
buffer.newline = TRUE;
|
||||
|
||||
if (This->baseShader.shader_mode == SHADER_GLSL) {
|
||||
|
||||
/* Create the hw GLSL shader object and assign it as the baseShader.prgId */
|
||||
GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB));
|
||||
|
||||
if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
|
||||
shader_addline(&buffer, "#extension GL_ARB_draw_buffers : enable\n");
|
||||
}
|
||||
if (GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
|
||||
/* The spec says that it doesn't have to be explicitly enabled, but the nvidia
|
||||
* drivers write a warning if we don't do so
|
||||
*/
|
||||
shader_addline(&buffer, "#extension GL_ARB_texture_rectangle : enable\n");
|
||||
}
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* Pack 3.0 inputs */
|
||||
if (This->baseShader.hex_version >= WINED3DPS_VERSION(3,0)) {
|
||||
|
||||
if(((IWineD3DDeviceImpl *) This->baseShader.device)->strided_streams.u.s.position_transformed) {
|
||||
This->vertexprocessing = pretransformed;
|
||||
pshader_glsl_input_pack(&buffer, This->semantics_in, iface);
|
||||
} else if(!use_vs((IWineD3DDeviceImpl *) This->baseShader.device)) {
|
||||
This->vertexprocessing = fixedfunction;
|
||||
pshader_glsl_input_pack(&buffer, This->semantics_in, iface);
|
||||
} else {
|
||||
This->vertexprocessing = vertexshader;
|
||||
}
|
||||
}
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction);
|
||||
|
||||
/* Pixel shaders < 2.0 place the resulting color in R0 implicitly */
|
||||
if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) {
|
||||
/* Some older cards like GeforceFX ones don't support multiple buffers, so also not gl_FragData */
|
||||
if(GL_SUPPORT(ARB_DRAW_BUFFERS))
|
||||
shader_addline(&buffer, "gl_FragData[0] = R0;\n");
|
||||
else
|
||||
shader_addline(&buffer, "gl_FragColor = R0;\n");
|
||||
}
|
||||
|
||||
if(GL_SUPPORT(ARB_DRAW_BUFFERS)) {
|
||||
fragcolor = "gl_FragData[0]";
|
||||
} else {
|
||||
fragcolor = "gl_FragColor";
|
||||
}
|
||||
if(This->srgb_enabled) {
|
||||
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);
|
||||
}
|
||||
/* Pixel shader < 3.0 do not replace the fog stage.
|
||||
* This implements linear fog computation and blending.
|
||||
* TODO: non linear fog
|
||||
* NOTE: gl_Fog.start and gl_Fog.end don't hold fog start s and end e but
|
||||
* -1/(e-s) and e/(e-s) respectively.
|
||||
*/
|
||||
if(This->baseShader.hex_version < WINED3DPS_VERSION(3,0)) {
|
||||
shader_addline(&buffer, "float Fog = clamp(gl_FogFragCoord * gl_Fog.start + gl_Fog.end, 0.0, 1.0);\n");
|
||||
shader_addline(&buffer, "%s.xyz = mix(gl_Fog.color.xyz, %s.xyz, Fog);\n", fragcolor, fragcolor);
|
||||
}
|
||||
|
||||
shader_addline(&buffer, "}\n");
|
||||
|
||||
TRACE("Compiling shader object %u\n", shader_obj);
|
||||
GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer.buffer, NULL));
|
||||
GL_EXTCALL(glCompileShaderARB(shader_obj));
|
||||
print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
|
||||
|
||||
/* Store the shader object */
|
||||
This->baseShader.prgId = shader_obj;
|
||||
|
||||
} else if (This->baseShader.shader_mode == SHADER_ARB) {
|
||||
/* Create the hw ARB shader */
|
||||
shader_addline(&buffer, "!!ARBfp1.0\n");
|
||||
|
||||
shader_addline(&buffer, "TEMP TMP;\n"); /* Used in matrix ops */
|
||||
shader_addline(&buffer, "TEMP TMP2;\n"); /* Used in matrix ops */
|
||||
shader_addline(&buffer, "TEMP TA;\n"); /* Used for modifiers */
|
||||
shader_addline(&buffer, "TEMP TB;\n"); /* Used for modifiers */
|
||||
shader_addline(&buffer, "TEMP TC;\n"); /* Used for modifiers */
|
||||
shader_addline(&buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
|
||||
shader_addline(&buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n");
|
||||
shader_addline(&buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* We need two variables for fog blending */
|
||||
shader_addline(&buffer, "TEMP TMP_FOG;\n");
|
||||
if (This->baseShader.hex_version >= WINED3DPS_VERSION(2,0)) {
|
||||
shader_addline(&buffer, "TEMP TMP_COLOR;\n");
|
||||
}
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction);
|
||||
|
||||
/* calculate fog and blend it
|
||||
* NOTE: state.fog.params.y and state.fog.params.z don't hold fog start s and end e but
|
||||
* -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)) {
|
||||
fragcolor = "R0";
|
||||
} else {
|
||||
fragcolor = "TMP_COLOR";
|
||||
}
|
||||
if(This->srgb_enabled) {
|
||||
/* Perform sRGB write correction. See GLX_EXT_framebuffer_sRGB */
|
||||
|
||||
/* Calculate the > 0.0031308 case */
|
||||
shader_addline(&buffer, "POW TMP.x, %s.x, srgb_pow.x;\n", fragcolor);
|
||||
shader_addline(&buffer, "POW TMP.y, %s.y, srgb_pow.y;\n", fragcolor);
|
||||
shader_addline(&buffer, "POW TMP.z, %s.z, srgb_pow.z;\n", fragcolor);
|
||||
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, %s;\n", fragcolor);
|
||||
/* Get 1.0 / 0.0 masks for > 0.0031308 and < 0.0031308 */
|
||||
shader_addline(&buffer, "SLT TA, srgb_comparison, %s;\n", fragcolor);
|
||||
shader_addline(&buffer, "SGE TB, srgb_comparison, %s;\n", fragcolor);
|
||||
/* Store the components > 0.0031308 in the destination */
|
||||
shader_addline(&buffer, "MUL %s, TMP, TA;\n", fragcolor);
|
||||
/* Add the components that are < 0.0031308 */
|
||||
shader_addline(&buffer, "MAD result.color.xyz, TMP2, TB, %s;\n", fragcolor);
|
||||
/* [0.0;1.0] clamping. Not needed, this is done implicitly */
|
||||
}
|
||||
if (This->baseShader.hex_version < WINED3DPS_VERSION(3,0)) {
|
||||
shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, %s, state.fog.color;\n", fragcolor);
|
||||
shader_addline(&buffer, "MOV result.color.a, %s.a;\n", fragcolor);
|
||||
}
|
||||
|
||||
shader_addline(&buffer, "END\n");
|
||||
|
||||
/* TODO: change to resource.glObjectHandle or something like that */
|
||||
GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
|
||||
|
||||
TRACE("Creating a hw pixel shader, prg=%d\n", This->baseShader.prgId);
|
||||
GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, This->baseShader.prgId));
|
||||
|
||||
TRACE("Created hw pixel shader, prg=%d\n", This->baseShader.prgId);
|
||||
/* Create the program and check for errors */
|
||||
GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
|
||||
buffer.bsize, buffer.buffer));
|
||||
|
||||
if (glGetError() == GL_INVALID_OPERATION) {
|
||||
GLint errPos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
|
||||
FIXME("HW PixelShader Error at position %d: %s\n",
|
||||
errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
|
||||
This->baseShader.prgId = -1;
|
||||
}
|
||||
}
|
||||
((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_generate_pshader(iface, &buffer);
|
||||
|
||||
#if 1 /* if were using the data buffer of device then we don't need to free it */
|
||||
HeapFree(GetProcessHeap(), 0, buffer.buffer);
|
||||
|
@ -652,7 +487,7 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader
|
|||
|
||||
/* Generate the HW shader */
|
||||
TRACE("(%p) : Generating hardware program\n", This);
|
||||
IWineD3DPixelShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);
|
||||
IWineD3DPixelShaderImpl_GenerateShader(iface);
|
||||
|
||||
This->baseShader.is_compiled = TRUE;
|
||||
|
||||
|
|
|
@ -360,131 +360,7 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
|
|||
buffer.lineNo = 0;
|
||||
buffer.newline = TRUE;
|
||||
|
||||
if (This->baseShader.shader_mode == SHADER_GLSL) {
|
||||
|
||||
/* Create the hw GLSL shader program and assign it as the baseShader.prgId */
|
||||
GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction);
|
||||
|
||||
/* Unpack 3.0 outputs */
|
||||
if (This->baseShader.hex_version >= WINED3DVS_VERSION(3,0)) {
|
||||
shader_addline(&buffer, "order_ps_input(OUT);\n");
|
||||
} else {
|
||||
shader_addline(&buffer, "order_ps_input();\n");
|
||||
}
|
||||
|
||||
/* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
|
||||
if (!reg_maps->fog)
|
||||
shader_addline(&buffer, "gl_FogFragCoord = gl_Position.z;\n");
|
||||
|
||||
/* Write the final position.
|
||||
*
|
||||
* OpenGL coordinates specify the center of the pixel while d3d coords specify
|
||||
* the corner. The offsets are stored in z and w in posFixup. posFixup.y contains
|
||||
* 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x
|
||||
* contains 1.0 to allow a mad.
|
||||
*/
|
||||
shader_addline(&buffer, "gl_Position.y = gl_Position.y * posFixup.y;\n");
|
||||
shader_addline(&buffer, "gl_Position.xy += posFixup.zw * gl_Position.ww;\n");
|
||||
|
||||
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
|
||||
*
|
||||
* Basically we want (in homogeneous coordinates) z = z * 2 - 1. However, shaders are run
|
||||
* before the homogeneous divide, so we have to take the w into account: z = ((z / w) * 2 - 1) * w,
|
||||
* which is the same as z = z / 2 - w.
|
||||
*/
|
||||
shader_addline(&buffer, "gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n");
|
||||
|
||||
shader_addline(&buffer, "}\n");
|
||||
|
||||
TRACE("Compiling shader object %u\n", shader_obj);
|
||||
GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer.buffer, NULL));
|
||||
GL_EXTCALL(glCompileShaderARB(shader_obj));
|
||||
print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
|
||||
|
||||
/* Store the shader object */
|
||||
This->baseShader.prgId = shader_obj;
|
||||
|
||||
} else if (This->baseShader.shader_mode == SHADER_ARB) {
|
||||
|
||||
/* Create the hw ARB shader */
|
||||
shader_addline(&buffer, "!!ARBvp1.0\n");
|
||||
shader_addline(&buffer, "PARAM helper_const = { 2.0, -1.0, %d.0, 0.0 };\n", This->rel_offset);
|
||||
|
||||
/* Mesa supports only 95 constants */
|
||||
if (GL_VEND(MESA) || GL_VEND(WINE))
|
||||
This->baseShader.limits.constant_float =
|
||||
min(95, This->baseShader.limits.constant_float);
|
||||
|
||||
shader_addline(&buffer, "TEMP TMP;\n");
|
||||
|
||||
/* Base Declarations */
|
||||
shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION);
|
||||
|
||||
/* We need a constant to fixup the final position */
|
||||
shader_addline(&buffer, "PARAM posFixup = program.env[%d];\n", ARB_SHADER_PRIVCONST_POS);
|
||||
|
||||
if((GLINFO_LOCATION).set_texcoord_w) {
|
||||
int i;
|
||||
for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
|
||||
if(This->baseShader.reg_maps.texcoord_mask[i] != 0 &&
|
||||
This->baseShader.reg_maps.texcoord_mask[i] != WINED3DSP_WRITEMASK_ALL) {
|
||||
shader_addline(&buffer, "MOV result.texcoord[%u].w, -helper_const.y;\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Base Shader Body */
|
||||
shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction);
|
||||
|
||||
/* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
|
||||
if (!reg_maps->fog)
|
||||
shader_addline(&buffer, "MOV result.fogcoord, TMP_OUT.z;\n");
|
||||
|
||||
/* Write the final position.
|
||||
*
|
||||
* OpenGL coordinates specify the center of the pixel while d3d coords specify
|
||||
* the corner. The offsets are stored in z and w in posFixup. posFixup.y contains
|
||||
* 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x
|
||||
* contains 1.0 to allow a mad, but arb vs swizzles are too restricted for that.
|
||||
*/
|
||||
shader_addline(&buffer, "MUL TMP, posFixup, TMP_OUT.w;\n");
|
||||
shader_addline(&buffer, "ADD TMP_OUT.x, TMP_OUT.x, TMP.z;\n");
|
||||
shader_addline(&buffer, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, TMP.w;\n");
|
||||
|
||||
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
|
||||
* and the glsl equivalent
|
||||
*/
|
||||
shader_addline(&buffer, "MAD TMP_OUT.z, TMP_OUT.z, helper_const.x, -TMP_OUT.w;\n");
|
||||
|
||||
shader_addline(&buffer, "MOV result.position, TMP_OUT;\n");
|
||||
|
||||
shader_addline(&buffer, "END\n");
|
||||
|
||||
/* TODO: change to resource.glObjectHandle or something like that */
|
||||
GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
|
||||
|
||||
TRACE("Creating a hw vertex shader, prg=%d\n", This->baseShader.prgId);
|
||||
GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->baseShader.prgId));
|
||||
|
||||
TRACE("Created hw vertex shader, prg=%d\n", This->baseShader.prgId);
|
||||
/* Create the program and check for errors */
|
||||
GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
|
||||
buffer.bsize, buffer.buffer));
|
||||
|
||||
if (glGetError() == GL_INVALID_OPERATION) {
|
||||
GLint errPos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
|
||||
FIXME("HW VertexShader Error at position %d: %s\n",
|
||||
errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
|
||||
This->baseShader.prgId = -1;
|
||||
}
|
||||
}
|
||||
((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_generate_vshader(iface, &buffer);
|
||||
|
||||
#if 1 /* if were using the data buffer of device then we don't need to free it */
|
||||
HeapFree(GetProcessHeap(), 0, buffer.buffer);
|
||||
|
|
|
@ -249,6 +249,14 @@ extern wined3d_settings_t wined3d_settings;
|
|||
/* Shader backends */
|
||||
struct SHADER_OPCODE_ARG;
|
||||
|
||||
#define SHADER_PGMSIZE 65535
|
||||
typedef struct SHADER_BUFFER {
|
||||
char* buffer;
|
||||
unsigned int bsize;
|
||||
unsigned int lineNo;
|
||||
BOOL newline;
|
||||
} SHADER_BUFFER;
|
||||
|
||||
typedef struct {
|
||||
void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL useVS);
|
||||
void (*shader_select_depth_blt)(IWineD3DDevice *iface);
|
||||
|
@ -260,6 +268,8 @@ typedef struct {
|
|||
HRESULT (*shader_alloc_private)(IWineD3DDevice *iface);
|
||||
void (*shader_free_private)(IWineD3DDevice *iface);
|
||||
BOOL (*shader_dirtifyable_constants)(IWineD3DDevice *iface);
|
||||
void (*shader_generate_pshader)(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer);
|
||||
void (*shader_generate_vshader)(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer);
|
||||
const struct StateEntry *StateTable;
|
||||
} shader_backend_t;
|
||||
|
||||
|
@ -1804,14 +1814,6 @@ typedef struct shader_reg_maps {
|
|||
|
||||
} shader_reg_maps;
|
||||
|
||||
#define SHADER_PGMSIZE 65535
|
||||
typedef struct SHADER_BUFFER {
|
||||
char* buffer;
|
||||
unsigned int bsize;
|
||||
unsigned int lineNo;
|
||||
BOOL newline;
|
||||
} SHADER_BUFFER;
|
||||
|
||||
/* Undocumented opcode controls */
|
||||
#define INST_CONTROLS_SHIFT 16
|
||||
#define INST_CONTROLS_MASK 0x00ff0000
|
||||
|
|
Loading…
Reference in New Issue