[PATCH 1/5] wined3d: Implement WINED3DSIH_SAMPLE in the GLSL shader backend.

Henri Verbeet hverbeet at codeweavers.com
Mon Jan 19 06:44:08 CST 2015


---
 dlls/wined3d/context.c         |   74 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/cs.c              |    3 ++
 dlls/wined3d/glsl_shader.c     |   72 +++++++++++++++++++++++++++++---------
 dlls/wined3d/shader.c          |   56 ++++++++++++++++++++++++++++++
 dlls/wined3d/state.c           |   10 ++++++
 dlls/wined3d/utils.c           |    2 ++
 dlls/wined3d/wined3d_private.h |   23 +++++++++++--
 7 files changed, 222 insertions(+), 18 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 851eb9a..d3f7629 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -2957,6 +2957,74 @@ static void context_preload_textures(struct wined3d_context *context, const stru
     }
 }
 
+static void context_bind_shader_resources(struct wined3d_context *context, const struct wined3d_state *state)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    struct wined3d_shader_sampler_map_entry *entry;
+    struct wined3d_shader_resource_view *view;
+    struct wined3d_sampler *sampler;
+    struct wined3d_texture *texture;
+    struct wined3d_shader *shader;
+    unsigned int i, j, count;
+
+    static const struct
+    {
+        enum wined3d_shader_type type;
+        unsigned int base_idx;
+        unsigned int count;
+    }
+    shader_types[] =
+    {
+        {WINED3D_SHADER_TYPE_PIXEL,     0,                      MAX_FRAGMENT_SAMPLERS},
+        {WINED3D_SHADER_TYPE_VERTEX,    MAX_FRAGMENT_SAMPLERS,  MAX_VERTEX_SAMPLERS},
+    };
+
+    for (i = 0; i < ARRAY_SIZE(shader_types); ++i)
+    {
+        if (!(shader = state->shader[shader_types[i].type]))
+            continue;
+
+        count = shader->reg_maps.sampler_map.count;
+        if (count > shader_types[i].count)
+        {
+            FIXME("Shader %p needs %u samplers, but only %u are supported.\n",
+                    shader, count, shader_types[i].count);
+            count = shader_types[i].count;
+        }
+
+        for (j = 0; j < count; ++j)
+        {
+            entry = &shader->reg_maps.sampler_map.entries[j];
+
+            if (!(view = state->shader_resource_view[shader_types[i].type][entry->resource_idx]))
+            {
+                WARN("No resource view bound at index %u, %u.\n", shader_types[i].type, entry->resource_idx);
+                continue;
+            }
+
+            if (view->resource->type == WINED3D_RTYPE_BUFFER)
+            {
+                FIXME("Buffer shader resources not supported.\n");
+                continue;
+            }
+
+            if (!(sampler = state->sampler[shader_types[i].type][entry->sampler_idx]))
+            {
+                WARN("No sampler object bound at index %u, %u.\n", shader_types[i].type, entry->sampler_idx);
+                continue;
+            }
+
+            texture = wined3d_texture_from_resource(view->resource);
+            wined3d_texture_load(texture, context, FALSE);
+            context_active_texture(context, gl_info, shader_types[i].base_idx + entry->bind_idx);
+            wined3d_texture_bind(texture, context, FALSE);
+
+            GL_EXTCALL(glBindSampler(shader_types[i].base_idx + entry->bind_idx, sampler->name));
+            checkGLcall("glBindSampler");
+        }
+    }
+}
+
 /* Context activation is done by the caller. */
 BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device)
 {
@@ -3030,6 +3098,12 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de
         context->constant_update_mask = 0;
     }
 
+    if (context->update_shader_resource_bindings)
+    {
+        context_bind_shader_resources(context, state);
+        context->update_shader_resource_bindings = 0;
+    }
+
     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
     {
         context_check_fbo_status(context, GL_FRAMEBUFFER);
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index b8a32e5..4a04b00 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -704,6 +704,7 @@ static void wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, cons
     const struct wined3d_cs_set_shader_resource_view *op = data;
 
     cs->state.shader_resource_view[op->type][op->view_idx] = op->view;
+    device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
 }
 
 void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type,
