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 
57 void APIENTRY
IaSetTopology(D3D10DDI_HDEVICE hDevice,D3D10_DDI_PRIMITIVE_TOPOLOGY PrimitiveTopology)58 IaSetTopology(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 
119 void APIENTRY
IaSetVertexBuffers(D3D10DDI_HDEVICE hDevice,UINT StartBuffer,UINT NumBuffers,__in_ecount (NumBuffers)const D3D10DDI_HRESOURCE * phBuffers,__in_ecount (NumBuffers)const UINT * pStrides,__in_ecount (NumBuffers)const UINT * pOffsets)120 IaSetVertexBuffers(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 
199 void APIENTRY
IaSetIndexBuffer(D3D10DDI_HDEVICE hDevice,D3D10DDI_HRESOURCE hBuffer,DXGI_FORMAT Format,UINT Offset)200 IaSetIndexBuffer(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 
247 SIZE_T APIENTRY
CalcPrivateElementLayoutSize(D3D10DDI_HDEVICE hDevice,__in const D3D10DDIARG_CREATEELEMENTLAYOUT * pCreateElementLayout)248 CalcPrivateElementLayoutSize(
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 
266 void APIENTRY
CreateElementLayout(D3D10DDI_HDEVICE hDevice,__in const D3D10DDIARG_CREATEELEMENTLAYOUT * pCreateElementLayout,D3D10DDI_HELEMENTLAYOUT hElementLayout,D3D10DDI_HRTELEMENTLAYOUT hRTElementLayout)267 CreateElementLayout(
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 
335 void APIENTRY
DestroyElementLayout(D3D10DDI_HDEVICE hDevice,D3D10DDI_HELEMENTLAYOUT hElementLayout)336 DestroyElementLayout(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 
358 void APIENTRY
IaSetInputLayout(D3D10DDI_HDEVICE hDevice,D3D10DDI_HELEMENTLAYOUT hInputLayout)359 IaSetInputLayout(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