wined3d: Specify geometry shader outputs to record in stream output buffers.

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>
oldstable
Józef Kucia 2017-03-28 12:00:06 +02:00 committed by Alexandre Julliard
parent d50745b7ae
commit 16ab203342
3 changed files with 157 additions and 7 deletions

View File

@ -727,6 +727,133 @@ static void shader_glsl_load_program_resources(const struct wined3d_context *con
shader_glsl_load_samplers(context, priv, program_id, reg_maps);
}
static void append_transform_feedback_varying(const char **varyings, unsigned int *varying_count,
char **strings, unsigned int *strings_length, struct wined3d_string_buffer *buffer)
{
if (varyings && *strings)
{
char *ptr = *strings;
varyings[*varying_count] = ptr;
memcpy(ptr, buffer->buffer, buffer->content_size + 1);
ptr += buffer->content_size + 1;
*strings = ptr;
}
*strings_length += buffer->content_size + 1;
++(*varying_count);
}
static void shader_glsl_generate_transform_feedback_varyings(const struct wined3d_stream_output_desc *so_desc,
struct wined3d_string_buffer *buffer, const char **varyings, unsigned int *varying_count,
char *strings, unsigned int *strings_length)
{
unsigned int i, j, buffer_idx, count, length, highest_output_slot;
count = length = 0;
highest_output_slot = 0;
for (buffer_idx = 0; buffer_idx < WINED3D_MAX_STREAM_OUTPUT_BUFFERS; ++buffer_idx)
{
for (i = 0; i < so_desc->element_count; ++i)
{
const struct wined3d_stream_output_element *e = &so_desc->elements[i];
highest_output_slot = max(highest_output_slot, e->output_slot);
if (e->output_slot != buffer_idx)
continue;
if (e->stream_idx)
{
FIXME("Unhandled stream %u.\n", e->stream_idx);
continue;
}
if (e->register_idx == WINED3D_STREAM_OUTPUT_GAP)
{
for (j = 0; j < e->component_count / 4; ++j)
{
string_buffer_sprintf(buffer, "gl_SkipComponents4");
append_transform_feedback_varying(varyings, &count, &strings, &length, buffer);
}
if (e->component_count % 4)
{
string_buffer_sprintf(buffer, "gl_SkipComponents%u", e->component_count % 4);
append_transform_feedback_varying(varyings, &count, &strings, &length, buffer);
}
continue;
}
if (e->component_idx || e->component_count != 4)
{
FIXME("Unsupported component range %u-%u.\n", e->component_idx, e->component_count);
continue;
}
string_buffer_sprintf(buffer, "ps_link[%u]", e->register_idx);
append_transform_feedback_varying(varyings, &count, &strings, &length, buffer);
}
if (highest_output_slot <= buffer_idx)
break;
string_buffer_sprintf(buffer, "gl_NextBuffer");
append_transform_feedback_varying(varyings, &count, &strings, &length, buffer);
}
if (varying_count)
*varying_count = count;
if (strings_length)
*strings_length = length;
}
static void shader_glsl_init_transform_feedback(const struct wined3d_context *context,
struct shader_glsl_priv *priv, GLuint program_id, const struct wined3d_shader *shader)
{
const struct wined3d_stream_output_desc *so_desc = &shader->u.gs.so_desc;
const struct wined3d_gl_info *gl_info = context->gl_info;
struct wined3d_string_buffer *buffer;
unsigned int count, length;
const char **varyings;
char *strings;
if (!gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
{
FIXME("ARB_transform_feedback3 not supported by OpenGL implementation.\n");
return;
}
if (so_desc->buffer_stride_count)
FIXME("Ignoring buffer strides.\n");
buffer = string_buffer_get(&priv->string_buffers);
shader_glsl_generate_transform_feedback_varyings(so_desc, buffer, NULL, &count, NULL, &length);
if (!(varyings = wined3d_calloc(count, sizeof(*varyings))))
{
ERR("Out of memory.\n");
string_buffer_release(&priv->string_buffers, buffer);
return;
}
if (!(strings = wined3d_calloc(length, sizeof(*strings))))
{
ERR("Out of memory.\n");
HeapFree(GetProcessHeap(), 0, varyings);
string_buffer_release(&priv->string_buffers, buffer);
return;
}
shader_glsl_generate_transform_feedback_varyings(so_desc, buffer, varyings, NULL, strings, NULL);
GL_EXTCALL(glTransformFeedbackVaryings(program_id, count, varyings, GL_INTERLEAVED_ATTRIBS));
checkGLcall("glTransformFeedbackVaryings");
HeapFree(GetProcessHeap(), 0, varyings);
HeapFree(GetProcessHeap(), 0, strings);
string_buffer_release(&priv->string_buffers, buffer);
}
/* Context activation is done by the caller. */
static inline void walk_constant_heap(const struct wined3d_gl_info *gl_info, const struct wined3d_vec4 *constants,
const GLint *constant_locations, const struct constant_heap *heap, unsigned char *stack, DWORD version)
@ -8994,6 +9121,8 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
checkGLcall("glProgramParameteriARB");
}
shader_glsl_init_transform_feedback(context, priv, program_id, gshader);
list_add_head(&gshader->linked_programs, &entry->gs.shader_entry);
}
@ -9588,7 +9717,8 @@ static void shader_glsl_get_caps(const struct wined3d_gl_info *gl_info, struct s
&& gl_info->supported[ARB_SHADER_ATOMIC_COUNTERS]
&& gl_info->supported[ARB_SHADER_IMAGE_LOAD_STORE]
&& gl_info->supported[ARB_SHADER_IMAGE_SIZE]
&& gl_info->supported[ARB_SHADING_LANGUAGE_PACKING])
&& gl_info->supported[ARB_SHADING_LANGUAGE_PACKING]
&& gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
shader_model = 5;
else if (gl_info->glsl_version >= MAKEDWORD_VERSION(1, 50) && gl_info->supported[WINED3D_GL_VERSION_3_2]
&& gl_info->supported[ARB_SHADER_BIT_ENCODING] && gl_info->supported[ARB_SAMPLER_OBJECTS]

View File

@ -2813,6 +2813,9 @@ static void shader_trace_init(const struct wined3d_shader_frontend *fe, void *fe
static void shader_cleanup(struct wined3d_shader *shader)
{
if (shader->reg_maps.shader_version.type == WINED3D_SHADER_TYPE_GEOMETRY)
HeapFree(GetProcessHeap(), 0, shader->u.gs.so_desc.elements);
HeapFree(GetProcessHeap(), 0, shader->output_signature.elements);
HeapFree(GetProcessHeap(), 0, shader->input_signature.elements);
HeapFree(GetProcessHeap(), 0, shader->signature_strings);
@ -3399,9 +3402,27 @@ static HRESULT hull_shader_init(struct wined3d_shader *shader, struct wined3d_de
}
static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3d_device *device,
const struct wined3d_shader_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops)
const struct wined3d_shader_desc *desc, const struct wined3d_stream_output_desc *so_desc,
void *parent, const struct wined3d_parent_ops *parent_ops)
{
return shader_init(shader, device, desc, 0, WINED3D_SHADER_TYPE_GEOMETRY, parent, parent_ops);
HRESULT hr;
if (FAILED(hr = shader_init(shader, device, desc, 0, WINED3D_SHADER_TYPE_GEOMETRY, parent, parent_ops)))
return hr;
if (so_desc)
{
struct wined3d_stream_output_desc *d = &shader->u.gs.so_desc;
*d = *so_desc;
if (!(d->elements = wined3d_calloc(so_desc->element_count, sizeof(*d->elements))))
{
shader_cleanup(shader);
return E_OUTOFMEMORY;
}
memcpy(d->elements, so_desc->elements, so_desc->element_count * sizeof(*d->elements));
}
return WINED3D_OK;
}
void find_gs_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader,
@ -3797,13 +3818,10 @@ 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 (so_desc)
FIXME("Stream output not supported.\n");
if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
return E_OUTOFMEMORY;
if (FAILED(hr = geometry_shader_init(object, device, desc, parent, parent_ops)))
if (FAILED(hr = geometry_shader_init(object, device, desc, so_desc, parent, parent_ops)))
{
WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
HeapFree(GetProcessHeap(), 0, object);

View File

@ -3610,6 +3610,8 @@ struct wined3d_geometry_shader
enum wined3d_primitive_type input_type;
enum wined3d_primitive_type output_type;
UINT vertices_out;
struct wined3d_stream_output_desc so_desc;
};
struct wined3d_pixel_shader