mesa/src/gallium/frontends/d3d10umd/InputAssembly.cpp

371 lines
11 KiB
C++

/**************************************************************************
*
* Copyright 2012-2021 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
**************************************************************************/
/*
* InputAssembly.cpp --
* Functions that manipulate the input assembly stage.
*/
#include <stdio.h>
#if defined(_MSC_VER) && !defined(snprintf)
#define snprintf _snprintf
#endif
#include "InputAssembly.h"
#include "State.h"
#include "Debug.h"
#include "Format.h"
/*
* ----------------------------------------------------------------------
*
* IaSetTopology --
*
* The IaSetTopology function sets the primitive topology to
* enable drawing for the input assember.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
IaSetTopology(D3D10DDI_HDEVICE hDevice, // IN
D3D10_DDI_PRIMITIVE_TOPOLOGY PrimitiveTopology) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
enum pipe_prim_type primitive;
switch (PrimitiveTopology) {
case D3D10_DDI_PRIMITIVE_TOPOLOGY_UNDEFINED:
/* Apps might set topology to UNDEFINED when cleaning up on exit. */
primitive = PIPE_PRIM_MAX;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_POINTLIST:
primitive = PIPE_PRIM_POINTS;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINELIST:
primitive = PIPE_PRIM_LINES;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINESTRIP:
primitive = PIPE_PRIM_LINE_STRIP;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
primitive = PIPE_PRIM_TRIANGLES;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
primitive = PIPE_PRIM_TRIANGLE_STRIP;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINELIST_ADJ:
primitive = PIPE_PRIM_LINES_ADJACENCY;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ:
primitive = PIPE_PRIM_LINE_STRIP_ADJACENCY;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ:
primitive = PIPE_PRIM_TRIANGLES_ADJACENCY;
break;
case D3D10_DDI_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ:
primitive = PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY;
break;
default:
assert(0);
primitive = PIPE_PRIM_MAX;
break;
}
pDevice->primitive = primitive;
}
/*
* ----------------------------------------------------------------------
*
* IaSetVertexBuffers --
*
* The IaSetVertexBuffers function sets vertex buffers
* for an input assembler.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
IaSetVertexBuffers(D3D10DDI_HDEVICE hDevice, // IN
UINT StartBuffer, // IN
UINT NumBuffers, // IN
__in_ecount (NumBuffers) const D3D10DDI_HRESOURCE *phBuffers, // IN
__in_ecount (NumBuffers) const UINT *pStrides, // IN
__in_ecount (NumBuffers) const UINT *pOffsets) // IN
{
static const float dummy[4] = {0.0f, 0.0f, 0.0f, 0.0f};
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
unsigned i;
for (i = 0; i < NumBuffers; i++) {
struct pipe_vertex_buffer *vb = &pDevice->vertex_buffers[StartBuffer + i];
struct pipe_resource *resource = CastPipeResource(phBuffers[i]);
Resource *res = CastResource(phBuffers[i]);
struct pipe_stream_output_target *so_target =
res ? res->so_target : NULL;
if (so_target && pDevice->draw_so_target != so_target) {
if (pDevice->draw_so_target) {
pipe_so_target_reference(&pDevice->draw_so_target, NULL);
}
pipe_so_target_reference(&pDevice->draw_so_target,
so_target);
}
if (resource) {
vb->stride = pStrides[i];
vb->buffer_offset = pOffsets[i];
if (vb->is_user_buffer) {
vb->buffer.resource = NULL;
vb->is_user_buffer = FALSE;
}
pipe_resource_reference(&vb->buffer.resource, resource);
}
else {
vb->stride = 0;
vb->buffer_offset = 0;
if (!vb->is_user_buffer) {
pipe_resource_reference(&vb->buffer.resource, NULL);
vb->is_user_buffer = TRUE;
}
vb->buffer.user = dummy;
}
}
for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) {
struct pipe_vertex_buffer *vb = &pDevice->vertex_buffers[i];
/* XXX this is odd... */
if (!vb->is_user_buffer && !vb->buffer.resource) {
vb->stride = 0;
vb->buffer_offset = 0;
vb->is_user_buffer = TRUE;
vb->buffer.user = dummy;
}
}
/* Resubmit old and new vertex buffers.
*/
pipe->set_vertex_buffers(pipe, 0, PIPE_MAX_ATTRIBS, 0, FALSE, pDevice->vertex_buffers);
}
/*
* ----------------------------------------------------------------------
*
* IaSetIndexBuffer --
*
* The IaSetIndexBuffer function sets an index buffer for
* an input assembler.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
IaSetIndexBuffer(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HRESOURCE hBuffer, // IN
DXGI_FORMAT Format, // IN
UINT Offset) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_resource *resource = CastPipeResource(hBuffer);
if (resource) {
pDevice->ib_offset = Offset;
switch (Format) {
case DXGI_FORMAT_R16_UINT:
pDevice->index_size = 2;
pDevice->restart_index = 0xffff;
break;
case DXGI_FORMAT_R32_UINT:
pDevice->restart_index = 0xffffffff;
pDevice->index_size = 4;
break;
default:
assert(0); /* should not happen */
pDevice->index_size = 2;
break;
}
pipe_resource_reference(&pDevice->index_buffer, resource);
} else {
pipe_resource_reference(&pDevice->index_buffer, NULL);
}
}
/*
* ----------------------------------------------------------------------
*
* CalcPrivateElementLayoutSize --
*
* The CalcPrivateElementLayoutSize function determines the size
* of the user-mode display driver's private region of memory
* (that is, the size of internal driver structures, not the size
* of the resource video memory) for an element layout.
*
* ----------------------------------------------------------------------
*/
SIZE_T APIENTRY
CalcPrivateElementLayoutSize(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATEELEMENTLAYOUT *pCreateElementLayout) // IN
{
return sizeof(ElementLayout);
}
/*
* ----------------------------------------------------------------------
*
* CreateElementLayout --
*
* The CreateElementLayout function creates an element layout.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateElementLayout(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATEELEMENTLAYOUT *pCreateElementLayout, // IN
D3D10DDI_HELEMENTLAYOUT hElementLayout, // IN
D3D10DDI_HRTELEMENTLAYOUT hRTElementLayout) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
ElementLayout *pElementLayout = CastElementLayout(hElementLayout);
struct pipe_vertex_element elements[PIPE_MAX_ATTRIBS];
memset(elements, 0, sizeof elements);
unsigned num_elements = pCreateElementLayout->NumElements;
unsigned max_elements = 0;
for (unsigned i = 0; i < num_elements; i++) {
const D3D10DDIARG_INPUT_ELEMENT_DESC* pVertexElement =
&pCreateElementLayout->pVertexElements[i];
struct pipe_vertex_element *ve =
&elements[pVertexElement->InputRegister];
ve->src_offset = pVertexElement->AlignedByteOffset;
ve->vertex_buffer_index = pVertexElement->InputSlot;
ve->src_format = FormatTranslate(pVertexElement->Format, FALSE);
switch (pVertexElement->InputSlotClass) {
case D3D10_DDI_INPUT_PER_VERTEX_DATA:
ve->instance_divisor = 0;
break;
case D3D10_DDI_INPUT_PER_INSTANCE_DATA:
if (!pVertexElement->InstanceDataStepRate) {
LOG_UNSUPPORTED(!pVertexElement->InstanceDataStepRate);
ve->instance_divisor = ~0;
} else {
ve->instance_divisor = pVertexElement->InstanceDataStepRate;
}
break;
default:
assert(0);
break;
}
max_elements = MAX2(max_elements, pVertexElement->InputRegister + 1);
}
/* XXX: What do we do when there's a gap? */
if (max_elements != num_elements) {
DebugPrintf("%s: gap\n", __FUNCTION__);
}
pElementLayout->handle =
pipe->create_vertex_elements_state(pipe, max_elements, elements);
}
/*
* ----------------------------------------------------------------------
*
* DestroyElementLayout --
*
* The DestroyElementLayout function destroys the specified
* element layout object. The element layout object can be
* destoyed only if it is not currently bound to a display device.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
DestroyElementLayout(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HELEMENTLAYOUT hElementLayout) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
ElementLayout *pElementLayout = CastElementLayout(hElementLayout);
pipe->delete_vertex_elements_state(pipe, pElementLayout->handle);}
/*
* ----------------------------------------------------------------------
*
* IaSetInputLayout --
*
* The IaSetInputLayout function sets an input layout for
* the input assembler.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
IaSetInputLayout(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HELEMENTLAYOUT hInputLayout) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
void *state = CastPipeInputLayout(hInputLayout);
pipe->bind_vertex_elements_state(pipe, state);
}