Commit a66fb40d authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

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.
parent 84258723
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment