[PATCH 3/9] wined3d: Implement indirect draws.

Józef Kucia <[email protected]>
Newsgroups gmane.comp.emulators.wine.patches
Message-ID <[email protected]>
From: Józef Kucia <[email protected]>

Signed-off-by: Józef Kucia <[email protected]>
---
 dlls/wined3d/cs.c              | 68 ++++++++++++++++++++++++++++++------------
 dlls/wined3d/device.c          | 18 +++++++++++
 dlls/wined3d/drawprim.c        | 58 ++++++++++++++++++++++++++++-------
 dlls/wined3d/wined3d.spec      |  2 ++
 dlls/wined3d/wined3d_private.h | 31 +++++++++++++++++--
 include/wine/wined3d.h         |  4 +++
 6 files changed, 149 insertions(+), 32 deletions(-)

diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index afc4b05df59d..104e4c41c1da 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -120,12 +120,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
@@ -758,14 +753,21 @@ 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;
     struct wined3d_state *state = &cs->state;
     const struct wined3d_cs_draw *op = data;
+    int load_base_vertex_idx;
     unsigned int i;
 
-    if (!cs->device->adapter->gl_info.supported[ARB_DRAW_ELEMENTS_BASE_VERTEX]
-            && state->load_base_vertex_index != op->base_vertex_idx)
+    /* ARB_draw_indirect always supports a base vertex offset. */
+    if (!op->parameters.indirect && !gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
+        load_base_vertex_idx = op->parameters.u.direct.base_vertex_idx;
+    else
+        load_base_vertex_idx = 0;
+
+    if (state->load_base_vertex_index != load_base_vertex_idx)
     {
-        state->load_base_vertex_index = op->base_vertex_idx;
+        state->load_base_vertex_index = load_base_vertex_idx;
         device_invalidate_state(cs->device, STATE_BASEVERTEXINDEX);
     }
 
@@ -777,10 +779,15 @@ 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);
+    draw_primitive(cs->device, state, &op->parameters);
+
+    if (op->parameters.indirect)
+    {
+        struct wined3d_buffer *buffer = op->parameters.u.indirect.buffer;
+        wined3d_resource_release(&buffer->resource);
+    }
 
-    if (op->indexed)
+    if (op->parameters.indexed)
         wined3d_resource_release(&state->index_buffer->resource);
     for (i = 0; i < ARRAY_SIZE(state->streams); ++i)
     {
@@ -797,7 +804,7 @@ static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
         if (state->textures[i])
             wined3d_resource_release(&state->textures[i]->resource);
     }
-    for (i = 0; i < cs->device->adapter->gl_info.limits.buffers; ++i)
+    for (i = 0; i < gl_info->limits.buffers; ++i)
     {
         if (state->fb->render_targets[i])
             wined3d_resource_release(state->fb->render_targets[i]->resource);
@@ -855,14 +862,37 @@ 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;
+
+    acquire_graphics_pipeline_resources(state, indexed, gl_info);
+
+    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_gl_info *gl_info = &cs->device->adapter->gl_info;
+    const struct wined3d_state *state = &cs->device->state;
+    struct wined3d_cs_draw *op;
+
+    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;
 
     acquire_graphics_pipeline_resources(state, indexed, gl_info);
+    wined3d_resource_acquire(&buffer->resource);
 
     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
 }
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 994c4b1a144b..e0e1781afe57 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3703,6 +3703,15 @@ void CDECL wined3d_device_draw_primitive_instanced(struct wined3d_device *device
             0, start_vertex, vertex_count, start_instance, instance_count, FALSE);
 }
 
+void CDECL wined3d_device_draw_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, FALSE);
+}
+
 HRESULT CDECL wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count)
 {
     TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
@@ -3733,6 +3742,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/drawprim.c b/dlls/wined3d/drawprim.c
index 41eabba1f3a4..67fca6299f2a 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -460,8 +460,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;
@@ -474,7 +473,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]))
@@ -541,10 +540,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)
@@ -631,12 +628,51 @@ 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)
+        {
+            struct wined3d_buffer *buffer = parameters->u.indirect.buffer;
+
+            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,
+                        (void *)(GLintptr)parameters->u.indirect.offset));
+            }
+            else
+            {
+                GL_EXTCALL(glDrawArraysIndirect(state->gl_primitive_type,
+                        (void *)(GLintptr)parameters->u.indirect.offset));
+            }
+
+            GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
+
+            checkGLcall("draw indirect");
+        }
+        else
+        {
+            FIXME("Indirect draws with immediate mode/emulation are not supported.\n");
+        }
+    }
     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 fb8188e29c86..0825b9366051 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -45,8 +45,10 @@
 @ 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_draw_primitive_instanced_indirect(ptr ptr long)
 @ cdecl wined3d_device_end_scene(ptr)
 @ cdecl wined3d_device_end_stateblock(ptr ptr)
 @ cdecl wined3d_device_evict_managed_resources(ptr)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index fad3fadeeaad..6dce9701728a 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1515,9 +1515,34 @@ struct wined3d_dispatch_parameters
     } u;
 };
 
+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;
+};
+
 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;
@@ -3472,6 +3497,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 6fa31e7ea626..131bbf4703e7 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2222,9 +2222,13 @@ 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);
+void __cdecl wined3d_device_draw_primitive_instanced_indirect(struct wined3d_device *device,
+        struct wined3d_buffer *buffer, unsigned int offset);
 HRESULT __cdecl wined3d_device_end_scene(struct wined3d_device *device);
 HRESULT __cdecl wined3d_device_end_stateblock(struct wined3d_device *device, struct wined3d_stateblock **stateblock);
 void __cdecl wined3d_device_evict_managed_resources(struct wined3d_device *device);
-- 
2.13.6
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.