[PATCH 06/10] wined3d: Add compute shaders initial support in GLSL backend.

Guillaume Charifi guillaume.charifi at sfr.fr
Sun Jan 29 07:43:37 CST 2017


Signed-off-by: Guillaume Charifi <guillaume.charifi at sfr.fr>
---
 dlls/wined3d/glsl_shader.c     | 261 +++++++++++++++++++++++++++++++----------
 dlls/wined3d/shader.c          |   5 +
 dlls/wined3d/wined3d_private.h |   8 ++
 3 files changed, 213 insertions(+), 61 deletions(-)

diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 9db03a6..b23e4f7 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -207,6 +207,12 @@ struct glsl_ps_program
     const struct ps_np2fixup_info *np2_fixup_info;
 };
 
+struct glsl_cs_program
+{
+    struct list shader_entry;
+    GLuint id;
+};
+
 /* Struct to maintain data about a linked GLSL program */
 struct glsl_shader_prog_link
 {
@@ -214,6 +220,7 @@ struct glsl_shader_prog_link
     struct glsl_vs_program vs;
     struct glsl_gs_program gs;
     struct glsl_ps_program ps;
+    struct glsl_cs_program cs;
     GLuint id;
     DWORD constant_update_mask;
     UINT constant_version;
@@ -224,6 +231,7 @@ struct glsl_program_key
     GLuint vs_id;
     GLuint gs_id;
     GLuint ps_id;
+    GLuint cs_id;
 };
 
 struct shader_glsl_ctx_priv {
@@ -257,6 +265,12 @@ struct glsl_gs_compiled_shader
     GLuint id;
 };
 
+struct glsl_cs_compiled_shader
+{
+    struct cs_compile_args args;
+    GLuint id;
+};
+
 struct glsl_shader_private
 {
     union
@@ -264,6 +278,7 @@ struct glsl_shader_private
         struct glsl_vs_compiled_shader *vs;
         struct glsl_gs_compiled_shader *gs;
         struct glsl_ps_compiled_shader *ps;
+        struct glsl_cs_compiled_shader *cs;
     } gl_shaders;
     UINT num_gl_shaders, shader_array_size;
 };
@@ -570,6 +585,7 @@ static void shader_glsl_load_samplers(const struct wined3d_gl_info *gl_info,
     {
         {WINED3D_SHADER_TYPE_PIXEL,     0,                      MAX_FRAGMENT_SAMPLERS},
         {WINED3D_SHADER_TYPE_VERTEX,    MAX_FRAGMENT_SAMPLERS,  MAX_VERTEX_SAMPLERS},
+        {WINED3D_SHADER_TYPE_COMPUTE,   0,  MAX_COMPUTE_SAMPLERS},
     };
 
     for (i = 0; i < ARRAY_SIZE(sampler_info); ++i)
@@ -2293,6 +2309,10 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
             shader_addline(buffer, "in vs_gs_iface { vec4 gs_in[%u]; } gs_in[];\n", shader->limits->packed_input);
         }
     }
