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