[PATCH 6/6] wined3d: Use ARB_clip_control to avoid vertex position fixups.

Matteo Bruni mbruni at codeweavers.com
Mon Oct 3 16:46:56 CDT 2016


Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
FTR, next in the queue there are a couple tests for the derivative
shader instructions.

 dlls/wined3d/arb_program_shader.c | 32 ++++++++++----------
 dlls/wined3d/context.c            | 15 ++++++++--
 dlls/wined3d/directx.c            | 17 +++++++++++
 dlls/wined3d/glsl_shader.c        | 26 +++++++++++-----
 dlls/wined3d/state.c              | 63 +++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/utils.c              | 26 +++++++++-------
 6 files changed, 143 insertions(+), 36 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index f8ecb80..87794ea 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -3264,22 +3264,24 @@ static void vshader_add_footer(struct shader_arb_ctx_priv *priv_ctx,
      * 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x
      * contains 1.0 to allow a mad, but arb vs swizzles are too restricted for that.
      */
-    shader_addline(buffer, "MUL TA, posFixup, TMP_OUT.w;\n");
-    shader_addline(buffer, "ADD TMP_OUT.x, TMP_OUT.x, TA.z;\n");
-    shader_addline(buffer, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, TA.w;\n");
-
-    /* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
-     * and the glsl equivalent
-     */
-    if (need_helper_const(shader_data, reg_maps, gl_info))
-    {
-        const char *two = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_TWO);
-        shader_addline(buffer, "MAD TMP_OUT.z, TMP_OUT.z, %s, -TMP_OUT.w;\n", two);
-    }
-    else
+    if (!gl_info->supported[ARB_CLIP_CONTROL])
     {
-        shader_addline(buffer, "ADD TMP_OUT.z, TMP_OUT.z, TMP_OUT.z;\n");
-        shader_addline(buffer, "ADD TMP_OUT.z, TMP_OUT.z, -TMP_OUT.w;\n");
+        shader_addline(buffer, "MUL TA, posFixup, TMP_OUT.w;\n");
+        shader_addline(buffer, "ADD TMP_OUT.x, TMP_OUT.x, TA.z;\n");
+        shader_addline(buffer, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, TA.w;\n");
+
+        /* Z coord [0;1]->[-1;1] mapping, see comment in
+         * get_projection_matrix() in utils.c. */
+        if (need_helper_const(shader_data, reg_maps, gl_info))
+        {
+            const char *two = arb_get_helper_value(WINED3D_SHADER_TYPE_VERTEX, ARB_TWO);
+            shader_addline(buffer, "MAD TMP_OUT.z, TMP_OUT.z, %s, -TMP_OUT.w;\n", two);
+        }
+        else
+        {
+            shader_addline(buffer, "ADD TMP_OUT.z, TMP_OUT.z, TMP_OUT.z;\n");
+            shader_addline(buffer, "ADD TMP_OUT.z, TMP_OUT.z, -TMP_OUT.w;\n");
+        }
     }
 
     shader_addline(buffer, "MOV result.position, TMP_OUT;\n");
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 8c08310..fa47850 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1971,6 +1971,8 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
     {
         GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
     }
+    if (gl_info->supported[ARB_CLIP_CONTROL])
+        GL_EXTCALL(glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT));
     device->shader_backend->shader_init_context_state(ret);
     ret->shader_update_mask = (1u << WINED3D_SHADER_TYPE_PIXEL)
             | (1u << WINED3D_SHADER_TYPE_VERTEX)
@@ -2261,6 +2263,10 @@ static void SetupForBlit(const struct wined3d_device *device, struct wined3d_con
     gl_info->gl_ops.gl.p_glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)");
     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CLIPPING));
 
+    /* FIXME: Make draw_textured_quad() able to work with a upper left origin. */
+    if (gl_info->supported[ARB_CLIP_CONTROL])
+        GL_EXTCALL(glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE));
+
     set_blit_dimension(gl_info, rt_size.cx, rt_size.cy);
 
     /* Disable shaders */