+    else if (version->type == WINED3D_SHADER_TYPE_COMPUTE)
+    {
+        shader_addline(buffer, "layout(local_size_x = %u, local_size_y = %u, local_size_z = %u) in;\n", shader->u.cs.local_size_x, shader->u.cs.local_size_y, shader->u.cs.local_size_z);
+    }
     else if (version->type == WINED3D_SHADER_TYPE_PIXEL)
     {
         if (version->major < 3 || ps_args->vp_mode != vertexshader)
@@ -5648,6 +5668,7 @@ static void add_glsl_program_entry(struct shader_glsl_priv *priv, struct glsl_sh
     key.vs_id = entry->vs.id;
     key.gs_id = entry->gs.id;
     key.ps_id = entry->ps.id;
+    key.cs_id = entry->cs.id;
 
     if (wine_rb_put(&priv->program_lookup, &key, &entry->program_lookup_entry) == -1)
     {
@@ -5656,7 +5677,7 @@ static void add_glsl_program_entry(struct shader_glsl_priv *priv, struct glsl_sh
 }
 
 static struct glsl_shader_prog_link *get_glsl_program_entry(const struct shader_glsl_priv *priv,
-        GLuint vs_id, GLuint gs_id, GLuint ps_id)
+        GLuint vs_id, GLuint gs_id, GLuint ps_id, GLuint cs_id)
 {
     struct wine_rb_entry *entry;
     struct glsl_program_key key;
@@ -5664,6 +5685,7 @@ static struct glsl_shader_prog_link *get_glsl_program_entry(const struct shader_
     key.vs_id = vs_id;
     key.gs_id = gs_id;
     key.ps_id = ps_id;
+    key.cs_id = cs_id;
 
     entry = wine_rb_get(&priv->program_lookup, &key);
     return entry ? WINE_RB_ENTRY_VALUE(entry, struct glsl_shader_prog_link, program_lookup_entry) : NULL;
@@ -5682,6 +5704,8 @@ static void delete_glsl_program_entry(struct shader_glsl_priv *priv, const struc
         list_remove(&entry->gs.shader_entry);
     if (entry->ps.id)
         list_remove(&entry->ps.shader_entry);
+    if (entry->cs.id)
+        list_remove(&entry->cs.shader_entry);
     HeapFree(GetProcessHeap(), 0, entry);
 }
 
@@ -6414,6 +6438,39 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context
     return shader_id;
 }
 
+/* Context activation is done by the caller. */
+static GLuint shader_glsl_generate_compute_shader(const struct wined3d_context *context,
+        struct shader_glsl_priv *priv, const struct wined3d_shader *shader, const struct cs_compile_args *args)
+{
+    struct wined3d_string_buffer_list *string_buffers = &priv->string_buffers;
+    const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps;
+    struct wined3d_string_buffer *buffer = &priv->shader_buffer;
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    const DWORD *function = shader->function;
+    struct shader_glsl_ctx_priv priv_ctx;
+    GLuint shader_id;
+
+    shader_id = GL_EXTCALL(glCreateShader(GL_COMPUTE_SHADER));
+
+    shader_addline(buffer, "%s\n", shader_glsl_get_version_declaration(gl_info, &reg_maps->shader_version));
+
+    shader_glsl_enable_extensions(buffer, gl_info);
+    if (gl_info->supported[ARB_COMPUTE_SHADER])
+        shader_addline(buffer, "#extension GL_ARB_compute_shader : enable\n");
+
+    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, "void main()\n{\n");
+    shader_generate_main(shader, buffer, reg_maps, function, &priv_ctx);
+    shader_addline(buffer, "}\n");
+
+    TRACE("Compiling shader object %u.\n", shader_id);
+    shader_glsl_compile(gl_info, shader_id, buffer->buffer);
+
+    return shader_id;
+}
+
 static void shader_glsl_generate_shader_epilogue(const struct wined3d_shader_context *ctx)
 {
     const struct shader_glsl_ctx_priv *priv = ctx->backend_data;
@@ -6430,6 +6487,8 @@ static void shader_glsl_generate_shader_epilogue(const struct wined3d_shader_con
             break;
         case WINED3D_SHADER_TYPE_GEOMETRY:
             break;
+        case WINED3D_SHADER_TYPE_COMPUTE:
+            break;
         default:
             FIXME("Unhandled shader type %#x.\n", shader->reg_maps.shader_version.type);
             break;
@@ -6651,6 +6710,62 @@ static GLuint find_glsl_geometry_shader(const struct wined3d_context *context,
     return ret;
 }
 
+static GLuint find_glsl_compute_shader(const struct wined3d_context *context,
+        struct shader_glsl_priv *priv, struct wined3d_shader *shader, const struct cs_compile_args *args)
+{
+    struct glsl_cs_compiled_shader *gl_shaders, *new_array;
+    struct glsl_shader_private *shader_data;
+    unsigned int i, new_size;
+    GLuint ret;
+
+    if (!shader->backend_data)
+    {
+        if (!(shader->backend_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*shader_data))))
+        {
+            ERR("Failed to allocate backend data.\n");
+            return 0;
+        }
+    }
+    shader_data = shader->backend_data;
+    gl_shaders = shader_data->gl_shaders.cs;
+
+    for (i = 0; i < shader_data->num_gl_shaders; ++i)
+    {
+        if (!memcmp(&gl_shaders[i].args, args, sizeof(*args)))
+            return gl_shaders[i].id;
+    }
+
+    TRACE("No matching GL shader found for shader %p, compiling a new shader.\n", shader);
+
+    if (shader_data->num_gl_shaders)
+    {
+        new_size = shader_data->shader_array_size + 1;
+        new_array = HeapReAlloc(GetProcessHeap(), 0, shader_data->gl_shaders.cs,
+                new_size * sizeof(*new_array));
+    }
+    else
+    {
+        new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
+        new_size = 1;
+    }
+
+    if (!new_array)
+    {
+        ERR("Failed to allocate GL shaders array.\n");
+        return 0;
+    }
+    shader_data->gl_shaders.cs = new_array;
+    shader_data->shader_array_size = new_size;
+    gl_shaders = new_array;
+
+    string_buffer_clear(&priv->shader_buffer);
+    ret = shader_glsl_generate_compute_shader(context, priv, shader, args);
+    gl_shaders[shader_data->num_gl_shaders].args = *args;
+    gl_shaders[shader_data->num_gl_shaders++].id = ret;
+
+    return ret;
+}
+
 static const char *shader_glsl_ffp_mcs(enum wined3d_material_color_source mcs, const char *material)
 {
     switch (mcs)
@@ -7982,24 +8097,65 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
     struct wined3d_shader *vshader = NULL;
     struct wined3d_shader *gshader = NULL;
     struct wined3d_shader *pshader = NULL;
+    struct wined3d_shader *cshader = NULL;
     GLuint program_id;
     GLuint reorder_shader_id = 0;
     unsigned int i;
     GLuint vs_id = 0;
     GLuint gs_id = 0;
     GLuint ps_id = 0;
+    GLuint cs_id = 0;
     struct list *ps_list, *vs_list;
     WORD attribs_map;
     struct wined3d_string_buffer *tmp_name;
 
-    if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_VERTEX)) && ctx_data->glsl_program)
+    cshader = state->shader[WINED3D_SHADER_TYPE_COMPUTE];
+    if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_COMPUTE))
+            && ctx_data->glsl_program->cs.id)
     {
-        vs_id = ctx_data->glsl_program->vs.id;
-        vs_list = &ctx_data->glsl_program->vs.shader_entry;
+        cs_id = ctx_data->glsl_program->cs.id;
+    }
+    else if (cshader)
+    {
+        struct cs_compile_args args;
 
-        if (use_vs(state))
+        find_cs_compile_args(state, cshader, &args);
+        cs_id = find_glsl_compute_shader(context, priv, cshader, &args);
+    }
+
+    if(!cs_id)
+    {
+        if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_VERTEX)) && ctx_data->glsl_program)
+        {
+            vs_id = ctx_data->glsl_program->vs.id;
+            vs_list = &ctx_data->glsl_program->vs.shader_entry;
+
+            if (use_vs(state))
+                vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX];
+        }
+        else if (use_vs(state))
         {
+            struct vs_compile_args vs_compile_args;
+
             vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX];
