1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-28 02:19:26 +01:00

[dxvk,d3d9,d3d11] Refactor input layout objects

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

View File

@ -3316,14 +3316,20 @@ namespace dxvk {
template<typename ContextType>
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)) {
EmitCs([
cInputLayout = std::move(inputLayout)
] (DxvkContext* ctx) {
cInputLayout->BindToContext(ctx);
EmitCsCmd<DxvkVertexInput>(D3D11CmdType::None, attributeCount + bindingCount, [
cAttributeCount = attributeCount,
cBindingCount = bindingCount
] (DxvkContext* ctx, const DxvkVertexInput* layout, size_t) {
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 {
EmitCs([] (DxvkContext* ctx) {
ctx->setInputLayout(0, nullptr, 0, nullptr);

View File

@ -668,29 +668,29 @@ namespace dxvk {
// works, provided the shader does not have any actual inputs
if (!pInputElementDescs)
return E_INVALIDARG;
try {
DxbcReader dxbcReader(reinterpret_cast<const char*>(
pShaderBytecodeWithInputSignature), BytecodeLength);
DxbcModule dxbcModule(dxbcReader);
const Rc<DxbcIsgn> inputSignature = dxbcModule.isgn();
uint32_t attrMask = 0;
uint32_t bindMask = 0;
uint32_t locationMask = 0;
uint32_t bindingsDefined = 0;
std::array<DxvkVertexAttribute, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> attrList = { };
std::array<DxvkVertexBinding, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> bindList = { };
for (uint32_t i = 0; i < NumElements; i++) {
const DxbcSgnEntry* entry = inputSignature->find(
pInputElementDescs[i].SemanticName,
pInputElementDescs[i].SemanticIndex, 0);
// Create vertex input attribute description
DxvkVertexAttribute attrib;
DxvkVertexAttribute attrib = { };
attrib.location = entry != nullptr ? entry->registerId : 0;
attrib.binding = pInputElementDescs[i].InputSlot;
attrib.format = LookupFormat(pInputElementDescs[i].Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
@ -714,17 +714,18 @@ namespace dxvk {
break;
}
}
} else if (attrib.offset & (alignment - 1))
} else if (attrib.offset & (alignment - 1)) {
return E_INVALIDARG;
}
attrList.at(i) = attrib;
// Create vertex input binding description. The
// stride is dynamic state in D3D11 and will be
// set by D3D11DeviceContext::IASetVertexBuffers.
DxvkVertexBinding binding;
DxvkVertexBinding binding = { };
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
? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
binding.extent = entry ? uint32_t(attrib.offset + formatInfo->elementSize) : 0u;

View File

@ -10,23 +10,22 @@ namespace dxvk {
uint32_t numBindings,
const DxvkVertexBinding* pBindings)
: D3D11DeviceChild<ID3D11InputLayout>(pDevice),
m_d3d10(this) {
m_attributes.resize(numAttributes);
m_bindings.resize(numBindings);
m_attributeCount (numAttributes),
m_bindingCount (numBindings),
m_d3d10 (this) {
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++)
m_bindings.at(i) = pBindings[i];
m_input.inputs[i + numAttributes] = DxvkVertexInput(pBindings[i]);
}
D3D11InputLayout::~D3D11InputLayout() {
}
HRESULT STDMETHODCALLTYPE D3D11InputLayout::QueryInterface(REFIID riid, void** ppvObject) {
if (ppvObject == nullptr)
return E_POINTER;
@ -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 eq = m_attributes.size() == pOther->m_attributes.size()
&& m_bindings.size() == pOther->m_bindings.size();
for (uint32_t i = 0; eq && i < m_attributes.size(); i++) {
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;
if (m_attributeCount != pOther->m_attributeCount || m_bindingCount != pOther->m_bindingCount)
return false;
return bit::bcmpeq(&m_input, &pOther->m_input);
}
}

View File

@ -7,7 +7,12 @@
namespace dxvk {
class D3D11Device;
struct alignas(16) D3D11VertexInput {
std::array<DxvkVertexInput, MaxNumVertexAttributes + MaxNumVertexBindings> inputs;
};
class D3D11InputLayout : public D3D11DeviceChild<ID3D11InputLayout> {
public:
@ -24,9 +29,19 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
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(
const D3D11InputLayout* pOther) const;
@ -35,9 +50,11 @@ namespace dxvk {
}
private:
std::vector<DxvkVertexAttribute> m_attributes;
std::vector<DxvkVertexBinding> m_bindings;
D3D11VertexInput m_input = { };
uint32_t m_attributeCount = 0;
uint32_t m_bindingCount = 0;
D3D10InputLayout m_d3d10;

View File

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

View File

@ -539,9 +539,6 @@ namespace dxvk {
/**
* \brief Vertex attribute description
*
* Stores information about a
* single vertex attribute.
*/
struct DxvkVertexAttribute {
uint32_t location;
@ -549,34 +546,113 @@ namespace dxvk {
VkFormat format;
uint32_t offset;
};
/**
* \brief Vertex binding description
*
* Stores information about a
* single vertex binding slot.
* \brief Packed vertex attribute
*
* Compact representation of a vertex attribute.
*/
struct DxvkVertexBinding {
uint32_t binding;
uint32_t fetchRate;
VkVertexInputRate inputRate;
uint32_t extent;
};
/**
* \brief Input layout
*
* Stores the description of all active
* vertex attributes and vertex bindings.
*/
struct DxvkInputLayout {
uint32_t numAttributes;
uint32_t numBindings;
std::array<DxvkVertexAttribute, DxvkLimits::MaxNumVertexAttributes> attributes;
std::array<DxvkVertexBinding, DxvkLimits::MaxNumVertexBindings> bindings;
struct DxvkPackedVertexAttribute {
DxvkPackedVertexAttribute() = default;
DxvkPackedVertexAttribute(const DxvkVertexAttribute& a)
: location (a.location),
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 Vertex binding description
*/
struct DxvkVertexBinding {
uint32_t binding;
uint32_t extent;
VkVertexInputRate inputRate;
uint32_t divisor;
};
/**
* \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,38 +2807,45 @@ namespace dxvk {
void DxvkContext::setInputLayout(
uint32_t attributeCount,
const DxvkVertexAttribute* attributes,
const DxvkVertexInput* attributes,
uint32_t bindingCount,
const DxvkVertexBinding* bindings) {
const DxvkVertexInput* bindings) {
m_flags.set(
DxvkContextFlag::GpDirtyPipelineState,
DxvkContextFlag::GpDirtyVertexBuffers);
for (uint32_t i = 0; i < bindingCount; i++) {
auto binding = bindings[i].binding();
m_state.gp.state.ilBindings[i] = DxvkIlBinding(
bindings[i].binding, 0, bindings[i].inputRate,
bindings[i].fetchRate);
m_state.vi.vertexExtents[i] = bindings[i].extent;
binding.binding, 0,
binding.inputRate,
binding.divisor);
m_state.vi.vertexExtents[i] = binding.extent;
}
for (uint32_t i = bindingCount; i < m_state.gp.state.il.bindingCount(); i++) {
m_state.gp.state.ilBindings[i] = DxvkIlBinding();
m_state.vi.vertexExtents[i] = 0;
}
for (uint32_t i = 0; i < attributeCount; i++) {
auto attribute = attributes[i].attribute();
m_state.gp.state.ilAttributes[i] = DxvkIlAttribute(
attributes[i].location, attributes[i].binding,
attributes[i].format, attributes[i].offset);
attribute.location,
attribute.binding,
attribute.format,
attribute.offset);
}
for (uint32_t i = attributeCount; i < m_state.gp.state.il.attributeCount(); i++)
m_state.gp.state.ilAttributes[i] = DxvkIlAttribute();
m_state.gp.state.il = DxvkIlInfo(attributeCount, bindingCount);
}
void DxvkContext::setRasterizerState(const DxvkRasterizerState& rs) {
VkCullModeFlags cullMode = rs.cullMode();
VkFrontFace frontFace = rs.frontFace();

View File

@ -1176,16 +1176,16 @@ namespace dxvk {
* \brief Sets input layout
*
* \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] bindings Vertex buffer bindigs
* \param [in] bindings Array of binding infos
*/
void setInputLayout(
uint32_t attributeCount,
const DxvkVertexAttribute* attributes,
const DxvkVertexInput* attributes,
uint32_t bindingCount,
const DxvkVertexBinding* bindings);
const DxvkVertexInput* bindings);
/**
* \brief Sets rasterizer state
* \param [in] rs New state object