[5/6] WINED3D: Add code for using register combiners for texture stage operations

H. Verbeet hverbeet at gmail.com
Tue Jun 27 16:42:35 CDT 2006


On nVidia cards the value of GL_MAX_TEXTURE_UNITS is generally not
larger than 4. In Direct3D that would correspond to
MaxSimultaneousTextures in the caps, rather than MaxTextureBlendStages
(which can be much larger) to which it currently corresponds in
wined3d. Using register combiners we can get around that limitation
and get up to GL_MAX_GENERAL_COMBINERS_NV (typically 8) texture
stages. This patch adds code for doing the texture operations with
register combiners instead of ARB_texture_env_combine or
NV_texture_env_combine4, but doesn't make use of that code yet. That's
what the next patch will do.
-------------- next part --------------
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 0a21fd9..a89a4c2 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -5,6 +5,7 @@
  * Copyright 2003-2004 Raphael Junqueira
  * Copyright 2004 Christian Costa
  * Copyright 2005 Oliver Stieber
+ * Copyright 2006 Henri Verbeet
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,6 +27,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 
+#define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
+
 /*****************************************************************************
  * Pixel format array
  */
@@ -563,6 +566,360 @@ GLenum StencilFunc(DWORD func) {
     }
 }
 
+static GLenum d3dta_to_combiner_input(DWORD d3dta, DWORD stage, INT texture_idx) {
+    switch (d3dta) {
+        case D3DTA_DIFFUSE:
+            return GL_PRIMARY_COLOR_NV;
+
+        case D3DTA_CURRENT:
+            if (stage) return GL_SPARE0_NV;
+            else return GL_PRIMARY_COLOR_NV;
+
+        case D3DTA_TEXTURE:
+            if (texture_idx > -1) return GL_TEXTURE0_ARB + texture_idx;
+            else return GL_PRIMARY_COLOR_NV;
+
+        case D3DTA_TFACTOR:
+            return GL_CONSTANT_COLOR0_NV;
+
+        case D3DTA_SPECULAR:
+            return GL_SECONDARY_COLOR_NV;
+
+        case D3DTA_TEMP:
+            /* TODO: Support D3DTSS_RESULTARG */
+            FIXME("D3DTA_TEMP, not properly supported.");
+            return GL_SPARE1_NV;
+
+        case D3DTA_CONSTANT:
+            /* TODO: Support per stage constants (D3DTSS_CONSTANT, NV_register_combiners2) */
+            FIXME("D3DTA_CONSTANT, not properly supported.");
+            return GL_CONSTANT_COLOR1_NV;
+
+        default:
+            FIXME("Unrecognized texture arg %#lx\n", d3dta);
+            return GL_TEXTURE;
+    }
+}
+
+static GLenum invert_mapping(GLenum mapping) {
+    if (mapping == GL_UNSIGNED_INVERT_NV) return GL_SIGNED_IDENTITY_NV;
+    else if (mapping == GL_SIGNED_IDENTITY_NV) return GL_UNSIGNED_INVERT_NV;
+
+    FIXME("Unhandled mapping %#x\n", mapping);
+    return mapping;
+}
+
+static void get_src_and_opr_nvrc(DWORD stage, DWORD arg, BOOL is_alpha, GLenum* input, GLenum* mapping, GLenum *component_usage, INT texture_idx) {
+    /* The D3DTA_COMPLEMENT flag specifies the complement of the input should
+     * be used. */
+    if (arg & D3DTA_COMPLEMENT) *mapping = GL_UNSIGNED_INVERT_NV;
+    else *mapping = GL_SIGNED_IDENTITY_NV;
+
+    /* The D3DTA_ALPHAREPLICATE flag specifies the alpha component of the input
+     * should be used for all input components. */
+    if (is_alpha || arg & D3DTA_ALPHAREPLICATE) *component_usage = GL_ALPHA;
+    else *component_usage = GL_RGB;
+
+    *input = d3dta_to_combiner_input(arg & D3DTA_SELECTMASK, stage, texture_idx);
+}
+
+typedef struct {
+    GLenum input[3];
+    GLenum mapping[3];
+    GLenum component_usage[3];
+} tex_op_args;
+
+void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, D3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx) {
+    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl*)iface;
+    tex_op_args tex_op_args = {{0}, {0}, {0}};
+    GLenum portion = is_alpha ? GL_ALPHA : GL_RGB;
+    GLenum target = GL_COMBINER0_NV + stage;
+
+    TRACE("stage %d, is_alpha %d, op %s, arg1 %#lx, arg2 %#lx, arg3 %#lx, texture_idx %d\n",
+            stage, is_alpha, debug_d3dtop(op), arg1, arg2, arg3, texture_idx);
+
+    get_src_and_opr_nvrc(stage, arg1, is_alpha, &tex_op_args.input[0],
+            &tex_op_args.mapping[0], &tex_op_args.component_usage[0], texture_idx);
+    get_src_and_opr_nvrc(stage, arg2, is_alpha, &tex_op_args.input[1],
+            &tex_op_args.mapping[1], &tex_op_args.component_usage[1], texture_idx);
+    get_src_and_opr_nvrc(stage, arg3, is_alpha, &tex_op_args.input[2],
+            &tex_op_args.mapping[2], &tex_op_args.component_usage[2], texture_idx);
+
+    ENTER_GL();
+
+    switch(op)
+    {
+        case D3DTOP_DISABLE:
+            /* Only for alpha */
+            if (!is_alpha) ERR("Shouldn't be called for D3DTSS_COLOROP (D3DTOP_DISABLE)\n");
+            /* Input, prev_alpha*1 */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV,
+                    GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_SELECTARG1:
+        case D3DTOP_SELECTARG2:
+            /* Input, arg*1 */
+            if (op == D3DTOP_SELECTARG1) {
+                GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                        tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            } else {
+                GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                        tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            }
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV,
+                    GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_MODULATE:
+        case D3DTOP_MODULATE2X:
+        case D3DTOP_MODULATE4X:
+            /* Input, arg1*arg2 */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+
+            /* Output */
+            if (op == D3DTOP_MODULATE) {
+                GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV,
+                        GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            } else if (op == D3DTOP_MODULATE2X) {
+                GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV,
+                        GL_DISCARD_NV, GL_SCALE_BY_TWO_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            } else if (op == D3DTOP_MODULATE4X) {
+                GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV,
+                        GL_DISCARD_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            }
+            break;
+
+        case D3DTOP_ADD:
+        case D3DTOP_ADDSIGNED:
+        case D3DTOP_ADDSIGNED2X:
+            /* Input, arg1*1+arg2*1 */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+
+            /* Output */
+            if (op == D3DTOP_ADD) {
+                GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                        GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            } else if (op == D3DTOP_ADDSIGNED) {
+                GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                        GL_SPARE0_NV, GL_NONE, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE));
+            } else if (op == D3DTOP_ADDSIGNED2X) {
+                GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                        GL_SPARE0_NV, GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE));
+            }
+            break;
+
+        case D3DTOP_SUBTRACT:
+            /* Input, arg1*1+-arg2*1 */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[1], GL_SIGNED_NEGATE_NV, tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_ADDSMOOTH:
+            /* Input, arg1*1+(1-arg1)*arg2 */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_BLENDDIFFUSEALPHA:
+        case D3DTOP_BLENDTEXTUREALPHA:
+        case D3DTOP_BLENDFACTORALPHA:
+        case D3DTOP_BLENDTEXTUREALPHAPM:
+        case D3DTOP_BLENDCURRENTALPHA:
+        {
+            GLenum alpha_src = GL_PRIMARY_COLOR_NV;
+            if (op == D3DTOP_BLENDDIFFUSEALPHA) alpha_src = d3dta_to_combiner_input(D3DTA_DIFFUSE, stage, texture_idx);
+            else if (op == D3DTOP_BLENDTEXTUREALPHA) alpha_src = d3dta_to_combiner_input(D3DTA_TEXTURE, stage, texture_idx);
+            else if (op == D3DTOP_BLENDFACTORALPHA) alpha_src = d3dta_to_combiner_input(D3DTA_TFACTOR, stage, texture_idx);
+            else if (op == D3DTOP_BLENDTEXTUREALPHAPM) alpha_src = d3dta_to_combiner_input(D3DTA_TEXTURE, stage, texture_idx);
+            else if (op == D3DTOP_BLENDCURRENTALPHA) alpha_src = d3dta_to_combiner_input(D3DTA_CURRENT, stage, texture_idx);
+            else FIXME("Unhandled D3DTOP %s, shouldn't happen\n", debug_d3dtop(op));
+
+            /* Input, arg1*alpha_src+arg2*(1-alpha_src) */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            if (op == D3DTOP_BLENDTEXTUREALPHAPM)
+            {
+                GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                        GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+            } else {
+                GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                        alpha_src, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA));
+            }
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    alpha_src, GL_UNSIGNED_INVERT_NV, GL_ALPHA));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+        }
+
+        case D3DTOP_MODULATEALPHA_ADDCOLOR:
+            /* Input, arg1_alpha*arg2_rgb+arg1_rgb*1 */
+            if (is_alpha) ERR("Only supported for D3DTSS_COLOROP (D3DTOP_MODULATEALPHA_ADDCOLOR)\n");
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], GL_ALPHA));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_MODULATECOLOR_ADDALPHA:
+            /* Input, arg1_rgb*arg2_rgb+arg1_alpha*1 */
+            if (is_alpha) ERR("Only supported for D3DTSS_COLOROP (D3DTOP_MODULATECOLOR_ADDALPHA)\n");
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], GL_ALPHA));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
+            /* Input, (1-arg1_alpha)*arg2_rgb+arg1_rgb*1 */
+            if (is_alpha) ERR("Only supported for D3DTSS_COLOROP (D3DTOP_MODULATEINVALPHA_ADDCOLOR)\n");
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), GL_ALPHA));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
+            /* Input, (1-arg1_rgb)*arg2_rgb+arg1_alpha*1 */
+            if (is_alpha) ERR("Only supported for D3DTSS_COLOROP (D3DTOP_MODULATEINVCOLOR_ADDALPHA)\n");
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], GL_ALPHA));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_DOTPRODUCT3:
+            /* Input, arg1 . arg2 */
+            /* FIXME: DX7 uses a different calculation? */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], GL_EXPAND_NORMAL_NV, tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    tex_op_args.input[1], GL_EXPAND_NORMAL_NV, tex_op_args.component_usage[1]));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV,
+                    GL_DISCARD_NV, GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_MULTIPLYADD:
+            /* Input, arg1*1+arg2*arg3 */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    GL_ZERO, GL_UNSIGNED_INVERT_NV, portion));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    tex_op_args.input[2], tex_op_args.mapping[2], tex_op_args.component_usage[2]));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        case D3DTOP_LERP:
+            /* Input, arg1*arg2+(1-arg1)*arg3 */
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV,
+                    tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV,
+                    tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV,
+                    tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), tex_op_args.component_usage[0]));
+            GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV,
+                    tex_op_args.input[2], tex_op_args.mapping[2], tex_op_args.component_usage[2]));
+
+            /* Output */
+            GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV,
+                    GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE));
+            break;
+
+        default:
+            FIXME("Unhandled D3DTOP: stage %d, is_alpha %d, op %s (%#x), arg1 %#lx, arg2 %#lx, arg3 %#lx, texture_idx %d\n",
+                    stage, is_alpha, debug_d3dtop(op), op, arg1, arg2, arg3, texture_idx);
+    }
+
+    checkGLcall("set_tex_op_nvrc()\n");
+
+    LEAVE_GL();
+}
+
 static void get_src_and_opr(DWORD arg, BOOL is_alpha, GLenum* source, GLenum* operand) {
     /* The D3DTA_ALPHAREPLICATE flag specifies the alpha component of the
      * input should be used for all input components. The D3DTA_COMPLEMENT
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9543cb2..53dee67 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1194,6 +1194,7 @@ const char* debug_d3dpool(WINED3DPOOL po
 GLenum StencilOp(DWORD op);
 GLenum StencilFunc(DWORD func);
 void   set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, D3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3);
+void   set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, D3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx);
 void   set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords);
 
 int D3DFmtMakeGlCfg(D3DFORMAT BackBufferFormat, D3DFORMAT StencilBufferFormat, int *attribs, int* nAttribs, BOOL alternate);


More information about the wine-patches mailing list