@@ -725,6 +726,7 @@ static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
     const struct wined3d_cs_set_sampler *op = data;
 
     cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
+    device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
 }
 
 void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
@@ -747,6 +749,7 @@ static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
 
     cs->state.shader[op->type] = op->shader;
     device_invalidate_state(cs->device, STATE_SHADER(op->type));
+    device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
 }
 
 void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index a829651..efae51e 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -1058,59 +1058,68 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
     }
 
     /* Declare texture samplers */
-    for (i = 0; i < shader->limits->sampler; ++i)
+    for (i = 0; i < reg_maps->sampler_map.count; ++i)
     {
+        struct wined3d_shader_sampler_map_entry *entry;
         BOOL shadow_sampler, tex_rect;
+        const char *sampler_type;
 
-        if (!reg_maps->resource_info[i].type)
+        entry = &reg_maps->sampler_map.entries[i];
+
+        if (entry->resource_idx >= ARRAY_SIZE(reg_maps->resource_info))
+        {
+            ERR("Invalid resource index %u.\n", entry->resource_idx);
             continue;
+        }
 
-        shadow_sampler = version->type == WINED3D_SHADER_TYPE_PIXEL && (ps_args->shadow & (1 << i));
-        switch (reg_maps->resource_info[i].type)
+        shadow_sampler = version->type == WINED3D_SHADER_TYPE_PIXEL && (ps_args->shadow & (1 << entry->sampler_idx));
+        switch (reg_maps->resource_info[entry->resource_idx].type)
         {
             case WINED3D_SHADER_RESOURCE_TEXTURE_1D:
                 if (shadow_sampler)
-                    shader_addline(buffer, "uniform sampler1DShadow %s_sampler%u;\n", prefix, i);
+                    sampler_type = "sampler1DShadow";
                 else
-                    shader_addline(buffer, "uniform sampler1D %s_sampler%u;\n", prefix, i);
+                    sampler_type = "sampler1D";
                 break;
 
             case WINED3D_SHADER_RESOURCE_TEXTURE_2D:
-                tex_rect = version->type == WINED3D_SHADER_TYPE_PIXEL && (ps_args->np2_fixup & (1 << i));
-                tex_rect = tex_rect && gl_info->supported[ARB_TEXTURE_RECTANGLE];
+                tex_rect = version->type == WINED3D_SHADER_TYPE_PIXEL
+                        && (ps_args->np2_fixup & (1 << entry->resource_idx))
+                        && gl_info->supported[ARB_TEXTURE_RECTANGLE];
                 if (shadow_sampler)
                 {
                     if (tex_rect)
-                        shader_addline(buffer, "uniform sampler2DRectShadow %s_sampler%u;\n", prefix, i);
+                        sampler_type = "sampler2DRectShadow";
                     else
-                        shader_addline(buffer, "uniform sampler2DShadow %s_sampler%u;\n", prefix, i);
+                        sampler_type = "sampler2DShadow";
                 }
                 else
                 {
                     if (tex_rect)
-                        shader_addline(buffer, "uniform sampler2DRect %s_sampler%u;\n", prefix, i);
+                        sampler_type = "sampler2DRect";
                     else
-                        shader_addline(buffer, "uniform sampler2D %s_sampler%u;\n", prefix, i);
+                        sampler_type = "sampler2D";
                 }
                 break;
 
             case WINED3D_SHADER_RESOURCE_TEXTURE_3D:
                 if (shadow_sampler)
                     FIXME("Unsupported 3D shadow sampler.\n");
-                shader_addline(buffer, "uniform sampler3D %s_sampler%u;\n", prefix, i);
+                sampler_type = "sampler3D";
                 break;
 
             case WINED3D_SHADER_RESOURCE_TEXTURE_CUBE:
                 if (shadow_sampler)
                     FIXME("Unsupported Cube shadow sampler.\n");
-                shader_addline(buffer, "uniform samplerCube %s_sampler%u;\n", prefix, i);
+                sampler_type = "samplerCube";
                 break;
 
             default:
-                shader_addline(buffer, "uniform unsupported_sampler %s_sampler%u;\n", prefix, i);
+                sampler_type = "unsupported_sampler";
                 FIXME("Unhandled resource type %#x.\n", reg_maps->resource_info[i].type);
                 break;
         }
+        shader_addline(buffer, "uniform %s %s_sampler%u;\n", sampler_type, prefix, entry->bind_idx);
     }
 
     /* Declare uniforms for NP2 texcoord fixup:
@@ -3611,6 +3620,37 @@ static void shader_glsl_texldl(const struct wined3d_shader_instruction *ins)
             "%s", coord_param.param_str);
 }
 
+static unsigned int shader_glsl_find_sampler(const struct wined3d_shader_sampler_map *sampler_map,
+        unsigned int resource_idx, unsigned int sampler_idx)
+{
+    struct wined3d_shader_sampler_map_entry *entries = sampler_map->entries;
+    unsigned int i;
+
+    for (i = 0; i < sampler_map->count; ++i)
+    {
+        if (entries[i].resource_idx == resource_idx && entries[i].sampler_idx == sampler_idx)
+            return entries[i].bind_idx;
+    }
+
+    ERR("No GLSL sampler found for resource %u / sampler %u.\n", resource_idx, sampler_idx);
+
+    return ~0u;
+}
+
+static void shader_glsl_sample(const struct wined3d_shader_instruction *ins)
+{
+    struct glsl_sample_function sample_function;
+    struct glsl_src_param coord_param;
+    unsigned int sampler_idx;
+
+    shader_glsl_get_sample_function(ins->ctx, ins->src[1].reg.idx[0].offset, 0, &sample_function);
+    shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask, &coord_param);
+    sampler_idx = shader_glsl_find_sampler(&ins->ctx->reg_maps->sampler_map,
+            ins->src[1].reg.idx[0].offset, ins->src[2].reg.idx[0].offset);
+    shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE,
+            NULL, NULL, NULL, "%s", coord_param.param_str);
+}
+
 static void shader_glsl_texcoord(const struct wined3d_shader_instruction *ins)
 {
     /* FIXME: Make this work for more than just 2D textures */
