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