📄 glsl_shader.c
字号:
void shader_glsl_dot(SHADER_OPCODE_ARG* arg) {
CONST SHADER_OPCODE* curOpcode = arg->opcode;
SHADER_BUFFER* buffer = arg->buffer;
glsl_src_param_t src0_param;
glsl_src_param_t src1_param;
DWORD dst_write_mask, src_write_mask;
size_t dst_size = 0;
dst_write_mask = shader_glsl_append_dst(buffer, arg);
dst_size = shader_glsl_get_write_mask_size(dst_write_mask);
/* dp3 works on vec3, dp4 on vec4 */
if (curOpcode->opcode == WINED3DSIO_DP4) {
src_write_mask = WINED3DSP_WRITEMASK_ALL;
} else {
src_write_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
}
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_write_mask, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], src_write_mask, &src1_param);
if (dst_size > 1) {
shader_addline(buffer, "vec%d(dot(%s, %s)));\n", dst_size, src0_param.param_str, src1_param.param_str);
} else {
shader_addline(buffer, "dot(%s, %s));\n", src0_param.param_str, src1_param.param_str);
}
}
/* Note that this instruction has some restrictions. The destination write mask
* can't contain the w component, and the source swizzles have to be .xyzw */
void shader_glsl_cross(SHADER_OPCODE_ARG *arg) {
DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2;
glsl_src_param_t src0_param;
glsl_src_param_t src1_param;
char dst_mask[6];
shader_glsl_get_write_mask(arg->dst, dst_mask);
shader_glsl_append_dst(arg->buffer, arg);
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], src_mask, &src1_param);
shader_addline(arg->buffer, "cross(%s, %s).%s);\n", src0_param.param_str, src1_param.param_str, dst_mask);
}
/* Process the WINED3DSIO_POW instruction in GLSL (dst = |src0|^src1)
* Src0 and src1 are scalars. Note that D3D uses the absolute of src0, while
* GLSL uses the value as-is. */
void shader_glsl_pow(SHADER_OPCODE_ARG *arg) {
SHADER_BUFFER *buffer = arg->buffer;
glsl_src_param_t src0_param;
glsl_src_param_t src1_param;
DWORD dst_write_mask;
size_t dst_size;
dst_write_mask = shader_glsl_append_dst(buffer, arg);
dst_size = shader_glsl_get_write_mask_size(dst_write_mask);
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_0, &src1_param);
if (dst_size > 1) {
shader_addline(buffer, "vec%d(pow(abs(%s), %s)));\n", dst_size, src0_param.param_str, src1_param.param_str);
} else {
shader_addline(buffer, "pow(abs(%s), %s));\n", src0_param.param_str, src1_param.param_str);
}
}
/* Map the opcode 1-to-1 to the GL code (arg->dst = instruction(src0, src1, ...) */
void shader_glsl_map2gl(SHADER_OPCODE_ARG* arg) {
CONST SHADER_OPCODE* curOpcode = arg->opcode;
SHADER_BUFFER* buffer = arg->buffer;
glsl_src_param_t src_param;
const char *instruction;
char arguments[256];
DWORD write_mask;
unsigned i;
/* Determine the GLSL function to use based on the opcode */
/* TODO: Possibly make this a table for faster lookups */
switch (curOpcode->opcode) {
case WINED3DSIO_MIN: instruction = "min"; break;
case WINED3DSIO_MAX: instruction = "max"; break;
case WINED3DSIO_ABS: instruction = "abs"; break;
case WINED3DSIO_FRC: instruction = "fract"; break;
case WINED3DSIO_NRM: instruction = "normalize"; break;
case WINED3DSIO_LOGP:
case WINED3DSIO_LOG: instruction = "log2"; break;
case WINED3DSIO_EXP: instruction = "exp2"; break;
case WINED3DSIO_SGN: instruction = "sign"; break;
case WINED3DSIO_DSX: instruction = "dFdx"; break;
case WINED3DSIO_DSY: instruction = "dFdy"; break;
default: instruction = "";
FIXME("Opcode %s not yet handled in GLSL\n", curOpcode->name);
break;
}
write_mask = shader_glsl_append_dst(buffer, arg);
arguments[0] = '\0';
if (curOpcode->num_params > 0) {
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src_param);
strcat(arguments, src_param.param_str);
for (i = 2; i < curOpcode->num_params; ++i) {
strcat(arguments, ", ");
shader_glsl_add_src_param(arg, arg->src[i-1], arg->src_addr[i-1], write_mask, &src_param);
strcat(arguments, src_param.param_str);
}
}
shader_addline(buffer, "%s(%s));\n", instruction, arguments);
}
/** Process the WINED3DSIO_EXPP instruction in GLSL:
* For shader model 1.x, do the following (and honor the writemask, so use a temporary variable):
* dst.x = 2^(floor(src))
* dst.y = src - floor(src)
* dst.z = 2^src (partial precision is allowed, but optional)
* dst.w = 1.0;
* For 2.0 shaders, just do this (honoring writemask and swizzle):
* dst = 2^src; (partial precision is allowed, but optional)
*/
void shader_glsl_expp(SHADER_OPCODE_ARG* arg) {
IWineD3DBaseShaderImpl *shader = (IWineD3DBaseShaderImpl *)arg->shader;
glsl_src_param_t src_param;
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src_param);
if (shader->baseShader.hex_version < WINED3DPS_VERSION(2,0)) {
char dst_mask[6];
shader_addline(arg->buffer, "tmp0.x = exp2(floor(%s));\n", src_param.param_str);
shader_addline(arg->buffer, "tmp0.y = %s - floor(%s);\n", src_param.param_str, src_param.param_str);
shader_addline(arg->buffer, "tmp0.z = exp2(%s);\n", src_param.param_str);
shader_addline(arg->buffer, "tmp0.w = 1.0;\n");
shader_glsl_append_dst(arg->buffer, arg);
shader_glsl_get_write_mask(arg->dst, dst_mask);
shader_addline(arg->buffer, "tmp0%s);\n", dst_mask);
} else {
DWORD write_mask;
size_t mask_size;
write_mask = shader_glsl_append_dst(arg->buffer, arg);
mask_size = shader_glsl_get_write_mask_size(write_mask);
if (mask_size > 1) {
shader_addline(arg->buffer, "vec%d(exp2(%s)));\n", mask_size, src_param.param_str);
} else {
shader_addline(arg->buffer, "exp2(%s));\n", src_param.param_str);
}
}
}
/** Process the RCP (reciprocal or inverse) opcode in GLSL (dst = 1 / src) */
void shader_glsl_rcp(SHADER_OPCODE_ARG* arg) {
glsl_src_param_t src_param;
DWORD write_mask;
size_t mask_size;
write_mask = shader_glsl_append_dst(arg->buffer, arg);
mask_size = shader_glsl_get_write_mask_size(write_mask);
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &src_param);
if (mask_size > 1) {
shader_addline(arg->buffer, "vec%d(1.0 / %s));\n", mask_size, src_param.param_str);
} else {
shader_addline(arg->buffer, "1.0 / %s);\n", src_param.param_str);
}
}
void shader_glsl_rsq(SHADER_OPCODE_ARG* arg) {
SHADER_BUFFER* buffer = arg->buffer;
glsl_src_param_t src_param;
DWORD write_mask;
size_t mask_size;
write_mask = shader_glsl_append_dst(buffer, arg);
mask_size = shader_glsl_get_write_mask_size(write_mask);
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &src_param);
if (mask_size > 1) {
shader_addline(buffer, "vec%d(inversesqrt(%s)));\n", mask_size, src_param.param_str);
} else {
shader_addline(buffer, "inversesqrt(%s));\n", src_param.param_str);
}
}
/** Process signed comparison opcodes in GLSL. */
void shader_glsl_compare(SHADER_OPCODE_ARG* arg) {
glsl_src_param_t src0_param;
glsl_src_param_t src1_param;
DWORD write_mask;
size_t mask_size;
write_mask = shader_glsl_append_dst(arg->buffer, arg);
mask_size = shader_glsl_get_write_mask_size(write_mask);
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param);
if (mask_size > 1) {
const char *compare;
switch(arg->opcode->opcode) {
case WINED3DSIO_SLT: compare = "lessThan"; break;
case WINED3DSIO_SGE: compare = "greaterThanEqual"; break;
default: compare = "";
FIXME("Can't handle opcode %s\n", arg->opcode->name);
}
shader_addline(arg->buffer, "vec%d(%s(%s, %s)));\n", mask_size, compare,
src0_param.param_str, src1_param.param_str);
} else {
const char *compare;
switch(arg->opcode->opcode) {
case WINED3DSIO_SLT: compare = "<"; break;
case WINED3DSIO_SGE: compare = ">="; break;
default: compare = "";
FIXME("Can't handle opcode %s\n", arg->opcode->name);
}
shader_addline(arg->buffer, "(%s %s %s) ? 1.0 : 0.0);\n",
src0_param.param_str, compare, src1_param.param_str);
}
}
/** Process CMP instruction in GLSL (dst = src0 >= 0.0 ? src1 : src2), per channel */
void shader_glsl_cmp(SHADER_OPCODE_ARG* arg) {
glsl_src_param_t src0_param;
glsl_src_param_t src1_param;
glsl_src_param_t src2_param;
DWORD write_mask, cmp_channel = 0;
unsigned int i, j;
/* Cycle through all source0 channels */
for (i=0; i<4; i++) {
write_mask = 0;
/* Find the destination channels which use the current source0 channel */
for (j=0; j<4; j++) {
if ( ((arg->src[0] >> (WINED3DSP_SWIZZLE_SHIFT + 2*j)) & 0x3) == i ) {
write_mask |= WINED3DSP_WRITEMASK_0 << j;
cmp_channel = WINED3DSP_WRITEMASK_0 << j;
}
}
write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask));
if (!write_mask) continue;
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], cmp_channel, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param);
shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param);
shader_addline(arg->buffer, "%s >= 0.0 ? %s : %s);\n",
src0_param.param_str, src1_param.param_str, src2_param.param_str);
}
}
/** Process the CND opcode in GLSL (dst = (src0 > 0.5) ? src1 : src2) */
/* For ps 1.1-1.3, only a single component of src0 is used. For ps 1.4
* the compare is done per component of src0. */
void shader_glsl_cnd(SHADER_OPCODE_ARG* arg) {
IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader;
glsl_src_param_t src0_param;
glsl_src_param_t src1_param;
glsl_src_param_t src2_param;
DWORD write_mask, cmp_channel = 0;
unsigned int i, j;
if (shader->baseShader.hex_version < WINED3DPS_VERSION(1, 4)) {
write_mask = shader_glsl_append_dst(arg->buffer, arg);
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param);
shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param);
shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n",
src0_param.param_str, src1_param.param_str, src2_param.param_str);
return;
}
/* Cycle through all source0 channels */
for (i=0; i<4; i++) {
write_mask = 0;
/* Find the destination channels which use the current source0 channel */
for (j=0; j<4; j++) {
if ( ((arg->src[0] >> (WINED3DSP_SWIZZLE_SHIFT + 2*j)) & 0x3) == i ) {
write_mask |= WINED3DSP_WRITEMASK_0 << j;
cmp_channel = WINED3DSP_WRITEMASK_0 << j;
}
}
write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask));
if (!write_mask) continue;
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], cmp_channel, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param);
shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param);
shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n",
src0_param.param_str, src1_param.param_str, src2_param.param_str);
}
}
/** GLSL code generation for WINED3DSIO_MAD: Multiply the first 2 opcodes, then add the last */
void shader_glsl_mad(SHADER_OPCODE_ARG* arg) {
glsl_src_param_t src0_param;
glsl_src_param_t src1_param;
glsl_src_param_t src2_param;
DWORD write_mask;
write_mask = shader_glsl_append_dst(arg->buffer, arg);
shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src0_param);
shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param);
shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param);
shader_addline(arg->buffer, "(%s * %s) + %s);\n",
src0_param.param_str, src1_param.param_str, src2_param.param_str);
}
/** Handles transforming all WINED3DSIO_M?x? opcodes for
Vertex shaders to GLSL codes */
void shader_glsl_mnxn(SHADER_OPCODE_ARG* arg) {
int i;
int nComponents = 0;
SHADER_OPCODE_ARG tmpArg;
memset(&tmpArg, 0, sizeof(SHADER_OPCODE_ARG));
/* Set constants for the temporary argument */
tmpArg.shader = arg->shader;
tmpArg.buffer = arg->buffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -