[PATCH 5/5] wined3d: Alpha test emulation for core profile contexts.

Matteo Bruni mbruni at codeweavers.com
Thu Mar 31 12:51:00 CDT 2016


Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
 dlls/wined3d/glsl_shader.c     | 117 ++++++++++++++++++++++++++++++++++-------
 dlls/wined3d/shader.c          |   5 ++
 dlls/wined3d/utils.c           |   5 ++
 dlls/wined3d/wined3d_private.h |  30 +++++++----
 4 files changed, 129 insertions(+), 28 deletions(-)

diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index dbb0956..4801e1f 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -178,6 +178,8 @@ struct glsl_ps_program
     GLint fog_density_location;
     GLint fog_end_location;
     GLint fog_scale_location;
+    GLint alpha_test_location;
+    GLint alpha_ref_location;
     GLint ycorrection_location;
     GLint np2_fixup_location;
     GLint color_key_location;
@@ -1480,6 +1482,22 @@ static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context
     if (update_mask & WINED3D_SHADER_CONST_PS_FOG)
         shader_glsl_load_fog_uniform(context, state, prog);
 
+    if (update_mask & WINED3D_SHADER_CONST_PS_ALPHA_TEST)
+    {
+        if (state->render_states[WINED3D_RS_ALPHATESTENABLE])
+        {
+            float ref = state->render_states[WINED3D_RS_ALPHAREF] / 255.0f;
+
+            GL_EXTCALL(glUniform1i(prog->ps.alpha_test_location, TRUE));
+            GL_EXTCALL(glUniform1f(prog->ps.alpha_ref_location, ref));
+        }
+        else
+        {
+            GL_EXTCALL(glUniform1i(prog->ps.alpha_test_location, FALSE));
+        }
+        checkGLcall("alpha test emulation uniforms");
+    }
+
     if (priv->next_constant_version == UINT_MAX)
     {
         TRACE("Max constant version reached, resetting to 0.\n");
@@ -2014,6 +2032,12 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
             shader_addline(buffer, "vec4 vpos;\n");
         }
 
+        if (ps_args->alpha_func != WINED3D_CMP_ALWAYS)
+        {
+            shader_addline(buffer, "uniform bool alpha_test;\n");
+            shader_addline(buffer, "uniform float alpha_ref;\n");
+        }
+
         if (!needs_legacy_glsl_syntax(gl_info))
             shader_addline(buffer, "out vec4 ps_out[%u];\n", gl_info->limits.buffers);
 
@@ -5446,6 +5470,33 @@ static void shader_glsl_generate_fog_code(struct wined3d_string_buffer *buffer,
             output, output);
 }
 
+static void shader_glsl_generate_alpha_test(struct wined3d_string_buffer *buffer,
+        const struct wined3d_gl_info *gl_info, enum wined3d_cmp_func alpha_func)
+{
+    /* alpha_func is the PASS condition, not the DISCARD condition. Instead of
+     * flipping all the operators here, just negate the comparison below. */
+    static const char *comparison_operator[] =
+    {
+        "",   /* WINED3D_CMP_NEVER */
+        "<",  /* WINED3D_CMP_LESS */
+        "==", /* WINED3D_CMP_EQUAL */
+        "<=", /* WINED3D_CMP_LESSEQUAL */
+        ">",  /* WINED3D_CMP_GREATER */
+        "!=", /* WINED3D_CMP_NOTEQUAL */
+        ">=", /* WINED3D_CMP_GREATEREQUAL */
+        ""    /* WINED3D_CMP_ALWAYS */
+    };
+
+    if (alpha_func == WINED3D_CMP_ALWAYS)
+        return;
+
+    shader_addline(buffer, "if (alpha_test)\n");
+    if (alpha_func != WINED3D_CMP_NEVER)
+        shader_addline(buffer, "    if (!(%s[0].a %s alpha_ref))\n",
+                get_fragment_output(gl_info), comparison_operator[alpha_func - WINED3D_CMP_NEVER]);
+    shader_addline(buffer, "        discard;\n");
+}
+
 /* Context activation is done by the caller. */
 static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context,
         struct wined3d_string_buffer *buffer, struct wined3d_string_buffer_list *string_buffers,