@@ -2413,11 +2419,14 @@ static void context_set_render_offscreen(struct wined3d_context *context, BOOL o
 {
     if (context->render_offscreen == offscreen) return;
 
-    context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN);
-    context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
     context_invalidate_state(context, STATE_VIEWPORT);
     context_invalidate_state(context, STATE_SCISSORRECT);
-    context_invalidate_state(context, STATE_FRONTFACE);
+    if (!context->gl_info->supported[ARB_CLIP_CONTROL])
+    {
+        context_invalidate_state(context, STATE_FRONTFACE);
+        context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN);
+        context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
+    }
     if (context->gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
         context_invalidate_state(context, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
     context->render_offscreen = offscreen;
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index b03ddf6..5d91981 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -3856,6 +3856,23 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter, DWORD
         if (!counter_bits)
             gl_info->supported[ARB_TIMER_QUERY] = FALSE;
     }
+    if (gl_info->supported[ARB_VIEWPORT_ARRAY])
+    {
+        GLint subpixel_bits;
+
+        gl_info->gl_ops.gl.p_glGetIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &subpixel_bits);
+        TRACE("Viewport supports %d subpixel bits.\n", subpixel_bits);
+        if (!subpixel_bits)
+            gl_info->supported[ARB_VIEWPORT_ARRAY] = FALSE;
+    }
+    if (gl_info->supported[ARB_CLIP_CONTROL] && !gl_info->supported[ARB_VIEWPORT_ARRAY])
+    {
+        /* When using ARB_clip_control we need the float viewport parameters
+         * introduced by ARB_viewport_array to take care of the shifted pixel
+         * coordinates. */
+        TRACE("Disabling ARB_clip_control because ARB_viewport_array is not supported.\n");
+        gl_info->supported[ARB_CLIP_CONTROL] = FALSE;
+    }
     if (!gl_info->supported[ATI_TEXTURE_MIRROR_ONCE] && gl_info->supported[EXT_TEXTURE_MIRROR_CLAMP])
     {
         TRACE(" IMPLIED: ATI_texture_mirror_once support (by EXT_texture_mirror_clamp).\n");
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 72740af..0a7af72 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -4398,7 +4398,8 @@ static void shader_glsl_emit(const struct wined3d_shader_instruction *ins)
     unsigned int stream = ins->handler_idx == WINED3DSIH_EMIT ? 0 : ins->src[0].reg.idx[0].offset;
 
     shader_addline(ins->ctx->buffer, "setup_gs_output(gs_out);\n");
-    shader_glsl_fixup_position(ins->ctx->buffer);
+    if (!ins->ctx->gl_info->supported[ARB_CLIP_CONTROL])
+        shader_glsl_fixup_position(ins->ctx->buffer);
 
     if (!stream)
         shader_addline(ins->ctx->buffer, "EmitVertex();\n");
@@ -6046,7 +6047,7 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context
     /* Base Declarations */
     shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx);
 
-    if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL)
+    if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL && !gl_info->supported[ARB_CLIP_CONTROL])
         shader_addline(buffer, "uniform vec4 pos_fixup;\n");
 
     if (reg_maps->shader_version.major >= 4)
@@ -6093,7 +6094,7 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context
     if (args->point_size && !args->per_vertex_point_size)
         shader_addline(buffer, "gl_PointSize = clamp(ffp_point.size, ffp_point.size_min, ffp_point.size_max);\n");
 
-    if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL)
+    if (args->next_shader_type == WINED3D_SHADER_TYPE_PIXEL && !gl_info->supported[ARB_CLIP_CONTROL])
         shader_glsl_fixup_position(buffer);
 
     shader_addline(buffer, "}\n");
@@ -6127,7 +6128,8 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context
     memset(&priv_ctx, 0, sizeof(priv_ctx));
     priv_ctx.string_buffers = string_buffers;
     shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx);
-    shader_addline(buffer, "uniform vec4 pos_fixup;\n");
+    if (!gl_info->supported[ARB_CLIP_CONTROL])
+        shader_addline(buffer, "uniform vec4 pos_fixup;\n");
     shader_glsl_generate_sm4_rasterizer_input_setup(priv, shader, args->ps_input_count, gl_info);
     shader_addline(buffer, "void main()\n{\n");
     shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx);
@@ -6767,12 +6769,21 @@ static GLuint shader_glsl_generate_ffp_vertex_shader(struct shader_glsl_priv *pr
 
         case WINED3D_FFP_VS_FOG_DEPTH:
             if (settings->ortho_fog)
-                /* Need to undo the [0.0 - 1.0] -> [-1.0 - 1.0] transformation from D3D to GL coordinates. */
-                shader_addline(buffer, "ffp_varying_fogcoord = gl_Position.z * 0.5 + 0.5;\n");
+            {
+                if (gl_info->supported[ARB_CLIP_CONTROL])
+                    shader_addline(buffer, "ffp_varying_fogcoord = gl_Position.z;\n");
+                else
+                    /* Need to undo the [0.0 - 1.0] -> [-1.0 - 1.0] transformation from D3D to GL coordinates. */
+                    shader_addline(buffer, "ffp_varying_fogcoord = gl_Position.z * 0.5 + 0.5;\n");
+            }
             else if (settings->transformed)
+            {
                 shader_addline(buffer, "ffp_varying_fogcoord = ec_pos.z;\n");
+            }
             else
+            {
                 shader_addline(buffer, "ffp_varying_fogcoord = abs(ec_pos.z);\n");
+            }
             break;
 
         default:
@@ -7994,7 +8005,8 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
 
     if (gshader)
     {
-        entry->constant_update_mask |= WINED3D_SHADER_CONST_POS_FIXUP;
+        if (entry->gs.pos_fixup_location != -1)
+            entry->constant_update_mask |= WINED3D_SHADER_CONST_POS_FIXUP;
         shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &gshader->reg_maps);
         shader_glsl_load_icb(gl_info, priv, program_id, &gshader->reg_maps);
     }
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 1b0d018..3b96acc 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -4648,6 +4648,55 @@ static void viewport_miscpart(struct wined3d_context *context, const struct wine
     checkGLcall("glViewport");
 }
 