+
+            find_vs_compile_args(state, vshader, context->stream_info.swizzle_map, &vs_compile_args, d3d_info);
+            vs_id = find_glsl_vshader(context, priv, vshader, &vs_compile_args);
+            vs_list = &vshader->linked_programs;
+        }
+        else if (priv->vertex_pipe == &glsl_vertex_pipe)
+        {
+            struct glsl_ffp_vertex_shader *ffp_shader;
+            struct wined3d_ffp_vs_settings settings;
+
+            wined3d_ffp_get_vs_settings(context, state, &settings);
+            ffp_shader = shader_glsl_find_ffp_vertex_shader(priv, gl_info, &settings);
+            vs_id = ffp_shader->id;
+            vs_list = &ffp_shader->linked_programs;
+        }
+
+        if (use_vs(state))
+        {
             gshader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY];
 
             if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_GEOMETRY))
@@ -8015,71 +8171,37 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
                 gs_id = find_glsl_geometry_shader(context, priv, gshader, &args);
             }
         }
-    }
-    else if (use_vs(state))
-    {
-        struct vs_compile_args vs_compile_args;
-
-        vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX];
-        gshader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY];
 
-        find_vs_compile_args(state, vshader, context->stream_info.swizzle_map, &vs_compile_args, d3d_info);
-        vs_id = find_glsl_vshader(context, priv, vshader, &vs_compile_args);
-        vs_list = &vshader->linked_programs;
+        if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_PIXEL)) && ctx_data->glsl_program)
+        {
+            ps_id = ctx_data->glsl_program->ps.id;
+            ps_list = &ctx_data->glsl_program->ps.shader_entry;
 
-        if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_GEOMETRY))
-                && ctx_data->glsl_program->gs.id)
+            if (use_ps(state))
+                pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
+        }
+        else if (use_ps(state))
         {
-            gs_id = ctx_data->glsl_program->gs.id;
+            struct ps_compile_args ps_compile_args;
+            pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
+            find_ps_compile_args(state, pshader, context->stream_info.position_transformed, &ps_compile_args, context);
+            ps_id = find_glsl_pshader(context, &priv->shader_buffer, &priv->string_buffers,
+                    pshader, &ps_compile_args, &np2fixup_info);
+            ps_list = &pshader->linked_programs;
         }