@@ -5536,6 +5587,8 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context
     if (reg_maps->shader_version.major < 3)
         shader_glsl_generate_fog_code(buffer, gl_info, args->fog);
 
+    shader_glsl_generate_alpha_test(buffer, gl_info, args->alpha_func);
+
     shader_addline(buffer, "}\n");
 
     TRACE("Compiling shader object %u.\n", shader_id);
@@ -6695,6 +6748,12 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
     shader_addline(buffer, "    float scale;\n");
     shader_addline(buffer, "} ffp_fog;\n");
 
+    if (settings->alpha_func != WINED3D_CMP_ALWAYS)
+    {
+        shader_addline(buffer, "uniform bool alpha_test;\n");
+        shader_addline(buffer, "uniform float alpha_ref;\n");
+    }
+
     if (legacy_context)
     {
         shader_addline(buffer, "vec4 ffp_varying_diffuse;\n");
@@ -6949,6 +7008,8 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
 
     shader_glsl_generate_fog_code(buffer, gl_info, settings->fog);
 
+    shader_glsl_generate_alpha_test(buffer, gl_info, settings->alpha_func);
+
     shader_addline(buffer, "}\n");
 
     shader_id = GL_EXTCALL(glCreateShader(GL_FRAGMENT_SHADER));
@@ -7133,6 +7194,9 @@ static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info *
     ps->fog_end_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_fog.end"));
     ps->fog_scale_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_fog.scale"));
 
+    ps->alpha_test_location = GL_EXTCALL(glGetUniformLocation(program_id, "alpha_test"));
+    ps->alpha_ref_location = GL_EXTCALL(glGetUniformLocation(program_id, "alpha_ref"));
+
     ps->np2_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "ps_samplerNP2Fixup"));
     ps->ycorrection_location = GL_EXTCALL(glGetUniformLocation(program_id, "ycorrection"));
     ps->color_key_location = GL_EXTCALL(glGetUniformLocation(program_id, "color_key"));
@@ -7480,6 +7544,8 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
 
         if (entry->ps.fog_color_location != -1)
             entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_FOG;
+        if (entry->ps.alpha_test_location != -1)
+            entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_ALPHA_TEST;
         if (entry->ps.np2_fixup_location != -1)
             entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_NP2_FIXUP;
         if (entry->ps.color_key_location != -1)
@@ -8934,34 +9000,46 @@ static void glsl_fragment_pipe_invalidate_constants(struct wined3d_context *cont
     context->constant_update_mask |= WINED3D_SHADER_CONST_FFP_PS;
 }
 
-static void glsl_fragment_pipe_alpha_test(struct wined3d_context *context,
+static void glsl_fragment_pipe_core_alpha_func(struct wined3d_context *context,
+        const struct wined3d_state *state, DWORD state_id)
+{
+    context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL;
+}
+
+static void glsl_fragment_pipe_alpha_func(struct wined3d_context *context,
         const struct wined3d_state *state, DWORD state_id)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
-    int glParm;
-    float ref;
+    GLint func = wined3d_gl_compare_func(state->render_states[WINED3D_RS_ALPHAFUNC]);
+    float ref = state->render_states[WINED3D_RS_ALPHAREF] / 255.0f;
 
-    TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id);
+    if (func)
+    {
+        gl_info->gl_ops.gl.p_glAlphaFunc(func, ref);
+        checkGLcall("glAlphaFunc");
+    }
+}
+
+static void glsl_fragment_pipe_core_alpha_test(struct wined3d_context *context,
+        const struct wined3d_state *state, DWORD state_id)
+{
+    context->constant_update_mask |= WINED3D_SHADER_CONST_PS_ALPHA_TEST;
+}
+
+static void glsl_fragment_pipe_alpha_test(struct wined3d_context *context,
+        const struct wined3d_state *state, DWORD state_id)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
 
     if (state->render_states[WINED3D_RS_ALPHATESTENABLE])
     {
         gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
-        checkGLcall("glEnable GL_ALPHA_TEST");
+        checkGLcall("glEnable(GL_ALPHA_TEST)");
     }
     else
     {
         gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
-        checkGLcall("glDisable GL_ALPHA_TEST");
-        return;
-    }
-
-    ref = ((float)state->render_states[WINED3D_RS_ALPHAREF]) / 255.0f;
-    glParm = wined3d_gl_compare_func(state->render_states[WINED3D_RS_ALPHAFUNC]);
-
-    if (glParm)
-    {
-        gl_info->gl_ops.gl.p_glAlphaFunc(glParm, ref);
-        checkGLcall("glAlphaFunc");
+        checkGLcall("glDisable(GL_ALPHA_TEST)");
     }
 }
 
