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