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