@@ -6736,7 +6776,7 @@ static const SHADER_HANDLER shader_glsl_instruction_handler_table[WINED3DSIH_TAB
     /* WINED3DSIH_RET                   */ shader_glsl_ret,
     /* WINED3DSIH_ROUND_NI              */ shader_glsl_map2gl,
     /* WINED3DSIH_RSQ                   */ shader_glsl_scalar_op,
-    /* WINED3DSIH_SAMPLE                */ NULL,
+    /* WINED3DSIH_SAMPLE                */ shader_glsl_sample,
     /* WINED3DSIH_SAMPLE_GRAD           */ NULL,
     /* WINED3DSIH_SAMPLE_LOD            */ NULL,
     /* WINED3DSIH_SETP                  */ NULL,
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index 6531803..7218290 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -570,6 +570,51 @@ static BOOL shader_record_register_usage(struct wined3d_shader *shader, struct w
     return TRUE;
 }
 
+static void shader_record_sample(struct wined3d_shader_reg_maps *reg_maps,
+        unsigned int resource_idx, unsigned int sampler_idx, unsigned int bind_idx)
+{
+    struct wined3d_shader_sampler_map_entry *entries, *entry;
+    struct wined3d_shader_sampler_map *map;
+    unsigned int i;
+
+    map = &reg_maps->sampler_map;
+    entries = map->entries;
+    for (i = 0; i < map->count; ++i)
+    {
+        if (entries[i].resource_idx == resource_idx && entries[i].sampler_idx == sampler_idx)
+            return;
+    }
+
+    if (!map->size)
+    {
+        if (!(entries = HeapAlloc(GetProcessHeap(), 0, sizeof(*entries) * 4)))
+        {
+            ERR("Failed to allocate sampler map entries.\n");
+            return;
+        }
+        map->size = 4;
+        map->entries = entries;
+    }
+    else if (map->count == map->size)
+    {
+        size_t new_size = map->size * 2;
+
+        if (sizeof(*entries) * new_size <= sizeof(*entries) * map->size
+                || !(entries = HeapReAlloc(GetProcessHeap(), 0, entries, sizeof(*entries) * new_size)))
+        {
+            ERR("Failed to resize sampler map entries.\n");
+            return;
+        }
+        map->size = new_size;
+        map->entries = entries;
+    }
+
+    entry = &entries[map->count++];
+    entry->resource_idx = resource_idx;
+    entry->sampler_idx = sampler_idx;
+    entry->bind_idx = bind_idx;
+}
+
 static unsigned int get_instr_extra_regcount(enum WINED3D_SHADER_INSTRUCTION_HANDLER instr, unsigned int param)
 {
     switch (instr)
@@ -663,6 +708,7 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
                     break;
 
                 case WINED3DSPR_SAMPLER:
+                    shader_record_sample(reg_maps, reg_idx, reg_idx, reg_idx);
                 case WINED3DSPR_RESOURCE:
                     if (reg_idx >= ARRAY_SIZE(reg_maps->resource_info))
                     {
@@ -903,6 +949,7 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
                     TRACE("Setting fake 2D resource for 1.x pixelshader.\n");
                     reg_maps->resource_info[reg_idx].type = WINED3D_SHADER_RESOURCE_TEXTURE_2D;
                     reg_maps->resource_info[reg_idx].data_type = WINED3D_DATA_FLOAT;
+                    shader_record_sample(reg_maps, reg_idx, reg_idx, reg_idx);
 
                     /* texbem is only valid with < 1.4 pixel shaders */
                     if (ins.handler_idx == WINED3DSIH_TEXBEM
@@ -939,7 +986,16 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
             }
             else if (ins.handler_idx == WINED3DSIH_ENDLOOP
                     || ins.handler_idx == WINED3DSIH_ENDREP)
+            {
                 --cur_loop_depth;
+            }
+            else if (ins.handler_idx == WINED3DSIH_SAMPLE
+                    || ins.handler_idx == WINED3DSIH_SAMPLE_GRAD
+                    || ins.handler_idx == WINED3DSIH_SAMPLE_LOD)
+            {
+                shader_record_sample(reg_maps, ins.src[1].reg.idx[0].offset,
+                        ins.src[2].reg.idx[0].offset, reg_maps->sampler_map.count);
+            }
 
             if (ins.predicate)
                 if (!shader_record_register_usage(shader, reg_maps, &ins.predicate->reg,
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 3c672db..14de5dd 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -5081,6 +5081,14 @@ static void state_cb_warn(struct wined3d_context *context, const struct wined3d_
     WARN("Constant buffers (%s) no supported.\n", debug_d3dstate(state_id));
 }
 
+static void state_shader_resource_binding(struct wined3d_context *context,
+        const struct wined3d_state *state, DWORD state_id)
+{
+    TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id);
+
+    context->update_shader_resource_bindings = 1;
+}
+
 const struct StateEntryTemplate misc_state_template[] =
 {
     { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX),  { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX),  state_cb_vs,        }, ARB_UNIFORM_BUFFER_OBJECT       },
@@ -5089,6 +5097,7 @@ const struct StateEntryTemplate misc_state_template[] =
     { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),state_cb_warn,      }, WINED3D_GL_EXT_NONE             },
     { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL),   { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL),   state_cb_ps,        }, ARB_UNIFORM_BUFFER_OBJECT       },
     { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL),   { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL),   state_cb_warn,      }, WINED3D_GL_EXT_NONE             },
