xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/d3d10umd/Draw.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2012-2021 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  **************************************************************************/
27 
28 /*
29  * Draw.h --
30  *    Functions that render 3D primitives.
31  */
32 
33 
34 #include "Draw.h"
35 #include "State.h"
36 #include "Shader.h"
37 
38 #include "Debug.h"
39 
40 #include "util/u_draw.h"
41 #include "util/u_memory.h"
42 
43 static unsigned
ClampedUAdd(unsigned a,unsigned b)44 ClampedUAdd(unsigned a,
45             unsigned b)
46 {
47    unsigned c = a + b;
48    if (c < a) {
49       return 0xffffffff;
50    }
51    return c;
52 }
53 
54 
55 /* stride is required in order to set the element data */
56 static void
update_velems(Device * pDevice)57 update_velems(Device *pDevice)
58 {
59    if (!pDevice->velems_changed)
60       return;
61 
62    if(pDevice->element_layout) {
63       struct cso_velems_state *state = &pDevice->element_layout->state;
64       for (unsigned i = 0; i < state->count; i++)
65          state->velems[i].src_stride = pDevice->vertex_strides[state->velems[i].vertex_buffer_index];
66       cso_set_vertex_elements(pDevice->cso, state);
67    }
68 
69    pDevice->velems_changed = false;
70 }
71 
72 /*
73  * We have to resolve the stream output state for empty geometry shaders.
74  * In particular we've remapped the output indices when translating the
75  * shaders so now the register_index variables in the stream output
76  * state are incorrect and we need to remap them back to the correct
77  * state.
78  */
79 static void
ResolveState(Device * pDevice)80 ResolveState(Device *pDevice)
81 {
82    if (pDevice->bound_empty_gs && pDevice->bound_vs &&
83        pDevice->bound_vs->state.tokens) {
84       Shader *gs = pDevice->bound_empty_gs;
85       Shader *vs = pDevice->bound_vs;
86       bool remapped = false;
87       struct pipe_context *pipe = pDevice->pipe;
88       if (!gs->output_resolved) {
89          for (unsigned i = 0; i < gs->state.stream_output.num_outputs; ++i) {
90             unsigned mapping =
91                ShaderFindOutputMapping(vs, gs->state.stream_output.output[i].register_index);
92             if (mapping != gs->state.stream_output.output[i].register_index) {
93                gs->state.stream_output.output[i].register_index = mapping;
94                remapped = true;
95             }
96          }
97          if (remapped) {
98             pipe->delete_gs_state(pipe, gs->handle);
99             gs->handle = pipe->create_gs_state(pipe, &gs->state);
100          }
101          gs->output_resolved = true;
102       }
103       pipe->bind_gs_state(pipe, gs->handle);
104    }
105    update_velems(pDevice);
106 
107    if (pDevice->vbuffers_changed) {
108       cso_set_vertex_buffers(pDevice->cso, PIPE_MAX_ATTRIBS, false, pDevice->vertex_buffers);
109       pDevice->vbuffers_changed = false;
110    }
111 }
112 
113 
114 static struct pipe_resource *
create_null_index_buffer(struct pipe_context * ctx,uint num_indices,unsigned * restart_index,unsigned * index_size,unsigned * ib_offset)115 create_null_index_buffer(struct pipe_context *ctx, uint num_indices,
116                          unsigned *restart_index, unsigned *index_size,
117                          unsigned *ib_offset)
118 {
119    unsigned buf_size = num_indices * sizeof(unsigned);
120    unsigned *buf = (unsigned*)MALLOC(buf_size);
121    struct pipe_resource *ibuf;
122 
123    memset(buf, 0, buf_size);
124 
125    ibuf = pipe_buffer_create_with_data(ctx,
126                                        PIPE_BIND_INDEX_BUFFER,
127                                        PIPE_USAGE_IMMUTABLE,
128                                        buf_size, buf);
129    *index_size = 4;
130    *restart_index = 0xffffffff;
131    *ib_offset = 0;
132 
133    FREE(buf);
134 
135    return ibuf;
136 }
137 
138 /*
139  * ----------------------------------------------------------------------
140  *
141  * Draw --
142  *
143  *    The Draw function draws nonindexed primitives.
144  *
145  * ----------------------------------------------------------------------
146  */
147 
148 void APIENTRY
Draw(D3D10DDI_HDEVICE hDevice,UINT VertexCount,UINT StartVertexLocation)149 Draw(D3D10DDI_HDEVICE hDevice,   // IN
150      UINT VertexCount,           // IN
151      UINT StartVertexLocation)   // IN
152 {
153    LOG_ENTRYPOINT();
154 
155    Device *pDevice = CastDevice(hDevice);
156 
157    ResolveState(pDevice);
158 
159    assert(pDevice->primitive < MESA_PRIM_COUNT);
160    util_draw_arrays(pDevice->pipe,
161                     pDevice->primitive,
162                     StartVertexLocation,
163                     VertexCount);
164 }
165 
166 
167 /*
168  * ----------------------------------------------------------------------
169  *
170  * DrawIndexed --
171  *
172  *    The DrawIndexed function draws indexed primitives.
173  *
174  * ----------------------------------------------------------------------
175  */
176 
177 void APIENTRY
DrawIndexed(D3D10DDI_HDEVICE hDevice,UINT IndexCount,UINT StartIndexLocation,INT BaseVertexLocation)178 DrawIndexed(D3D10DDI_HDEVICE hDevice,  // IN
179             UINT IndexCount,           // IN
180             UINT StartIndexLocation,   // IN
181             INT BaseVertexLocation)    // IN
182 {
183    LOG_ENTRYPOINT();
184 
185    Device *pDevice = CastDevice(hDevice);
186    struct pipe_draw_info info;
187    struct pipe_draw_start_count_bias draw;
188    struct pipe_resource *null_ib = NULL;
189    unsigned restart_index = pDevice->restart_index;
190    unsigned index_size = pDevice->index_size;
191    unsigned ib_offset = pDevice->ib_offset;
192 
193    assert(pDevice->primitive < MESA_PRIM_COUNT);
194 
195    /* XXX I don't think draw still needs this? */
196    if (!pDevice->index_buffer) {
197       null_ib =
198          create_null_index_buffer(pDevice->pipe,
199                                   StartIndexLocation + IndexCount,
200                                   &restart_index, &index_size, &ib_offset);
201    }
202 
203    ResolveState(pDevice);
204 
205    util_draw_init_info(&info);
206    info.index_size = index_size;
207    info.mode = pDevice->primitive;
208    draw.start = ClampedUAdd(StartIndexLocation, ib_offset / index_size);
209    draw.count = IndexCount;
210    info.index.resource = null_ib ? null_ib : pDevice->index_buffer;
211    draw.index_bias = BaseVertexLocation;
212    info.primitive_restart = true;
213    info.restart_index = restart_index;
214 
215    pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, NULL, &draw, 1);
216 
217    if (null_ib) {
218       pipe_resource_reference(&null_ib, NULL);
219    }
220 }
221 
222 
223 /*
224  * ----------------------------------------------------------------------
225  *
226  * DrawInstanced --
227  *
228  *    The DrawInstanced function draws particular instances
229  *    of nonindexed primitives.
230  *
231  * ----------------------------------------------------------------------
232  */
233 
234 void APIENTRY
DrawInstanced(D3D10DDI_HDEVICE hDevice,UINT VertexCountPerInstance,UINT InstanceCount,UINT StartVertexLocation,UINT StartInstanceLocation)235 DrawInstanced(D3D10DDI_HDEVICE hDevice,      // IN
236               UINT VertexCountPerInstance,   // IN
237               UINT InstanceCount,            // IN
238               UINT StartVertexLocation,      // IN
239               UINT StartInstanceLocation)    // IN
240 {
241    LOG_ENTRYPOINT();
242 
243    Device *pDevice = CastDevice(hDevice);
244 
245    if (!InstanceCount) {
246       return;
247    }
248 
249    ResolveState(pDevice);
250 
251    assert(pDevice->primitive < MESA_PRIM_COUNT);
252    util_draw_arrays_instanced(pDevice->pipe,
253                               pDevice->primitive,
254                               StartVertexLocation,
255                               VertexCountPerInstance,
256                               StartInstanceLocation,
257                               InstanceCount);
258 }
259 
260 
261 /*
262  * ----------------------------------------------------------------------
263  *
264  * DrawIndexedInstanced --
265  *
266  *    The DrawIndexedInstanced function draws particular
267  *    instances of indexed primitives.
268  *
269  * ----------------------------------------------------------------------
270  */
271 
272 void APIENTRY
DrawIndexedInstanced(D3D10DDI_HDEVICE hDevice,UINT IndexCountPerInstance,UINT InstanceCount,UINT StartIndexLocation,INT BaseVertexLocation,UINT StartInstanceLocation)273 DrawIndexedInstanced(D3D10DDI_HDEVICE hDevice,   // IN
274                      UINT IndexCountPerInstance, // IN
275                      UINT InstanceCount,         // IN
276                      UINT StartIndexLocation,    // IN
277                      INT BaseVertexLocation,     // IN
278                      UINT StartInstanceLocation) // IN
279 {
280    LOG_ENTRYPOINT();
281 
282    Device *pDevice = CastDevice(hDevice);
283    struct pipe_draw_info info;
284    struct pipe_draw_start_count_bias draw;
285    struct pipe_resource *null_ib = NULL;
286    unsigned restart_index = pDevice->restart_index;
287    unsigned index_size = pDevice->index_size;
288    unsigned ib_offset = pDevice->ib_offset;
289 
290    assert(pDevice->primitive < MESA_PRIM_COUNT);
291 
292    if (!InstanceCount) {
293       return;
294    }
295 
296    /* XXX I don't think draw still needs this? */
297    if (!pDevice->index_buffer) {
298       null_ib =
299          create_null_index_buffer(pDevice->pipe,
300                                   StartIndexLocation + IndexCountPerInstance,
301                                   &restart_index, &index_size, &ib_offset);
302    }
303 
304    ResolveState(pDevice);
305 
306    util_draw_init_info(&info);
307    info.index_size = index_size;
308    info.mode = pDevice->primitive;
309    draw.start = ClampedUAdd(StartIndexLocation, ib_offset / index_size);
310    draw.count = IndexCountPerInstance;
311    info.index.resource = null_ib ? null_ib : pDevice->index_buffer;
312    draw.index_bias = BaseVertexLocation;
313    info.start_instance = StartInstanceLocation;
314    info.instance_count = InstanceCount;
315    info.primitive_restart = true;
316    info.restart_index = restart_index;
317 
318    pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, NULL, &draw, 1);
319 
320    if (null_ib) {
321       pipe_resource_reference(&null_ib, NULL);
322    }
323 }
324 
325 
326 /*
327  * ----------------------------------------------------------------------
328  *
329  * DrawAuto --
330  *
331  *    The DrawAuto function works similarly to the Draw function,
332  *    except DrawAuto is used for the special case where vertex
333  *    data is written through the stream-output unit and then
334  *    recycled as a vertex buffer. The driver determines the number
335  *    of primitives, in part, by how much data was written to the
336  *    buffer through stream output.
337  *
338  * ----------------------------------------------------------------------
339  */
340 
341 void APIENTRY
DrawAuto(D3D10DDI_HDEVICE hDevice)342 DrawAuto(D3D10DDI_HDEVICE hDevice)  // IN
343 {
344    LOG_ENTRYPOINT();
345 
346    Device *pDevice = CastDevice(hDevice);
347    struct pipe_draw_info info;
348    struct pipe_draw_indirect_info indirect;
349 
350 
351    if (!pDevice->draw_so_target) {
352       LOG_UNSUPPORTED("DrawAuto without a set source buffer!");
353       return;
354    }
355 
356    assert(pDevice->primitive < MESA_PRIM_COUNT);
357 
358    ResolveState(pDevice);
359 
360    util_draw_init_info(&info);
361    info.mode = pDevice->primitive;
362    memset(&indirect, 0, sizeof indirect);
363    indirect.count_from_stream_output = pDevice->draw_so_target;
364 
365    pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, &indirect, NULL, 1);
366 }
367