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