+    { STATE_SHADER_RESOURCE_BINDING,                      { STATE_SHADER_RESOURCE_BINDING,                      state_shader_resource_binding}, WINED3D_GL_EXT_NONE    },
     { STATE_RENDER(WINED3D_RS_SRCBLEND),                  { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE),          NULL                }, WINED3D_GL_EXT_NONE             },
     { STATE_RENDER(WINED3D_RS_DESTBLEND),                 { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE),          NULL                }, WINED3D_GL_EXT_NONE             },
     { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE),          { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE),          state_blend         }, WINED3D_GL_EXT_NONE             },
@@ -6020,6 +6029,7 @@ static void validate_state_table(struct StateEntry *state_table)
         STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX),
         STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),
         STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL),
+        STATE_SHADER_RESOURCE_BINDING,
         STATE_VIEWPORT,
         STATE_LIGHT_TYPE,
         STATE_SCISSORRECT,
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 6ce07b8..688cf90d 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -2901,6 +2901,8 @@ const char *debug_d3dstate(DWORD state)
         return wine_dbg_sprintf("STATE_SHADER(%s)", debug_shader_type(state - STATE_SHADER(0)));
     if (STATE_IS_CONSTANT_BUFFER(state))
         return wine_dbg_sprintf("STATE_CONSTANT_BUFFER(%s)", debug_shader_type(state - STATE_CONSTANT_BUFFER(0)));
