1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-04-03 07:25:18 +02:00

[dxvk,d3d9,d3d11] Refactor input layout objects

This commit is contained in:
Philip Rebohle 2025-03-22 19:18:31 +01:00
parent 86c74eb4d5
commit 1be2354e04
8 changed files with 202 additions and 119 deletions

View File

@ -3316,14 +3316,20 @@ namespace dxvk {
template<typename ContextType> template<typename ContextType>
void D3D11CommonContext<ContextType>::ApplyInputLayout() { void D3D11CommonContext<ContextType>::ApplyInputLayout() {
auto inputLayout = m_state.ia.inputLayout.prvRef(); if (likely(m_state.ia.inputLayout != nullptr)) {
uint32_t attributeCount = m_state.ia.inputLayout->GetAttributeCount();
uint32_t bindingCount = m_state.ia.inputLayout->GetBindingCount();
if (likely(inputLayout != nullptr)) { EmitCsCmd<DxvkVertexInput>(D3D11CmdType::None, attributeCount + bindingCount, [
EmitCs([ cAttributeCount = attributeCount,
cInputLayout = std::move(inputLayout) cBindingCount = bindingCount
] (DxvkContext* ctx) { ] (DxvkContext* ctx, const DxvkVertexInput* layout, size_t) {
cInputLayout->BindToContext(ctx); ctx->setInputLayout(cAttributeCount, &layout[0],
cBindingCount, &layout[cAttributeCount]);
}); });
for (uint32_t i = 0; i < attributeCount + bindingCount; i++)
new (m_csData->at(i)) DxvkVertexInput(m_state.ia.inputLayout->GetInput(i));
} else { } else {
EmitCs([] (DxvkContext* ctx) { EmitCs([] (DxvkContext* ctx) {
ctx->setInputLayout(0, nullptr, 0, nullptr); ctx->setInputLayout(0, nullptr, 0, nullptr);

View File

@ -690,7 +690,7 @@ namespace dxvk {
pInputElementDescs[i].SemanticIndex, 0); pInputElementDescs[i].SemanticIndex, 0);
// Create vertex input attribute description // Create vertex input attribute description
DxvkVertexAttribute attrib; DxvkVertexAttribute attrib = { };
attrib.location = entry != nullptr ? entry->registerId : 0; attrib.location = entry != nullptr ? entry->registerId : 0;
attrib.binding = pInputElementDescs[i].InputSlot; attrib.binding = pInputElementDescs[i].InputSlot;
attrib.format = LookupFormat(pInputElementDescs[i].Format, DXGI_VK_FORMAT_MODE_COLOR).Format; attrib.format = LookupFormat(pInputElementDescs[i].Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
@ -714,17 +714,18 @@ namespace dxvk {
break; break;
} }
} }
} else if (attrib.offset & (alignment - 1)) } else if (attrib.offset & (alignment - 1)) {
return E_INVALIDARG; return E_INVALIDARG;
}
attrList.at(i) = attrib; attrList.at(i) = attrib;
// Create vertex input binding description. The // Create vertex input binding description. The
// stride is dynamic state in D3D11 and will be // stride is dynamic state in D3D11 and will be
// set by D3D11DeviceContext::IASetVertexBuffers. // set by D3D11DeviceContext::IASetVertexBuffers.
DxvkVertexBinding binding; DxvkVertexBinding binding = { };
binding.binding = pInputElementDescs[i].InputSlot; binding.binding = pInputElementDescs[i].InputSlot;
binding.fetchRate = pInputElementDescs[i].InstanceDataStepRate; binding.divisor = pInputElementDescs[i].InstanceDataStepRate;
binding.inputRate = pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA binding.inputRate = pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA
? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
binding.extent = entry ? uint32_t(attrib.offset + formatInfo->elementSize) : 0u; binding.extent = entry ? uint32_t(attrib.offset + formatInfo->elementSize) : 0u;

View File

@ -10,15 +10,14 @@ namespace dxvk {
uint32_t numBindings, uint32_t numBindings,
const DxvkVertexBinding* pBindings) const DxvkVertexBinding* pBindings)
: D3D11DeviceChild<ID3D11InputLayout>(pDevice), : D3D11DeviceChild<ID3D11InputLayout>(pDevice),
m_d3d10(this) { m_attributeCount (numAttributes),
m_attributes.resize(numAttributes); m_bindingCount (numBindings),
m_bindings.resize(numBindings); m_d3d10 (this) {
for (uint32_t i = 0; i < numAttributes; i++) for (uint32_t i = 0; i < numAttributes; i++)
m_attributes.at(i) = pAttributes[i]; m_input.inputs[i] = DxvkVertexInput(pAttributes[i]);
for (uint32_t i = 0; i < numBindings; i++) for (uint32_t i = 0; i < numBindings; i++)
m_bindings.at(i) = pBindings[i]; m_input.inputs[i + numAttributes] = DxvkVertexInput(pBindings[i]);
} }
@ -55,33 +54,11 @@ namespace dxvk {
} }
void D3D11InputLayout::BindToContext(DxvkContext* ctx) {
ctx->setInputLayout(
m_attributes.size(),
m_attributes.data(),
m_bindings.size(),
m_bindings.data());
}
bool D3D11InputLayout::Compare(const D3D11InputLayout* pOther) const { bool D3D11InputLayout::Compare(const D3D11InputLayout* pOther) const {
bool eq = m_attributes.size() == pOther->m_attributes.size() if (m_attributeCount != pOther->m_attributeCount || m_bindingCount != pOther->m_bindingCount)
&& m_bindings.size() == pOther->m_bindings.size(); return false;
for (uint32_t i = 0; eq && i < m_attributes.size(); i++) { return bit::bcmpeq(&m_input, &pOther->m_input);
eq &= m_attributes[i].location == pOther->m_attributes[i].location
&& m_attributes[i].binding == pOther->m_attributes[i].binding
&& m_attributes[i].format == pOther->m_attributes[i].format
&& m_attributes[i].offset == pOther->m_attributes[i].offset;
}
for (uint32_t i = 0; eq && i < m_bindings.size(); i++) {
eq &= m_bindings[i].binding == pOther->m_bindings[i].binding
&& m_bindings[i].fetchRate == pOther->m_bindings[i].fetchRate
&& m_bindings[i].inputRate == pOther->m_bindings[i].inputRate;
}
return eq;
} }
} }

