Implement more GLSL instructions
Jason Green
jave27 at gmail.com
Tue Jun 13 21:32:14 CDT 2006
- Implemented: D3DSIO_SGN, LOOP, ENDLOOP, LOGP, LIT, DST, SINCOS
- Process instruction-based modifiers (function existed, it just
wasn't being called)
- Add loop checking to register maps.
- Renamed "sng" to "sgn" for D3DSIO_SGN - it's not handled anywhere
except for GLSL, so won't matter.
- Note: The LOOP opcodes won't actually work until we handle integer
constants (will submit a patch after i get all the kinks worked out)
As of this patch, Wine now supports more opcodes in GLSL than
ARB_vp/fp and we can handle many of the shader 2.0+ instructions not
available before. There are a few missing texture operations compared
to ARB still, and we're not properly handling textures for any shaders
<2.0, but that's true in ARB as well.
-------------- next part --------------
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index b148bb3..f19a03b 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -411,6 +411,9 @@ void shader_get_registers_used(
else if (D3DSPR_INPUT == regtype && !pshader)
reg_maps->attributes[reg] = 1;
+
+ else if (D3DSPR_LOOP == regtype)
+ reg_maps->loop = 1;
}
}
}
@@ -792,6 +795,10 @@ void shader_generate_glsl_declarations(
shader_addline(buffer, "attribute vec4 attrib%i;\n", i);
}
+ /* Declare loop register aL */
+ if (reg_maps->loop)
+ shader_addline(buffer, "int aL;\n");
+
/* Temporary variables for matrix operations */
shader_addline(buffer, "vec4 tmp0;\n");
shader_addline(buffer, "vec4 tmp1;\n");
@@ -901,6 +908,10 @@ void shader_generate_main(
/* Call appropriate function for output target */
hw_fct(&hw_arg);
+ /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */
+ if (wined3d_settings.shader_mode == SHADER_GLSL)
+ shader_glsl_add_instruction_modifiers(&hw_arg);
+
/* Unhandled opcode */
} else {
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 3661d06..e99a2a2 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -245,6 +245,9 @@ static void shader_glsl_get_register_nam
sprintf(tmpStr, "A%lu", reg);
}
break;
+ case D3DSPR_LOOP:
+ sprintf(tmpStr, "aL");
+ break;
case D3DSPR_SAMPLER:
if (pshader)
sprintf(tmpStr, "psampler%lu", reg);
@@ -508,11 +511,13 @@ void shader_glsl_map2gl(SHADER_OPCODE_AR
case D3DSIO_POW: strcat(tmpLine, "pow"); break;
case D3DSIO_CRS: strcat(tmpLine, "cross"); break;
case D3DSIO_NRM: strcat(tmpLine, "normalize"); break;
+ case D3DSIO_LOGP:
case D3DSIO_LOG: strcat(tmpLine, "log2"); break;
case D3DSIO_EXPP:
case D3DSIO_EXP: strcat(tmpLine, "exp2"); break;
case D3DSIO_SGE: strcat(tmpLine, "greaterThanEqual"); break;
case D3DSIO_SLT: strcat(tmpLine, "lessThan"); break;
+ case D3DSIO_SGN: strcat(tmpLine, "sign"); break;
default:
FIXME("Opcode %s not yet handled in GLSL\n", curOpcode->name);
break;
@@ -728,6 +733,93 @@ void shader_glsl_def(SHADER_OPCODE_ARG*
arg->reg_maps->constantsF[reg] = 1;
}
+/** Process the D3DSIO_LIT instruction in GLSL:
+ * dst.x = dst.w = 1.0
+ * dst.y = (src0.x > 0) ? src0.x
+ * dst.z = (src0.x > 0) ? ((src0.y > 0) ? pow(src0.y, src.w) : 0) : 0
+ * where src.w is clamped at +- 128
+ */
+void shader_glsl_lit(SHADER_OPCODE_ARG* arg) {
+
+ char dst_str[100], src0_str[100];
+ char dst_reg[50], src0_reg[50];
+ char dst_mask[6], src0_mask[6];
+
+ shader_glsl_add_param(arg, arg->dst, 0, FALSE, dst_reg, dst_mask, dst_str);
+ shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+
+ shader_addline(arg->buffer,
+ "%s = vec4(1.0, (%s.x > 0.0 ? %s.x : 0.0), (%s.x > 0.0 ? ((%s.y > 0.0) ? pow(%s.y, clamp(%s.w, -128.0, 128.0)) : 0.0) : 0.0), 1.0)%s;\n",
+ dst_str, src0_reg, src0_reg, src0_reg, src0_reg, src0_reg, src0_reg, dst_mask);
+}
+
+/** Process the D3DSIO_DST instruction in GLSL:
+ * dst.x = 1.0
+ * dst.y = src0.x * src0.y
+ * dst.z = src0.z
+ * dst.w = src1.w
+ */
+void shader_glsl_dst(SHADER_OPCODE_ARG* arg) {
+
+ char dst_str[100], src0_str[100], src1_str[100];
+ char dst_reg[50], src0_reg[50], src1_reg[50];
+ char dst_mask[6], src0_mask[6], src1_mask[6];
+
+ shader_glsl_add_param(arg, arg->dst, 0, FALSE, dst_reg, dst_mask, dst_str);
+ shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+ shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str);
+
+ shader_addline(arg->buffer, "%s = vec4(1.0, %s.x * %s.y, %s.z, %s.w)%s;\n",
+ dst_str, src0_reg, src1_reg, src0_reg, src1_reg, dst_mask);
+}
+
+/** Process the D3DSIO_SINCOS instruction in GLSL:
+ * VS 2.0 requires that specific cosine and sine constants be passed to this instruction so the hardware
+ * can handle it. But, these functions are built-in for GLSL, so we can just ignore the last 2 params.
+ *
+ * dst.x = cos(src0.?)
+ * dst.y = sin(src0.?)
+ * dst.z = dst.z
+ * dst.w = dst.w
+ */
+void shader_glsl_sincos(SHADER_OPCODE_ARG* arg) {
+
+ char dst_str[100], src0_str[100];
+ char dst_reg[50], src0_reg[50];
+ char dst_mask[6], src0_mask[6];
+
+ shader_glsl_add_param(arg, arg->dst, 0, FALSE, dst_reg, dst_mask, dst_str);
+ shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+
+ shader_addline(arg->buffer, "%s = vec4(cos(%s), sin(%s), %s.z, %s.w)%s;\n",
+ dst_str, src0_str, src0_str, dst_reg, dst_reg, dst_mask);
+}
+
+/** Process the D3DSIO_LOOP instruction in GLSL:
+ * Start a for() loop where src0.y is the initial value of aL,
+ * increment aL by src0.z while (aL < src0.x).
+ */
+void shader_glsl_loop(SHADER_OPCODE_ARG* arg) {
+
+ char src0_str[100];
+ char src0_reg[50];
+ char src0_mask[6];
+
+ shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+
+ shader_addline(arg->buffer, "for (aL = %s.y; aL < %s.x; aL += %s.z) {\n",
+ src0_reg, src0_reg, src0_reg);
+}
+
+/** Process the D3DSIO_ENDLOOP instruction in GLSL:
+ * End the for() loop
+ */
+void shader_glsl_endloop(SHADER_OPCODE_ARG* arg) {
+
+ shader_addline(arg->buffer, "}\n");
+}
+
+
/*********************************************
* Pixel Shader Specific Code begins here
********************************************/
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 60bbfaf..4c72390 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -654,8 +654,8 @@ CONST SHADER_OPCODE IWineD3DPixelShaderI
{D3DSIO_EXP, "exp", "EX2", 1, 2, pshader_exp, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
{D3DSIO_LOG, "log", "LG2", 1, 2, pshader_log, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
{D3DSIO_EXPP, "expp", "EXP", 1, 2, pshader_expp, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
- {D3DSIO_LOGP, "logp", "LOG", 1, 2, pshader_logp, pshader_hw_map2gl, NULL, 0, 0},
- {D3DSIO_DST, "dst", "DST", 1, 3, pshader_dst, pshader_hw_map2gl, NULL, 0, 0},
+ {D3DSIO_LOGP, "logp", "LOG", 1, 2, pshader_logp, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
+ {D3DSIO_DST, "dst", "DST", 1, 3, pshader_dst, pshader_hw_map2gl, shader_glsl_dst, 0, 0},
{D3DSIO_LRP, "lrp", "LRP", 1, 4, pshader_lrp, pshader_hw_map2gl, shader_glsl_lrp, 0, 0},
{D3DSIO_FRC, "frc", "FRC", 1, 2, pshader_frc, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
{D3DSIO_CND, "cnd", NULL, 1, 4, pshader_cnd, pshader_hw_cnd, shader_glsl_cnd, D3DPS_VERSION(1,1), D3DPS_VERSION(1,4)},
@@ -673,8 +673,8 @@ CONST SHADER_OPCODE IWineD3DPixelShaderI
*/
{D3DSIO_NRM, "nrm", NULL, 1, 2, pshader_nrm, NULL, shader_glsl_map2gl, 0, 0},
- {D3DSIO_SINCOS, "sincos", NULL, 1, 4, pshader_sincos2, NULL, NULL, D3DPS_VERSION(2,0), D3DPS_VERSION(2,0)},
- {D3DSIO_SINCOS, "sincos", NULL, 1, 2, pshader_sincos3, NULL, NULL, D3DPS_VERSION(3,0), -1},
+ {D3DSIO_SINCOS, "sincos", NULL, 1, 4, pshader_sincos2, NULL, shader_glsl_sincos, D3DPS_VERSION(2,0), D3DPS_VERSION(2,0)},
+ {D3DSIO_SINCOS, "sincos", NULL, 1, 2, pshader_sincos3, NULL, shader_glsl_sincos, D3DPS_VERSION(3,0), -1},
/* TODO: dp2add can be made out of multiple instuctions */
{D3DSIO_DP2ADD, "dp2add", GLNAME_REQUIRE_GLSL, 1, 4, pshader_dp2add, NULL, NULL, D3DPS_VERSION(2,0), -1},
@@ -700,9 +700,9 @@ CONST SHADER_OPCODE IWineD3DPixelShaderI
{D3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 0, 1, pshader_breakp, NULL, NULL, 0, 0},
{D3DSIO_CALL, "call", GLNAME_REQUIRE_GLSL, 0, 1, pshader_call, NULL, NULL, 0, 0},
{D3DSIO_CALLNZ, "callnz", GLNAME_REQUIRE_GLSL, 0, 2, pshader_callnz, NULL, NULL, 0, 0},
- {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 0, 2, pshader_loop, NULL, NULL, 0, 0},
+ {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 0, 2, pshader_loop, NULL, shader_glsl_loop, 0, 0},
{D3DSIO_RET, "ret", GLNAME_REQUIRE_GLSL, 0, 0, pshader_ret, NULL, NULL, 0, 0},
- {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, 0, pshader_endloop, NULL, NULL, 0, 0},
+ {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, 0, pshader_endloop, NULL, shader_glsl_endloop, 0, 0},
{D3DSIO_LABEL, "label", GLNAME_REQUIRE_GLSL, 0, 1, pshader_label, NULL, NULL, 0, 0},
/* Constant definitions */
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 56648b9..d2028f2 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -397,7 +397,7 @@ static void vshader_pow(WINED3DSHADERVEC
FIXME(" : Stub\n");
}
-static void vshader_sng(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
+static void vshader_sgn(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
FIXME(" : Stub\n");
}
@@ -501,9 +501,9 @@ CONST SHADER_OPCODE IWineD3DVertexShader
{D3DSIO_EXP, "exp", "EX2", 1, 2, vshader_exp, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
{D3DSIO_LOG, "log", "LG2", 1, 2, vshader_log, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
{D3DSIO_EXPP, "expp", "EXP", 1, 2, vshader_expp, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
- {D3DSIO_LOGP, "logp", "LOG", 1, 2, vshader_logp, vshader_hw_map2gl, NULL, 0, 0},
- {D3DSIO_LIT, "lit", "LIT", 1, 2, vshader_lit, vshader_hw_map2gl, NULL, 0, 0},
- {D3DSIO_DST, "dst", "DST", 1, 3, vshader_dst, vshader_hw_map2gl, NULL, 0, 0},
+ {D3DSIO_LOGP, "logp", "LOG", 1, 2, vshader_logp, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
+ {D3DSIO_LIT, "lit", "LIT", 1, 2, vshader_lit, vshader_hw_map2gl, shader_glsl_lit, 0, 0},
+ {D3DSIO_DST, "dst", "DST", 1, 3, vshader_dst, vshader_hw_map2gl, shader_glsl_dst, 0, 0},
{D3DSIO_LRP, "lrp", "LRP", 1, 4, vshader_lrp, NULL, shader_glsl_lrp, 0, 0},
{D3DSIO_FRC, "frc", "FRC", 1, 2, vshader_frc, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
{D3DSIO_POW, "pow", "POW", 1, 3, vshader_pow, NULL, shader_glsl_map2gl, 0, 0},
@@ -511,7 +511,7 @@ CONST SHADER_OPCODE IWineD3DVertexShader
/* TODO: sng can possibly be performed a s
RCP tmp, vec
MUL out, tmp, vec*/
- {D3DSIO_SGN, "sng", NULL, 1, 2, vshader_sng, NULL, NULL, 0, 0},
+ {D3DSIO_SGN, "sgn", NULL, 1, 2, vshader_sgn, NULL, shader_glsl_map2gl, 0, 0},
/* TODO: xyz normalise can be performed as VS_ARB using one temporary register,
DP3 tmp , vec, vec;
RSQ tmp, tmp.x;
@@ -523,8 +523,8 @@ CONST SHADER_OPCODE IWineD3DVertexShader
*/
{D3DSIO_NRM, "nrm", NULL, 1, 2, vshader_nrm, NULL, shader_glsl_map2gl, 0, 0},
- {D3DSIO_SINCOS, "sincos", NULL, 1, 4, vshader_sincos2, NULL, NULL, D3DVS_VERSION(2,0), D3DVS_VERSION(2,0)},
- {D3DSIO_SINCOS, "sincos", NULL, 1, 2, vshader_sincos3, NULL, NULL, D3DVS_VERSION(3,0), -1},
+ {D3DSIO_SINCOS, "sincos", NULL, 1, 4, vshader_sincos2, NULL, shader_glsl_sincos, D3DVS_VERSION(2,0), D3DVS_VERSION(2,0)},
+ {D3DSIO_SINCOS, "sincos", NULL, 1, 2, vshader_sincos3, NULL, shader_glsl_sincos, D3DVS_VERSION(3,0), -1},
/* Matrix */
{D3DSIO_M4x4, "m4x4", "undefined", 1, 3, vshader_m4x4, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0},
@@ -553,9 +553,9 @@ CONST SHADER_OPCODE IWineD3DVertexShader
{D3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 0, 1, vshader_breakp, NULL, NULL, 0, 0},
{D3DSIO_CALL, "call", GLNAME_REQUIRE_GLSL, 0, 1, vshader_call, NULL, NULL, 0, 0},
{D3DSIO_CALLNZ, "callnz", GLNAME_REQUIRE_GLSL, 0, 2, vshader_callnz, NULL, NULL, 0, 0},
- {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 0, 2, vshader_loop, NULL, NULL, 0, 0},
+ {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 0, 2, vshader_loop, NULL, shader_glsl_loop, 0, 0},
{D3DSIO_RET, "ret", GLNAME_REQUIRE_GLSL, 0, 0, vshader_ret, NULL, NULL, 0, 0},
- {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, 0, vshader_endloop, NULL, NULL, 0, 0},
+ {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, 0, vshader_endloop, NULL, shader_glsl_endloop, 0, 0},
{D3DSIO_LABEL, "label", GLNAME_REQUIRE_GLSL, 0, 1, vshader_label, NULL, NULL, 0, 0},
{D3DSIO_MOVA, "mova", GLNAME_REQUIRE_GLSL, 1, 2, vshader_mova, NULL, shader_glsl_mov, 0, 0},
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index cb9abc6..22f194c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1277,6 +1277,9 @@ typedef struct shader_reg_maps {
* Use 0 as default (bit 31 is always 1 on a valid token) */
DWORD samplers[MAX_SAMPLERS];
+ /* Whether or not a loop is used in this shader */
+ char loop;
+
} shader_reg_maps;
#define SHADER_PGMSIZE 65535
@@ -1344,8 +1347,9 @@ extern const SHADER_OPCODE* shader_get_o
/* ARB shader program Prototypes */
extern void shader_hw_def(SHADER_OPCODE_ARG *arg);
-/* GLSL helper programs */
+/* GLSL helper functions */
extern void set_glsl_shader_program(IWineD3DDevice *iface);
+extern void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG *arg);
/** The following translate DirectX pixel/vertex shader opcodes to GLSL lines */
extern void shader_glsl_map2gl(SHADER_OPCODE_ARG* arg);
@@ -1360,6 +1364,11 @@ extern void shader_glsl_cnd(SHADER_OPCOD
extern void shader_glsl_compare(SHADER_OPCODE_ARG* arg);
extern void shader_glsl_def(SHADER_OPCODE_ARG* arg);
extern void shader_glsl_cmp(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_lit(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_dst(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_sincos(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_loop(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_endloop(SHADER_OPCODE_ARG* arg);
/** GLSL Pixel Shader Prototypes */
extern void pshader_glsl_tex(SHADER_OPCODE_ARG* arg);
More information about the wine-patches
mailing list