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