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 /*
56 * We have to resolve the stream output state for empty geometry shaders.
57 * In particular we've remapped the output indices when translating the
58 * shaders so now the register_index variables in the stream output
59 * state are incorrect and we need to remap them back to the correct
60 * state.
61 */
62 static void
ResolveState(Device * pDevice)63 ResolveState(Device *pDevice)
64 {
65 if (pDevice->bound_empty_gs && pDevice->bound_vs &&
66 pDevice->bound_vs->state.tokens) {
67 Shader *gs = pDevice->bound_empty_gs;
68 Shader *vs = pDevice->bound_vs;
69 boolean remapped = FALSE;
70 struct pipe_context *pipe = pDevice->pipe;
71 if (!gs->output_resolved) {
72 for (unsigned i = 0; i < gs->state.stream_output.num_outputs; ++i) {
73 unsigned mapping =
74 ShaderFindOutputMapping(vs, gs->state.stream_output.output[i].register_index);
75 if (mapping != gs->state.stream_output.output[i].register_index) {
76 gs->state.stream_output.output[i].register_index = mapping;
77 remapped = TRUE;
78 }
79 }
80 if (remapped) {
81 pipe->delete_gs_state(pipe, gs->handle);
82 gs->handle = pipe->create_gs_state(pipe, &gs->state);
83 }
84 gs->output_resolved = TRUE;
85 }
86 pipe->bind_gs_state(pipe, gs->handle);
87 }
88 }
89
90
91 static struct pipe_resource *
create_null_index_buffer(struct pipe_context * ctx,uint num_indices,unsigned * restart_index,unsigned * index_size,unsigned * ib_offset)92 create_null_index_buffer(struct pipe_context *ctx, uint num_indices,
93 unsigned *restart_index, unsigned *index_size,
94 unsigned *ib_offset)
95 {
96 unsigned buf_size = num_indices * sizeof(unsigned);
97 unsigned *buf = (unsigned*)MALLOC(buf_size);
98 struct pipe_resource *ibuf;
99
100 memset(buf, 0, buf_size);
101
102 ibuf = pipe_buffer_create_with_data(ctx,
103 PIPE_BIND_INDEX_BUFFER,
104 PIPE_USAGE_IMMUTABLE,
105 buf_size, buf);
106 *index_size = 4;
107 *restart_index = 0xffffffff;
108 *ib_offset = 0;
109
110 FREE(buf);
111
112 return ibuf;
113 }
114
115 /*
116 * ----------------------------------------------------------------------
117 *
118 * Draw --
119 *
120 * The Draw function draws nonindexed primitives.
121 *
122 * ----------------------------------------------------------------------
123 */
124
125 void APIENTRY
Draw(D3D10DDI_HDEVICE hDevice,UINT VertexCount,UINT StartVertexLocation)126 Draw(D3D10DDI_HDEVICE hDevice, // IN
127 UINT VertexCount, // IN
128 UINT StartVertexLocation) // IN
129 {
130 LOG_ENTRYPOINT();
131
132 Device *pDevice = CastDevice(hDevice);
133
134 ResolveState(pDevice);
135
136 assert(pDevice->primitive < PIPE_PRIM_MAX);
137 util_draw_arrays(pDevice->pipe,
138 pDevice->primitive,
139 StartVertexLocation,
140 VertexCount);
141 }
142
143
144 /*
145 * ----------------------------------------------------------------------
146 *
147 * DrawIndexed --
148 *
149 * The DrawIndexed function draws indexed primitives.
150 *
151 * ----------------------------------------------------------------------
152 */
153
154 void APIENTRY
DrawIndexed(D3D10DDI_HDEVICE hDevice,UINT IndexCount,UINT StartIndexLocation,INT BaseVertexLocation)155 DrawIndexed(D3D10DDI_HDEVICE hDevice, // IN
156 UINT IndexCount, // IN
157 UINT StartIndexLocation, // IN
158 INT BaseVertexLocation) // IN
159 {
160 LOG_ENTRYPOINT();
161
162 Device *pDevice = CastDevice(hDevice);
163 struct pipe_draw_info info;
164 struct pipe_draw_start_count_bias draw;
165 struct pipe_resource *null_ib = NULL;
166 unsigned restart_index = pDevice->restart_index;
167 unsigned index_size = pDevice->index_size;
168 unsigned ib_offset = pDevice->ib_offset;
169
170 assert(pDevice->primitive < PIPE_PRIM_MAX);
171
172 /* XXX I don't think draw still needs this? */
173 if (!pDevice->index_buffer) {
174 null_ib =
175 create_null_index_buffer(pDevice->pipe,
176 StartIndexLocation + IndexCount,
177 &restart_index, &index_size, &ib_offset);
178 }
179
180 ResolveState(pDevice);
181
182 util_draw_init_info(&info);
183 info.index_size = index_size;
184 info.mode = pDevice->primitive;
185 draw.start = ClampedUAdd(StartIndexLocation, ib_offset / index_size);
186 draw.count = IndexCount;
187 info.index.resource = null_ib ? null_ib : pDevice->index_buffer;
188 draw.index_bias = BaseVertexLocation;
189 info.primitive_restart = TRUE;
190 info.restart_index = restart_index;
191
192 pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, NULL, &draw, 1);
193
194 if (null_ib) {
195 pipe_resource_reference(&null_ib, NULL);
196 }
197 }
198
199
200 /*
201 * ----------------------------------------------------------------------
202 *
203 * DrawInstanced --
204 *
205 * The DrawInstanced function draws particular instances
206 * of nonindexed primitives.
207 *
208 * ----------------------------------------------------------------------
209 */
210
211 void APIENTRY
DrawInstanced(D3D10DDI_HDEVICE hDevice,UINT VertexCountPerInstance,UINT InstanceCount,UINT StartVertexLocation,UINT StartInstanceLocation)212 DrawInstanced(D3D10DDI_HDEVICE hDevice, // IN
213 UINT VertexCountPerInstance, // IN
214 UINT InstanceCount, // IN
215 UINT StartVertexLocation, // IN
216 UINT StartInstanceLocation) // IN
217 {
218 LOG_ENTRYPOINT();
219
220 Device *pDevice = CastDevice(hDevice);
221
222 if (!InstanceCount) {
223 return;
224 }
225
226 ResolveState(pDevice);
227
228 assert(pDevice->primitive < PIPE_PRIM_MAX);
229 util_draw_arrays_instanced(pDevice->pipe,
230 pDevice->primitive,
231 StartVertexLocation,
232 VertexCountPerInstance,
233 StartInstanceLocation,
234 InstanceCount);
235 }
236
237
238 /*
239 * ----------------------------------------------------------------------
240 *
241 * DrawIndexedInstanced --
242 *
243 * The DrawIndexedInstanced function draws particular
244 * instances of indexed primitives.
245 *
246 * ----------------------------------------------------------------------
247 */
248
249 void APIENTRY
DrawIndexedInstanced(D3D10DDI_HDEVICE hDevice,UINT IndexCountPerInstance,UINT InstanceCount,UINT StartIndexLocation,INT BaseVertexLocation,UINT StartInstanceLocation)250 DrawIndexedInstanced(D3D10DDI_HDEVICE hDevice, // IN
251 UINT IndexCountPerInstance, // IN
252 UINT InstanceCount, // IN
253 UINT StartIndexLocation, // IN
254 INT BaseVertexLocation, // IN
255 UINT StartInstanceLocation) // IN
256 {
257 LOG_ENTRYPOINT();
258
259 Device *pDevice = CastDevice(hDevice);
260 struct pipe_draw_info info;
261 struct pipe_draw_start_count_bias draw;
262 struct pipe_resource *null_ib = NULL;
263 unsigned restart_index = pDevice->restart_index;
264 unsigned index_size = pDevice->index_size;
265 unsigned ib_offset = pDevice->ib_offset;
266
267 assert(pDevice->primitive < PIPE_PRIM_MAX);
268
269 if (!InstanceCount) {
270 return;
271 }
272
273 /* XXX I don't think draw still needs this? */
274 if (!pDevice->index_buffer) {
275 null_ib =
276 create_null_index_buffer(pDevice->pipe,
277 StartIndexLocation + IndexCountPerInstance,
278 &restart_index, &index_size, &ib_offset);
279 }
280
281 ResolveState(pDevice);
282
283 util_draw_init_info(&info);
284 info.index_size = index_size;
285 info.mode = pDevice->primitive;
286 draw.start = ClampedUAdd(StartIndexLocation, ib_offset / index_size);
287 draw.count = IndexCountPerInstance;
288 info.index.resource = null_ib ? null_ib : pDevice->index_buffer;
289 draw.index_bias = BaseVertexLocation;
290 info.start_instance = StartInstanceLocation;
291 info.instance_count = InstanceCount;
292 info.primitive_restart = TRUE;
293 info.restart_index = restart_index;
294
295 pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, NULL, &draw, 1);
296
297 if (null_ib) {
298 pipe_resource_reference(&null_ib, NULL);
299 }
300 }
301
302
303 /*
304 * ----------------------------------------------------------------------
305 *
306 * DrawAuto --
307 *
308 * The DrawAuto function works similarly to the Draw function,
309 * except DrawAuto is used for the special case where vertex
310 * data is written through the stream-output unit and then
311 * recycled as a vertex buffer. The driver determines the number
312 * of primitives, in part, by how much data was written to the
313 * buffer through stream output.
314 *
315 * ----------------------------------------------------------------------
316 */
317
318 void APIENTRY
DrawAuto(D3D10DDI_HDEVICE hDevice)319 DrawAuto(D3D10DDI_HDEVICE hDevice) // IN
320 {
321 LOG_ENTRYPOINT();
322
323 Device *pDevice = CastDevice(hDevice);
324 struct pipe_draw_info info;
325 struct pipe_draw_indirect_info indirect;
326
327
328 if (!pDevice->draw_so_target) {
329 LOG_UNSUPPORTED("DrawAuto without a set source buffer!");
330 return;
331 }
332
333 assert(pDevice->primitive < PIPE_PRIM_MAX);
334
335 ResolveState(pDevice);
336
337 util_draw_init_info(&info);
338 info.mode = pDevice->primitive;
339 memset(&indirect, 0, sizeof indirect);
340 indirect.count_from_stream_output = pDevice->draw_so_target;
341
342 pDevice->pipe->draw_vbo(pDevice->pipe, &info, 0, &indirect, NULL, 1);
343 }
344