d3d10/effect: Support stream output declaration when creating geometry shaders.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Matteo Bruni <mbruni@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2021-08-30 08:06:39 +03:00 committed by Alexandre Julliard
parent 87ac914e82
commit 5071836f3e
1 changed files with 166 additions and 6 deletions

View File

@ -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;