Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/effect.c | 86 ++++++++++++++++-------- dlls/d3d10/tests/effect.c | 134 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 186 insertions(+), 34 deletions(-)
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index acc7199138b..d2d0817673d 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -6780,12 +6780,66 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_shader_variable_GetRawValue(
/* ID3D10EffectShaderVariable methods */
+static HRESULT d3d10_get_shader_variable(struct d3d10_effect_variable *v, UINT shader_index, + struct d3d10_effect_shader_variable **s) +{ + unsigned int i; + + if (v->type->element_count) + v = &v->elements[0]; + + if (shader_index == 0) + { + *s = &v->u.shader; + } + else + { + /* Index is used as an offset from this variable. */ + + for (i = 0; i < v->effect->used_shader_count; ++i) + { + if (v == v->effect->used_shaders[i]) break; + } + + if (i + shader_index >= v->effect->used_shader_count) + { + WARN("Invalid shader index %u.\n", shader_index); + return E_FAIL; + } + + *s = &v->effect->used_shaders[i + shader_index]->u.shader; + } + + return S_OK; +} + static HRESULT STDMETHODCALLTYPE d3d10_effect_shader_variable_GetShaderDesc( ID3D10EffectShaderVariable *iface, UINT index, D3D10_EFFECT_SHADER_DESC *desc) { - FIXME("iface %p, index %u, desc %p stub!\n", iface, index, desc); + struct d3d10_effect_variable *v = impl_from_ID3D10EffectShaderVariable(iface); + struct d3d10_effect_shader_variable *s; + D3D10_SHADER_DESC shader_desc; + HRESULT hr;
- return E_NOTIMPL; + FIXME("iface %p, index %u, desc %p semi-stub.\n", iface, index, desc); + + if (FAILED(hr = d3d10_get_shader_variable(v, index, &s))) + return hr; + + memset(desc, 0, sizeof(*desc)); + if (s->input_signature) + desc->pInputSignature = ID3D10Blob_GetBufferPointer(s->input_signature); + desc->SODecl = s->stream_output_declaration; + if (s->reflection) + { + if (SUCCEEDED(hr = s->reflection->lpVtbl->GetDesc(s->reflection, &shader_desc))) + { + desc->NumInputSignatureEntries = shader_desc.InputParameters; + desc->NumOutputSignatureEntries = shader_desc.OutputParameters; + } + } + + return hr; }
static HRESULT STDMETHODCALLTYPE d3d10_effect_shader_variable_GetVertexShader( @@ -6858,32 +6912,10 @@ static HRESULT d3d10_get_shader_variable_signature(struct d3d10_effect_variable UINT shader_index, UINT element_index, BOOL output, D3D10_SIGNATURE_PARAMETER_DESC *desc) { struct d3d10_effect_shader_variable *s; - unsigned int i; - - if (v->type->element_count) - v = &v->elements[0]; - - if (shader_index == 0) - { - s = &v->u.shader; - } - else - { - /* Index is used as an offset from this variable. */ - - for (i = 0; i < v->effect->used_shader_count; ++i) - { - if (v == v->effect->used_shaders[i]) break; - } - - if (i + shader_index >= v->effect->used_shader_count) - { - WARN("This should crash!\n"); - return E_FAIL; - } + HRESULT hr;
- s = &v->effect->used_shaders[i + shader_index]->u.shader; - } + if (FAILED(hr = d3d10_get_shader_variable(v, shader_index, &s))) + return hr;
if (!s->reflection) return D3DERR_INVALIDCALL; diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index 5fcece4695b..3ca1eed0603 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -3642,14 +3642,10 @@ if (0) v = effect->lpVtbl->GetVariableByName(effect, "g_so"); gs = v->lpVtbl->AsShader(v); hr = gs->lpVtbl->GetShaderDesc(gs, 0, &shaderdesc); -todo_wine ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); - if (hr == S_OK) - { - ok(!shaderdesc.IsInline, "Unexpected inline flag.\n"); - ok(!strcmp(shaderdesc.SODecl, "SV_POSITION.x"), "Unexpected stream output declaration %s.\n", - shaderdesc.SODecl); - } + ok(!shaderdesc.IsInline, "Unexpected inline flag.\n"); + ok(!strcmp(shaderdesc.SODecl, "SV_POSITION.x"), "Unexpected stream output declaration %s.\n", + shaderdesc.SODecl);
/* Signature description */ v = effect->lpVtbl->GetVariableByName(effect, "p"); @@ -5865,6 +5861,128 @@ static void test_effect_resource_variable(void) ok(!refcount, "Device has %u references left.\n", refcount); }
+static void test_effect_optimize(void) +{ + D3D10_EFFECT_SHADER_DESC shaderdesc; + ID3D10EffectShaderVariable *gs; + ID3D10EffectVariable *v; + ID3D10Effect* effect; + ID3D10Device *device; + ULONG refcount; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + hr = create_effect(fx_local_shader, 0, device, NULL, &effect); + ok(SUCCEEDED(hr), "Failed to create an effect!\n"); + + v = effect->lpVtbl->GetVariableByName(effect, "g_so"); + + gs = v->lpVtbl->AsShader(v); + hr = gs->lpVtbl->GetShaderDesc(gs, 0, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); + ok(!!shaderdesc.pInputSignature, "Expected input signature.\n"); + ok(!shaderdesc.IsInline, "Unexpected inline flag.\n"); +todo_wine { + ok(!!shaderdesc.pBytecode, "Expected bytecode.\n"); + ok(!!shaderdesc.BytecodeLength, "Unexpected bytecode length.\n"); +} + ok(!strcmp(shaderdesc.SODecl, "SV_POSITION.x"), "Unexpected stream output declaration %s.\n", shaderdesc.SODecl); + ok(!!shaderdesc.NumInputSignatureEntries, "Unexpected input signature count.\n"); + ok(!!shaderdesc.NumOutputSignatureEntries, "Unexpected output signature count.\n"); + + hr = effect->lpVtbl->Optimize(effect); +todo_wine + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = gs->lpVtbl->GetShaderDesc(gs, 0, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); + ok(!!shaderdesc.pInputSignature, "Expected input signature.\n"); + ok(!shaderdesc.IsInline, "Unexpected inline flag.\n"); + ok(!shaderdesc.pBytecode, "Unexpected bytecode.\n"); + ok(!shaderdesc.BytecodeLength, "Unexpected bytecode length.\n"); +todo_wine { + ok(!shaderdesc.SODecl, "Unexpected stream output declaration %p.\n", shaderdesc.SODecl); + ok(!shaderdesc.NumInputSignatureEntries, "Unexpected input signature count.\n"); + ok(!shaderdesc.NumOutputSignatureEntries, "Unexpected output signature count.\n"); +} + effect->lpVtbl->Release(effect); + + refcount = ID3D10Device_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); +} + +static void test_effect_shader_description(void) +{ + D3D10_EFFECT_SHADER_DESC shaderdesc; + ID3D10EffectShaderVariable *s; + ID3D10EffectVariable *v; + ID3D10Effect* effect; + ID3D10Device *device; + ULONG refcount; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + hr = create_effect(fx_local_shader, 0, device, NULL, &effect); + ok(SUCCEEDED(hr), "Failed to create an effect!\n"); + + v = effect->lpVtbl->GetVariableByName(effect, "v0"); + + /* GetShaderDesc() is indexing through all shaders in the effect.*/ + s = v->lpVtbl->AsShader(v); + hr = s->lpVtbl->GetShaderDesc(s, 0, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); + ok(!shaderdesc.BytecodeLength, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); + hr = s->lpVtbl->GetShaderDesc(s, 1, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); + ok(!shaderdesc.BytecodeLength, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); + hr = s->lpVtbl->GetShaderDesc(s, 2, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); + ok(!shaderdesc.BytecodeLength, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); + hr = s->lpVtbl->GetShaderDesc(s, 3, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); +todo_wine + ok(shaderdesc.BytecodeLength == 424, "Unexpected bytecode length %u.\n", + shaderdesc.BytecodeLength); + hr = s->lpVtbl->GetShaderDesc(s, 4, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); +todo_wine + ok(shaderdesc.BytecodeLength == 424, "Unexpected bytecode length %u.\n", + shaderdesc.BytecodeLength); + hr = s->lpVtbl->GetShaderDesc(s, 5, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); +todo_wine + ok(shaderdesc.BytecodeLength == 420, "Unexpected bytecode length %u.\n", + shaderdesc.BytecodeLength); + hr = s->lpVtbl->GetShaderDesc(s, 6, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); +todo_wine + ok(shaderdesc.BytecodeLength == 516, "Unexpected bytecode length %u.\n", + shaderdesc.BytecodeLength); + ok(!shaderdesc.SODecl, "Unexpected SO declaration %p.\n", shaderdesc.SODecl); + hr = s->lpVtbl->GetShaderDesc(s, 7, &shaderdesc); + ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); +todo_wine + ok(shaderdesc.BytecodeLength == 516, "Unexpected bytecode length %u.\n", + shaderdesc.BytecodeLength); + ok(!strcmp(shaderdesc.SODecl, "SV_POSITION.x"), "Unexpected SO declaration %s.\n", + wine_dbgstr_a(shaderdesc.SODecl)); + + effect->lpVtbl->Release(effect); + + refcount = ID3D10Device_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); +} + START_TEST(effect) { test_effect_constant_buffer_type(); @@ -5881,4 +5999,6 @@ START_TEST(effect) test_effect_vector_variable(); test_effect_matrix_variable(); test_effect_resource_variable(); + test_effect_optimize(); + test_effect_shader_description(); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/d3d10_private.h | 1 + dlls/d3d10/effect.c | 12 ++++++++++++ dlls/d3d10/tests/effect.c | 9 +-------- 3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/dlls/d3d10/d3d10_private.h b/dlls/d3d10/d3d10_private.h index 5e406110988..64c445ec07a 100644 --- a/dlls/d3d10/d3d10_private.h +++ b/dlls/d3d10/d3d10_private.h @@ -107,6 +107,7 @@ struct d3d10_effect_shader_variable { ID3D10ShaderReflection *reflection; ID3D10Blob *input_signature; + ID3D10Blob *bytecode; union { ID3D10VertexShader *vs; diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index d2d0817673d..a74dad3763d 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -606,6 +606,11 @@ static HRESULT parse_fx10_shader(const char *data, size_t data_size, DWORD offse
D3DGetInputSignatureBlob(ptr, dxbc_size, &v->u.shader.input_signature);
+ if (FAILED(hr = D3DCreateBlob(dxbc_size, &v->u.shader.bytecode))) + return hr; + + memcpy(ID3D10Blob_GetBufferPointer(v->u.shader.bytecode), ptr, dxbc_size); + if (FAILED(hr = get_fx10_shader_resources(v, ptr, dxbc_size))) return hr;
@@ -2589,6 +2594,8 @@ static void d3d10_effect_shader_variable_destroy(struct d3d10_effect_shader_vari s->reflection->lpVtbl->Release(s->reflection); if (s->input_signature) ID3D10Blob_Release(s->input_signature); + if (s->bytecode) + ID3D10Blob_Release(s->bytecode);
switch (type) { @@ -6830,6 +6837,11 @@ static HRESULT STDMETHODCALLTYPE d3d10_effect_shader_variable_GetShaderDesc( if (s->input_signature) desc->pInputSignature = ID3D10Blob_GetBufferPointer(s->input_signature); desc->SODecl = s->stream_output_declaration; + if (s->bytecode) + { + desc->pBytecode = ID3D10Blob_GetBufferPointer(s->bytecode); + desc->BytecodeLength = ID3D10Blob_GetBufferSize(s->bytecode); + } if (s->reflection) { if (SUCCEEDED(hr = s->reflection->lpVtbl->GetDesc(s->reflection, &shader_desc))) diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index 3ca1eed0603..4eb2e5876de 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -5887,10 +5887,8 @@ static void test_effect_optimize(void) ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); ok(!!shaderdesc.pInputSignature, "Expected input signature.\n"); ok(!shaderdesc.IsInline, "Unexpected inline flag.\n"); -todo_wine { ok(!!shaderdesc.pBytecode, "Expected bytecode.\n"); ok(!!shaderdesc.BytecodeLength, "Unexpected bytecode length.\n"); -} ok(!strcmp(shaderdesc.SODecl, "SV_POSITION.x"), "Unexpected stream output declaration %s.\n", shaderdesc.SODecl); ok(!!shaderdesc.NumInputSignatureEntries, "Unexpected input signature count.\n"); ok(!!shaderdesc.NumOutputSignatureEntries, "Unexpected output signature count.\n"); @@ -5903,9 +5901,9 @@ todo_wine ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); ok(!!shaderdesc.pInputSignature, "Expected input signature.\n"); ok(!shaderdesc.IsInline, "Unexpected inline flag.\n"); +todo_wine { ok(!shaderdesc.pBytecode, "Unexpected bytecode.\n"); ok(!shaderdesc.BytecodeLength, "Unexpected bytecode length.\n"); -todo_wine { ok(!shaderdesc.SODecl, "Unexpected stream output declaration %p.\n", shaderdesc.SODecl); ok(!shaderdesc.NumInputSignatureEntries, "Unexpected input signature count.\n"); ok(!shaderdesc.NumOutputSignatureEntries, "Unexpected output signature count.\n"); @@ -5950,28 +5948,23 @@ static void test_effect_shader_description(void) ok(!shaderdesc.BytecodeLength, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); hr = s->lpVtbl->GetShaderDesc(s, 3, &shaderdesc); ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); -todo_wine ok(shaderdesc.BytecodeLength == 424, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); hr = s->lpVtbl->GetShaderDesc(s, 4, &shaderdesc); ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); -todo_wine ok(shaderdesc.BytecodeLength == 424, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); hr = s->lpVtbl->GetShaderDesc(s, 5, &shaderdesc); ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); -todo_wine ok(shaderdesc.BytecodeLength == 420, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); hr = s->lpVtbl->GetShaderDesc(s, 6, &shaderdesc); ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); -todo_wine ok(shaderdesc.BytecodeLength == 516, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); ok(!shaderdesc.SODecl, "Unexpected SO declaration %p.\n", shaderdesc.SODecl); hr = s->lpVtbl->GetShaderDesc(s, 7, &shaderdesc); ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); -todo_wine ok(shaderdesc.BytecodeLength == 516, "Unexpected bytecode length %u.\n", shaderdesc.BytecodeLength); ok(!strcmp(shaderdesc.SODecl, "SV_POSITION.x"), "Unexpected SO declaration %s.\n",
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/effect.c | 26 ++++++++++++++++++++++++-- dlls/d3d10/tests/effect.c | 4 +--- 2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index a74dad3763d..113125e9cbd 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -3225,9 +3225,31 @@ static struct ID3D10EffectTechnique * STDMETHODCALLTYPE d3d10_effect_GetTechniqu
static HRESULT STDMETHODCALLTYPE d3d10_effect_Optimize(ID3D10Effect *iface) { - FIXME("iface %p stub!\n", iface); + struct d3d10_effect *effect = impl_from_ID3D10Effect(iface); + struct d3d10_effect_variable *v; + unsigned int i;
- return E_NOTIMPL; + FIXME("iface %p semi-stub!\n", iface); + + for (i = 0; i < effect->used_shader_count; ++i) + { + v = effect->used_shaders[i]; + + if (v->u.shader.reflection) + { + v->u.shader.reflection->lpVtbl->Release(v->u.shader.reflection); + v->u.shader.reflection = NULL; + } + if (v->u.shader.bytecode) + { + ID3D10Blob_Release(v->u.shader.bytecode); + v->u.shader.bytecode = NULL; + } + heap_free(v->u.shader.stream_output_declaration); + v->u.shader.stream_output_declaration = NULL; + } + + return S_OK; }
static BOOL STDMETHODCALLTYPE d3d10_effect_IsOptimized(ID3D10Effect *iface) diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index 4eb2e5876de..c1d3fcfbcc9 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -5894,20 +5894,18 @@ static void test_effect_optimize(void) ok(!!shaderdesc.NumOutputSignatureEntries, "Unexpected output signature count.\n");
hr = effect->lpVtbl->Optimize(effect); -todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = gs->lpVtbl->GetShaderDesc(gs, 0, &shaderdesc); ok(hr == S_OK, "Failed to get shader description, hr %#x.\n", hr); ok(!!shaderdesc.pInputSignature, "Expected input signature.\n"); ok(!shaderdesc.IsInline, "Unexpected inline flag.\n"); -todo_wine { ok(!shaderdesc.pBytecode, "Unexpected bytecode.\n"); ok(!shaderdesc.BytecodeLength, "Unexpected bytecode length.\n"); ok(!shaderdesc.SODecl, "Unexpected stream output declaration %p.\n", shaderdesc.SODecl); ok(!shaderdesc.NumInputSignatureEntries, "Unexpected input signature count.\n"); ok(!shaderdesc.NumOutputSignatureEntries, "Unexpected output signature count.\n"); -} + effect->lpVtbl->Release(effect);
refcount = ID3D10Device_Release(device);
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- 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 113125e9cbd..c3c98a0da31 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;
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- v2 (Matteo): Fix "CompilerShader" typo.
dlls/d3d10/tests/effect.c | 86 ++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 24 deletions(-)
diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index da698078f08..70bcf1ea72b 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -2584,14 +2584,20 @@ technique10 Render SetVertexShader( v[1] ); SetGeometryShader( g ); } + pass P8 + { + SetPixelShader( p ); + SetVertexShader( v[1] ); + SetGeometryShader( ConstructGSWithSO(CompileShader( gs_4_0, GS()), "SV_POSITION.y") ); + } } #endif static DWORD fx_local_shader[] = { - 0x43425844, 0x0a74ff0f, 0xea10b516, 0x8be88332, 0x2a273ca7, 0x00000001, 0x0000182d, 0x00000001, - 0x00000024, 0x30315846, 0x00001801, 0xfeff1001, 0x00000000, 0x00000000, 0x00000007, 0x00000000, - 0x00000000, 0x00000000, 0x00000001, 0x00001549, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000e, 0x00000006, 0x00000000, 0x74726556, + 0x43425844, 0xd50d5743, 0xb5236e8f, 0x9a35cd8d, 0x59e3afe1, 0x00000001, 0x00001a92, 0x00000001, + 0x00000024, 0x30315846, 0x00001a66, 0xfeff1001, 0x00000000, 0x00000000, 0x00000007, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00001772, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x00000007, 0x00000000, 0x74726556, 0x68537865, 0x72656461, 0x00000400, 0x00000200, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00307600, 0x65786950, 0x6168536c, 0x00726564, 0x00000030, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000005, 0x47003070, 0x656d6f65, 0x53797274, 0x65646168, @@ -2762,26 +2768,45 @@ static DWORD fx_local_shader[] = 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00001320, 0x00000000, 0x50003550, 0x00a50036, 0x00000000, 0x37500000, 0x0000a500, 0x00000100, - 0x00002d00, 0x00001100, 0x00000000, 0xffffff00, 0x000000ff, 0x00000000, 0x00005800, 0x00003c00, - 0x00000000, 0xffffff00, 0x000000ff, 0x00000000, 0x00008600, 0x00006a00, 0x00000000, 0xffffff00, - 0x000000ff, 0x00000000, 0x0000a500, 0x00008900, 0x00000000, 0xffffff00, 0x0000a7ff, 0x00025300, - 0x00000000, 0x0003ff00, 0x00003c00, 0x00000000, 0xffffff00, 0x000401ff, 0x00000000, 0x0005a900, - 0x00006a00, 0x00000000, 0xffffff00, 0x0005abff, 0x00000000, 0x0007cf00, 0x0007b300, 0x00000000, - 0xffffff00, 0x0007d4ff, 0x0009dc00, 0x00000000, 0x0009ea00, 0x00000800, 0x00000000, 0x0009f100, - 0x00000000, 0x00000000, 0x0009f400, 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000100, - 0x0009f700, 0x00000600, 0x00000000, 0x00000100, 0x000a0300, 0x00000800, 0x00000000, 0x00000100, - 0x000a0f00, 0x000a1b00, 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000100, 0x000a1e00, - 0x00000600, 0x00000000, 0x00000100, 0x000a2a00, 0x00000800, 0x00000000, 0x00000100, 0x000a3600, - 0x000a4200, 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000700, 0x000bed00, 0x00000600, - 0x00000000, 0x00000700, 0x000da100, 0x00000800, 0x00000000, 0x00000700, 0x000fb100, 0x000fb900, - 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000700, 0x00116400, 0x00000600, 0x00000000, - 0x00000700, 0x00131800, 0x00000800, 0x00000000, 0x00000700, 0x00152800, 0x00153000, 0x00000300, - 0x00000000, 0x00000700, 0x00000000, 0x00000200, 0x00005800, 0x00000600, 0x00000000, 0x00000200, - 0x00002d00, 0x00000800, 0x00000000, 0x00000200, 0x00008600, 0x00153300, 0x00000300, 0x00000000, - 0x00000700, 0x00000000, 0x00000200, 0x0003ff00, 0x00000600, 0x00000000, 0x00000300, 0x00153600, - 0x00000800, 0x00000000, 0x00000200, 0x0005a900, 0x00153e00, 0x00000300, 0x00000000, 0x00000700, - 0x00000000, 0x00000200, 0x0003ff00, 0x00000600, 0x00000000, 0x00000300, 0x00154100, 0x00000800, - 0x00000000, 0x00000200, 0x0005a900, 0x00000000, + 0x00385000, 0x000000a5, 0x00000001, 0x00000204, 0x43425844, 0x8e325e23, 0x0774e86e, 0xe636e15f, + 0xd3f67abf, 0x00000001, 0x00000204, 0x00000005, 0x00000034, 0x00000080, 0x000000b4, 0x000000e8, + 0x00000188, 0x46454452, 0x00000044, 0x00000000, 0x00000000, 0x00000000, 0x0000001c, 0x47530400, + 0x00000100, 0x0000001c, 0x7263694d, 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, + 0x6f432072, 0x6c69706d, 0x31207265, 0x00312e30, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, + 0x00000020, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, + 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x00000098, + 0x00020040, 0x00000026, 0x05000061, 0x002010f2, 0x00000003, 0x00000000, 0x00000001, 0x0100185d, + 0x0100285c, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x0200005e, 0x00000003, 0x06000036, + 0x001020f2, 0x00000000, 0x00201e46, 0x00000000, 0x00000000, 0x01000013, 0x06000036, 0x001020f2, + 0x00000000, 0x00201e46, 0x00000001, 0x00000000, 0x01000013, 0x06000036, 0x001020f2, 0x00000000, + 0x00201e46, 0x00000002, 0x00000000, 0x01000013, 0x01000009, 0x0100003e, 0x54415453, 0x00000074, + 0x00000008, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, + 0x00000005, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x505f5653, 0x5449534f, 0x2e4e4f49, + 0x15540079, 0x175c0000, 0x002d0000, 0x00110000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, + 0x00580000, 0x003c0000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00860000, 0x006a0000, + 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00a50000, 0x00890000, 0x00000000, 0xffff0000, + 0x00a7ffff, 0x02530000, 0x00000000, 0x03ff0000, 0x003c0000, 0x00000000, 0xffff0000, 0x0401ffff, + 0x00000000, 0x05a90000, 0x006a0000, 0x00000000, 0xffff0000, 0x05abffff, 0x00000000, 0x07cf0000, + 0x07b30000, 0x00000000, 0xffff0000, 0x07d4ffff, 0x09dc0000, 0x00000000, 0x09ea0000, 0x00090000, + 0x00000000, 0x09f10000, 0x00000000, 0x00000000, 0x09f40000, 0x00030000, 0x00000000, 0x00070000, + 0x00000000, 0x00010000, 0x09f70000, 0x00060000, 0x00000000, 0x00010000, 0x0a030000, 0x00080000, + 0x00000000, 0x00010000, 0x0a0f0000, 0x0a1b0000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, + 0x00010000, 0x0a1e0000, 0x00060000, 0x00000000, 0x00010000, 0x0a2a0000, 0x00080000, 0x00000000, + 0x00010000, 0x0a360000, 0x0a420000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00070000, + 0x0bed0000, 0x00060000, 0x00000000, 0x00070000, 0x0da10000, 0x00080000, 0x00000000, 0x00070000, + 0x0fb10000, 0x0fb90000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00070000, 0x11640000, + 0x00060000, 0x00000000, 0x00070000, 0x13180000, 0x00080000, 0x00000000, 0x00070000, 0x15280000, + 0x15300000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00020000, 0x00580000, 0x00060000, + 0x00000000, 0x00020000, 0x002d0000, 0x00080000, 0x00000000, 0x00020000, 0x00860000, 0x15330000, + 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00020000, 0x03ff0000, 0x00060000, 0x00000000, + 0x00030000, 0x15360000, 0x00080000, 0x00000000, 0x00020000, 0x05a90000, 0x153e0000, 0x00030000, + 0x00000000, 0x00070000, 0x00000000, 0x00020000, 0x03ff0000, 0x00060000, 0x00000000, 0x00030000, + 0x15410000, 0x00080000, 0x00000000, 0x00020000, 0x05a90000, 0x15490000, 0x00030000, 0x00000000, + 0x00070000, 0x00000000, 0x00020000, 0x03ff0000, 0x00060000, 0x00000000, 0x00030000, 0x154c0000, + 0x00080000, 0x00000000, 0x00070000, 0x176a0000, 0x00000000, };
static void test_effect_local_shader(void) @@ -3639,6 +3664,19 @@ if (0) ok(typedesc.Stride == 0x0, "Stride is %#x, expected 0x0\n", typedesc.Stride);
/* Geometry shader with stream output */ + + /* Inline variant */ + p = t->lpVtbl->GetPassByName(t, "P8"); + hr = p->lpVtbl->GetGeometryShaderDesc(p, &pdesc); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = pdesc.pShaderVariable->lpVtbl->GetShaderDesc(pdesc.pShaderVariable, 0, &shaderdesc); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine { + ok(shaderdesc.IsInline, "Unexpected inline flag.\n"); + ok(shaderdesc.SODecl && !strcmp(shaderdesc.SODecl, "SV_POSITION.y"), "Unexpected stream output declaration %s.\n", + shaderdesc.SODecl); +} + v = effect->lpVtbl->GetVariableByName(effect, "g_so"); gs = v->lpVtbl->AsShader(v); hr = gs->lpVtbl->GetShaderDesc(gs, 0, &shaderdesc);
On Mon, Aug 30, 2021 at 7:07 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/effect.c | 172 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 6 deletions(-)
Patch is okay, a few notes below.
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 113125e9cbd..c3c98a0da31 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c
@@ -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";
Usually in HLSL you can use "rgba" in place of "xyzw" for swizzles / writemasks, it might be worth checking if those also work (and are passed through to the effect bytecode unchanged).
- 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;
I think it would be nice to have a small comment showing the expected syntax of a stream out declaration (entry) somewhere around here. Just something to quickly glance at while reading the following code.
- 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);
Did you verify that it's illegal to have a wrongly ordered mask (e.g. something like .wzyx)? I expect that to be invalid but better to be sure. Likewise for other assumptions involved here, like repeating the same component twice.
In general, some more tests with interesting stream out declarations would be nice. I guess you have more planned after the test in patch 5/5.
}
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);
This looks weird, but that's probably because the API for ID3D10Device_CreateGeometryShaderWithStreamOutput() is confusing (just one stride for up to 4 output buffers? What does it even mean?) and neither the documentation nor our tests seem to clarify that. Any clue what's supposed to happen with multiple output buffers?
FWIW that function's signature makes a lot more sense in d3d11.
On 8/31/21 4:32 PM, Matteo Bruni wrote:
On Mon, Aug 30, 2021 at 7:07 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/effect.c | 172 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 6 deletions(-)
Patch is okay, a few notes below.
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 113125e9cbd..c3c98a0da31 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -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";
Usually in HLSL you can use "rgba" in place of "xyzw" for swizzles / writemasks, it might be worth checking if those also work (and are passed through to the effect bytecode unchanged).
Yes, "rgba" also works apparently. Compiler preserves string as is, does not convert to coordinate mask names. I'll add a test for that.
- 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;
I think it would be nice to have a small comment showing the expected syntax of a stream out declaration (entry) somewhere around here. Just something to quickly glance at while reading the following code.
Okay.
- 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);
Did you verify that it's illegal to have a wrongly ordered mask (e.g. something like .wzyx)? I expect that to be invalid but better to be sure. Likewise for other assumptions involved here, like repeating the same component twice.
Yes, it is disallowed to break the order. API manifestation is that you specify start and count, which assumes it's always forward looking. Regarding error, it won't pass compiler check first, complaining about "invalid mask declaration". As far as I can tell that's the only thing that compiler checks in this string, you can have non-existent semantics as much as you like. That will break effect creation later though, presumably because shader object can't be created with invalid declaration.
In general, some more tests with interesting stream out declarations would be nice. I guess you have more planned after the test in patch 5/5.
I can think of adding more variations with spaces around, and maybe with multiple entries. Do you have other ideas?
}
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);
This looks weird, but that's probably because the API for ID3D10Device_CreateGeometryShaderWithStreamOutput() is confusing (just one stride for up to 4 output buffers? What does it even mean?) and neither the documentation nor our tests seem to clarify that. Any clue what's supposed to happen with multiple output buffers?
FWIW that function's signature makes a lot more sense in d3d11.
My understanding is that in d3d10 you can specify stride only when you use one SO buffer. And if you use multiple buffers runtime will use default strides for all. For d3d11 you can set each explicitly.
On Tue, Aug 31, 2021 at 3:57 PM Nikolay Sivov nsivov@codeweavers.com wrote:
On 8/31/21 4:32 PM, Matteo Bruni wrote:
On Mon, Aug 30, 2021 at 7:07 AM Nikolay Sivov nsivov@codeweavers.com wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/d3d10/effect.c | 172 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 6 deletions(-)
Patch is okay, a few notes below.
diff --git a/dlls/d3d10/effect.c b/dlls/d3d10/effect.c index 113125e9cbd..c3c98a0da31 100644 --- a/dlls/d3d10/effect.c +++ b/dlls/d3d10/effect.c @@ -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";
Usually in HLSL you can use "rgba" in place of "xyzw" for swizzles / writemasks, it might be worth checking if those also work (and are passed through to the effect bytecode unchanged).
Yes, "rgba" also works apparently. Compiler preserves string as is, does not convert to coordinate mask names. I'll add a test for that.
- 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;
I think it would be nice to have a small comment showing the expected syntax of a stream out declaration (entry) somewhere around here. Just something to quickly glance at while reading the following code.
Okay.
- 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);
Did you verify that it's illegal to have a wrongly ordered mask (e.g. something like .wzyx)? I expect that to be invalid but better to be sure. Likewise for other assumptions involved here, like repeating the same component twice.
Yes, it is disallowed to break the order. API manifestation is that you specify start and count, which assumes it's always forward looking. Regarding error, it won't pass compiler check first, complaining about "invalid mask declaration". As far as I can tell that's the only thing that compiler checks in this string, you can have non-existent semantics as much as you like. That will break effect creation later though, presumably because shader object can't be created with invalid declaration.
Excellent. That should already do the right thing then.
In general, some more tests with interesting stream out declarations would be nice. I guess you have more planned after the test in patch 5/5.
I can think of adding more variations with spaces around, and maybe with multiple entries. Do you have other ideas?
Yes, that sounds good. I guess generally trying to exercise all the edge cases of the parser.
I just noticed that there is probably one case that needs special handling. From the MS docs:
'There is one special Semantic, labeled "$SKIP" which indicates an empty semantic, leaving the corresponding memory in the stream out buffer untouched. The $SKIP semantic cannot have a SemanticIndex, but can have a Mask.'
It should probably be translated into a declaration entry with NULL semantic name. See test_stream_output() in d3d10core/tests/d3d10core.c for a few examples (both valid and not) if you haven't yet.
}
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);
This looks weird, but that's probably because the API for ID3D10Device_CreateGeometryShaderWithStreamOutput() is confusing (just one stride for up to 4 output buffers? What does it even mean?) and neither the documentation nor our tests seem to clarify that. Any clue what's supposed to happen with multiple output buffers?
FWIW that function's signature makes a lot more sense in d3d11.
My understanding is that in d3d10 you can specify stride only when you use one SO buffer. And if you use multiple buffers runtime will use default strides for all. For d3d11 you can set each explicitly.
Somehow I missed the relevant tests in d3d10core.c. It is still weird but I guess not as mysterious now.
After playing with this a bit, it looks like it's actually more strict than that: if there is just one buffer you need to pass a non-zero stride; OTOH when there are multiple buffers you need to pass 0 as stride. Please double check that it's the case (as I still don't trust myself a lot on this) and consider sending a fix if necessary.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d3d10/tests/effect.c | 86 ++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 24 deletions(-)
diff --git a/dlls/d3d10/tests/effect.c b/dlls/d3d10/tests/effect.c index c1d3fcfbcc9..83bfe371c99 100644 --- a/dlls/d3d10/tests/effect.c +++ b/dlls/d3d10/tests/effect.c @@ -2584,14 +2584,20 @@ technique10 Render SetVertexShader( v[1] ); SetGeometryShader( g ); } + pass P8 + { + SetPixelShader( p ); + SetVertexShader( v[1] ); + SetGeometryShader( ConstructGSWithSO(CompilerShader( gs_4_0, GS()), "SV_POSITION.y") ); + } } #endif static DWORD fx_local_shader[] = { - 0x43425844, 0x0a74ff0f, 0xea10b516, 0x8be88332, 0x2a273ca7, 0x00000001, 0x0000182d, 0x00000001, - 0x00000024, 0x30315846, 0x00001801, 0xfeff1001, 0x00000000, 0x00000000, 0x00000007, 0x00000000, - 0x00000000, 0x00000000, 0x00000001, 0x00001549, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000e, 0x00000006, 0x00000000, 0x74726556, + 0x43425844, 0xd50d5743, 0xb5236e8f, 0x9a35cd8d, 0x59e3afe1, 0x00000001, 0x00001a92, 0x00000001, + 0x00000024, 0x30315846, 0x00001a66, 0xfeff1001, 0x00000000, 0x00000000, 0x00000007, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00001772, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x00000007, 0x00000000, 0x74726556, 0x68537865, 0x72656461, 0x00000400, 0x00000200, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00307600, 0x65786950, 0x6168536c, 0x00726564, 0x00000030, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000005, 0x47003070, 0x656d6f65, 0x53797274, 0x65646168, @@ -2762,26 +2768,45 @@ static DWORD fx_local_shader[] = 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000005, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00001320, 0x00000000, 0x50003550, 0x00a50036, 0x00000000, 0x37500000, 0x0000a500, 0x00000100, - 0x00002d00, 0x00001100, 0x00000000, 0xffffff00, 0x000000ff, 0x00000000, 0x00005800, 0x00003c00, - 0x00000000, 0xffffff00, 0x000000ff, 0x00000000, 0x00008600, 0x00006a00, 0x00000000, 0xffffff00, - 0x000000ff, 0x00000000, 0x0000a500, 0x00008900, 0x00000000, 0xffffff00, 0x0000a7ff, 0x00025300, - 0x00000000, 0x0003ff00, 0x00003c00, 0x00000000, 0xffffff00, 0x000401ff, 0x00000000, 0x0005a900, - 0x00006a00, 0x00000000, 0xffffff00, 0x0005abff, 0x00000000, 0x0007cf00, 0x0007b300, 0x00000000, - 0xffffff00, 0x0007d4ff, 0x0009dc00, 0x00000000, 0x0009ea00, 0x00000800, 0x00000000, 0x0009f100, - 0x00000000, 0x00000000, 0x0009f400, 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000100, - 0x0009f700, 0x00000600, 0x00000000, 0x00000100, 0x000a0300, 0x00000800, 0x00000000, 0x00000100, - 0x000a0f00, 0x000a1b00, 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000100, 0x000a1e00, - 0x00000600, 0x00000000, 0x00000100, 0x000a2a00, 0x00000800, 0x00000000, 0x00000100, 0x000a3600, - 0x000a4200, 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000700, 0x000bed00, 0x00000600, - 0x00000000, 0x00000700, 0x000da100, 0x00000800, 0x00000000, 0x00000700, 0x000fb100, 0x000fb900, - 0x00000300, 0x00000000, 0x00000700, 0x00000000, 0x00000700, 0x00116400, 0x00000600, 0x00000000, - 0x00000700, 0x00131800, 0x00000800, 0x00000000, 0x00000700, 0x00152800, 0x00153000, 0x00000300, - 0x00000000, 0x00000700, 0x00000000, 0x00000200, 0x00005800, 0x00000600, 0x00000000, 0x00000200, - 0x00002d00, 0x00000800, 0x00000000, 0x00000200, 0x00008600, 0x00153300, 0x00000300, 0x00000000, - 0x00000700, 0x00000000, 0x00000200, 0x0003ff00, 0x00000600, 0x00000000, 0x00000300, 0x00153600, - 0x00000800, 0x00000000, 0x00000200, 0x0005a900, 0x00153e00, 0x00000300, 0x00000000, 0x00000700, - 0x00000000, 0x00000200, 0x0003ff00, 0x00000600, 0x00000000, 0x00000300, 0x00154100, 0x00000800, - 0x00000000, 0x00000200, 0x0005a900, 0x00000000, + 0x00385000, 0x000000a5, 0x00000001, 0x00000204, 0x43425844, 0x8e325e23, 0x0774e86e, 0xe636e15f, + 0xd3f67abf, 0x00000001, 0x00000204, 0x00000005, 0x00000034, 0x00000080, 0x000000b4, 0x000000e8, + 0x00000188, 0x46454452, 0x00000044, 0x00000000, 0x00000000, 0x00000000, 0x0000001c, 0x47530400, + 0x00000100, 0x0000001c, 0x7263694d, 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, + 0x6f432072, 0x6c69706d, 0x31207265, 0x00312e30, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, + 0x00000020, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, + 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x00000098, + 0x00020040, 0x00000026, 0x05000061, 0x002010f2, 0x00000003, 0x00000000, 0x00000001, 0x0100185d, + 0x0100285c, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x0200005e, 0x00000003, 0x06000036, + 0x001020f2, 0x00000000, 0x00201e46, 0x00000000, 0x00000000, 0x01000013, 0x06000036, 0x001020f2, + 0x00000000, 0x00201e46, 0x00000001, 0x00000000, 0x01000013, 0x06000036, 0x001020f2, 0x00000000, + 0x00201e46, 0x00000002, 0x00000000, 0x01000013, 0x01000009, 0x0100003e, 0x54415453, 0x00000074, + 0x00000008, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, + 0x00000005, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x505f5653, 0x5449534f, 0x2e4e4f49, + 0x15540079, 0x175c0000, 0x002d0000, 0x00110000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, + 0x00580000, 0x003c0000, 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00860000, 0x006a0000, + 0x00000000, 0xffff0000, 0x0000ffff, 0x00000000, 0x00a50000, 0x00890000, 0x00000000, 0xffff0000, + 0x00a7ffff, 0x02530000, 0x00000000, 0x03ff0000, 0x003c0000, 0x00000000, 0xffff0000, 0x0401ffff, + 0x00000000, 0x05a90000, 0x006a0000, 0x00000000, 0xffff0000, 0x05abffff, 0x00000000, 0x07cf0000, + 0x07b30000, 0x00000000, 0xffff0000, 0x07d4ffff, 0x09dc0000, 0x00000000, 0x09ea0000, 0x00090000, + 0x00000000, 0x09f10000, 0x00000000, 0x00000000, 0x09f40000, 0x00030000, 0x00000000, 0x00070000, + 0x00000000, 0x00010000, 0x09f70000, 0x00060000, 0x00000000, 0x00010000, 0x0a030000, 0x00080000, + 0x00000000, 0x00010000, 0x0a0f0000, 0x0a1b0000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, + 0x00010000, 0x0a1e0000, 0x00060000, 0x00000000, 0x00010000, 0x0a2a0000, 0x00080000, 0x00000000, + 0x00010000, 0x0a360000, 0x0a420000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00070000, + 0x0bed0000, 0x00060000, 0x00000000, 0x00070000, 0x0da10000, 0x00080000, 0x00000000, 0x00070000, + 0x0fb10000, 0x0fb90000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00070000, 0x11640000, + 0x00060000, 0x00000000, 0x00070000, 0x13180000, 0x00080000, 0x00000000, 0x00070000, 0x15280000, + 0x15300000, 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00020000, 0x00580000, 0x00060000, + 0x00000000, 0x00020000, 0x002d0000, 0x00080000, 0x00000000, 0x00020000, 0x00860000, 0x15330000, + 0x00030000, 0x00000000, 0x00070000, 0x00000000, 0x00020000, 0x03ff0000, 0x00060000, 0x00000000, + 0x00030000, 0x15360000, 0x00080000, 0x00000000, 0x00020000, 0x05a90000, 0x153e0000, 0x00030000, + 0x00000000, 0x00070000, 0x00000000, 0x00020000, 0x03ff0000, 0x00060000, 0x00000000, 0x00030000, + 0x15410000, 0x00080000, 0x00000000, 0x00020000, 0x05a90000, 0x15490000, 0x00030000, 0x00000000, + 0x00070000, 0x00000000, 0x00020000, 0x03ff0000, 0x00060000, 0x00000000, 0x00030000, 0x154c0000, + 0x00080000, 0x00000000, 0x00070000, 0x176a0000, 0x00000000, };
static void test_effect_local_shader(void) @@ -3639,6 +3664,19 @@ if (0) ok(typedesc.Stride == 0x0, "Stride is %#x, expected 0x0\n", typedesc.Stride);
/* Geometry shader with stream output */ + + /* Inline variant */ + p = t->lpVtbl->GetPassByName(t, "P8"); + hr = p->lpVtbl->GetGeometryShaderDesc(p, &pdesc); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = pdesc.pShaderVariable->lpVtbl->GetShaderDesc(pdesc.pShaderVariable, 0, &shaderdesc); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine { + ok(shaderdesc.IsInline, "Unexpected inline flag.\n"); + ok(shaderdesc.SODecl && !strcmp(shaderdesc.SODecl, "SV_POSITION.y"), "Unexpected stream output declaration %s.\n", + shaderdesc.SODecl); +} + v = effect->lpVtbl->GetVariableByName(effect, "g_so"); gs = v->lpVtbl->AsShader(v); hr = gs->lpVtbl->GetShaderDesc(gs, 0, &shaderdesc);