📄 glsl_shader.c
字号:
}
programId = stateBlock->glsl_program->programId;
if (useVertexShader) {
IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader;
GLint pos;
constant_locations = stateBlock->glsl_program->vuniformF_locations;
constant_list = &stateBlock->set_vconstantsF;
/* Load vertex shader samplers */
shader_glsl_load_vsamplers(gl_info, (IWineD3DStateBlock*)stateBlock);
/* Load DirectX 9 float constants/uniforms for vertex shader */
shader_glsl_load_constantsF(vshader, gl_info, GL_LIMITS(vshader_constantsF),
stateBlock->vertexShaderConstantF, constant_locations, constant_list);
/* Load DirectX 9 integer constants/uniforms for vertex shader */
shader_glsl_load_constantsI(vshader, gl_info, programId, MAX_CONST_I,
stateBlock->vertexShaderConstantI,
stateBlock->changed.vertexShaderConstantsI);
/* Load DirectX 9 boolean constants/uniforms for vertex shader */
shader_glsl_load_constantsB(vshader, gl_info, programId, MAX_CONST_B,
stateBlock->vertexShaderConstantB,
stateBlock->changed.vertexShaderConstantsB);
/* Upload the position fixup params */
pos = GL_EXTCALL(glGetUniformLocationARB(programId, "posFixup"));
checkGLcall("glGetUniformLocationARB");
GL_EXTCALL(glUniform4fvARB(pos, 1, &deviceImpl->posFixup[0]));
checkGLcall("glUniform4fvARB");
}
if (usePixelShader) {
IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
constant_locations = stateBlock->glsl_program->puniformF_locations;
constant_list = &stateBlock->set_pconstantsF;
/* Load pixel shader samplers */
shader_glsl_load_psamplers(gl_info, (IWineD3DStateBlock*) stateBlock);
/* Load DirectX 9 float constants/uniforms for pixel shader */
shader_glsl_load_constantsF(pshader, gl_info, GL_LIMITS(pshader_constantsF),
stateBlock->pixelShaderConstantF, constant_locations, constant_list);
/* Load DirectX 9 integer constants/uniforms for pixel shader */
shader_glsl_load_constantsI(pshader, gl_info, programId, MAX_CONST_I,
stateBlock->pixelShaderConstantI,
stateBlock->changed.pixelShaderConstantsI);
/* Load DirectX 9 boolean constants/uniforms for pixel shader */
shader_glsl_load_constantsB(pshader, gl_info, programId, MAX_CONST_B,
stateBlock->pixelShaderConstantB,
stateBlock->changed.pixelShaderConstantsB);
/* Upload the environment bump map matrix if needed. The needsbumpmat member specifies the texture stage to load the matrix from.
* It can't be 0 for a valid texbem instruction.
*/
if(((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat != -1) {
float *data = (float *) &stateBlock->textureState[(int) ((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat][WINED3DTSS_BUMPENVMAT00];
pos = GL_EXTCALL(glGetUniformLocationARB(programId, "bumpenvmat"));
checkGLcall("glGetUniformLocationARB");
GL_EXTCALL(glUniformMatrix2fvARB(pos, 1, 0, data));
checkGLcall("glUniform4fvARB");
}
}
}
/** Generate the variable & register declarations for the GLSL output target */
void shader_generate_glsl_declarations(
IWineD3DBaseShader *iface,
shader_reg_maps* reg_maps,
SHADER_BUFFER* buffer,
WineD3D_GL_Info* gl_info) {
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
int i;
/* There are some minor differences between pixel and vertex shaders */
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
char prefix = pshader ? 'P' : 'V';
/* Prototype the subroutines */
for (i = 0; i < This->baseShader.limits.label; i++) {
if (reg_maps->labels[i])
shader_addline(buffer, "void subroutine%lu();\n", i);
}
/* Declare the constants (aka uniforms) */
if (This->baseShader.limits.constant_float > 0) {
unsigned max_constantsF = min(This->baseShader.limits.constant_float,
(pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF)));
shader_addline(buffer, "uniform vec4 %cC[%u];\n", prefix, max_constantsF);
}
if (This->baseShader.limits.constant_int > 0)
shader_addline(buffer, "uniform ivec4 %cI[%u];\n", prefix, This->baseShader.limits.constant_int);
if (This->baseShader.limits.constant_bool > 0)
shader_addline(buffer, "uniform bool %cB[%u];\n", prefix, This->baseShader.limits.constant_bool);
if(!pshader)
shader_addline(buffer, "uniform vec4 posFixup;\n");
else if(reg_maps->bumpmat != -1)
shader_addline(buffer, "uniform mat2 bumpenvmat;\n");
/* Declare texture samplers */
for (i = 0; i < This->baseShader.limits.sampler; i++) {
if (reg_maps->samplers[i]) {
DWORD stype = reg_maps->samplers[i] & WINED3DSP_TEXTURETYPE_MASK;
switch (stype) {
case WINED3DSTT_1D:
shader_addline(buffer, "uniform sampler1D %csampler%lu;\n", prefix, i);
break;
case WINED3DSTT_2D:
shader_addline(buffer, "uniform sampler2D %csampler%lu;\n", prefix, i);
break;
case WINED3DSTT_CUBE:
shader_addline(buffer, "uniform samplerCube %csampler%lu;\n", prefix, i);
break;
case WINED3DSTT_VOLUME:
shader_addline(buffer, "uniform sampler3D %csampler%lu;\n", prefix, i);
break;
default:
shader_addline(buffer, "uniform unsupported_sampler %csampler%lu;\n", prefix, i);
FIXME("Unrecognized sampler type: %#x\n", stype);
break;
}
}
}
/* Declare address variables */
for (i = 0; i < This->baseShader.limits.address; i++) {
if (reg_maps->address[i])
shader_addline(buffer, "ivec4 A%d;\n", i);
}
/* Declare texture coordinate temporaries and initialize them */
for (i = 0; i < This->baseShader.limits.texcoord; i++) {
if (reg_maps->texcoord[i])
shader_addline(buffer, "vec4 T%lu = gl_TexCoord[%lu];\n", i, i);
}
/* Declare input register temporaries */
for (i=0; i < This->baseShader.limits.packed_input; i++) {
if (reg_maps->packed_input[i])
shader_addline(buffer, "vec4 IN%lu;\n", i);
}
/* Declare output register temporaries */
for (i = 0; i < This->baseShader.limits.packed_output; i++) {
if (reg_maps->packed_output[i])
shader_addline(buffer, "vec4 OUT%lu;\n", i);
}
/* Declare temporary variables */
for(i = 0; i < This->baseShader.limits.temporary; i++) {
if (reg_maps->temporary[i])
shader_addline(buffer, "vec4 R%lu;\n", i);
}
/* Declare attributes */
for (i = 0; i < This->baseShader.limits.attributes; i++) {
if (reg_maps->attributes[i])
shader_addline(buffer, "attribute vec4 attrib%i;\n", i);
}
/* Declare loop register aL */
if (reg_maps->loop) {
shader_addline(buffer, "int aL;\n");
shader_addline(buffer, "int tmpInt;\n");
}
/* Temporary variables for matrix operations */
shader_addline(buffer, "vec4 tmp0;\n");
shader_addline(buffer, "vec4 tmp1;\n");
/* Start the main program */
shader_addline(buffer, "void main() {\n");
}
/*****************************************************************************
* Functions to generate GLSL strings from DirectX Shader bytecode begin here.
*
* For more information, see http://wiki.winehq.org/DirectX-Shaders
****************************************************************************/
/* Prototypes */
static void shader_glsl_add_src_param(SHADER_OPCODE_ARG* arg, const DWORD param,
const DWORD addr_token, DWORD mask, glsl_src_param_t *src_param);
/** Used for opcode modifiers - They multiply the result by the specified amount */
static const char * const shift_glsl_tab[] = {
"", /* 0 (none) */
"2.0 * ", /* 1 (x2) */
"4.0 * ", /* 2 (x4) */
"8.0 * ", /* 3 (x8) */
"16.0 * ", /* 4 (x16) */
"32.0 * ", /* 5 (x32) */
"", /* 6 (x64) */
"", /* 7 (x128) */
"", /* 8 (d256) */
"", /* 9 (d128) */
"", /* 10 (d64) */
"", /* 11 (d32) */
"0.0625 * ", /* 12 (d16) */
"0.125 * ", /* 13 (d8) */
"0.25 * ", /* 14 (d4) */
"0.5 * " /* 15 (d2) */
};
/* Generate a GLSL parameter that does the input modifier computation and return the input register/mask to use */
static void shader_glsl_gen_modifier (
const DWORD instr,
const char *in_reg,
const char *in_regswizzle,
char *out_str) {
out_str[0] = 0;
if (instr == WINED3DSIO_TEXKILL)
return;
switch (instr & WINED3DSP_SRCMOD_MASK) {
case WINED3DSPSM_DZ: /* Need to handle this in the instructions itself (texld & texcrd). */
case WINED3DSPSM_DW:
case WINED3DSPSM_NONE:
sprintf(out_str, "%s%s", in_reg, in_regswizzle);
break;
case WINED3DSPSM_NEG:
sprintf(out_str, "-%s%s", in_reg, in_regswizzle);
break;
case WINED3DSPSM_NOT:
sprintf(out_str, "!%s%s", in_reg, in_regswizzle);
break;
case WINED3DSPSM_BIAS:
sprintf(out_str, "(%s%s - vec4(0.5)%s)", in_reg, in_regswizzle, in_regswizzle);
break;
case WINED3DSPSM_BIASNEG:
sprintf(out_str, "-(%s%s - vec4(0.5)%s)", in_reg, in_regswizzle, in_regswizzle);
break;
case WINED3DSPSM_SIGN:
sprintf(out_str, "(2.0 * (%s%s - 0.5))", in_reg, in_regswizzle);
break;
case WINED3DSPSM_SIGNNEG:
sprintf(out_str, "-(2.0 * (%s%s - 0.5))", in_reg, in_regswizzle);
break;
case WINED3DSPSM_COMP:
sprintf(out_str, "(1.0 - %s%s)", in_reg, in_regswizzle);
break;
case WINED3DSPSM_X2:
sprintf(out_str, "(2.0 * %s%s)", in_reg, in_regswizzle);
break;
case WINED3DSPSM_X2NEG:
sprintf(out_str, "-(2.0 * %s%s)", in_reg, in_regswizzle);
break;
case WINED3DSPSM_ABS:
sprintf(out_str, "abs(%s%s)", in_reg, in_regswizzle);
break;
case WINED3DSPSM_ABSNEG:
sprintf(out_str, "-abs(%s%s)", in_reg, in_regswizzle);
break;
default:
FIXME("Unhandled modifier %u\n", (instr & WINED3DSP_SRCMOD_MASK));
sprintf(out_str, "%s%s", in_reg, in_regswizzle);
}
}
/** Writes the GLSL variable name that corresponds to the register that the
* DX opcode parameter is trying to access */
static void shader_glsl_get_register_name(
const DWORD param,
const DWORD addr_token,
char* regstr,
BOOL* is_color,
SHADER_OPCODE_ARG* arg) {
/* oPos, oFog and oPts in D3D */
static const char * const hwrastout_reg_names[] = { "gl_Position", "gl_FogFragCoord", "gl_PointSize" };
DWORD reg = param & WINED3DSP_REGNUM_MASK;
DWORD regtype = shader_get_regtype(param);
IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) arg->shader;
IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
WineD3D_GL_Info* gl_info = &deviceImpl->adapter->gl_info;
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
char tmpStr[50];
*is_color = FALSE;
switch (regtype) {
case WINED3DSPR_TEMP:
sprintf(tmpStr, "R%u", reg);
break;
case WINED3DSPR_INPUT:
if (pshader) {
/* Pixel shaders >= 3.0 */
if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3)
sprintf(tmpStr, "IN%u", reg);
else {
if (reg==0)
strcpy(tmpStr, "gl_Color");
else
strcpy(tmpStr, "gl_SecondaryColor");
}
} else {
if (vshader_input_is_color((IWineD3DVertexShader*) This, reg))
*is_color = TRUE;
sprintf(tmpStr, "attrib%u", reg);
}
break;
case WINED3DSPR_CONST:
{
const char* prefix = pshader? "PC":"VC";
/* Relative addressing */
if (param & WINED3DSHADER_ADDRMODE_RELATIVE) {
/* Relative addressing on shaders 2.0+ have a relative address token,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -