Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/wined3d/shader.c | 24 +++++++++++++++ dlls/wined3d/shader_sm4.c | 69 +++++++++++++++++++++++++----------------- dlls/wined3d/wined3d_private.h | 4 +++ 3 files changed, 70 insertions(+), 27 deletions(-)
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index c20c1da14bcf..8934c4f5d6d3 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -419,6 +419,15 @@ static const struct wined3d_shader_frontend *shader_select_frontend(enum wined3d } }
+static enum wined3d_shader_type shader_get_shader_type(const struct wined3d_shader_desc *desc) +{ + if (desc->format == WINED3D_SHADER_BYTE_CODE_FORMAT_SM4) + return wined3d_get_sm4_shader_type(desc->byte_code, desc->byte_code_size); + + FIXME("Could not get shader type for byte code format %#x.\n", desc->format); + return WINED3D_SHADER_TYPE_INVALID; +} + void string_buffer_clear(struct wined3d_string_buffer *buffer) { buffer->buffer[0] = '\0'; @@ -3722,8 +3731,23 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3 void *parent, const struct wined3d_parent_ops *parent_ops) { struct wined3d_stream_output_element *elements = NULL; + enum wined3d_shader_type shader_type; HRESULT hr;
+ if (so_desc) + { + shader_type = shader_get_shader_type(desc); + switch (shader_type) + { + case WINED3D_SHADER_TYPE_VERTEX: + case WINED3D_SHADER_TYPE_DOMAIN: + FIXME("Stream output not supported for %s.\n", debug_shader_type(shader_type)); + return E_NOTIMPL; + default: + break; + } + } + if (so_desc && !(elements = heap_calloc(so_desc->element_count, sizeof(*elements)))) return E_OUTOFMEMORY;
diff --git a/dlls/wined3d/shader_sm4.c b/dlls/wined3d/shader_sm4.c index 8eac746ac507..f11af7630253 100644 --- a/dlls/wined3d/shader_sm4.c +++ b/dlls/wined3d/shader_sm4.c @@ -1218,6 +1218,43 @@ static enum wined3d_data_type map_data_type(char t) } }
+enum wined3d_shader_type wined3d_get_sm4_shader_type(const DWORD *byte_code, size_t byte_code_size) +{ + DWORD shader_type; + + if (byte_code_size / sizeof(*byte_code) < 1) + { + WARN("Invalid byte code size %lu.\n", (long)byte_code_size); + return WINED3D_SHADER_TYPE_INVALID; + } + + shader_type = byte_code[0] >> 16; + switch (shader_type) + { + case WINED3D_SM4_PS: + return WINED3D_SHADER_TYPE_PIXEL; + break; + case WINED3D_SM4_VS: + return WINED3D_SHADER_TYPE_VERTEX; + break; + case WINED3D_SM4_GS: + return WINED3D_SHADER_TYPE_GEOMETRY; + break; + case WINED3D_SM5_HS: + return WINED3D_SHADER_TYPE_HULL; + break; + case WINED3D_SM5_DS: + return WINED3D_SHADER_TYPE_DOMAIN; + break; + case WINED3D_SM5_CS: + return WINED3D_SHADER_TYPE_COMPUTE; + break; + default: + FIXME("Unrecognised shader type %#x.\n", shader_type); + return WINED3D_SHADER_TYPE_INVALID; + } +} + static void *shader_sm4_init(const DWORD *byte_code, size_t byte_code_size, const struct wined3d_shader_signature *output_signature) { @@ -1251,35 +1288,13 @@ static void *shader_sm4_init(const DWORD *byte_code, size_t byte_code_size, priv->start = &byte_code[2]; priv->end = &byte_code[token_count];
- switch (version_token >> 16) + priv->shader_version.type = wined3d_get_sm4_shader_type(byte_code, byte_code_size); + if (priv->shader_version.type == WINED3D_SHADER_TYPE_INVALID) { - case WINED3D_SM4_PS: - priv->shader_version.type = WINED3D_SHADER_TYPE_PIXEL; - break; - - case WINED3D_SM4_VS: - priv->shader_version.type = WINED3D_SHADER_TYPE_VERTEX; - break; - - case WINED3D_SM4_GS: - priv->shader_version.type = WINED3D_SHADER_TYPE_GEOMETRY; - break; - - case WINED3D_SM5_HS: - priv->shader_version.type = WINED3D_SHADER_TYPE_HULL; - break; - - case WINED3D_SM5_DS: - priv->shader_version.type = WINED3D_SHADER_TYPE_DOMAIN; - break; - - case WINED3D_SM5_CS: - priv->shader_version.type = WINED3D_SHADER_TYPE_COMPUTE; - break; - - default: - FIXME("Unrecognised shader type %#x.\n", version_token >> 16); + heap_free(priv); + return NULL; } + priv->shader_version.major = WINED3D_SM4_VERSION_MAJOR(version_token); priv->shader_version.minor = WINED3D_SM4_VERSION_MINOR(version_token);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 8cdc3ef6f937..ed01da02997e 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -929,6 +929,7 @@ enum wined3d_shader_type
WINED3D_SHADER_TYPE_COMPUTE = WINED3D_SHADER_TYPE_GRAPHICS_COUNT, WINED3D_SHADER_TYPE_COUNT, + WINED3D_SHADER_TYPE_INVALID = WINED3D_SHADER_TYPE_COUNT, };
struct wined3d_shader_version @@ -1265,6 +1266,9 @@ struct wined3d_shader_frontend extern const struct wined3d_shader_frontend sm1_shader_frontend DECLSPEC_HIDDEN; extern const struct wined3d_shader_frontend sm4_shader_frontend DECLSPEC_HIDDEN;
+enum wined3d_shader_type wined3d_get_sm4_shader_type(const DWORD *byte_code, + size_t byte_code_size) DECLSPEC_HIDDEN; + typedef void (*SHADER_HANDLER)(const struct wined3d_shader_instruction *);
#define WINED3D_SHADER_CAP_VS_CLIPPING 0x00000001
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/wined3d/shader.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 8934c4f5d6d3..cda812a214ca 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -3730,7 +3730,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, void *parent, const struct wined3d_parent_ops *parent_ops) { - struct wined3d_stream_output_element *elements = NULL; + struct wined3d_stream_output_element *elements; enum wined3d_shader_type shader_type; HRESULT hr;
@@ -3748,17 +3748,17 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3 } }
- if (so_desc && !(elements = heap_calloc(so_desc->element_count, sizeof(*elements)))) - return E_OUTOFMEMORY; - if (FAILED(hr = shader_init(shader, device, desc, 0, WINED3D_SHADER_TYPE_GEOMETRY, parent, parent_ops))) - { - heap_free(elements); return hr; - }
if (so_desc) { + if (!(elements = heap_calloc(so_desc->element_count, sizeof(*elements)))) + { + shader_cleanup(shader); + return E_OUTOFMEMORY; + } + shader->u.gs.so_desc = *so_desc; shader->u.gs.so_desc.elements = elements; memcpy(elements, so_desc->elements, so_desc->element_count * sizeof(*elements));
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
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 --- dlls/d3d10core/tests/device.c | 1 - dlls/d3d11/tests/d3d11.c | 4 --- dlls/wined3d/context.c | 4 ++- dlls/wined3d/cs.c | 3 +++ dlls/wined3d/device.c | 2 +- dlls/wined3d/glsl_shader.c | 56 +++++++++++++++++++++++++++++++++++--- dlls/wined3d/shader.c | 61 ++++++++++++++++++++++++++++++++---------- dlls/wined3d/wined3d_private.h | 2 ++ 8 files changed, 108 insertions(+), 25 deletions(-)
diff --git a/dlls/d3d10core/tests/device.c b/dlls/d3d10core/tests/device.c index 26218bf8e057..ba0a914e7eec 100644 --- a/dlls/d3d10core/tests/device.c +++ b/dlls/d3d10core/tests/device.c @@ -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), 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, gs_code, sizeof(gs_code), so_declaration, 0, 64, FALSE); diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index e59145292e82..91cf2d1b5dbb 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -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), stride, 1, D3D11_SO_NO_RASTERIZED_STREAM);
- todo_wine check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), NULL, 0, D3D11_SO_NO_RASTERIZED_STREAM); - todo_wine check_so_desc(device, vs_code, sizeof(vs_code), so_declaration, ARRAY_SIZE(so_declaration), 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), stride, 1, 0);
- todo_wine 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_invalid_so_desc(device, gs_code, sizeof(gs_code), so_declaration, 0, stride, 1, 0); diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index d5378e203e04..fae837b271e6 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -4932,7 +4932,9 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s } 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)); checkGLcall("glBeginTransformFeedback"); context->transform_feedback_active = 1; diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 221e51eb94bf..4b83f3c241c4 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -778,6 +778,7 @@ void wined3d_cs_emit_dispatch_indirect(struct wined3d_cs *cs, 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_shader *geometry_shader; struct wined3d_state *state = &cs->state; const struct wined3d_cs_draw *op = data; int load_base_vertex_idx; @@ -797,6 +798,8 @@ static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
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) device_invalidate_state(cs->device, STATE_POINT_ENABLE); state->gl_primitive_type = op->primitive_type; diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 8d4f4cde0e0a..36110e197170 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -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) { diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index dfd8e61f9024..56f7968be6d5 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -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; struct wined3d_string_buffer *buffer = &priv->shader_buffer; 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; + unsigned int max_vertices; + unsigned int i, j; GLuint shader_id;
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_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) shader_addline(buffer, ", invocations = %u", shader->u.gs.instance_count); 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", - 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);
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, gl_info, TRUE, args->interpolation_mode); } + shader_addline(buffer, "void main()\n{\n"); - if (FAILED(shader_generate_code(shader, buffer, reg_maps, &priv_ctx, NULL, NULL))) - return 0; + if (shader->function) + { + 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_id = GL_EXTCALL(glCreateShader(GL_GEOMETRY_SHADER)); diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index cda812a214ca..07e810cc2dde 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -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", 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))) { 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); }
- if (!(shader->function = heap_alloc(byte_code_size))) + if (desc->byte_code && byte_code_size) { - shader_cleanup(shader); - return E_OUTOFMEMORY; - } - memcpy(shader->function, desc->byte_code, byte_code_size); - shader->functionLength = byte_code_size; + if (!(shader->function = heap_alloc(byte_code_size))) + { + shader_cleanup(shader); + return E_OUTOFMEMORY; + } + 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_cleanup(shader); - return hr; + shader->reg_maps.shader_version.type = type; + shader->reg_maps.shader_version.major = 4; + shader->reg_maps.shader_version.minor = 0; + shader_set_limits(shader); }
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, void *parent, const struct wined3d_parent_ops *parent_ops) { + struct wined3d_shader_desc shader_desc = *desc; struct wined3d_stream_output_element *elements; enum wined3d_shader_type shader_type; HRESULT hr; @@ -3740,6 +3748,9 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3 switch (shader_type) { case WINED3D_SHADER_TYPE_VERTEX: + shader_desc.byte_code = NULL; + shader_desc.byte_code_size = 0; + break; case WINED3D_SHADER_TYPE_DOMAIN: FIXME("Stream output not supported for %s.\n", debug_shader_type(shader_type)); 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;
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;
+ 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); }
@@ -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", device, desc, parent, parent_ops, shader);
+ if (!desc->byte_code) + return WINED3DERR_INVALIDCALL; + if (!(object = heap_alloc_zero(sizeof(*object)))) 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", device, desc, parent, parent_ops, shader);
+ if (!desc->byte_code) + return WINED3DERR_INVALIDCALL; + if (!(object = heap_alloc_zero(sizeof(*object)))) 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", device, desc, so_desc, parent, parent_ops, shader);
+ if (!desc->byte_code) + return WINED3DERR_INVALIDCALL; + if (!(object = heap_alloc_zero(sizeof(*object)))) 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", device, desc, parent, parent_ops, shader);
+ if (!desc->byte_code) + return WINED3DERR_INVALIDCALL; + if (!(object = heap_alloc_zero(sizeof(*object)))) 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", device, desc, parent, parent_ops, shader);
+ if (!desc->byte_code) + return WINED3DERR_INVALIDCALL; + if (!(object = heap_alloc_zero(sizeof(*object)))) 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", device, desc, parent, parent_ops, shader);
+ if (!desc->byte_code) + return WINED3DERR_INVALIDCALL; + if (!(object = heap_alloc_zero(sizeof(*object)))) return E_OUTOFMEMORY;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index ed01da02997e..55abee4225ba 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1395,6 +1395,7 @@ struct ds_compile_args struct gs_compile_args { unsigned int output_count; + enum wined3d_primitive_type primitive_type; DWORD interpolation_mode[WINED3D_PACKED_INTERPOLATION_SIZE]; };
@@ -3903,6 +3904,7 @@ void state_shademode(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) 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 */ void multiply_matrix(struct wined3d_matrix *dest, const struct wined3d_matrix *src1,
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Fixes geometry shaders when ARB_viewport_array is not available.
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/wined3d/glsl_shader.c | 16 +++++++++------- dlls/wined3d/shader.c | 4 ++++ dlls/wined3d/wined3d_private.h | 3 ++- 3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 56f7968be6d5..e29730cce24b 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -5152,11 +5152,11 @@ static void shader_glsl_else(const struct wined3d_shader_instruction *ins) static void shader_glsl_emit(const struct wined3d_shader_instruction *ins) { unsigned int stream = ins->handler_idx == WINED3DSIH_EMIT ? 0 : ins->src[0].reg.idx[0].offset; + const struct wined3d_shader_reg_maps *reg_maps = ins->ctx->reg_maps;
- shader_addline(ins->ctx->buffer, "gl_ViewportIndex = 0;\n"); shader_addline(ins->ctx->buffer, "setup_gs_output(gs_out);\n"); if (!ins->ctx->gl_info->supported[ARB_CLIP_CONTROL]) - shader_glsl_fixup_position(ins->ctx->buffer, TRUE); + shader_glsl_fixup_position(ins->ctx->buffer, reg_maps->viewport_array);
if (!stream) shader_addline(ins->ctx->buffer, "EmitVertex();\n"); @@ -8244,7 +8244,12 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context shader_addline(buffer, "in shader_in_out { vec4 reg[%u]; } shader_in[];\n", shader->limits->packed_input);
if (!gl_info->supported[ARB_CLIP_CONTROL]) - shader_addline(buffer, "uniform vec4 pos_fixup[%u];\n", WINED3D_MAX_VIEWPORTS); + { + shader_addline(buffer, "uniform vec4 pos_fixup"); + if (reg_maps->viewport_array) + shader_addline(buffer, "[%u]", WINED3D_MAX_VIEWPORTS); + shader_addline(buffer, ";\n"); + }
if (is_rasterization_disabled(shader)) { @@ -8274,10 +8279,7 @@ static GLuint shader_glsl_generate_geometry_shader(const struct wined3d_context } 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_glsl_fixup_position(buffer, FALSE); shader_addline(buffer, "EmitVertex();\n"); } } diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 07e810cc2dde..b757d930da88 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -1807,6 +1807,10 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st return hr; reg_maps->cull_distance_mask |= mask; } + else if (e->sysval_semantic == WINED3D_SV_VIEWPORT_ARRAY_INDEX) + { + reg_maps->viewport_array = 1; + } } } else if (reg_maps->output_registers) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 55abee4225ba..ca392e25f843 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1030,7 +1030,8 @@ struct wined3d_shader_reg_maps DWORD point_size : 1; DWORD vocp : 1; DWORD input_rel_addressing : 1; - DWORD padding : 16; + DWORD viewport_array : 1; + DWORD padding : 15;
DWORD rt_mask; /* Used render targets, 32 max. */
On 23 April 2018 at 18:50, Józef Kucia jkucia@codeweavers.com wrote:
Fixes geometry shaders when ARB_viewport_array is not available.
While the patch seems fine, should that situation ever happen? I.e., shouldn't SM4 simply require ARB_viewport_array?
On Mon, Apr 23, 2018 at 10:49 PM, Henri Verbeet hverbeet@gmail.com wrote:
On 23 April 2018 at 18:50, Józef Kucia jkucia@codeweavers.com wrote:
Fixes geometry shaders when ARB_viewport_array is not available.
While the patch seems fine, should that situation ever happen? I.e., shouldn't SM4 simply require ARB_viewport_array?
Yes, it might be right thing to require ARB_viewport_array. On the other hand, it might be quite inconvenient for Wine users because it might disable SM4 on some systems. e.g. on macOS with OpenGL 3.3 (ARB_viewport_array is core since OpenGL 4.1). If we really want to do this we probably should add a way to force a higher shader model than supported by extensions reported by an OpenGL implementation.
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Signed-off-by: Józef Kucia jkucia@codeweavers.com --- dlls/d3d11/tests/d3d11.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+)
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 91cf2d1b5dbb..82790932b149 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -22974,6 +22974,187 @@ static void test_stream_output_components(void) release_test_context(&test_context); }
+static void test_stream_output_vs(void) +{ + const D3D11_SO_DECLARATION_ENTRY *current_so_declaration; + struct d3d11_test_context test_context; + ID3D11InputLayout *input_layout; + ID3D11Buffer *vb, *so_buffer; + ID3D11DeviceContext *context; + struct resource_readback rb; + ID3D11GeometryShader *gs; + ID3D11VertexShader *vs; + ID3D11Device *device; + const float *result; + unsigned int offset; + unsigned int i, j; + HRESULT hr; + + static const D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_11_0; + static const DWORD vs_code[] = + { +#if 0 + struct vertex + { + float4 position : POSITION; + float4 color0 : COLOR0; + float4 color1 : COLOR1; + }; + + vertex main(in vertex i) + { + return i; + } +#endif + 0x43425844, 0xa67e993e, 0x1632c139, 0x02a7725f, 0xfb0221cd, 0x00000001, 0x00000194, 0x00000003, + 0x0000002c, 0x00000094, 0x000000fc, 0x4e475349, 0x00000060, 0x00000003, 0x00000008, 0x00000050, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00000059, 0x00000000, 0x00000000, + 0x00000003, 0x00000001, 0x00000f0f, 0x00000059, 0x00000001, 0x00000000, 0x00000003, 0x00000002, + 0x00000f0f, 0x49534f50, 0x4e4f4954, 0x4c4f4300, 0xab00524f, 0x4e47534f, 0x00000060, 0x00000003, + 0x00000008, 0x00000050, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x0000000f, 0x00000059, + 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x0000000f, 0x00000059, 0x00000001, 0x00000000, + 0x00000003, 0x00000002, 0x0000000f, 0x49534f50, 0x4e4f4954, 0x4c4f4300, 0xab00524f, 0x52444853, + 0x00000090, 0x00010040, 0x00000024, 0x0300005f, 0x001010f2, 0x00000000, 0x0300005f, 0x001010f2, + 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, 0x00000000, 0x03000065, + 0x001020f2, 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x05000036, 0x001020f2, 0x00000000, + 0x00101e46, 0x00000000, 0x05000036, 0x001020f2, 0x00000001, 0x00101e46, 0x00000001, 0x05000036, + 0x001020f2, 0x00000002, 0x00101e46, 0x00000002, 0x0100003e, + }; + static const D3D11_INPUT_ELEMENT_DESC layout_desc[] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + static const D3D11_SO_DECLARATION_ENTRY all_so_decl[] = + { + {0, "POSITION", 0, 0, 4, 0}, + {0, "COLOR", 0, 0, 3, 0}, + {0, "COLOR", 1, 0, 2, 0}, + }; + static const D3D11_SO_DECLARATION_ENTRY position_so_decl[] = + { + {0, "POSITION", 0, 0, 4, 0}, + }; + static const D3D11_SO_DECLARATION_ENTRY position2_so_decl[] = + { + {0, "POSITION", 0, 0, 2, 0}, + }; + static const struct + { + struct vec4 position; + struct vec4 color0; + struct vec4 color1; + } + vb_data[] = + { + {{-1.0f, -1.0f, 0.0f, 1.0f}, {1.0f, 2.0f, 3.0f, 4.0f}, {5.0f, 6.0f, 7.0f, 8.0f}}, + {{-1.0f, 1.0f, 0.0f, 1.0f}, {9.0f, 1.1f, 1.2f, 1.3f}, {1.4f, 1.5f, 1.6f, 1.7f}}, + {{ 1.0f, -1.0f, 0.0f, 1.0f}, {1.8f, 1.9f, 2.0f, 2.1f}, {2.2f, 2.3f, 2.4f, 2.5f}}, + {{ 1.0f, 1.0f, 0.0f, 1.0f}, {2.5f, 2.6f, 2.7f, 2.8f}, {2.9f, 3.0f, 3.1f, 3.2f}}, + }; + static const unsigned int vb_stride[] = {sizeof(*vb_data)}; + static const float expected_data[] = + { + -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 2.0f, 3.0f, 5.0f, 6.0f, + -1.0f, 1.0f, 0.0f, 1.0f, 9.0f, 1.1f, 1.2f, 1.4f, 1.5f, + 1.0f, -1.0f, 0.0f, 1.0f, 1.8f, 1.9f, 2.0f, 2.2f, 2.3f, + 1.0f, 1.0f, 0.0f, 1.0f, 2.5f, 2.6f, 2.7f, 2.9f, 3.0f, + }; + static const float expected_data2[] = + { + -1.0f, -1.0f, 0.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 1.0f, + }; + static const float expected_data3[] = + { + -1.0f, -1.0f, + -1.0f, 1.0f, + 1.0f, -1.0f, + 1.0f, 1.0f, + }; + static const struct + { + const D3D11_SO_DECLARATION_ENTRY *so_declaration; + unsigned int so_entry_count; + const float *expected_data; + unsigned int expected_data_size; + } + tests[] = + { + {all_so_decl, ARRAY_SIZE(all_so_decl), expected_data, ARRAY_SIZE(expected_data)}, + {position_so_decl, ARRAY_SIZE(position_so_decl), expected_data2, ARRAY_SIZE(expected_data2)}, + {position2_so_decl, ARRAY_SIZE(position2_so_decl), expected_data3, ARRAY_SIZE(expected_data3)}, + }; + + if (!init_test_context(&test_context, &feature_level)) + return; + + device = test_context.device; + context = test_context.immediate_context; + + vb = create_buffer(device, D3D11_BIND_VERTEX_BUFFER, sizeof(vb_data), vb_data); + + hr = ID3D11Device_CreateInputLayout(device, layout_desc, ARRAY_SIZE(layout_desc), + vs_code, sizeof(vs_code), &input_layout); + ok(SUCCEEDED(hr), "Failed to create input layout, hr %#x.\n", hr); + + hr = ID3D11Device_CreateVertexShader(device, vs_code, sizeof(vs_code), NULL, &vs); + ok(SUCCEEDED(hr), "Failed to create vertex shader, hr %#x.\n", hr); + + so_buffer = create_buffer(device, D3D11_BIND_STREAM_OUTPUT, 1024, NULL); + + ID3D11DeviceContext_IASetInputLayout(context, input_layout); + offset = 0; + ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &vb, vb_stride, &offset); + ID3D11DeviceContext_VSSetShader(context, vs, NULL, 0); + + ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + + gs = NULL; + current_so_declaration = NULL; + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + if (current_so_declaration != tests[i].so_declaration) + { + if (gs) + ID3D11GeometryShader_Release(gs); + + hr = ID3D11Device_CreateGeometryShaderWithStreamOutput(device, vs_code, sizeof(vs_code), + tests[i].so_declaration, tests[i].so_entry_count, NULL, 0, + D3D11_SO_NO_RASTERIZED_STREAM, NULL, &gs); + ok(hr == S_OK, "Failed to create geometry shader with stream output, hr %#x.\n", hr); + ID3D11DeviceContext_GSSetShader(context, gs, NULL, 0); + current_so_declaration = tests[i].so_declaration; + } + + offset = 0; + ID3D11DeviceContext_SOSetTargets(context, 1, &so_buffer, &offset); + + ID3D11DeviceContext_Draw(context, 4, 0); + + get_buffer_readback(so_buffer, &rb); + result = rb.map_desc.pData; + for (j = 0; j < tests[i].expected_data_size; ++j) + { + float expected_value = tests[i].expected_data[j]; + ok(compare_float(result[j], expected_value, 2), + "Test %u: Got %.8e, expected %.8e at %u.\n", + i, result[j], expected_value, j); + } + release_resource_readback(&rb); + } + + ID3D11Buffer_Release(vb); + ID3D11Buffer_Release(so_buffer); + ID3D11VertexShader_Release(vs); + ID3D11GeometryShader_Release(gs); + ID3D11InputLayout_Release(input_layout); + release_test_context(&test_context); +} + static void test_gather(void) { struct @@ -26390,6 +26571,7 @@ START_TEST(d3d11) test_fl10_stream_output_desc(); test_stream_output_resume(); test_stream_output_components(); + test_stream_output_vs(); test_gather(); test_gather_c(); test_depth_bias();
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com