View File

@ -8,6 +8,11 @@ namespace dxvk {
class D3D11Device; class D3D11Device;
struct alignas(16) D3D11VertexInput {
std::array<DxvkVertexInput, MaxNumVertexAttributes + MaxNumVertexBindings> inputs;
};
class D3D11InputLayout : public D3D11DeviceChild<ID3D11InputLayout> { class D3D11InputLayout : public D3D11DeviceChild<ID3D11InputLayout> {
public: public:
@ -25,7 +30,17 @@ namespace dxvk {
REFIID riid, REFIID riid,
void** ppvObject) final; void** ppvObject) final;
void BindToContext(DxvkContext* ctx); uint32_t GetAttributeCount() const {
return m_attributeCount;
}
uint32_t GetBindingCount() const {
return m_bindingCount;
}
DxvkVertexInput GetInput(uint32_t Index) const {
return m_input.inputs[Index];
}
bool Compare( bool Compare(
const D3D11InputLayout* pOther) const; const D3D11InputLayout* pOther) const;
@ -36,8 +51,10 @@ namespace dxvk {
private: private:
std::vector<DxvkVertexAttribute> m_attributes; D3D11VertexInput m_input = { };
std::vector<DxvkVertexBinding> m_bindings;
uint32_t m_attributeCount = 0;
uint32_t m_bindingCount = 0;
D3D10InputLayout m_d3d10; D3D10InputLayout m_d3d10;

View File

@ -7519,8 +7519,9 @@ namespace dxvk {
const auto& elements = cVertexDecl->GetElements(); const auto& elements = cVertexDecl->GetElements();
std::array<DxvkVertexAttribute, 2 * caps::InputRegisterCount> attrList; std::array<DxvkVertexInput, 2 * caps::InputRegisterCount> attrList = { };
std::array<DxvkVertexBinding, 2 * caps::InputRegisterCount> bindList; std::array<DxvkVertexInput, 2 * caps::InputRegisterCount> bindList = { };
std::array<uint32_t, 2 * caps::InputRegisterCount> vertexSizes = { };
uint32_t attrMask = 0; uint32_t attrMask = 0;
uint32_t bindMask = 0; uint32_t bindMask = 0;
@ -7532,7 +7533,7 @@ namespace dxvk {
for (uint32_t i = 0; i < isgn.elemCount; i++) { for (uint32_t i = 0; i < isgn.elemCount; i++) {
const auto& decl = isgn.elems[i]; const auto& decl = isgn.elems[i];
DxvkVertexAttribute attrib; DxvkVertexAttribute attrib = { };
attrib.location = i; attrib.location = i;
attrib.binding = NullStreamIdx; attrib.binding = NullStreamIdx;
attrib.format = VK_FORMAT_R32G32B32A32_SFLOAT; attrib.format = VK_FORMAT_R32G32B32A32_SFLOAT;
@ -7553,28 +7554,26 @@ namespace dxvk {
} }
} }
attrList[i] = attrib; attrList[i] = DxvkVertexInput(attrib);
DxvkVertexBinding binding; vertexSizes[attrib.binding] = std::max(vertexSizes[attrib.binding],
uint32_t(attrib.offset + lookupFormatInfo(attrib.format)->elementSize));
DxvkVertexBinding binding = { };
binding.binding = attrib.binding; binding.binding = attrib.binding;
binding.extent = attrib.offset + lookupFormatInfo(attrib.format)->elementSize; binding.extent = vertexSizes[attrib.binding];
uint32_t instanceData = cStreamFreq[binding.binding % caps::MaxStreams]; uint32_t instanceData = cStreamFreq[binding.binding % caps::MaxStreams];
if (instanceData & D3DSTREAMSOURCE_INSTANCEDATA) { if (instanceData & D3DSTREAMSOURCE_INSTANCEDATA) {
binding.fetchRate = instanceData & 0x7FFFFF; // Remove instance packed-in flags in the data. binding.divisor = instanceData & 0x7FFFFF; // Remove instance packed-in flags in the data.
binding.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; binding.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
} }
else { else {
binding.fetchRate = 0; binding.divisor = 0u;
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
} }
if (bindMask & (1u << binding.binding)) { bindList[binding.binding] = DxvkVertexInput(binding);
bindList.at(binding.binding).extent = std::max(
bindList.at(binding.binding).extent, binding.extent);
} else {
bindList.at(binding.binding) = binding;
}
attrMask |= 1u << i; attrMask |= 1u << i;
bindMask |= 1u << binding.binding; bindMask |= 1u << binding.binding;

View File

@ -539,9 +539,6 @@ namespace dxvk {
/** /**
* \brief Vertex attribute description * \brief Vertex attribute description
*
* Stores information about a
* single vertex attribute.
*/ */
struct DxvkVertexAttribute { struct DxvkVertexAttribute {
uint32_t location; uint32_t location;
@ -552,31 +549,110 @@ namespace dxvk {
/** /**
* \brief Vertex binding description * \brief Packed vertex attribute
* *
* Stores information about a * Compact representation of a vertex attribute.
* single vertex binding slot.
*/ */
struct DxvkVertexBinding { struct DxvkPackedVertexAttribute {
uint32_t binding; DxvkPackedVertexAttribute() = default;
uint32_t fetchRate; DxvkPackedVertexAttribute(const DxvkVertexAttribute& a)
VkVertexInputRate inputRate; : location (a.location),
uint32_t extent; binding (a.binding),
format (uint32_t(a.format)),
offset (a.offset),
reserved (0u) { }
uint32_t location : 5;
uint32_t binding : 5;
uint32_t format : 7;
uint32_t offset : 11;
uint32_t reserved : 4;
DxvkVertexAttribute unpack() const {
DxvkVertexAttribute result = { };
result.location = location;
result.binding = binding;
result.format = VkFormat(format);
result.offset = offset;
return result;
}
}; };
/** /**
* \brief Input layout * \brief Vertex binding description
*
* Stores the description of all active
* vertex attributes and vertex bindings.
*/ */
struct DxvkInputLayout { struct DxvkVertexBinding {
uint32_t numAttributes; uint32_t binding;
uint32_t numBindings; uint32_t extent;
VkVertexInputRate inputRate;
std::array<DxvkVertexAttribute, DxvkLimits::MaxNumVertexAttributes> attributes; uint32_t divisor;
std::array<DxvkVertexBinding, DxvkLimits::MaxNumVertexBindings> bindings;
}; };
/**
* \brief Packed vertex attribute
*
* Compact representation of a vertex binding.
*/
struct DxvkPackedVertexBinding {
DxvkPackedVertexBinding() = default;
DxvkPackedVertexBinding(const DxvkVertexBinding& b)
: binding (b.binding),
extent (b.extent),
inputRate (uint32_t(b.inputRate)),
divisor (b.divisor < (1u << 14) ? b.divisor : 0u) { }
uint32_t binding : 5;
uint32_t extent : 12;
uint32_t inputRate : 1;
uint32_t divisor : 14;
DxvkVertexBinding unpack() const {
DxvkVertexBinding result = { };
result.binding = binding;
result.extent = extent;
result.inputRate = VkVertexInputRate(inputRate);
result.divisor = divisor;
return result;
}
};
/**
* \brief Packed attribute binding
*
* Relies on attriute and bining
* structures to have the same size.
*/
class DxvkVertexInput {
public:
DxvkVertexInput() = default;
DxvkVertexInput(const DxvkVertexAttribute& attribute)
: m_attribute(attribute) { }
DxvkVertexInput(const DxvkVertexBinding& binding)
: m_binding(binding) { }
DxvkVertexAttribute attribute() const {
return m_attribute.unpack();
}
DxvkVertexBinding binding() const {
return m_binding.unpack();
}
private:
union {
DxvkPackedVertexAttribute m_attribute;
DxvkPackedVertexBinding m_binding;
};
};
static_assert(sizeof(DxvkVertexInput) == sizeof(uint32_t));
} }

View File

@ -2807,18 +2807,21 @@ namespace dxvk {
void DxvkContext::setInputLayout( void DxvkContext::setInputLayout(
uint32_t attributeCount, uint32_t attributeCount,
const DxvkVertexAttribute* attributes, const DxvkVertexInput* attributes,
uint32_t bindingCount, uint32_t bindingCount,
const DxvkVertexBinding* bindings) { const DxvkVertexInput* bindings) {
m_flags.set( m_flags.set(
DxvkContextFlag::GpDirtyPipelineState, DxvkContextFlag::GpDirtyPipelineState,
DxvkContextFlag::GpDirtyVertexBuffers); DxvkContextFlag::GpDirtyVertexBuffers);
for (uint32_t i = 0; i < bindingCount; i++) { for (uint32_t i = 0; i < bindingCount; i++) {
auto binding = bindings[i].binding();
m_state.gp.state.ilBindings[i] = DxvkIlBinding( m_state.gp.state.ilBindings[i] = DxvkIlBinding(
bindings[i].binding, 0, bindings[i].inputRate, binding.binding, 0,
bindings[i].fetchRate); binding.inputRate,
m_state.vi.vertexExtents[i] = bindings[i].extent; binding.divisor);
m_state.vi.vertexExtents[i] = binding.extent;
} }
for (uint32_t i = bindingCount; i < m_state.gp.state.il.bindingCount(); i++) { for (uint32_t i = bindingCount; i < m_state.gp.state.il.bindingCount(); i++) {
@ -2827,9 +2830,13 @@ namespace dxvk {
} }
for (uint32_t i = 0; i < attributeCount; i++) { for (uint32_t i = 0; i < attributeCount; i++) {
auto attribute = attributes[i].attribute();
m_state.gp.state.ilAttributes[i] = DxvkIlAttribute( m_state.gp.state.ilAttributes[i] = DxvkIlAttribute(
attributes[i].location, attributes[i].binding, attribute.location,
attributes[i].format, attributes[i].offset); attribute.binding,
attribute.format,
attribute.offset);
} }
for (uint32_t i = attributeCount; i < m_state.gp.state.il.attributeCount(); i++) for (uint32_t i = attributeCount; i < m_state.gp.state.il.attributeCount(); i++)

View File

@ -1176,15 +1176,15 @@ namespace dxvk {
* \brief Sets input layout * \brief Sets input layout
* *
* \param [in] attributeCount Number of vertex attributes * \param [in] attributeCount Number of vertex attributes
* \param [in] attributes The vertex attributes * \param [in] attributes Array of attribute infos
* \param [in] bindingCount Number of buffer bindings * \param [in] bindingCount Number of buffer bindings
* \param [in] bindings Vertex buffer bindigs * \param [in] bindings Array of binding infos
*/ */
void setInputLayout( void setInputLayout(
uint32_t attributeCount, uint32_t attributeCount,
const DxvkVertexAttribute* attributes, const DxvkVertexInput* attributes,
uint32_t bindingCount, uint32_t bindingCount,
const DxvkVertexBinding* bindings); const DxvkVertexInput* bindings);
/** /**
* \brief Sets rasterizer state * \brief Sets rasterizer state