Nikolay Sivov : d3d10/effect: Support stream output declaration when creating geometry shaders.
Alexandre Julliard
julliard at winehq.org
Tue Aug 31 15:40:23 CDT 2021
Module: wine
Branch: master
Commit: 5071836f3e6796814fa561839b1e6e3c44657e8e
URL: https://source.winehq.org/git/wine.git/?a=commit;h=5071836f3e6796814fa561839b1e6e3c44657e8e
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Mon Aug 30 08:06:39 2021 +0300
d3d10/effect: Support stream output declaration when creating geometry shaders.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/d3d10/effect.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 166 insertions(+), 6 deletions(-)
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c
index b5ea0be1554..81745f7f239 100644
--- a/dlls/d3d10/effect.c
+++ b/dlls/d3d10/effect.c
@@ -314,6 +314,32 @@ static const char *debug_d3d10_shader_variable_type(D3D10_SHADER_VARIABLE_TYPE t
#undef WINE_D3D10_TO_STR
+static BOOL d3d_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
+{
+ SIZE_T max_capacity, new_capacity;
+ void *new_elements;
+
+ if (count <= *capacity)
+ return TRUE;
+
+ max_capacity = ~(SIZE_T)0 / size;
+ if (count > max_capacity)
+ return FALSE;
+
+ new_capacity = max(1, *capacity);
+ while (new_capacity < count && new_capacity <= max_capacity / 2)
+ new_capacity *= 2;
+ if (new_capacity < count)
+ new_capacity = count;
+
+ if (!(new_elements = heap_realloc(*elements, new_capacity * size)))
+ return FALSE;
+
+ *elements = new_elements;
+ *capacity = new_capacity;
+ return TRUE;
+}
+
static void read_dword(const char **ptr, DWORD *d)
{
memcpy(d, *ptr, sizeof(*d));
@@ -566,6 +592,127 @@ static HRESULT get_fx10_shader_resources(struct d3d10_effect_variable *v, const
return S_OK;
}
+struct d3d10_effect_so_decl
+{
+ D3D10_SO_DECLARATION_ENTRY *entries;
+ SIZE_T capacity;
+ SIZE_T count;
+ unsigned int stride;
+ char *decl;
+};
+
+static void d3d10_effect_cleanup_so_decl(struct d3d10_effect_so_decl *so_decl)
+{
+ heap_free(so_decl->entries);
+ heap_free(so_decl->decl);
+ memset(so_decl, 0, sizeof(*so_decl));
+}
+
+static HRESULT d3d10_effect_parse_stream_output_declaration(const char *decl,
+ struct d3d10_effect_so_decl *so_decl)
+{
+ static const char * allmask = "xyzw";
+ char *p, *ptr, *end, *next, *mask, *m, *slot;
+ unsigned int len = strlen(decl);
+ D3D10_SO_DECLARATION_ENTRY e;
+
+ memset(so_decl, 0, sizeof(*so_decl));
+
+ if (!(so_decl->decl = heap_alloc(len + 1)))
+ return E_OUTOFMEMORY;
+ memcpy(so_decl->decl, decl, len + 1);
+
+ p = so_decl->decl;
+
+ while (p && *p)
+ {
+ memset(&e, 0, sizeof(e));
+
+ end = strchr(p, ';');
+ next = end ? end + 1 : p + strlen(p);
+
+ len = next - p;
+ if (end) len--;
+
+ /* Remove leading and trailing spaces. */
+ while (len && isspace(*p)) { len--; p++; }
+ while (len && isspace(p[len - 1])) len--;
+
+ p[len] = 0;
+
+ /* Output slot */
+ if ((slot = strchr(p, ':')))
+ {
+ *slot = 0;
+
+ ptr = p;
+ while (*ptr)
+ {
+ if (!isdigit(*ptr))
+ {
+ WARN("Invalid output slot %s.\n", debugstr_a(p));
+ goto failed;
+ }
+ ptr++;
+ }
+
+ e.OutputSlot = atoi(p);
+ p = slot + 1;
+ }
+
+ /* Mask */
+ if ((mask = strchr(p, '.')))
+ {
+ *mask = 0; mask++;
+
+ if (!(m = strstr(allmask, mask)))
+ {
+ WARN("Invalid component mask %s.\n", debugstr_a(mask));
+ goto failed;
+ }
+
+ e.StartComponent = m - allmask;
+ e.ComponentCount = strlen(mask);
+ }
+ else
+ {
+ e.StartComponent = 0;
+ e.ComponentCount = 4;
+ }
+
+ /* Semantic index and name */
+ len = strlen(p);
+ while (isdigit(p[len - 1]))
+ len--;
+
+ if (p[len])
+ {
+ e.SemanticIndex = atoi(&p[len]);
+ p[len] = 0;
+ }
+
+ e.SemanticName = p;
+
+ if (!d3d_array_reserve((void **)&so_decl->entries, &so_decl->capacity, so_decl->count + 1,
+ sizeof(*so_decl->entries)))
+ goto failed;
+
+ so_decl->entries[so_decl->count++] = e;
+
+ if (e.OutputSlot == 0)
+ so_decl->stride += e.ComponentCount * sizeof(float);
+
+ p = next;
+ }
+
+ return S_OK;
+
+failed:
+ d3d10_effect_cleanup_so_decl(so_decl);
+
+ return E_FAIL;
+}
+
static HRESULT parse_fx10_shader(const char *data, size_t data_size, DWORD offset, struct d3d10_effect_variable *v)
{
ID3D10Device *device = v->effect->device;
@@ -628,9 +775,22 @@ static HRESULT parse_fx10_shader(const char *data, size_t data_size, DWORD offse
case D3D10_SVT_GEOMETRYSHADER:
if (v->type->flags & D3D10_EOT_FLAG_GS_SO)
- FIXME("Create geometry shader with stream output.\n");
- hr = ID3D10Device_CreateGeometryShader(device, ptr, dxbc_size, &v->u.shader.shader.gs);
- if (FAILED(hr)) return hr;
+ {
+ struct d3d10_effect_so_decl so_decl;
+
+ if (FAILED(hr = d3d10_effect_parse_stream_output_declaration(v->u.shader.stream_output_declaration, &so_decl)))
+ {
+ WARN("Failed to parse stream output declaration, hr %#x.\n", hr);
+ break;
+ }
+
+ hr = ID3D10Device_CreateGeometryShaderWithStreamOutput(device, ptr, dxbc_size,
+ so_decl.entries, so_decl.count, so_decl.stride, &v->u.shader.shader.gs);
+
+ d3d10_effect_cleanup_so_decl(&so_decl);
+ }
+ else
+ hr = ID3D10Device_CreateGeometryShader(device, ptr, dxbc_size, &v->u.shader.shader.gs);
break;
default:
@@ -1996,9 +2156,6 @@ static HRESULT parse_fx10_local_variable(const char *data, size_t data_size,
read_dword(ptr, &shader_offset);
TRACE("Shader offset: %#x.\n", shader_offset);
- if (FAILED(hr = parse_fx10_shader(data, data_size, shader_offset, var)))
- return hr;
-
if (v->type->flags & D3D10_EOT_FLAG_GS_SO)
{
read_dword(ptr, &sodecl_offset);
@@ -2013,6 +2170,9 @@ static HRESULT parse_fx10_local_variable(const char *data, size_t data_size,
TRACE("Stream output declaration: %s.\n", debugstr_a(var->u.shader.stream_output_declaration));
}
+
+ if (FAILED(hr = parse_fx10_shader(data, data_size, shader_offset, var)))
+ return hr;
}
break;
More information about the wine-cvs
mailing list