wined3d: Add support for stream output with vertex shaders.

In Direct3D, a stream-output geometry shader can be created from a
vertex shader bytecode. We generate a pass-through geometry shader in
this case. Pass-through geometry shaders are helpful because they can
easily split outputs when rasterization is disabed. We could also add
another codepath in order to avoid geometry shaders when possible.

Signed-off-by: Józef Kucia <jkucia@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Józef Kucia 2018-04-23 16:20:16 +02:00 committed by Alexandre Julliard
parent 9d70df6a40
commit ca8e05154e
8 changed files with 108 additions and 25 deletions

View File

@ -14335,7 +14335,6 @@ static void test_stream_output(void)
check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), 64, TRUE); check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), 64, TRUE);
check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), 0, FALSE); check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), 0, FALSE);
todo_wine
check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), 64, TRUE); check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), 64, TRUE);
check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, 0, 64, FALSE); check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, 0, 64, FALSE);

View File

@ -22204,10 +22204,8 @@ static void test_stream_output(void)
check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration),
stride, 1, D3D11_SO_NO_RASTERIZED_STREAM); stride, 1, D3D11_SO_NO_RASTERIZED_STREAM);
todo_wine
check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration),
NULL, 0, D3D11_SO_NO_RASTERIZED_STREAM); NULL, 0, D3D11_SO_NO_RASTERIZED_STREAM);
todo_wine
check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration),
stride, 1, D3D11_SO_NO_RASTERIZED_STREAM); stride, 1, D3D11_SO_NO_RASTERIZED_STREAM);
@ -22489,9 +22487,7 @@ static void test_fl10_stream_output_desc(void)
check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), NULL, 0, 0); check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), NULL, 0, 0);
check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), stride, 1, 0); check_so_desc(device, gs_code, sizeof(gs_code), so_declaration, ARRAY_SIZE(so_declaration), stride, 1, 0);
todo_wine
check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), NULL, 0, 0); check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), NULL, 0, 0);
todo_wine
check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), stride, 1, 0); check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), stride, 1, 0);
check_invalid_so_desc(device, gs_code, sizeof(gs_code), so_declaration, 0, stride, 1, 0); check_invalid_so_desc(device, gs_code, sizeof(gs_code), so_declaration, 0, stride, 1, 0);

View File

