This allows us to compare them by pointer.
Signed-off-by: Henri Verbeet hverbeet@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,