-        else if (gshader)
+        else if (priv->fragment_pipe == &glsl_fragment_pipe)
         {
-            struct gs_compile_args gs_compile_args;
+            struct glsl_ffp_fragment_shader *ffp_shader;
+            struct ffp_frag_settings settings;
 
-            find_gs_compile_args(state, gshader, &gs_compile_args);
-            gs_id = find_glsl_geometry_shader(context, priv, gshader, &gs_compile_args);
+            gen_ffp_frag_op(context, state, &settings, FALSE);
+            ffp_shader = shader_glsl_find_ffp_fragment_shader(priv, gl_info, &settings);
+            ps_id = ffp_shader->id;
+            ps_list = &ffp_shader->linked_programs;
         }
     }
-    else if (priv->vertex_pipe == &glsl_vertex_pipe)
-    {
-        struct glsl_ffp_vertex_shader *ffp_shader;
-        struct wined3d_ffp_vs_settings settings;
-
-        wined3d_ffp_get_vs_settings(context, state, &settings);
-        ffp_shader = shader_glsl_find_ffp_vertex_shader(priv, gl_info, &settings);
-        vs_id = ffp_shader->id;
-        vs_list = &ffp_shader->linked_programs;
-    }
 
-    if (!(context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_PIXEL)) && ctx_data->glsl_program)
-    {
-        ps_id = ctx_data->glsl_program->ps.id;
-        ps_list = &ctx_data->glsl_program->ps.shader_entry;
-
-        if (use_ps(state))
-            pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
-    }
-    else if (use_ps(state))
-    {
-        struct ps_compile_args ps_compile_args;
-        pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
-        find_ps_compile_args(state, pshader, context->stream_info.position_transformed, &ps_compile_args, context);
-        ps_id = find_glsl_pshader(context, &priv->shader_buffer, &priv->string_buffers,
-                pshader, &ps_compile_args, &np2fixup_info);
-        ps_list = &pshader->linked_programs;
-    }
-    else if (priv->fragment_pipe == &glsl_fragment_pipe)
-    {
-        struct glsl_ffp_fragment_shader *ffp_shader;
-        struct ffp_frag_settings settings;
-
-        gen_ffp_frag_op(context, state, &settings, FALSE);
-        ffp_shader = shader_glsl_find_ffp_fragment_shader(priv, gl_info, &settings);
-        ps_id = ffp_shader->id;
-        ps_list = &ffp_shader->linked_programs;
-    }
-
-    if ((!vs_id && !gs_id && !ps_id) || (entry = get_glsl_program_entry(priv, vs_id, gs_id, ps_id)))
+    if ((!vs_id && !gs_id && !ps_id && !cs_id) || (entry = get_glsl_program_entry(priv, vs_id, gs_id, ps_id, cs_id)))
     {
         ctx_data->glsl_program = entry;
         return;
@@ -8095,6 +8217,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
     entry->vs.id = vs_id;
     entry->gs.id = gs_id;
     entry->ps.id = ps_id;
+    entry->cs.id = cs_id;
     entry->constant_version = 0;
     entry->ps.np2_fixup_info = np2fixup_info;
     /* Add the hash table entry */
@@ -8200,6 +8323,15 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
         list_add_head(ps_list, &entry->ps.shader_entry);
     }
 