@ -4936,7 +4936,9 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s
} }
else if (!context->transform_feedback_active) else if (!context->transform_feedback_active)
{ {
GLenum mode = gl_tfb_primitive_type_from_d3d(shader->u.gs.output_type); enum wined3d_primitive_type primitive_type = shader->u.gs.output_type
? shader->u.gs.output_type : d3d_primitive_type_from_gl(state->gl_primitive_type);
GLenum mode = gl_tfb_primitive_type_from_d3d(primitive_type);
GL_EXTCALL(glBeginTransformFeedback(mode)); GL_EXTCALL(glBeginTransformFeedback(mode));
checkGLcall("glBeginTransformFeedback"); checkGLcall("glBeginTransformFeedback");
context->transform_feedback_active = 1; context->transform_feedback_active = 1;

View File

@ -779,6 +779,7 @@ void wined3d_cs_emit_dispatch_indirect(struct wined3d_cs *cs,
static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data) static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
{ {
const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info; const struct wined3d_gl_info *gl_info = &cs->device->adapter->gl_info;
const struct wined3d_shader *geometry_shader;
struct wined3d_state *state = &cs->state; struct wined3d_state *state = &cs->state;
const struct wined3d_cs_draw *op = data; const struct wined3d_cs_draw *op = data;
int load_base_vertex_idx; int load_base_vertex_idx;
@ -798,6 +799,8 @@ static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
if (state->gl_primitive_type != op->primitive_type) if (state->gl_primitive_type != op->primitive_type)
{ {
if ((geometry_shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]) && !geometry_shader->function)
device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_GEOMETRY));
if (state->gl_primitive_type == GL_POINTS || op->primitive_type == GL_POINTS) if (state->gl_primitive_type == GL_POINTS || op->primitive_type == GL_POINTS)
device_invalidate_state(cs->device, STATE_POINT_ENABLE); device_invalidate_state(cs->device, STATE_POINT_ENABLE);
state->gl_primitive_type = op->primitive_type; state->gl_primitive_type = op->primitive_type;

View File

@ -99,7 +99,7 @@ GLenum gl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
} }
} }
static enum wined3d_primitive_type d3d_primitive_type_from_gl(GLenum primitive_type) enum wined3d_primitive_type d3d_primitive_type_from_gl(GLenum primitive_type)
{ {
switch (primitive_type) switch (primitive_type)
{ {

View File

@ -8198,7 +8198,11 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context
const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps; const struct wined3d_shader_reg_maps *reg_maps = &shader->reg_maps;
struct wined3d_string_buffer *buffer = &priv->shader_buffer; struct wined3d_string_buffer *buffer = &priv->shader_buffer;
const struct wined3d_gl_info *gl_info = context->gl_info; const struct wined3d_gl_info *gl_info = context->gl_info;
const struct wined3d_shader_signature_element *output;
enum wined3d_primitive_type primitive_type;
struct shader_glsl_ctx_priv priv_ctx; struct shader_glsl_ctx_priv priv_ctx;
unsigned int max_vertices;
unsigned int i, j;
GLuint shader_id; GLuint shader_id;
memset(&priv_ctx, 0, sizeof(priv_ctx)); memset(&priv_ctx, 0, sizeof(priv_ctx));
@ -8210,12 +8214,33 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context
shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx); shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx);
shader_addline(buffer, "layout(%s", glsl_primitive_type_from_d3d(shader->u.gs.input_type)); primitive_type = shader->u.gs.input_type ? shader->u.gs.input_type : args->primitive_type;
shader_addline(buffer, "layout(%s", glsl_primitive_type_from_d3d(primitive_type));
if (shader->u.gs.instance_count > 1) if (shader->u.gs.instance_count > 1)
shader_addline(buffer, ", invocations = %u", shader->u.gs.instance_count); shader_addline(buffer, ", invocations = %u", shader->u.gs.instance_count);
shader_addline(buffer, ") in;\n"); shader_addline(buffer, ") in;\n");
primitive_type = shader->u.gs.output_type ? shader->u.gs.output_type : args->primitive_type;
if (!(max_vertices = shader->u.gs.vertices_out))
{
switch (args->primitive_type)
{
case WINED3D_PT_POINTLIST:
max_vertices = 1;
break;
case WINED3D_PT_LINELIST:
max_vertices = 2;
break;
case WINED3D_PT_TRIANGLELIST:
max_vertices = 3;
break;
default:
FIXME("Unhandled primitive type %s.\n", debug_d3dprimitivetype(args->primitive_type));
break;
}
}
shader_addline(buffer, "layout(%s, max_vertices = %u) out;\n", shader_addline(buffer, "layout(%s, max_vertices = %u) out;\n",
glsl_primitive_type_from_d3d(shader->u.gs.output_type), shader->u.gs.vertices_out); glsl_primitive_type_from_d3d(primitive_type), max_vertices);
shader_addline(buffer, "in shader_in_out { vec4 reg[%u]; } shader_in[];\n", shader->limits->packed_input); shader_addline(buffer, "in shader_in_out { vec4 reg[%u]; } shader_in[];\n", shader->limits->packed_input);
if (!gl_info->supported[ARB_CLIP_CONTROL]) if (!gl_info->supported[ARB_CLIP_CONTROL])
@ -8230,9 +8255,32 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context
shader_glsl_generate_sm4_output_setup(priv, shader, args->output_count, shader_glsl_generate_sm4_output_setup(priv, shader, args->output_count,
gl_info, TRUE, args->interpolation_mode); gl_info, TRUE, args->interpolation_mode);
} }
shader_addline(buffer, "void main()\n{\n"); shader_addline(buffer, "void main()\n{\n");
if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) if (shader->function)
return 0; {
if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL)))
return 0;
}
else
{
for (i = 0; i < max_vertices; ++i)
{
for (j = 0; j < shader->output_signature.element_count; ++j)
{
output = &shader->output_signature.elements[j];
shader_addline(buffer, "gs_out[%u] = shader_in[%u].reg[%u];\n",
output->register_idx, i, output->register_idx);
}
shader_addline(buffer, "setup_gs_output(gs_out);\n");
if (!gl_info->supported[ARB_CLIP_CONTROL])
{
shader_addline(buffer, "gl_ViewportIndex = 0;\n");
shader_glsl_fixup_position(buffer, TRUE);
}
shader_addline(buffer, "EmitVertex();\n");
}
}
shader_addline(buffer, "}\n"); shader_addline(buffer, "}\n");
shader_id = GL_EXTCALL(glCreateShader(GL_GEOMETRY_SHADER)); shader_id = GL_EXTCALL(glCreateShader(GL_GEOMETRY_SHADER));