+static void viewport_miscpart_cc(struct wined3d_context *context,
+        const struct wined3d_state *state, DWORD state_id)
+{
+    const struct wined3d_rendertarget_view *depth_stencil = state->fb->depth_stencil;
+    const struct wined3d_rendertarget_view *target = state->fb->render_targets[0];
+    float pixel_center_offset = context->swapchain->device->wined3d->flags
+            & WINED3D_PIXEL_CENTER_INTEGER ? 0.5f : 0.0f;
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    struct wined3d_viewport vp = state->viewport;
+    unsigned int width, height;
+
+    if (target)
+    {
+        if (vp.width > target->width)
+            vp.width = target->width;
+        if (vp.height > target->height)
+            vp.height = target->height;
+
+        surface_get_drawable_size(wined3d_rendertarget_view_get_surface(target), context, &width, &height);
+    }
+    else if (depth_stencil)
+    {
+        width = depth_stencil->width;
+        height = depth_stencil->height;
+    }
+    else
+    {
+        FIXME("No attachments draw calls not supported.\n");
+        return;
+    }
+
+    gl_info->gl_ops.gl.p_glDepthRange(vp.min_z, vp.max_z);
+    checkGLcall("glDepthRange");
+
+    if (context->render_offscreen)
+    {
+        GL_EXTCALL(glClipControl(GL_UPPER_LEFT, GL_ZERO_TO_ONE));
+        GL_EXTCALL(glViewportIndexedf(0, vp.x + pixel_center_offset, vp.y + pixel_center_offset,
+                vp.width, vp.height));
+    }
+    else
+    {
+        GL_EXTCALL(glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE));
+        GL_EXTCALL(glViewportIndexedf(0, vp.x + pixel_center_offset,
+                (height - (vp.y + vp.height)) + pixel_center_offset, vp.width, vp.height));
+    }
+    checkGLcall("setting clip space and viewport");
+}
+
 static void viewport_vertexpart(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
     if (!isStateDirty(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION)))
@@ -4837,6 +4886,17 @@ static void frontface(struct wined3d_context *context, const struct wined3d_stat
     checkGLcall("glFrontFace");
 }
 
+static void frontface_cc(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    GLenum mode;
+
+    mode = state->rasterizer_state && state->rasterizer_state->desc.front_ccw ? GL_CCW : GL_CW;
+
+    gl_info->gl_ops.gl.p_glFrontFace(mode);
+    checkGLcall("glFrontFace");
+}
+
 static void psorigin_w(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
     static BOOL warned;
@@ -4923,8 +4983,10 @@ const struct StateEntryTemplate misc_state_template[] =
     { STATE_RENDER(WINED3D_RS_BLENDOPALPHA),              { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE),          NULL                }, WINED3D_GL_EXT_NONE             },
     { STATE_STREAMSRC,                                    { STATE_STREAMSRC,                                    streamsrc           }, WINED3D_GL_EXT_NONE             },
     { STATE_VDECL,                                        { STATE_VDECL,                                        vdecl_miscpart      }, WINED3D_GL_EXT_NONE             },
+    { STATE_FRONTFACE,                                    { STATE_FRONTFACE,                                    frontface_cc        }, ARB_CLIP_CONTROL                },
     { STATE_FRONTFACE,                                    { STATE_FRONTFACE,                                    frontface           }, WINED3D_GL_EXT_NONE             },
     { STATE_SCISSORRECT,                                  { STATE_SCISSORRECT,                                  scissorrect         }, WINED3D_GL_EXT_NONE             },
+    { STATE_POINTSPRITECOORDORIGIN,                       { STATE_POINTSPRITECOORDORIGIN,                       state_nop           }, ARB_CLIP_CONTROL                },
     { STATE_POINTSPRITECOORDORIGIN,                       { STATE_POINTSPRITECOORDORIGIN,                       psorigin            }, WINED3D_GL_VERSION_2_0          },
     { STATE_POINTSPRITECOORDORIGIN,                       { STATE_POINTSPRITECOORDORIGIN,                       psorigin_w          }, WINED3D_GL_EXT_NONE             },
 