@@ -9055,9 +9133,12 @@ static const struct StateEntryTemplate glsl_fragment_pipe_state_template[] =
     {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG0),             {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL),                    NULL                                   }, WINED3D_GL_EXT_NONE },
     {STATE_TEXTURESTAGE(7, WINED3D_TSS_RESULT_ARG),             {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL),                    NULL                                   }, WINED3D_GL_EXT_NONE },
     {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL),                   {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL),                    glsl_fragment_pipe_shader              }, WINED3D_GL_EXT_NONE },
-    {STATE_RENDER(WINED3D_RS_ALPHAFUNC),                        {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                   NULL                                   }, WINED3D_GL_EXT_NONE },
+    {STATE_RENDER(WINED3D_RS_ALPHAFUNC),                        {STATE_RENDER(WINED3D_RS_ALPHAFUNC),                         glsl_fragment_pipe_alpha_func          }, WINED3D_GL_LEGACY_CONTEXT},
+    {STATE_RENDER(WINED3D_RS_ALPHAFUNC),                        {STATE_RENDER(WINED3D_RS_ALPHAFUNC),                         glsl_fragment_pipe_core_alpha_func     }, WINED3D_GL_EXT_NONE },
+    {STATE_RENDER(WINED3D_RS_ALPHAREF),                         {STATE_RENDER(WINED3D_RS_ALPHAFUNC),                         NULL                                   }, WINED3D_GL_LEGACY_CONTEXT},
     {STATE_RENDER(WINED3D_RS_ALPHAREF),                         {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                   NULL                                   }, WINED3D_GL_EXT_NONE },
-    {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                  {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                   glsl_fragment_pipe_alpha_test          }, WINED3D_GL_EXT_NONE },
+    {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                  {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                   glsl_fragment_pipe_alpha_test          }, WINED3D_GL_LEGACY_CONTEXT},
+    {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                  {STATE_RENDER(WINED3D_RS_ALPHATESTENABLE),                   glsl_fragment_pipe_core_alpha_test     }, WINED3D_GL_EXT_NONE },
     {STATE_RENDER(WINED3D_RS_COLORKEYENABLE),                   {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL),                    NULL                                   }, WINED3D_GL_EXT_NONE },
     {STATE_COLOR_KEY,                                           { STATE_COLOR_KEY,                                           glsl_fragment_pipe_color_key           }, WINED3D_GL_EXT_NONE },
     {STATE_RENDER(WINED3D_RS_FOGENABLE),                        {STATE_RENDER(WINED3D_RS_FOGENABLE),                         glsl_fragment_pipe_fog                 }, WINED3D_GL_EXT_NONE },
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index 0aa77b0..4445292 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -2957,6 +2957,11 @@ void find_ps_compile_args(const struct wined3d_state *state, const struct wined3
     args->pointsprite = state->render_states[WINED3D_RS_POINTSPRITEENABLE]
             && state->gl_primitive_type == GL_POINTS;
 
+    if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
+        args->alpha_func = WINED3D_CMP_ALWAYS;
+    else
+        args->alpha_func = wined3d_sanitize_cmp_func(state->render_states[WINED3D_RS_ALPHAFUNC]);
+
     if (d3d_info->emulated_flatshading)
         args->flatshading = state->render_states[WINED3D_RS_SHADEMODE] == WINED3D_SHADE_FLAT;
 }
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index efda6f2..5159c66 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -5093,6 +5093,11 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d
     settings->pointsprite = state->render_states[WINED3D_RS_POINTSPRITEENABLE]
             && state->gl_primitive_type == GL_POINTS;
 