View File

@ -3600,9 +3600,6 @@ static HRESULT shader_init(struct wined3d_shader *shader, struct wined3d_device
TRACE("byte_code %p, byte_code_size %#lx, format %#x, max_version %#x.\n", TRACE("byte_code %p, byte_code_size %#lx, format %#x, max_version %#x.\n",
desc->byte_code, (long)desc->byte_code_size, desc->format, desc->max_version); desc->byte_code, (long)desc->byte_code_size, desc->format, desc->max_version);
if (!desc->byte_code)
return WINED3DERR_INVALIDCALL;
if (!(shader->frontend = shader_select_frontend(desc->format))) if (!(shader->frontend = shader_select_frontend(desc->format)))
{ {
FIXME("Unable to find frontend for shader.\n"); FIXME("Unable to find frontend for shader.\n");
@ -3677,19 +3674,29 @@ static HRESULT shader_init(struct wined3d_shader *shader, struct wined3d_device
byte_code_size = (ptr - desc->byte_code) * sizeof(*ptr); byte_code_size = (ptr - desc->byte_code) * sizeof(*ptr);
} }
if (!(shader->function = heap_alloc(byte_code_size))) if (desc->byte_code && byte_code_size)
{ {
shader_cleanup(shader); if (!(shader->function = heap_alloc(byte_code_size)))
return E_OUTOFMEMORY; {
} shader_cleanup(shader);
memcpy(shader->function, desc->byte_code, byte_code_size); return E_OUTOFMEMORY;
shader->functionLength = byte_code_size; }
memcpy(shader->function, desc->byte_code, byte_code_size);
shader->functionLength = byte_code_size;
if (FAILED(hr = shader_set_function(shader, float_const_count, type, desc->max_version))) if (FAILED(hr = shader_set_function(shader, float_const_count, type, desc->max_version)))
{
WARN("Failed to set function, hr %#x.\n", hr);
shader_cleanup(shader);
return hr;
}
}
else
{ {
WARN("Failed to set function, hr %#x.\n", hr); shader->reg_maps.shader_version.type = type;
shader_cleanup(shader); shader->reg_maps.shader_version.major = 4;
return hr; shader->reg_maps.shader_version.minor = 0;
shader_set_limits(shader);
} }
shader->load_local_constsF = shader->lconst_inf_or_nan; shader->load_local_constsF = shader->lconst_inf_or_nan;
@ -3730,6 +3737,7 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3
const struct wined3d_shader_desc *desc, const struct wined3d_stream_output_desc *so_desc, const struct wined3d_shader_desc *desc, const struct wined3d_stream_output_desc *so_desc,
void *parent, const struct wined3d_parent_ops *parent_ops) void *parent, const struct wined3d_parent_ops *parent_ops)
{ {
struct wined3d_shader_desc shader_desc = *desc;
struct wined3d_stream_output_element *elements; struct wined3d_stream_output_element *elements;
enum wined3d_shader_type shader_type; enum wined3d_shader_type shader_type;
HRESULT hr; HRESULT hr;
@ -3740,6 +3748,9 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3
switch (shader_type) switch (shader_type)
{ {
case WINED3D_SHADER_TYPE_VERTEX: case WINED3D_SHADER_TYPE_VERTEX:
shader_desc.byte_code = NULL;
shader_desc.byte_code_size = 0;
break;
case WINED3D_SHADER_TYPE_DOMAIN: case WINED3D_SHADER_TYPE_DOMAIN:
FIXME("Stream output not supported for %s.\n", debug_shader_type(shader_type)); FIXME("Stream output not supported for %s.\n", debug_shader_type(shader_type));
return E_NOTIMPL; return E_NOTIMPL;
@ -3748,7 +3759,8 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3
} }
} }
if (FAILED(hr = shader_init(shader, device, desc, 0, WINED3D_SHADER_TYPE_GEOMETRY, parent, parent_ops))) if (FAILED(hr = shader_init(shader, device, &shader_desc, 0,
WINED3D_SHADER_TYPE_GEOMETRY, parent, parent_ops)))
return hr; return hr;
if (so_desc) if (so_desc)
@ -3798,6 +3810,9 @@ void find_gs_compile_args(const struct wined3d_state *state, const struct wined3
args->output_count = pixel_shader ? pixel_shader->limits->packed_input : shader->limits->packed_output; args->output_count = pixel_shader ? pixel_shader->limits->packed_input : shader->limits->packed_output;
if (!(args->primitive_type = shader->u.gs.input_type))
args->primitive_type = d3d_primitive_type_from_gl(state->gl_primitive_type);
init_interpolation_compile_args(args->interpolation_mode, pixel_shader, gl_info); init_interpolation_compile_args(args->interpolation_mode, pixel_shader, gl_info);
} }
@ -4129,6 +4144,9 @@ HRESULT CDECL wined3d_shader_create_cs(struct wined3d_device *device, const stru
TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n", TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n",
device, desc, parent, parent_ops, shader); device, desc, parent, parent_ops, shader);
if (!desc->byte_code)
return WINED3DERR_INVALIDCALL;
if (!(object = heap_alloc_zero(sizeof(*object)))) if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
@ -4156,6 +4174,9 @@ HRESULT CDECL wined3d_shader_create_ds(struct wined3d_device *device, const stru
TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n", TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n",
device, desc, parent, parent_ops, shader); device, desc, parent, parent_ops, shader);
if (!desc->byte_code)
return WINED3DERR_INVALIDCALL;
if (!(object = heap_alloc_zero(sizeof(*object)))) if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
@ -4184,6 +4205,9 @@ HRESULT CDECL wined3d_shader_create_gs(struct wined3d_device *device, const stru
TRACE("device %p, desc %p, so_desc %p, parent %p, parent_ops %p, shader %p.\n", TRACE("device %p, desc %p, so_desc %p, parent %p, parent_ops %p, shader %p.\n",
device, desc, so_desc, parent, parent_ops, shader); device, desc, so_desc, parent, parent_ops, shader);
if (!desc->byte_code)
return WINED3DERR_INVALIDCALL;
if (!(object = heap_alloc_zero(sizeof(*object)))) if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
@ -4211,6 +4235,9 @@ HRESULT CDECL wined3d_shader_create_hs(struct wined3d_device *device, const stru
TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n", TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n",
device, desc, parent, parent_ops, shader); device, desc, parent, parent_ops, shader);
if (!desc->byte_code)
return WINED3DERR_INVALIDCALL;
if (!(object = heap_alloc_zero(sizeof(*object)))) if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
@ -4238,6 +4265,9 @@ HRESULT CDECL wined3d_shader_create_ps(struct wined3d_device *device, const stru
TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n", TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n",
device, desc, parent, parent_ops, shader); device, desc, parent, parent_ops, shader);
if (!desc->byte_code)
return WINED3DERR_INVALIDCALL;
if (!(object = heap_alloc_zero(sizeof(*object)))) if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
@ -4265,6 +4295,9 @@ HRESULT CDECL wined3d_shader_create_vs(struct wined3d_device *device, const stru
TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n", TRACE("device %p, desc %p, parent %p, parent_ops %p, shader %p.\n",
device, desc, parent, parent_ops, shader); device, desc, parent, parent_ops, shader);
if (!desc->byte_code)
return WINED3DERR_INVALIDCALL;
if (!(object = heap_alloc_zero(sizeof(*object)))) if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;

View File

@ -1395,6 +1395,7 @@ struct ds_compile_args
struct gs_compile_args struct gs_compile_args
{ {
unsigned int output_count; unsigned int output_count;
enum wined3d_primitive_type primitive_type;
DWORD interpolation_mode[WINED3D_PACKED_INTERPOLATION_SIZE]; DWORD interpolation_mode[WINED3D_PACKED_INTERPOLATION_SIZE];
}; };
@ -3905,6 +3906,7 @@ void state_shademode(struct wined3d_context *context,
const struct wined3d_state *state, DWORD state_id) DECLSPEC_HIDDEN; const struct wined3d_state *state, DWORD state_id) DECLSPEC_HIDDEN;
GLenum gl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type) DECLSPEC_HIDDEN; GLenum gl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type) DECLSPEC_HIDDEN;
enum wined3d_primitive_type d3d_primitive_type_from_gl(GLenum primitive_type) DECLSPEC_HIDDEN;
/* Math utils */ /* Math utils */
void multiply_matrix(struct wined3d_matrix *dest, const struct wined3d_matrix *src1, void multiply_matrix(struct wined3d_matrix *dest, const struct wined3d_matrix *src1,