@@ -4980,6 +5042,7 @@ const struct StateEntryTemplate misc_state_template[] =
     { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LSCALE),  { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LSCALE),  shader_bumpenv      }, WINED3D_GL_EXT_NONE             },
     { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LOFFSET), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_LSCALE),  NULL                }, WINED3D_GL_EXT_NONE             },
 
+    { STATE_VIEWPORT,                                     { STATE_VIEWPORT,                                     viewport_miscpart_cc}, ARB_CLIP_CONTROL                },
     { STATE_VIEWPORT,                                     { STATE_VIEWPORT,                                     viewport_miscpart   }, WINED3D_GL_EXT_NONE             },
     { STATE_INDEXBUFFER,                                  { STATE_INDEXBUFFER,                                  indexbuffer         }, ARB_VERTEX_BUFFER_OBJECT        },
     { STATE_INDEXBUFFER,                                  { STATE_INDEXBUFFER,                                  state_nop           }, WINED3D_GL_EXT_NONE             },
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 0dae0d0..173b028 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -4494,6 +4494,8 @@ void get_modelview_matrix(const struct wined3d_context *context, const struct wi
 void get_projection_matrix(const struct wined3d_context *context, const struct wined3d_state *state,
         struct wined3d_matrix *mat)
 {
+    BOOL clip_control = context->gl_info->supported[ARB_CLIP_CONTROL];
+    BOOL flip = !clip_control && context->render_offscreen;
     float center_offset;
 
     /* There are a couple of additional things we have to take into account
@@ -4511,7 +4513,7 @@ void get_projection_matrix(const struct wined3d_context *context, const struct w
      * driver, but small enough to prevent it from interfering with any
      * anti-aliasing. */
 
-    if (context->swapchain->device->wined3d->flags & WINED3D_PIXEL_CENTER_INTEGER)
+    if (!clip_control && context->swapchain->device->wined3d->flags & WINED3D_PIXEL_CENTER_INTEGER)
         center_offset = 63.0f / 64.0f;
     else
         center_offset = -1.0f / 64.0f;
@@ -4525,14 +4527,14 @@ void get_projection_matrix(const struct wined3d_context *context, const struct w
         float h = state->viewport.height;
         float x_scale = 2.0f / w;
         float x_offset = (center_offset - (2.0f * x) - w) / w;
-        float y_scale = context->render_offscreen ? 2.0f / h : 2.0f / -h;
-        float y_offset = context->render_offscreen
+        float y_scale = flip ? 2.0f / h : 2.0f / -h;
+        float y_offset = flip
                 ? (center_offset - (2.0f * y) - h) / h
                 : (center_offset - (2.0f * y) - h) / -h;
         enum wined3d_depth_buffer_type zenable = state->fb->depth_stencil ?
                 state->render_states[WINED3D_RS_ZENABLE] : WINED3D_ZB_FALSE;
-        float z_scale = zenable ? 2.0f : 0.0f;
-        float z_offset = zenable ? -1.0f : 0.0f;
+        float z_scale = zenable ? clip_control ? 1.0f : 2.0f : 0.0f;
+        float z_offset = zenable ? clip_control ? 0.0f : -1.0f : 0.0f;
         const struct wined3d_matrix projection =
         {
              x_scale,     0.0f,      0.0f, 0.0f,
@@ -4545,17 +4547,19 @@ void get_projection_matrix(const struct wined3d_context *context, const struct w
     }
     else
     {
-        float y_scale = context->render_offscreen ? -1.0f : 1.0f;
+        float y_scale = flip ? -1.0f : 1.0f;
         float x_offset = center_offset / state->viewport.width;
-        float y_offset = context->render_offscreen
+        float y_offset = flip
                 ? center_offset / state->viewport.height
                 : -center_offset / state->viewport.height;
+        float z_scale = clip_control ? 1.0f : 2.0f;
+        float z_offset = clip_control ? 0.0f : -1.0f;
         const struct wined3d_matrix projection =
         {
-                1.0f,     0.0f,  0.0f, 0.0f,
-                0.0f,  y_scale,  0.0f, 0.0f,
-                0.0f,     0.0f,  2.0f, 0.0f,
-            x_offset, y_offset, -1.0f, 1.0f,
+                1.0f,     0.0f,     0.0f, 0.0f,
+                0.0f,  y_scale,     0.0f, 0.0f,
+                0.0f,     0.0f,  z_scale, 0.0f,
+            x_offset, y_offset, z_offset, 1.0f,
         };
 
         multiply_matrix(mat, &projection, &state->transforms[WINED3D_TS_PROJECTION]);
-- 
2.7.3




More information about the wine-patches mailing list