17ec681f3Smrg/**************************************************************************
27ec681f3Smrg *
37ec681f3Smrg * Copyright 2012-2021 VMware, Inc.
47ec681f3Smrg * All Rights Reserved.
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the
87ec681f3Smrg * "Software"), to deal in the Software without restriction, including
97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish,
107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to
117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to
127ec681f3Smrg * the following conditions:
137ec681f3Smrg *
147ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
177ec681f3Smrg * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
187ec681f3Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
197ec681f3Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
207ec681f3Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
217ec681f3Smrg *
227ec681f3Smrg * The above copyright notice and this permission notice (including the
237ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions
247ec681f3Smrg * of the Software.
257ec681f3Smrg *
267ec681f3Smrg **************************************************************************/
277ec681f3Smrg
287ec681f3Smrg/*
297ec681f3Smrg * InputAssembly.cpp --
307ec681f3Smrg *    Functions that manipulate the input assembly stage.
317ec681f3Smrg */
327ec681f3Smrg
337ec681f3Smrg
347ec681f3Smrg#include <stdio.h>
357ec681f3Smrg#if defined(_MSC_VER) && !defined(snprintf)
367ec681f3Smrg#define snprintf _snprintf
377ec681f3Smrg#endif
387ec681f3Smrg
397ec681f3Smrg#include "InputAssembly.h"
407ec681f3Smrg#include "State.h"
417ec681f3Smrg
427ec681f3Smrg#include "Debug.h"
437ec681f3Smrg#include "Format.h"
447ec681f3Smrg
457ec681f3Smrg
467ec681f3Smrg/*
477ec681f3Smrg * ----------------------------------------------------------------------
487ec681f3Smrg *
497ec681f3Smrg * IaSetTopology --
507ec681f3Smrg *
517ec681f3Smrg *    The IaSetTopology function sets the primitive topology to
527ec681f3Smrg *    enable drawing for the input assember.
537ec681f3Smrg *
547ec681f3Smrg * ----------------------------------------------------------------------
557ec681f3Smrg */
567ec681f3Smrg
577ec681f3Smrgvoid APIENTRY
587ec681f3SmrgIaSetTopology(D3D10DDI_HDEVICE hDevice,                        // IN
597ec681f3Smrg              D3D10_DDI_PRIMITIVE_TOPOLOGY PrimitiveTopology)  // IN
607ec681f3Smrg{
617ec681f3Smrg   LOG_ENTRYPOINT();
627ec681f3Smrg
637ec681f3Smrg   Device *pDevice = CastDevice(hDevice);
647ec681f3Smrg
657ec681f3Smrg   enum pipe_prim_type primitive;
667ec681f3Smrg   switch (PrimitiveTopology) {
677ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_UNDEFINED:
687ec681f3Smrg      /* Apps might set topology to UNDEFINED when cleaning up on exit. */
697ec681f3Smrg      primitive = PIPE_PRIM_MAX;
707ec681f3Smrg      break;
717ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_POINTLIST:
727ec681f3Smrg      primitive = PIPE_PRIM_POINTS;
737ec681f3Smrg      break;
747ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINELIST:
757ec681f3Smrg      primitive = PIPE_PRIM_LINES;
767ec681f3Smrg      break;
777ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINESTRIP:
787ec681f3Smrg      primitive = PIPE_PRIM_LINE_STRIP;
797ec681f3Smrg      break;
807ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
817ec681f3Smrg      primitive = PIPE_PRIM_TRIANGLES;
827ec681f3Smrg      break;
837ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
847ec681f3Smrg      primitive = PIPE_PRIM_TRIANGLE_STRIP;
857ec681f3Smrg      break;
867ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINELIST_ADJ:
877ec681f3Smrg      primitive = PIPE_PRIM_LINES_ADJACENCY;
887ec681f3Smrg      break;
897ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ:
907ec681f3Smrg      primitive = PIPE_PRIM_LINE_STRIP_ADJACENCY;
917ec681f3Smrg      break;
927ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ:
937ec681f3Smrg      primitive = PIPE_PRIM_TRIANGLES_ADJACENCY;
947ec681f3Smrg      break;
957ec681f3Smrg   case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ:
967ec681f3Smrg      primitive = PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY;
977ec681f3Smrg      break;
987ec681f3Smrg   default:
997ec681f3Smrg      assert(0);
1007ec681f3Smrg      primitive = PIPE_PRIM_MAX;
1017ec681f3Smrg      break;
1027ec681f3Smrg   }
1037ec681f3Smrg
1047ec681f3Smrg   pDevice->primitive = primitive;
1057ec681f3Smrg}
1067ec681f3Smrg
1077ec681f3Smrg
1087ec681f3Smrg/*
1097ec681f3Smrg * ----------------------------------------------------------------------
1107ec681f3Smrg *
1117ec681f3Smrg * IaSetVertexBuffers --
1127ec681f3Smrg *
1137ec681f3Smrg *    The IaSetVertexBuffers function sets vertex buffers
1147ec681f3Smrg *    for an input assembler.
1157ec681f3Smrg *
1167ec681f3Smrg * ----------------------------------------------------------------------
1177ec681f3Smrg */
1187ec681f3Smrg
1197ec681f3Smrgvoid APIENTRY
1207ec681f3SmrgIaSetVertexBuffers(D3D10DDI_HDEVICE hDevice,                                     // IN
1217ec681f3Smrg                   UINT StartBuffer,                                             // IN
1227ec681f3Smrg                   UINT NumBuffers,                                              // IN
1237ec681f3Smrg                   __in_ecount (NumBuffers) const D3D10DDI_HRESOURCE *phBuffers, // IN
1247ec681f3Smrg                   __in_ecount (NumBuffers) const UINT *pStrides,                // IN
1257ec681f3Smrg                   __in_ecount (NumBuffers) const UINT *pOffsets)                // IN
1267ec681f3Smrg{
1277ec681f3Smrg   static const float dummy[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1287ec681f3Smrg
1297ec681f3Smrg   LOG_ENTRYPOINT();
1307ec681f3Smrg
1317ec681f3Smrg   Device *pDevice = CastDevice(hDevice);
1327ec681f3Smrg   struct pipe_context *pipe = pDevice->pipe;
1337ec681f3Smrg   unsigned i;
1347ec681f3Smrg
1357ec681f3Smrg   for (i = 0; i < NumBuffers; i++) {
1367ec681f3Smrg      struct pipe_vertex_buffer *vb = &pDevice->vertex_buffers[StartBuffer + i];
1377ec681f3Smrg      struct pipe_resource *resource = CastPipeResource(phBuffers[i]);
1387ec681f3Smrg      Resource *res = CastResource(phBuffers[i]);
1397ec681f3Smrg      struct pipe_stream_output_target *so_target =
1407ec681f3Smrg         res ? res->so_target : NULL;
1417ec681f3Smrg
1427ec681f3Smrg      if (so_target && pDevice->draw_so_target != so_target) {
1437ec681f3Smrg         if (pDevice->draw_so_target) {
1447ec681f3Smrg            pipe_so_target_reference(&pDevice->draw_so_target, NULL);
1457ec681f3Smrg         }
1467ec681f3Smrg         pipe_so_target_reference(&pDevice->draw_so_target,
1477ec681f3Smrg                                  so_target);
1487ec681f3Smrg      }
1497ec681f3Smrg
1507ec681f3Smrg      if (resource) {
1517ec681f3Smrg         vb->stride = pStrides[i];
1527ec681f3Smrg         vb->buffer_offset = pOffsets[i];
1537ec681f3Smrg         if (vb->is_user_buffer) {
1547ec681f3Smrg            vb->buffer.resource = NULL;
1557ec681f3Smrg            vb->is_user_buffer = FALSE;
1567ec681f3Smrg         }
1577ec681f3Smrg         pipe_resource_reference(&vb->buffer.resource, resource);
1587ec681f3Smrg      }
1597ec681f3Smrg      else {
1607ec681f3Smrg         vb->stride = 0;
1617ec681f3Smrg         vb->buffer_offset = 0;
1627ec681f3Smrg         if (!vb->is_user_buffer) {
1637ec681f3Smrg            pipe_resource_reference(&vb->buffer.resource, NULL);
1647ec681f3Smrg            vb->is_user_buffer = TRUE;
1657ec681f3Smrg         }
1667ec681f3Smrg         vb->buffer.user = dummy;
1677ec681f3Smrg      }
1687ec681f3Smrg   }
1697ec681f3Smrg
1707ec681f3Smrg   for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) {
1717ec681f3Smrg      struct pipe_vertex_buffer *vb = &pDevice->vertex_buffers[i];
1727ec681f3Smrg
1737ec681f3Smrg      /* XXX this is odd... */
1747ec681f3Smrg      if (!vb->is_user_buffer && !vb->buffer.resource) {
1757ec681f3Smrg         vb->stride = 0;
1767ec681f3Smrg         vb->buffer_offset = 0;
1777ec681f3Smrg         vb->is_user_buffer = TRUE;
1787ec681f3Smrg         vb->buffer.user = dummy;
1797ec681f3Smrg      }
1807ec681f3Smrg   }
1817ec681f3Smrg
1827ec681f3Smrg   /* Resubmit old and new vertex buffers.
1837ec681f3Smrg    */
1847ec681f3Smrg   pipe->set_vertex_buffers(pipe, 0, PIPE_MAX_ATTRIBS, 0, FALSE, pDevice->vertex_buffers);
1857ec681f3Smrg}
1867ec681f3Smrg
1877ec681f3Smrg
1887ec681f3Smrg/*
1897ec681f3Smrg * ----------------------------------------------------------------------
1907ec681f3Smrg *
1917ec681f3Smrg * IaSetIndexBuffer --
1927ec681f3Smrg *
1937ec681f3Smrg *    The IaSetIndexBuffer function sets an index buffer for
1947ec681f3Smrg *    an input assembler.
1957ec681f3Smrg *
1967ec681f3Smrg * ----------------------------------------------------------------------
1977ec681f3Smrg */
1987ec681f3Smrg
1997ec681f3Smrgvoid APIENTRY
2007ec681f3SmrgIaSetIndexBuffer(D3D10DDI_HDEVICE hDevice,   // IN
2017ec681f3Smrg                 D3D10DDI_HRESOURCE hBuffer, // IN
2027ec681f3Smrg                 DXGI_FORMAT Format,         // IN
2037ec681f3Smrg                 UINT Offset)                // IN
2047ec681f3Smrg{
2057ec681f3Smrg   LOG_ENTRYPOINT();
2067ec681f3Smrg
2077ec681f3Smrg   Device *pDevice = CastDevice(hDevice);
2087ec681f3Smrg   struct pipe_resource *resource = CastPipeResource(hBuffer);
2097ec681f3Smrg
2107ec681f3Smrg   if (resource) {
2117ec681f3Smrg      pDevice->ib_offset = Offset;
2127ec681f3Smrg
2137ec681f3Smrg      switch (Format) {
2147ec681f3Smrg      case DXGI_FORMAT_R16_UINT:
2157ec681f3Smrg         pDevice->index_size = 2;
2167ec681f3Smrg         pDevice->restart_index = 0xffff;
2177ec681f3Smrg         break;
2187ec681f3Smrg      case DXGI_FORMAT_R32_UINT:
2197ec681f3Smrg         pDevice->restart_index = 0xffffffff;
2207ec681f3Smrg         pDevice->index_size = 4;
2217ec681f3Smrg         break;
2227ec681f3Smrg      default:
2237ec681f3Smrg         assert(0);             /* should not happen */
2247ec681f3Smrg         pDevice->index_size = 2;
2257ec681f3Smrg         break;
2267ec681f3Smrg      }
2277ec681f3Smrg      pipe_resource_reference(&pDevice->index_buffer, resource);
2287ec681f3Smrg   } else {
2297ec681f3Smrg      pipe_resource_reference(&pDevice->index_buffer, NULL);
2307ec681f3Smrg   }
2317ec681f3Smrg}
2327ec681f3Smrg
2337ec681f3Smrg
2347ec681f3Smrg/*
2357ec681f3Smrg * ----------------------------------------------------------------------
2367ec681f3Smrg *
2377ec681f3Smrg * CalcPrivateElementLayoutSize --
2387ec681f3Smrg *
2397ec681f3Smrg *    The CalcPrivateElementLayoutSize function determines the size
2407ec681f3Smrg *    of the user-mode display driver's private region of memory
2417ec681f3Smrg *    (that is, the size of internal driver structures, not the size
2427ec681f3Smrg *    of the resource video memory) for an element layout.
2437ec681f3Smrg *
2447ec681f3Smrg * ----------------------------------------------------------------------
2457ec681f3Smrg */
2467ec681f3Smrg
2477ec681f3SmrgSIZE_T APIENTRY
2487ec681f3SmrgCalcPrivateElementLayoutSize(
2497ec681f3Smrg   D3D10DDI_HDEVICE hDevice,                                         // IN
2507ec681f3Smrg   __in const D3D10DDIARG_CREATEELEMENTLAYOUT *pCreateElementLayout) // IN
2517ec681f3Smrg{
2527ec681f3Smrg   return sizeof(ElementLayout);
2537ec681f3Smrg}
2547ec681f3Smrg
2557ec681f3Smrg
2567ec681f3Smrg/*
2577ec681f3Smrg * ----------------------------------------------------------------------
2587ec681f3Smrg *
2597ec681f3Smrg * CreateElementLayout --
2607ec681f3Smrg *
2617ec681f3Smrg *    The CreateElementLayout function creates an element layout.
2627ec681f3Smrg *
2637ec681f3Smrg * ----------------------------------------------------------------------
2647ec681f3Smrg */
2657ec681f3Smrg
2667ec681f3Smrgvoid APIENTRY
2677ec681f3SmrgCreateElementLayout(
2687ec681f3Smrg   D3D10DDI_HDEVICE hDevice,                                         // IN
2697ec681f3Smrg   __in const D3D10DDIARG_CREATEELEMENTLAYOUT *pCreateElementLayout, // IN
2707ec681f3Smrg   D3D10DDI_HELEMENTLAYOUT hElementLayout,                           // IN
2717ec681f3Smrg   D3D10DDI_HRTELEMENTLAYOUT hRTElementLayout)                       // IN
2727ec681f3Smrg{
2737ec681f3Smrg   LOG_ENTRYPOINT();
2747ec681f3Smrg
2757ec681f3Smrg   struct pipe_context *pipe = CastPipeContext(hDevice);
2767ec681f3Smrg   ElementLayout *pElementLayout = CastElementLayout(hElementLayout);
2777ec681f3Smrg
2787ec681f3Smrg   struct pipe_vertex_element elements[PIPE_MAX_ATTRIBS];
2797ec681f3Smrg   memset(elements, 0, sizeof elements);
2807ec681f3Smrg
2817ec681f3Smrg   unsigned num_elements = pCreateElementLayout->NumElements;
2827ec681f3Smrg   unsigned max_elements = 0;
2837ec681f3Smrg   for (unsigned i = 0; i < num_elements; i++) {
2847ec681f3Smrg      const D3D10DDIARG_INPUT_ELEMENT_DESC* pVertexElement =
2857ec681f3Smrg            &pCreateElementLayout->pVertexElements[i];
2867ec681f3Smrg      struct pipe_vertex_element *ve =
2877ec681f3Smrg            &elements[pVertexElement->InputRegister];
2887ec681f3Smrg
2897ec681f3Smrg      ve->src_offset          = pVertexElement->AlignedByteOffset;
2907ec681f3Smrg      ve->vertex_buffer_index = pVertexElement->InputSlot;
2917ec681f3Smrg      ve->src_format          = FormatTranslate(pVertexElement->Format, FALSE);
2927ec681f3Smrg
2937ec681f3Smrg      switch (pVertexElement->InputSlotClass) {
2947ec681f3Smrg      case D3D10_DDI_INPUT_PER_VERTEX_DATA:
2957ec681f3Smrg         ve->instance_divisor = 0;
2967ec681f3Smrg         break;
2977ec681f3Smrg      case D3D10_DDI_INPUT_PER_INSTANCE_DATA:
2987ec681f3Smrg         if (!pVertexElement->InstanceDataStepRate) {
2997ec681f3Smrg            LOG_UNSUPPORTED(!pVertexElement->InstanceDataStepRate);
3007ec681f3Smrg            ve->instance_divisor = ~0;
3017ec681f3Smrg         } else {
3027ec681f3Smrg            ve->instance_divisor = pVertexElement->InstanceDataStepRate;
3037ec681f3Smrg         }
3047ec681f3Smrg         break;
3057ec681f3Smrg      default:
3067ec681f3Smrg         assert(0);
3077ec681f3Smrg         break;
3087ec681f3Smrg      }
3097ec681f3Smrg
3107ec681f3Smrg      max_elements = MAX2(max_elements, pVertexElement->InputRegister + 1);
3117ec681f3Smrg   }
3127ec681f3Smrg
3137ec681f3Smrg   /* XXX: What do we do when there's a gap? */
3147ec681f3Smrg   if (max_elements != num_elements) {
3157ec681f3Smrg      DebugPrintf("%s: gap\n", __FUNCTION__);
3167ec681f3Smrg   }
3177ec681f3Smrg
3187ec681f3Smrg   pElementLayout->handle =
3197ec681f3Smrg         pipe->create_vertex_elements_state(pipe, max_elements, elements);
3207ec681f3Smrg}
3217ec681f3Smrg
3227ec681f3Smrg
3237ec681f3Smrg/*
3247ec681f3Smrg * ----------------------------------------------------------------------
3257ec681f3Smrg *
3267ec681f3Smrg * DestroyElementLayout --
3277ec681f3Smrg *
3287ec681f3Smrg *    The DestroyElementLayout function destroys the specified
3297ec681f3Smrg *    element layout object. The element layout object can be
3307ec681f3Smrg *    destoyed only if it is not currently bound to a display device.
3317ec681f3Smrg *
3327ec681f3Smrg * ----------------------------------------------------------------------
3337ec681f3Smrg */
3347ec681f3Smrg
3357ec681f3Smrgvoid APIENTRY
3367ec681f3SmrgDestroyElementLayout(D3D10DDI_HDEVICE hDevice,                 // IN
3377ec681f3Smrg                     D3D10DDI_HELEMENTLAYOUT hElementLayout)   // IN
3387ec681f3Smrg{
3397ec681f3Smrg   LOG_ENTRYPOINT();
3407ec681f3Smrg
3417ec681f3Smrg   struct pipe_context *pipe = CastPipeContext(hDevice);
3427ec681f3Smrg   ElementLayout *pElementLayout = CastElementLayout(hElementLayout);
3437ec681f3Smrg
3447ec681f3Smrg   pipe->delete_vertex_elements_state(pipe, pElementLayout->handle);}
3457ec681f3Smrg
3467ec681f3Smrg
3477ec681f3Smrg/*
3487ec681f3Smrg * ----------------------------------------------------------------------
3497ec681f3Smrg *
3507ec681f3Smrg * IaSetInputLayout --
3517ec681f3Smrg *
3527ec681f3Smrg *    The IaSetInputLayout function sets an input layout for
3537ec681f3Smrg *    the input assembler.
3547ec681f3Smrg *
3557ec681f3Smrg * ----------------------------------------------------------------------
3567ec681f3Smrg */
3577ec681f3Smrg
3587ec681f3Smrgvoid APIENTRY
3597ec681f3SmrgIaSetInputLayout(D3D10DDI_HDEVICE hDevice,               // IN
3607ec681f3Smrg                 D3D10DDI_HELEMENTLAYOUT hInputLayout)   // IN
3617ec681f3Smrg{
3627ec681f3Smrg   LOG_ENTRYPOINT();
3637ec681f3Smrg
3647ec681f3Smrg   struct pipe_context *pipe = CastPipeContext(hDevice);
3657ec681f3Smrg   void *state = CastPipeInputLayout(hInputLayout);
3667ec681f3Smrg
3677ec681f3Smrg   pipe->bind_vertex_elements_state(pipe, state);
3687ec681f3Smrg}
3697ec681f3Smrg
3707ec681f3Smrg
371