+    if (STATE_IS_SHADER_RESOURCE_BINDING(state))
+        return "STATE_SHADER_RESOURCE_BINDING";
     if (STATE_IS_TRANSFORM(state))
         return wine_dbg_sprintf("STATE_TRANSFORM(%s)", debug_d3dtstype(state - STATE_TRANSFORM(0)));
     if (STATE_IS_STREAMSRC(state))
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9107697..4373805 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -581,6 +581,20 @@ struct wined3d_shader_resource_info
     enum wined3d_data_type data_type;
 };
 
+struct wined3d_shader_sampler_map_entry
+{
+    unsigned int resource_idx;
+    unsigned int sampler_idx;
+    unsigned int bind_idx;
+};
+
+struct wined3d_shader_sampler_map
+{
+    struct wined3d_shader_sampler_map_entry *entries;
+    size_t size;
+    size_t count;
+};
+
 #define WINED3D_SHADER_VERSION(major, minor) (((major) << 8) | (minor))
 
 struct wined3d_shader_reg_maps
@@ -601,6 +615,7 @@ struct wined3d_shader_reg_maps
     UINT cb_sizes[WINED3D_MAX_CBS];
 
     struct wined3d_shader_resource_info resource_info[max(MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS)];
+    struct wined3d_shader_sampler_map sampler_map;
     BYTE bumpmat;                           /* MAX_TEXTURES, 8 */
     BYTE luminanceparams;                   /* MAX_TEXTURES, 8 */
 
@@ -1002,7 +1017,10 @@ DWORD get_flexible_vertex_size(DWORD d3dvtVertexType) DECLSPEC_HIDDEN;
 #define STATE_CONSTANT_BUFFER(a) (STATE_SHADER(WINED3D_SHADER_TYPE_COUNT) + (a))
 #define STATE_IS_CONSTANT_BUFFER(a) ((a) >= STATE_CONSTANT_BUFFER(0) && (a) < STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT))
 
-#define STATE_TRANSFORM(a) (STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT) + (a) - 1)
+#define STATE_SHADER_RESOURCE_BINDING (STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT))
+#define STATE_IS_SHADER_RESOURCE_BINDING(a) ((a) == STATE_SHADER_RESOURCE_BINDING)
+
+#define STATE_TRANSFORM(a) (STATE_SHADER_RESOURCE_BINDING + (a))
 #define STATE_IS_TRANSFORM(a) ((a) >= STATE_TRANSFORM(1) && (a) <= STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(255)))
 
 #define STATE_STREAMSRC (STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(255)) + 1)
@@ -1141,7 +1159,8 @@ struct wined3d_context
     DWORD needs_set : 1;
     DWORD hdc_is_private : 1;
     DWORD hdc_has_format : 1;           /* only meaningful if hdc_is_private */
-    DWORD padding : 16;
+    DWORD update_shader_resource_bindings : 1;
+    DWORD padding : 15;
     DWORD shader_update_mask;
     DWORD constant_update_mask;
     DWORD                   numbered_array_mask;
-- 
1.7.10.4




More information about the wine-patches mailing list