+    if (cshader)
+    {
+        TRACE("Attaching GLSL compute shader object %u to program %u.\n", cs_id, program_id);
+        GL_EXTCALL(glAttachShader(program_id, cs_id));
+        checkGLcall("glAttachShader");
+
+        list_add_head(&cshader->linked_programs, &entry->cs.shader_entry);
+    }
+
     /* Link the program */
     TRACE("Linking GLSL shader program %u.\n", program_id);
     GL_EXTCALL(glLinkProgram(program_id));
@@ -8337,6 +8469,13 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
         if (entry->ps.color_key_location != -1)
             entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_COLOR_KEY;
     }
+
+    if (cshader)
+    {
+        shader_glsl_init_uniform_block_bindings(gl_info, priv, program_id, &cshader->reg_maps);
+        shader_glsl_load_icb(gl_info, priv, program_id, &cshader->reg_maps);
+        shader_glsl_load_images(gl_info, priv, program_id, &cshader->reg_maps);
+    }
 }
 
 /* Context activation is done by the caller. */
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index bc51bad..0bec61a 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -3212,6 +3212,11 @@ void find_gs_compile_args(const struct wined3d_state *state, const struct wined3
             ? state->shader[WINED3D_SHADER_TYPE_PIXEL]->limits->packed_input : 0;
 }
 
+void find_cs_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader,
+        struct cs_compile_args *args)
+{
+}
+
 void find_ps_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader,
         BOOL position_transformed, struct ps_compile_args *args, const struct wined3d_context *context)
 {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b0c623a..fbf85fd 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1193,6 +1193,11 @@ struct gs_compile_args
     unsigned int ps_input_count;
 };
 
+struct cs_compile_args
+{
+    int unused;
+};
+
 struct wined3d_context;
 struct wined3d_state;
 struct fragment_pipeline;
@@ -3590,6 +3595,9 @@ void find_vs_compile_args(const struct wined3d_state *state, const struct wined3
 void find_gs_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader,
         struct gs_compile_args *args) DECLSPEC_HIDDEN;
 
+void find_cs_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader,
+        struct cs_compile_args *args) DECLSPEC_HIDDEN;
+
 void string_buffer_clear(struct wined3d_string_buffer *buffer) DECLSPEC_HIDDEN;
 BOOL string_buffer_init(struct wined3d_string_buffer *buffer) DECLSPEC_HIDDEN;
 void string_buffer_free(struct wined3d_string_buffer *buffer) DECLSPEC_HIDDEN;
-- 
Guillaume Charifi <guillaume.charifi at sfr.fr>




More information about the wine-patches mailing list