[PATCH 4/7] wined3d: Only store unique stream output descriptions.

Henri Verbeet hverbeet at codeweavers.com
Wed Oct 7 07:57:10 CDT 2020


This allows us to compare them by pointer.

Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/device.c          | 54 ++++++++++++++++++++++++
 dlls/wined3d/glsl_shader.c     | 10 ++---
 dlls/wined3d/shader.c          | 77 +++++++++++++++++++++++++++-------
 dlls/wined3d/shader_spirv.c    | 12 +++---
 dlls/wined3d/wined3d_private.h | 16 +++++--
 5 files changed, 140 insertions(+), 29 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index b077d5317db..cc40125ac95 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -176,6 +176,13 @@ ULONG CDECL wined3d_device_incref(struct wined3d_device *device)
     return refcount;
 }
 
+static void device_free_so_desc(struct wine_rb_entry *entry, void *context)
+{
+    struct wined3d_so_desc_entry *s = WINE_RB_ENTRY_VALUE(entry, struct wined3d_so_desc_entry, entry);
+
+    heap_free(s);
+}
+
 static void device_leftover_sampler(struct wine_rb_entry *entry, void *context)
 {
     struct wined3d_sampler *sampler = WINE_RB_ENTRY_VALUE(entry, struct wined3d_sampler, entry);
@@ -242,6 +249,7 @@ void wined3d_device_cleanup(struct wined3d_device *device)
     wine_rb_destroy(&device->rasterizer_states, device_leftover_rasterizer_state, NULL);
     wine_rb_destroy(&device->blend_states, device_leftover_blend_state, NULL);
     wine_rb_destroy(&device->depth_stencil_states, device_leftover_depth_stencil_state, NULL);
+    wine_rb_destroy(&device->so_descs, device_free_so_desc, NULL);
 
     wined3d_decref(device->wined3d);
     device->wined3d = NULL;
@@ -5686,6 +5694,49 @@ void device_resource_released(struct wined3d_device *device, struct wined3d_reso
     TRACE("Resource released.\n");
 }
 
+static int wined3d_so_desc_compare(const void *key, const struct wine_rb_entry *entry)
+{
+    const struct wined3d_stream_output_desc *desc = &WINE_RB_ENTRY_VALUE(entry,
+            struct wined3d_so_desc_entry, entry)->desc;
+    const struct wined3d_stream_output_desc *k = key;
+    unsigned int i;
+    int ret;
+
+    if ((ret = (k->element_count - desc->element_count)))
+        return ret;
+    if ((ret = (k->buffer_stride_count - desc->buffer_stride_count)))
+        return ret;
+    if ((ret = (k->rasterizer_stream_idx - desc->rasterizer_stream_idx)))
+        return ret;
+
+    for (i = 0; i < k->element_count; ++i)
+    {
+        const struct wined3d_stream_output_element *b = &desc->elements[i];
+        const struct wined3d_stream_output_element *a = &k->elements[i];
+
+        if ((ret = (a->stream_idx - b->stream_idx)))
+            return ret;
+        if ((ret = strcmp(a->semantic_name, b->semantic_name)))
+            return ret;
+        if ((ret = (a->semantic_idx - b->semantic_idx)))
+            return ret;
+        if ((ret = (a->component_idx - b->component_idx)))
+            return ret;
+        if ((ret = (a->component_count - b->component_count)))
+            return ret;
+        if ((ret = (a->output_slot - b->output_slot)))
+            return ret;
+    }
+
+    for (i = 0; i < k->buffer_stride_count; ++i)
+    {
+        if ((ret = (k->buffer_strides[i] - desc->buffer_strides[i])))
+            return ret;
+    }
+
+    return 0;
+}
+
 static int wined3d_sampler_compare(const void *key, const struct wine_rb_entry *entry)
 {
     const struct wined3d_sampler *sampler = WINE_RB_ENTRY_VALUE(entry, struct wined3d_sampler, entry);
@@ -5773,6 +5824,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined
 
     fragment_pipeline = adapter->fragment_pipe;
 
+    wine_rb_init(&device->so_descs, wined3d_so_desc_compare);
     wine_rb_init(&device->samplers, wined3d_sampler_compare);
     wine_rb_init(&device->rasterizer_states, wined3d_rasterizer_state_compare);
     wine_rb_init(&device->blend_states, wined3d_blend_state_compare);
@@ -5788,6 +5840,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined
         wine_rb_destroy(&device->rasterizer_states, NULL, NULL);
         wine_rb_destroy(&device->blend_states, NULL, NULL);
         wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
+        wine_rb_destroy(&device->so_descs, NULL, NULL);
         wined3d_decref(device->wined3d);
         return hr;
     }
@@ -5815,6 +5868,7 @@ err:
     wine_rb_destroy(&device->rasterizer_states, NULL, NULL);
     wine_rb_destroy(&device->blend_states, NULL, NULL);
     wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
+    wine_rb_destroy(&device->so_descs, NULL, NULL);
     wined3d_decref(device->wined3d);
     return hr;
 }
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index cdc36ce77d2..7423b2003a6 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -859,7 +859,7 @@ static BOOL shader_glsl_generate_transform_feedback_varyings(struct wined3d_stri
         const char **varyings, unsigned int *varying_count, char *strings, unsigned int *strings_length,
         GLenum buffer_mode, struct wined3d_shader *shader)
 {
-    const struct wined3d_stream_output_desc *so_desc = &shader->u.gs.so_desc;
+    const struct wined3d_stream_output_desc *so_desc = shader->u.gs.so_desc;
     unsigned int buffer_idx, count, length, highest_output_slot, stride;
     unsigned int i, register_idx, component_idx;
     BOOL have_varyings_to_record = FALSE;
@@ -948,7 +948,7 @@ static BOOL shader_glsl_generate_transform_feedback_varyings(struct wined3d_stri
 static void shader_glsl_init_transform_feedback(const struct wined3d_context_gl *context_gl,
         struct shader_glsl_priv *priv, GLuint program_id, struct wined3d_shader *shader)
 {
-    const struct wined3d_stream_output_desc *so_desc = &shader->u.gs.so_desc;
+    const struct wined3d_stream_output_desc *so_desc = shader->u.gs.so_desc;
     const struct wined3d_gl_info *gl_info = context_gl->gl_info;
     struct wined3d_string_buffer *buffer;
     unsigned int i, count, length;
@@ -956,7 +956,7 @@ static void shader_glsl_init_transform_feedback(const struct wined3d_context_gl
     char *strings;
     GLenum mode;
 
-    if (!so_desc->element_count)
+    if (!so_desc)
         return;
 
     if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
@@ -1005,7 +1005,7 @@ static void shader_glsl_init_transform_feedback(const struct wined3d_context_gl
     if (!shader_glsl_generate_transform_feedback_varyings(buffer, NULL, &count, NULL, &length, mode, shader))
     {
         FIXME("No varyings to record, disabling transform feedback.\n");
-        shader->u.gs.so_desc.element_count = 0;
+        shader->u.gs.so_desc = NULL;
         string_buffer_release(&priv->string_buffers, buffer);
         return;
     }
@@ -7217,7 +7217,7 @@ static GLuint shader_glsl_generate_vs3_rasterizer_input_setup(struct shader_glsl
 static void shader_glsl_generate_stream_output_setup(struct wined3d_string_buffer *buffer,
         const struct wined3d_shader *shader)
 {
-    const struct wined3d_stream_output_desc *so_desc = &shader->u.gs.so_desc;
+    const struct wined3d_stream_output_desc *so_desc = shader->u.gs.so_desc;
     unsigned int i, register_idx, component_idx;
 
     shader_addline(buffer, "out shader_in_out\n{\n");
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index d3921d5a981..8843e6883fc 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -3137,10 +3137,6 @@ static void shader_cleanup(struct wined3d_shader *shader)
         heap_free(shader->u.hs.phases.fork);
         heap_free(shader->u.hs.phases.join);
     }
-    else if (shader->reg_maps.shader_version.type == WINED3D_SHADER_TYPE_GEOMETRY)
-    {
-        heap_free((void *)shader->u.gs.so_desc.elements);
-    }
 
     heap_free(shader->patch_constant_signature.elements);
     heap_free(shader->output_signature.elements);
@@ -3749,13 +3745,67 @@ BOOL shader_get_stream_output_register_info(const struct wined3d_shader *shader,
     return TRUE;
 }
 
+static HRESULT geometry_shader_init_so_desc(struct wined3d_geometry_shader *gs, struct wined3d_device *device,
+        const struct wined3d_stream_output_desc *so_desc)
+{
+    struct wined3d_so_desc_entry *s;
+    struct wine_rb_entry *entry;
+    unsigned int i;
+    size_t size;
+    char *name;
+
+    if ((entry = wine_rb_get(&device->so_descs, so_desc)))
+    {
+        gs->so_desc = &WINE_RB_ENTRY_VALUE(entry, struct wined3d_so_desc_entry, entry)->desc;
+        return WINED3D_OK;
+    }
+
+    size = FIELD_OFFSET(struct wined3d_so_desc_entry, elements[so_desc->element_count]);
+    for (i = 0; i < so_desc->element_count; ++i)
+    {
+        const char *n = so_desc->elements[i].semantic_name;
+
+        if (n)
+            size += strlen(n) + 1;
+    }
+    if (!(s = heap_alloc(size)))
+        return E_OUTOFMEMORY;
+
+    s->desc = *so_desc;
+
+    memcpy(s->elements, so_desc->elements, so_desc->element_count * sizeof(*s->elements));
+    s->desc.elements = s->elements;
+
+    name = (char *)&s->elements[s->desc.element_count];
+    for (i = 0; i < so_desc->element_count; ++i)
+    {
+        struct wined3d_stream_output_element *e = &s->elements[i];
+
+        if (!e->semantic_name)
+            continue;
+
+        size = strlen(e->semantic_name) + 1;
+        memcpy(name, e->semantic_name, size);
+        e->semantic_name = name;
+        name += size;
+    }
+
+    if (wine_rb_put(&device->so_descs, &s->desc, &s->entry) == -1)
+    {
+        heap_free(s);
+        return E_FAIL;
+    }
+    gs->so_desc = &s->desc;
+
+    return WINED3D_OK;
+}
+
 static HRESULT geometry_shader_init_stream_output(struct wined3d_shader *shader,
         const struct wined3d_stream_output_desc *so_desc)
 {
     const struct wined3d_shader_frontend *fe = shader->frontend;
     const struct wined3d_shader_signature_element *output;
     unsigned int i, component_idx, register_idx, mask;
-    struct wined3d_stream_output_element *elements;
     struct wined3d_shader_version shader_version;
     const DWORD *ptr;
     void *fe_data;
@@ -3795,16 +3845,9 @@ static HRESULT geometry_shader_init_stream_output(struct wined3d_shader *shader,
             return hr;
     }
 
-    if (!(elements = heap_calloc(so_desc->element_count, sizeof(*elements))))
-        return E_OUTOFMEMORY;
-
-    shader->u.gs.so_desc = *so_desc;
-    shader->u.gs.so_desc.elements = elements;
-    memcpy(elements, so_desc->elements, so_desc->element_count * sizeof(*elements));
-
     for (i = 0; i < so_desc->element_count; ++i)
     {
-        struct wined3d_stream_output_element *e = &elements[i];
+        const struct wined3d_stream_output_element *e = &so_desc->elements[i];
 
         if (!e->semantic_name)
             continue;
@@ -3816,8 +3859,6 @@ static HRESULT geometry_shader_init_stream_output(struct wined3d_shader *shader,
             return E_INVALIDARG;
         }
 
-        e->semantic_name = output->semantic_name;
-
         mask = ((1u << e->component_count) - 1) << component_idx;
         if ((output->mask & 0xff & mask) != mask)
         {
@@ -3827,6 +3868,12 @@ static HRESULT geometry_shader_init_stream_output(struct wined3d_shader *shader,
         }
     }
 
+    if (FAILED(hr = geometry_shader_init_so_desc(&shader->u.gs, shader->device, so_desc)))
+    {
+        WARN("Failed to initialise stream output description, hr %#x.\n", hr);
+        return hr;
+    }
+
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/shader_spirv.c b/dlls/wined3d/shader_spirv.c
index 974fdab14eb..d729bf5c390 100644
--- a/dlls/wined3d/shader_spirv.c
+++ b/dlls/wined3d/shader_spirv.c
@@ -283,15 +283,17 @@ static void shader_spirv_init_shader_interface_vk(struct wined3d_shader_spirv_sh
     memset(iface, 0, sizeof(*iface));
     iface->vkd3d_interface.type = VKD3D_SHADER_STRUCTURE_TYPE_INTERFACE_INFO;
 
-    if (shader_type == WINED3D_SHADER_TYPE_GEOMETRY && shader->u.gs.so_desc.element_count)
+    if (shader_type == WINED3D_SHADER_TYPE_GEOMETRY && shader->u.gs.so_desc)
     {
+        const struct wined3d_stream_output_desc *so_desc = shader->u.gs.so_desc;
+
         iface->xfb_info.type = VKD3D_SHADER_STRUCTURE_TYPE_TRANSFORM_FEEDBACK_INFO;
         iface->xfb_info.next = NULL;
 
-        iface->xfb_info.elements = (const struct vkd3d_shader_transform_feedback_element *)shader->u.gs.so_desc.elements;
-        iface->xfb_info.element_count = shader->u.gs.so_desc.element_count;
-        iface->xfb_info.buffer_strides = shader->u.gs.so_desc.buffer_strides;
-        iface->xfb_info.buffer_stride_count = shader->u.gs.so_desc.buffer_stride_count;
+        iface->xfb_info.elements = (const struct vkd3d_shader_transform_feedback_element *)so_desc->elements;
+        iface->xfb_info.element_count = so_desc->element_count;
+        iface->xfb_info.buffer_strides = so_desc->buffer_strides;
+        iface->xfb_info.buffer_stride_count = so_desc->buffer_stride_count;
 
         iface->vkd3d_interface.next = &iface->xfb_info;
     }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index a4ab61b186b..778b26a6757 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3671,6 +3671,13 @@ struct wined3d_dummy_textures
  * wined3d_device_create() ignores it. */
 #define WINED3DCREATE_MULTITHREADED 0x00000004
 
+struct wined3d_so_desc_entry
+{
+    struct wine_rb_entry entry;
+    struct wined3d_stream_output_desc desc;
+    struct wined3d_stream_output_element elements[1];
+};
+
 struct wined3d_device
 {
     LONG ref;
@@ -3715,6 +3722,7 @@ struct wined3d_device
 
     struct list             resources; /* a linked list to track resources created by the device */
     struct list             shaders;   /* a linked list to track shaders (pixel and vertex)      */
+    struct wine_rb_tree so_descs;
     struct wine_rb_tree samplers, rasterizer_states, blend_states, depth_stencil_states;
 
     /* Render Target Support */
@@ -5327,7 +5335,7 @@ struct wined3d_geometry_shader
     unsigned int vertices_out;
     unsigned int instance_count;
 
-    struct wined3d_stream_output_desc so_desc;
+    const struct wined3d_stream_output_desc *so_desc;
 };
 
 struct wined3d_pixel_shader
@@ -5723,7 +5731,7 @@ static inline BOOL use_transform_feedback(const struct wined3d_state *state)
 
     if (!(shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]))
         return FALSE;
-    return shader->u.gs.so_desc.element_count;
+    return !!shader->u.gs.so_desc;
 }
 
 static inline void context_apply_state(struct wined3d_context *context,
@@ -5787,8 +5795,8 @@ static inline BOOL can_use_texture_swizzle(const struct wined3d_d3d_info *d3d_in
 
 static inline BOOL is_rasterization_disabled(const struct wined3d_shader *geometry_shader)
 {
-    return geometry_shader
-            && geometry_shader->u.gs.so_desc.rasterizer_stream_idx == WINED3D_NO_RASTERIZER_STREAM;
+    return geometry_shader && geometry_shader->u.gs.so_desc
+            && geometry_shader->u.gs.so_desc->rasterizer_stream_idx == WINED3D_NO_RASTERIZER_STREAM;
 }
 
 static inline DWORD wined3d_extract_bits(const DWORD *bitstream,
-- 
2.20.1




More information about the wine-devel mailing list