+    if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
+        settings->alpha_func = WINED3D_CMP_ALWAYS;
+    else
+        settings->alpha_func = wined3d_sanitize_cmp_func(state->render_states[WINED3D_RS_ALPHAFUNC]);
+
     if (d3d_info->emulated_flatshading)
         settings->flatshading = state->render_states[WINED3D_RS_SHADEMODE] == WINED3D_SHADE_FLAT;
     else
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b86c460..259c632 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -197,6 +197,13 @@ extern const GLenum magLookup[WINED3D_TEXF_LINEAR + 1] DECLSPEC_HIDDEN;
 
 GLenum wined3d_gl_compare_func(enum wined3d_cmp_func f) DECLSPEC_HIDDEN;
 
+static inline enum wined3d_cmp_func wined3d_sanitize_cmp_func(enum wined3d_cmp_func func)
+{
+    if (func < WINED3D_CMP_NEVER || func > WINED3D_CMP_ALWAYS)
+        return WINED3D_CMP_ALWAYS;
+    return func;
+}
+
 static inline GLenum wined3d_gl_mag_filter(enum wined3d_texture_filter_type mag_filter)
 {
     return magLookup[mag_filter];
@@ -325,16 +332,17 @@ enum wined3d_shader_resource_type
 #define WINED3D_SHADER_CONST_PS_B            0x00000080
 #define WINED3D_SHADER_CONST_PS_BUMP_ENV     0x00000100
 #define WINED3D_SHADER_CONST_PS_FOG          0x00000200
-#define WINED3D_SHADER_CONST_PS_Y_CORR       0x00000400
-#define WINED3D_SHADER_CONST_PS_NP2_FIXUP    0x00000800
-#define WINED3D_SHADER_CONST_FFP_MODELVIEW   0x00001000
-#define WINED3D_SHADER_CONST_FFP_VERTEXBLEND 0x00002000
-#define WINED3D_SHADER_CONST_FFP_PROJ        0x00004000
-#define WINED3D_SHADER_CONST_FFP_TEXMATRIX   0x00008000
-#define WINED3D_SHADER_CONST_FFP_MATERIAL    0x00010000
-#define WINED3D_SHADER_CONST_FFP_LIGHTS      0x00020000
-#define WINED3D_SHADER_CONST_FFP_PS          0x00040000
-#define WINED3D_SHADER_CONST_FFP_COLOR_KEY   0x00080000
+#define WINED3D_SHADER_CONST_PS_ALPHA_TEST   0x00000400
+#define WINED3D_SHADER_CONST_PS_Y_CORR       0x00000800
+#define WINED3D_SHADER_CONST_PS_NP2_FIXUP    0x00001000
+#define WINED3D_SHADER_CONST_FFP_MODELVIEW   0x00002000
+#define WINED3D_SHADER_CONST_FFP_VERTEXBLEND 0x00004000
+#define WINED3D_SHADER_CONST_FFP_PROJ        0x00008000
+#define WINED3D_SHADER_CONST_FFP_TEXMATRIX   0x00010000
+#define WINED3D_SHADER_CONST_FFP_MATERIAL    0x00020000
+#define WINED3D_SHADER_CONST_FFP_LIGHTS      0x00040000
+#define WINED3D_SHADER_CONST_FFP_PS          0x00080000
+#define WINED3D_SHADER_CONST_FFP_COLOR_KEY   0x00100000
 
 enum wined3d_shader_register_type
 {
@@ -973,6 +981,7 @@ struct ps_compile_args {
     WORD texcoords_initialized; /* MAX_TEXTURES, 8 */
     BOOL pointsprite;
     BOOL flatshading;
+    enum wined3d_cmp_func alpha_func;
 };
 
 enum fog_src_type {
@@ -2022,6 +2031,7 @@ struct ffp_frag_settings
     unsigned char pointsprite : 1;
     unsigned char flatshading : 1;
     unsigned char padding : 5;
+    enum wined3d_cmp_func alpha_func;
 };
 
 struct ffp_frag_desc
-- 
2.7.3




More information about the wine-patches mailing list