From 016f75697806c91b84dd0099396f13fce147e066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Sun, 23 Jul 2017 23:59:28 +0200 Subject: wined3d: Implement indirect drawing. --- dlls/d3d11/device.c | 12 ++++- dlls/wined3d/cs.c | 99 ++++++++++++++++++++++++++++++++---------- dlls/wined3d/device.c | 9 ++++ dlls/wined3d/directx.c | 5 +++ dlls/wined3d/drawprim.c | 68 ++++++++++++++++++++++++----- dlls/wined3d/wined3d.spec | 1 + dlls/wined3d/wined3d_gl.h | 1 + dlls/wined3d/wined3d_private.h | 31 ++++++++++++- include/wine/wined3d.h | 2 + 9 files changed, 192 insertions(+), 36 deletions(-) diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 9cffa8a9961..2ecce826042 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -1786,7 +1786,17 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_DrawAuto(ID3D11DeviceConte static void STDMETHODCALLTYPE d3d11_immediate_context_DrawIndexedInstancedIndirect(ID3D11DeviceContext *iface, ID3D11Buffer *buffer, UINT offset) { - FIXME("iface %p, buffer %p, offset %u stub!\n", iface, buffer, offset); + struct d3d_device *device = device_from_immediate_ID3D11DeviceContext(iface); + struct d3d_buffer *d3d_buffer; + + TRACE("iface %p, buffer %p, offset %u.\n", iface, buffer, offset); + + d3d_buffer = unsafe_impl_from_ID3D11Buffer(buffer); + + wined3d_mutex_lock(); + wined3d_device_draw_indexed_primitive_instanced_indirect(device->wined3d_device, + d3d_buffer->wined3d_buffer, offset); + wined3d_mutex_unlock(); } static void STDMETHODCALLTYPE d3d11_immediate_context_DrawInstancedIndirect(ID3D11DeviceContext *iface, diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 171287dc99c..805867a3e20 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -121,12 +121,7 @@ struct wined3d_cs_draw enum wined3d_cs_op opcode; GLenum primitive_type; GLint patch_vertex_count; - int base_vertex_idx; - unsigned int start_idx; - unsigned int index_count; - unsigned int start_instance; - unsigned int instance_count; - BOOL indexed; + struct wined3d_draw_parameters parameters; }; struct wined3d_cs_flush @@ -772,13 +767,6 @@ static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data) const struct wined3d_cs_draw *op = data; unsigned int i; - if (!cs->device->adapter->gl_info.supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] - && state->load_base_vertex_index != op->base_vertex_idx) - { - state->load_base_vertex_index = op->base_vertex_idx; - device_invalidate_state(cs->device, STATE_BASEVERTEXINDEX); - } - if (state->gl_primitive_type != op->primitive_type) { if (state->gl_primitive_type == GL_POINTS || op->primitive_type == GL_POINTS) @@ -787,10 +775,27 @@ static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data) } state->gl_patch_vertices = op->patch_vertex_count; - draw_primitive(cs->device, state, op->base_vertex_idx, op->start_idx, - op->index_count, op->start_instance, op->instance_count, op->indexed); + if (!op->parameters.indirect) + { + const struct wined3d_direct_draw_parameters *p = &op->parameters.u.direct; + + if (!cs->device->adapter->gl_info.supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] + && state->load_base_vertex_index != p->base_vertex_idx) + { + state->load_base_vertex_index = p->base_vertex_idx; + device_invalidate_state(cs->device, STATE_BASEVERTEXINDEX); + } + } + + draw_primitive(cs->device, state, &op->parameters); + + if (op->parameters.indirect) + { + const struct wined3d_indirect_draw_parameters *p = &op->parameters.u.indirect; - if (op->indexed) + wined3d_resource_release(&p->buffer->resource); + } + if (op->parameters.indexed) wined3d_resource_release(&state->index_buffer->resource); for (i = 0; i < ARRAY_SIZE(state->streams); ++i) { @@ -831,12 +836,62 @@ void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned op->opcode = WINED3D_CS_OP_DRAW; op->primitive_type = primitive_type; op->patch_vertex_count = patch_vertex_count; - op->base_vertex_idx = base_vertex_idx; - op->start_idx = start_idx; - op->index_count = index_count; - op->start_instance = start_instance; - op->instance_count = instance_count; - op->indexed = indexed; + op->parameters.indirect = FALSE; + op->parameters.u.direct.base_vertex_idx = base_vertex_idx; + op->parameters.u.direct.start_idx = start_idx; + op->parameters.u.direct.index_count = index_count; + op->parameters.u.direct.start_instance = start_instance; + op->parameters.u.direct.instance_count = instance_count; + op->parameters.indexed = indexed; + + if (indexed) + wined3d_resource_acquire(&state->index_buffer->resource); + for (i = 0; i < ARRAY_SIZE(state->streams); ++i) + { + if (state->streams[i].buffer) + wined3d_resource_acquire(&state->streams[i].buffer->resource); + } + for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i) + { + if (state->stream_output[i].buffer) + wined3d_resource_acquire(&state->stream_output[i].buffer->resource); + } + for (i = 0; i < ARRAY_SIZE(state->textures); ++i) + { + if (state->textures[i]) + wined3d_resource_acquire(&state->textures[i]->resource); + } + for (i = 0; i < cs->device->adapter->gl_info.limits.buffers; ++i) + { + if (state->fb->render_targets[i]) + wined3d_resource_acquire(state->fb->render_targets[i]->resource); + } + if (state->fb->depth_stencil) + wined3d_resource_acquire(state->fb->depth_stencil->resource); + acquire_shader_resources(state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE)); + acquire_unordered_access_resources(state->shader[WINED3D_SHADER_TYPE_PIXEL], + state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]); + + cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); +} + +void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count, + struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed) +{ + const struct wined3d_state *state = &cs->device->state; + struct wined3d_cs_draw *op; + unsigned int i; + + op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); + op->opcode = WINED3D_CS_OP_DRAW; + op->primitive_type = primitive_type; + op->patch_vertex_count = patch_vertex_count; + op->parameters.indirect = TRUE; + op->parameters.u.indirect.buffer = buffer; + op->parameters.u.indirect.offset = offset; + op->parameters.indexed = indexed; + + wined3d_resource_acquire(&buffer->resource); if (indexed) wined3d_resource_acquire(&state->index_buffer->resource); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 54a058ae1ed..b6458cfde53 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3782,6 +3782,15 @@ void CDECL wined3d_device_draw_indexed_primitive_instanced(struct wined3d_device device->state.base_vertex_index, start_idx, index_count, start_instance, instance_count, TRUE); } +void CDECL wined3d_device_draw_indexed_primitive_instanced_indirect(struct wined3d_device *device, + struct wined3d_buffer *buffer, unsigned int offset) +{ + TRACE("device %p, buffer %p, offset %u.\n", device, buffer, offset); + + wined3d_cs_emit_draw_indirect(device->cs, device->state.gl_primitive_type, device->state.gl_patch_vertices, + buffer, offset, TRUE); +} + HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device, struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture) { diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 82f6300d0f5..0553a16ee4e 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -126,6 +126,7 @@ static const struct wined3d_extension_map gl_extension_map[] = {"GL_ARB_derivative_control", ARB_DERIVATIVE_CONTROL }, {"GL_ARB_draw_buffers", ARB_DRAW_BUFFERS }, {"GL_ARB_draw_elements_base_vertex", ARB_DRAW_ELEMENTS_BASE_VERTEX }, + {"GL_ARB_draw_indirect", ARB_DRAW_INDIRECT }, {"GL_ARB_draw_instanced", ARB_DRAW_INSTANCED }, {"GL_ARB_ES2_compatibility", ARB_ES2_COMPATIBILITY }, {"GL_ARB_ES3_compatibility", ARB_ES3_COMPATIBILITY }, @@ -2735,6 +2736,9 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info) USE_GL_FUNC(glDrawElementsInstancedBaseVertex) USE_GL_FUNC(glDrawRangeElementsBaseVertex) USE_GL_FUNC(glMultiDrawElementsBaseVertex) + /* GL_ARB_draw_indirect */ + USE_GL_FUNC(glDrawArraysIndirect) + USE_GL_FUNC(glDrawElementsIndirect) /* GL_ARB_draw_instanced */ USE_GL_FUNC(glDrawArraysInstancedARB) USE_GL_FUNC(glDrawElementsInstancedARB) @@ -3886,6 +3890,7 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter, {ARB_TIMER_QUERY, MAKEDWORD_VERSION(3, 3)}, {ARB_VERTEX_TYPE_2_10_10_10_REV, MAKEDWORD_VERSION(3, 3)}, + {ARB_DRAW_INDIRECT, MAKEDWORD_VERSION(4, 0)}, {ARB_GPU_SHADER5, MAKEDWORD_VERSION(4, 0)}, {ARB_TESSELLATION_SHADER, MAKEDWORD_VERSION(4, 0)}, {ARB_TEXTURE_CUBE_MAP_ARRAY, MAKEDWORD_VERSION(4, 0)}, diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 6de0d613d2d..bec0155c6ef 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -168,6 +168,38 @@ static void draw_primitive_arrays(struct wined3d_context *context, const struct } } +/* Context activation is done by the caller. */ +static void draw_primitive_arrays_indirect(struct wined3d_context *context, const struct wined3d_state *state, + const void *idx_data, unsigned int idx_size, struct wined3d_buffer *buffer, unsigned int offset) +{ + const struct wined3d_gl_info *gl_info = context->gl_info; + + if (!gl_info->supported[ARB_DRAW_INDIRECT]) + { + FIXME("Indirect draw not supported.\n"); + return; + } + + wined3d_buffer_load(buffer, context, state); + GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->buffer_object)); + + if (idx_size) + { + GLenum idx_type = (idx_size == 2) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; + + GL_EXTCALL(glDrawElementsIndirect(state->gl_primitive_type, idx_type, + (const BYTE *)NULL + offset)); + } + else + { + GL_EXTCALL(glDrawArraysIndirect(state->gl_primitive_type, + (const BYTE *)NULL + offset)); + } + + GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0)); + checkGLcall("draw indirect"); +} + static unsigned int get_stride_idx(const void *idx_data, unsigned int idx_size, unsigned int base_vertex_idx, unsigned int start_idx, unsigned int vertex_idx) { @@ -477,8 +509,7 @@ static GLenum gl_tfb_primitive_type_from_d3d(enum wined3d_primitive_type primiti /* Routine common to the draw primitive and draw indexed primitive routines */ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *state, - int base_vertex_idx, unsigned int start_idx, unsigned int index_count, - unsigned int start_instance, unsigned int instance_count, BOOL indexed) + const struct wined3d_draw_parameters *parameters) { BOOL emulation = FALSE, rasterizer_discard = FALSE; const struct wined3d_fb_state *fb = state->fb; @@ -491,7 +522,7 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s unsigned int i, idx_size = 0; const void *idx_data = NULL; - if (!index_count) + if (!parameters->indirect && !parameters->u.direct.index_count) return; if (!(rtv = fb->render_targets[0])) @@ -558,10 +589,8 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s } stream_info = &context->stream_info; - if (context->instance_count) - instance_count = context->instance_count; - if (indexed) + if (parameters->indexed) { struct wined3d_buffer *index_buffer = state->index_buffer; if (!index_buffer->buffer_object || !stream_info->all_vbo) @@ -648,12 +677,29 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s checkGLcall("glPatchParameteri"); } - if (context->use_immediate_mode_draw || emulation) - draw_primitive_immediate_mode(context, state, stream_info, idx_data, - idx_size, base_vertex_idx, start_idx, index_count, instance_count); + if (parameters->indirect) + { + if (context->use_immediate_mode_draw || emulation) + FIXME("Indirect draw with immediate mode/emulation is not supported.\n"); + else + draw_primitive_arrays_indirect(context, state, idx_data, idx_size, + parameters->u.indirect.buffer, parameters->u.indirect.offset); + } else - draw_primitive_arrays(context, state, idx_data, idx_size, base_vertex_idx, - start_idx, index_count, start_instance, instance_count); + { + unsigned int instance_count = parameters->u.direct.instance_count; + if (context->instance_count) + instance_count = context->instance_count; + + if (context->use_immediate_mode_draw || emulation) + draw_primitive_immediate_mode(context, state, stream_info, idx_data, + idx_size, parameters->u.direct.base_vertex_idx, + parameters->u.direct.start_idx, parameters->u.direct.index_count, instance_count); + else + draw_primitive_arrays(context, state, idx_data, idx_size, parameters->u.direct.base_vertex_idx, + parameters->u.direct.start_idx, parameters->u.direct.index_count, + parameters->u.direct.start_instance, instance_count); + } if (context->uses_uavs) { diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 122e39ba8ee..2d80b3a8772 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -45,6 +45,7 @@ @ cdecl wined3d_device_dispatch_compute_indirect(ptr ptr long) @ cdecl wined3d_device_draw_indexed_primitive(ptr long long) @ cdecl wined3d_device_draw_indexed_primitive_instanced(ptr long long long long) +@ cdecl wined3d_device_draw_indexed_primitive_instanced_indirect(ptr ptr long) @ cdecl wined3d_device_draw_primitive(ptr long long) @ cdecl wined3d_device_draw_primitive_instanced(ptr long long long long) @ cdecl wined3d_device_end_scene(ptr) diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h index 4fe1971b5e6..4f73478a3b4 100644 --- a/dlls/wined3d/wined3d_gl.h +++ b/dlls/wined3d/wined3d_gl.h @@ -60,6 +60,7 @@ enum wined3d_gl_extension ARB_DERIVATIVE_CONTROL, ARB_DRAW_BUFFERS, ARB_DRAW_ELEMENTS_BASE_VERTEX, + ARB_DRAW_INDIRECT, ARB_DRAW_INSTANCED, ARB_ES2_COMPATIBILITY, ARB_ES3_COMPATIBILITY, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index e2461100a5a..50143a91425 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1481,6 +1481,32 @@ void wined3d_stream_info_from_declaration(struct wined3d_stream_info *stream_inf const struct wined3d_state *state, const struct wined3d_gl_info *gl_info, const struct wined3d_d3d_info *d3d_info) DECLSPEC_HIDDEN; +struct wined3d_direct_draw_parameters +{ + int base_vertex_idx; + unsigned int start_idx; + unsigned int index_count; + unsigned int start_instance; + unsigned int instance_count; +}; + +struct wined3d_indirect_draw_parameters +{ + struct wined3d_buffer *buffer; + unsigned int offset; +}; + +struct wined3d_draw_parameters +{ + BOOL indirect; + union + { + struct wined3d_direct_draw_parameters direct; + struct wined3d_indirect_draw_parameters indirect; + } u; + BOOL indexed; +}; + struct wined3d_direct_dispatch_parameters { unsigned int group_count_x; @@ -1505,8 +1531,7 @@ struct wined3d_dispatch_parameters }; void draw_primitive(struct wined3d_device *device, const struct wined3d_state *state, - int base_vertex_idx, unsigned int start_idx, unsigned int index_count, - unsigned int start_instance, unsigned int instance_count, BOOL indexed) DECLSPEC_HIDDEN; + const struct wined3d_draw_parameters *draw_parameters) DECLSPEC_HIDDEN; void dispatch_compute(struct wined3d_device *device, const struct wined3d_state *state, const struct wined3d_dispatch_parameters *dispatch_parameters) DECLSPEC_HIDDEN; DWORD get_flexible_vertex_size(DWORD d3dvtVertexType) DECLSPEC_HIDDEN; @@ -3460,6 +3485,8 @@ void wined3d_cs_emit_dispatch_indirect(struct wined3d_cs *cs, void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count, int base_vertex_idx, unsigned int start_idx, unsigned int index_count, unsigned int start_instance, unsigned int instance_count, BOOL indexed) DECLSPEC_HIDDEN; +void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count, + struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed) DECLSPEC_HIDDEN; void wined3d_cs_emit_flush(struct wined3d_cs *cs) DECLSPEC_HIDDEN; void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource) DECLSPEC_HIDDEN; void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain, diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index a99dbf64686..0b4c97fad54 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2245,6 +2245,8 @@ void __cdecl wined3d_device_dispatch_compute_indirect(struct wined3d_device *dev HRESULT __cdecl wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count); void __cdecl wined3d_device_draw_indexed_primitive_instanced(struct wined3d_device *device, UINT start_idx, UINT index_count, UINT start_instance, UINT instance_count); +void __cdecl wined3d_device_draw_indexed_primitive_instanced_indirect(struct wined3d_device *device, + struct wined3d_buffer *buffer, unsigned int offset); HRESULT __cdecl wined3d_device_draw_primitive(struct wined3d_device *device, UINT start_vertex, UINT vertex_count); void __cdecl wined3d_device_draw_primitive_instanced(struct wined3d_device *device, UINT start_vertex, UINT vertex_count, UINT start_instance, UINT instance_count); -- 2.13.1