InputAssembly.cpp revision 7ec681f3
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 * InputAssembly.cpp --
30 *    Functions that manipulate the input assembly stage.
31 */
32
33
34#include <stdio.h>
35#if defined(_MSC_VER) && !defined(snprintf)
36#define snprintf _snprintf
37#endif
38
39#include "InputAssembly.h"
40#include "State.h"
41
42#include "Debug.h"
43#include "Format.h"
44
45
46/*
47 * ----------------------------------------------------------------------
48 *
49 * IaSetTopology --
50 *
51 *    The IaSetTopology function sets the primitive topology to
52 *    enable drawing for the input assember.
53 *
54 * ----------------------------------------------------------------------
55 */
56
57void APIENTRY
58IaSetTopology(D3D10DDI_HDEVICE hDevice,                        // IN
59              D3D10_DDI_PRIMITIVE_TOPOLOGY PrimitiveTopology)  // IN
60{
61   LOG_ENTRYPOINT();
62
63   Device *pDevice = CastDevice(hDevice);
64
65   enum pipe_prim_type primitive;
66   switch (PrimitiveTopology) {
67   case D3D10_DDI_PRIMITIVE_TOPOLOGY_UNDEFINED:
68      /* Apps might set topology to UNDEFINED when cleaning up on exit. */
69      primitive = PIPE_PRIM_MAX;
70      break;
71   case D3D10_DDI_PRIMITIVE_TOPOLOGY_POINTLIST:
72      primitive = PIPE_PRIM_POINTS;
73      break;
74   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINELIST:
75      primitive = PIPE_PRIM_LINES;
76      break;
77   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINESTRIP:
78      primitive = PIPE_PRIM_LINE_STRIP;
79      break;
80   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
81      primitive = PIPE_PRIM_TRIANGLES;
82      break;
83   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
84      primitive = PIPE_PRIM_TRIANGLE_STRIP;
85      break;
86   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINELIST_ADJ:
87      primitive = PIPE_PRIM_LINES_ADJACENCY;
88      break;
89   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ:
90      primitive = PIPE_PRIM_LINE_STRIP_ADJACENCY;
91      break;
92   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ:
93      primitive = PIPE_PRIM_TRIANGLES_ADJACENCY;
94      break;
95   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ:
96      primitive = PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY;
97      break;
98   default:
99      assert(0);
100      primitive = PIPE_PRIM_MAX;
101      break;
102   }
103
104   pDevice->primitive = primitive;
105}
106
107
108/*
109 * ----------------------------------------------------------------------
110 *
111 * IaSetVertexBuffers --
112 *
113 *    The IaSetVertexBuffers function sets vertex buffers
114 *    for an input assembler.
115 *
116 * ----------------------------------------------------------------------
117 */
118
119void APIENTRY
120IaSetVertexBuffers(D3D10DDI_HDEVICE hDevice,                                     // IN
121                   UINT StartBuffer,                                             // IN
122                   UINT NumBuffers,                                              // IN
123                   __in_ecount (NumBuffers) const D3D10DDI_HRESOURCE *phBuffers, // IN
124                   __in_ecount (NumBuffers) const UINT *pStrides,                // IN
125                   __in_ecount (NumBuffers) const UINT *pOffsets)                // IN
126{
127   static const float dummy[4] = {0.0f, 0.0f, 0.0f, 0.0f};
128
129   LOG_ENTRYPOINT();
130
131   Device *pDevice = CastDevice(hDevice);
132   struct pipe_context *pipe = pDevice->pipe;
133   unsigned i;
134
135   for (i = 0; i < NumBuffers; i++) {
136      struct pipe_vertex_buffer *vb = &pDevice->vertex_buffers[StartBuffer + i];
137      struct pipe_resource *resource = CastPipeResource(phBuffers[i]);
138      Resource *res = CastResource(phBuffers[i]);
139      struct pipe_stream_output_target *so_target =
140         res ? res->so_target : NULL;
141
142      if (so_target && pDevice->draw_so_target != so_target) {
143         if (pDevice->draw_so_target) {
144            pipe_so_target_reference(&pDevice->draw_so_target, NULL);
145         }
146         pipe_so_target_reference(&pDevice->draw_so_target,
147                                  so_target);
148      }
149
150      if (resource) {
151         vb->stride = pStrides[i];
152         vb->buffer_offset = pOffsets[i];
153         if (vb->is_user_buffer) {
154            vb->buffer.resource = NULL;
155            vb->is_user_buffer = FALSE;
156         }
157         pipe_resource_reference(&vb->buffer.resource, resource);
158      }
159      else {
160         vb->stride = 0;
161         vb->buffer_offset = 0;
162         if (!vb->is_user_buffer) {
163            pipe_resource_reference(&vb->buffer.resource, NULL);
164            vb->is_user_buffer = TRUE;
165         }
166         vb->buffer.user = dummy;
167      }
168   }
169
170   for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) {
171      struct pipe_vertex_buffer *vb = &pDevice->vertex_buffers[i];
172
173      /* XXX this is odd... */
174      if (!vb->is_user_buffer && !vb->buffer.resource) {
175         vb->stride = 0;
176         vb->buffer_offset = 0;
177         vb->is_user_buffer = TRUE;
178         vb->buffer.user = dummy;
179      }
180   }
181
182   /* Resubmit old and new vertex buffers.
183    */
184   pipe->set_vertex_buffers(pipe, 0, PIPE_MAX_ATTRIBS, 0, FALSE, pDevice->vertex_buffers);
185}
186
187
188/*
189 * ----------------------------------------------------------------------
190 *
191 * IaSetIndexBuffer --
192 *
193 *    The IaSetIndexBuffer function sets an index buffer for
194 *    an input assembler.
195 *
196 * ----------------------------------------------------------------------
197 */
198
199void APIENTRY
200IaSetIndexBuffer(D3D10DDI_HDEVICE hDevice,   // IN
201                 D3D10DDI_HRESOURCE hBuffer, // IN
202                 DXGI_FORMAT Format,         // IN
203                 UINT Offset)                // IN
204{
205   LOG_ENTRYPOINT();
206
207   Device *pDevice = CastDevice(hDevice);
208   struct pipe_resource *resource = CastPipeResource(hBuffer);
209
210   if (resource) {
211      pDevice->ib_offset = Offset;
212
213      switch (Format) {
214      case DXGI_FORMAT_R16_UINT:
215         pDevice->index_size = 2;
216         pDevice->restart_index = 0xffff;
217         break;
218      case DXGI_FORMAT_R32_UINT:
219         pDevice->restart_index = 0xffffffff;
220         pDevice->index_size = 4;
221         break;
222      default:
223         assert(0);             /* should not happen */
224         pDevice->index_size = 2;
225         break;
226      }
227      pipe_resource_reference(&pDevice->index_buffer, resource);
228   } else {
229      pipe_resource_reference(&pDevice->index_buffer, NULL);
230   }
231}
232
233
234/*
235 * ----------------------------------------------------------------------
236 *
237 * CalcPrivateElementLayoutSize --
238 *
239 *    The CalcPrivateElementLayoutSize function determines the size
240 *    of the user-mode display driver's private region of memory
241 *    (that is, the size of internal driver structures, not the size
242 *    of the resource video memory) for an element layout.
243 *
244 * ----------------------------------------------------------------------
245 */
246
247SIZE_T APIENTRY
248CalcPrivateElementLayoutSize(
249   D3D10DDI_HDEVICE hDevice,                                         // IN
250   __in const D3D10DDIARG_CREATEELEMENTLAYOUT *pCreateElementLayout) // IN
251{
252   return sizeof(ElementLayout);
253}
254
255
256/*
257 * ----------------------------------------------------------------------
258 *
259 * CreateElementLayout --
260 *
261 *    The CreateElementLayout function creates an element layout.
262 *
263 * ----------------------------------------------------------------------
264 */
265
266void APIENTRY
267CreateElementLayout(
268   D3D10DDI_HDEVICE hDevice,                                         // IN
269   __in const D3D10DDIARG_CREATEELEMENTLAYOUT *pCreateElementLayout, // IN
270   D3D10DDI_HELEMENTLAYOUT hElementLayout,                           // IN
271   D3D10DDI_HRTELEMENTLAYOUT hRTElementLayout)                       // IN
272{
273   LOG_ENTRYPOINT();
274
275   struct pipe_context *pipe = CastPipeContext(hDevice);
276   ElementLayout *pElementLayout = CastElementLayout(hElementLayout);
277
278   struct pipe_vertex_element elements[PIPE_MAX_ATTRIBS];
279   memset(elements, 0, sizeof elements);
280
281   unsigned num_elements = pCreateElementLayout->NumElements;
282   unsigned max_elements = 0;
283   for (unsigned i = 0; i < num_elements; i++) {
284      const D3D10DDIARG_INPUT_ELEMENT_DESC* pVertexElement =
285            &pCreateElementLayout->pVertexElements[i];
286      struct pipe_vertex_element *ve =
287            &elements[pVertexElement->InputRegister];
288
289      ve->src_offset          = pVertexElement->AlignedByteOffset;
290      ve->vertex_buffer_index = pVertexElement->InputSlot;
291      ve->src_format          = FormatTranslate(pVertexElement->Format, FALSE);
292
293      switch (pVertexElement->InputSlotClass) {
294      case D3D10_DDI_INPUT_PER_VERTEX_DATA:
295         ve->instance_divisor = 0;
296         break;
297      case D3D10_DDI_INPUT_PER_INSTANCE_DATA:
298         if (!pVertexElement->InstanceDataStepRate) {
299            LOG_UNSUPPORTED(!pVertexElement->InstanceDataStepRate);
300            ve->instance_divisor = ~0;
301         } else {
302            ve->instance_divisor = pVertexElement->InstanceDataStepRate;
303         }
304         break;
305      default:
306         assert(0);
307         break;
308      }
309
310      max_elements = MAX2(max_elements, pVertexElement->InputRegister + 1);
311   }
312
313   /* XXX: What do we do when there's a gap? */
314   if (max_elements != num_elements) {
315      DebugPrintf("%s: gap\n", __FUNCTION__);
316   }
317
318   pElementLayout->handle =
319         pipe->create_vertex_elements_state(pipe, max_elements, elements);
320}
321
322
323/*
324 * ----------------------------------------------------------------------
325 *
326 * DestroyElementLayout --
327 *
328 *    The DestroyElementLayout function destroys the specified
329 *    element layout object. The element layout object can be
330 *    destoyed only if it is not currently bound to a display device.
331 *
332 * ----------------------------------------------------------------------
333 */
334
335void APIENTRY
336DestroyElementLayout(D3D10DDI_HDEVICE hDevice,                 // IN
337                     D3D10DDI_HELEMENTLAYOUT hElementLayout)   // IN
338{
339   LOG_ENTRYPOINT();
340
341   struct pipe_context *pipe = CastPipeContext(hDevice);
342   ElementLayout *pElementLayout = CastElementLayout(hElementLayout);
343
344   pipe->delete_vertex_elements_state(pipe, pElementLayout->handle);}
345
346
347/*
348 * ----------------------------------------------------------------------
349 *
350 * IaSetInputLayout --
351 *
352 *    The IaSetInputLayout function sets an input layout for
353 *    the input assembler.
354 *
355 * ----------------------------------------------------------------------
356 */
357
358void APIENTRY
359IaSetInputLayout(D3D10DDI_HDEVICE hDevice,               // IN
360                 D3D10DDI_HELEMENTLAYOUT hInputLayout)   // IN
361{
362   LOG_ENTRYPOINT();
363
364   struct pipe_context *pipe = CastPipeContext(hDevice);
365   void *state = CastPipeInputLayout(hInputLayout);
366
367   pipe->bind_vertex_elements_state(pipe, state);
368}
369
370
371