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
43static unsigned
44ClampedUAdd(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 */
62static void
63ResolveState(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
91static struct pipe_resource *
92create_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
125void APIENTRY
126Draw(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
154void APIENTRY
155DrawIndexed(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
211void APIENTRY
212DrawInstanced(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
249void APIENTRY
250DrawIndexedInstanced(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
318void APIENTRY
319DrawAuto(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