diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 9ffcbe44..a0509647 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2259,28 +2259,24 @@ namespace dxvk { DxvkContextFlag::GpDirtyVertexBuffers); for (uint32_t i = 0; i < attributeCount; i++) { - m_state.gp.state.ilAttributes[i].location = attributes[i].location; - m_state.gp.state.ilAttributes[i].binding = attributes[i].binding; - m_state.gp.state.ilAttributes[i].format = attributes[i].format; - m_state.gp.state.ilAttributes[i].offset = attributes[i].offset; + m_state.gp.state.ilAttributes[i] = DxvkIlAttribute( + attributes[i].location, attributes[i].binding, + attributes[i].format, attributes[i].offset); } - for (uint32_t i = attributeCount; i < m_state.gp.state.ilAttributeCount; i++) - m_state.gp.state.ilAttributes[i] = VkVertexInputAttributeDescription(); + for (uint32_t i = attributeCount; i < m_state.gp.state.il.attributeCount(); i++) + m_state.gp.state.ilAttributes[i] = DxvkIlAttribute(); for (uint32_t i = 0; i < bindingCount; i++) { - m_state.gp.state.ilBindings[i].binding = bindings[i].binding; - m_state.gp.state.ilBindings[i].inputRate = bindings[i].inputRate; - m_state.gp.state.ilDivisors[i] = bindings[i].fetchRate; + m_state.gp.state.ilBindings[i] = DxvkIlBinding( + bindings[i].binding, 0, bindings[i].inputRate, + bindings[i].fetchRate); } - for (uint32_t i = bindingCount; i < m_state.gp.state.ilBindingCount; i++) { - m_state.gp.state.ilBindings[i] = VkVertexInputBindingDescription(); - m_state.gp.state.ilDivisors[i] = 0; - } + for (uint32_t i = bindingCount; i < m_state.gp.state.il.bindingCount(); i++) + m_state.gp.state.ilBindings[i] = DxvkIlBinding(); - m_state.gp.state.ilAttributeCount = attributeCount; - m_state.gp.state.ilBindingCount = bindingCount; + m_state.gp.state.il = DxvkIlInfo(attributeCount, bindingCount); } @@ -3620,9 +3616,9 @@ namespace dxvk { this->pauseTransformFeedback(); // Set up vertex buffer strides for active bindings - for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) { - const uint32_t binding = m_state.gp.state.ilBindings[i].binding; - m_state.gp.state.ilBindings[i].stride = m_state.vi.vertexStrides[binding]; + for (uint32_t i = 0; i < m_state.gp.state.il.bindingCount(); i++) { + const uint32_t binding = m_state.gp.state.ilBindings[i].binding(); + m_state.gp.state.ilBindings[i].setStride(m_state.vi.vertexStrides[binding]); } // Check which dynamic states need to be active. States that @@ -4015,15 +4011,15 @@ namespace dxvk { void DxvkContext::updateVertexBufferBindings() { m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers); - if (unlikely(!m_state.gp.state.ilBindingCount)) + if (unlikely(!m_state.gp.state.il.bindingCount())) return; std::array buffers; std::array offsets; // Set buffer handles and offsets for active bindings - for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) { - uint32_t binding = m_state.gp.state.ilBindings[i].binding; + for (uint32_t i = 0; i < m_state.gp.state.il.bindingCount(); i++) { + uint32_t binding = m_state.gp.state.ilBindings[i].binding(); if (likely(m_state.vi.vertexBuffers[binding].defined())) { auto vbo = m_state.vi.vertexBuffers[binding].getDescriptor(); @@ -4042,7 +4038,7 @@ namespace dxvk { // Vertex bindigs get remapped when compiling the // pipeline, so this actually does the right thing m_cmd->cmdBindVertexBuffers( - 0, m_state.gp.state.ilBindingCount, + 0, m_state.gp.state.il.bindingCount(), buffers.data(), offsets.data()); } diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index c6ac6390..384f027c 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -231,14 +231,14 @@ namespace dxvk { // Generate per-instance attribute divisors std::array viDivisorDesc; uint32_t viDivisorCount = 0; - - for (uint32_t i = 0; i < state.ilBindingCount; i++) { - if (state.ilBindings[i].inputRate == VK_VERTEX_INPUT_RATE_INSTANCE - && state.ilDivisors[i] != 1) { + + for (uint32_t i = 0; i < state.il.bindingCount(); i++) { + if (state.ilBindings[i].inputRate() == VK_VERTEX_INPUT_RATE_INSTANCE + && state.ilBindings[i].divisor() != 1) { const uint32_t id = viDivisorCount++; - viDivisorDesc[id].binding = i; - viDivisorDesc[id].divisor = state.ilDivisors[i]; + viDivisorDesc[id].binding = i; /* see below */ + viDivisorDesc[id].divisor = state.ilBindings[i].divisor(); } } @@ -251,15 +251,15 @@ namespace dxvk { std::array viBindings; std::array viBindingMap = { }; - for (uint32_t i = 0; i < state.ilBindingCount; i++) { - viBindings[i] = state.ilBindings[i]; + for (uint32_t i = 0; i < state.il.bindingCount(); i++) { + viBindings[i] = state.ilBindings[i].description(); viBindings[i].binding = i; - viBindingMap[state.ilBindings[i].binding] = i; + viBindingMap[state.ilBindings[i].binding()] = i; } - for (uint32_t i = 0; i < state.ilAttributeCount; i++) { - viAttribs[i] = state.ilAttributes[i]; - viAttribs[i].binding = viBindingMap[state.ilAttributes[i].binding]; + for (uint32_t i = 0; i < state.il.attributeCount(); i++) { + viAttribs[i] = state.ilAttributes[i].description(); + viAttribs[i].binding = viBindingMap[state.ilAttributes[i].binding()]; } VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo; @@ -272,9 +272,9 @@ namespace dxvk { viInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; viInfo.pNext = &viDivisorInfo; viInfo.flags = 0; - viInfo.vertexBindingDescriptionCount = state.ilBindingCount; + viInfo.vertexBindingDescriptionCount = state.il.bindingCount(); viInfo.pVertexBindingDescriptions = viBindings.data(); - viInfo.vertexAttributeDescriptionCount = state.ilAttributeCount; + viInfo.vertexAttributeDescriptionCount = state.il.attributeCount(); viInfo.pVertexAttributeDescriptions = viAttribs.data(); if (viDivisorCount == 0) @@ -453,8 +453,8 @@ namespace dxvk { // vertex shader must be provided by the input layout. uint32_t providedVertexInputs = 0; - for (uint32_t i = 0; i < state.ilAttributeCount; i++) - providedVertexInputs |= 1u << state.ilAttributes[i].location; + for (uint32_t i = 0; i < state.il.attributeCount(); i++) + providedVertexInputs |= 1u << state.ilAttributes[i].location(); if ((providedVertexInputs & m_vsIn) != m_vsIn) return false; @@ -470,8 +470,8 @@ namespace dxvk { return false; // Prevent unintended out-of-bounds access to the IL arrays - if (state.ilAttributeCount > DxvkLimits::MaxNumVertexAttributes - || state.ilBindingCount > DxvkLimits::MaxNumVertexBindings) + if (state.il.attributeCount() > DxvkLimits::MaxNumVertexAttributes + || state.il.bindingCount() > DxvkLimits::MaxNumVertexBindings) return false; // No errors @@ -505,13 +505,13 @@ namespace dxvk { if (m_shaders.gs != nullptr) Logger::log(level, str::format(" gs : ", m_shaders.gs ->debugName())); if (m_shaders.fs != nullptr) Logger::log(level, str::format(" fs : ", m_shaders.fs ->debugName())); - for (uint32_t i = 0; i < state.ilAttributeCount; i++) { - const VkVertexInputAttributeDescription& attr = state.ilAttributes[i]; - Logger::log(level, str::format(" attr ", i, " : location ", attr.location, ", binding ", attr.binding, ", format ", attr.format, ", offset ", attr.offset)); + for (uint32_t i = 0; i < state.il.attributeCount(); i++) { + const auto& attr = state.ilAttributes[i]; + Logger::log(level, str::format(" attr ", i, " : location ", attr.location(), ", binding ", attr.binding(), ", format ", attr.format(), ", offset ", attr.offset())); } - for (uint32_t i = 0; i < state.ilBindingCount; i++) { - const VkVertexInputBindingDescription& bind = state.ilBindings[i]; - Logger::log(level, str::format(" binding ", i, " : binding ", bind.binding, ", stride ", bind.stride, ", rate ", bind.inputRate, ", divisor ", state.ilDivisors[i])); + for (uint32_t i = 0; i < state.il.bindingCount(); i++) { + const auto& bind = state.ilBindings[i]; + Logger::log(level, str::format(" binding ", i, " : binding ", bind.binding(), ", stride ", bind.stride(), ", rate ", bind.inputRate(), ", divisor ", bind.divisor())); } // TODO log more pipeline state diff --git a/src/dxvk/dxvk_graphics_state.h b/src/dxvk/dxvk_graphics_state.h index ed89a294..83020fe5 100644 --- a/src/dxvk/dxvk_graphics_state.h +++ b/src/dxvk/dxvk_graphics_state.h @@ -51,6 +51,162 @@ namespace dxvk { }; + /** + * \brief Packed input layout metadata + * + * Stores the number of vertex attributes + * and bindings in one byte each. + */ + class DxvkIlInfo { + + public: + + DxvkIlInfo() = default; + + DxvkIlInfo( + uint32_t attributeCount, + uint32_t bindingCount) + : m_attributeCount(uint8_t(attributeCount)), + m_bindingCount (uint8_t(bindingCount)) { } + + uint32_t attributeCount() const { + return m_attributeCount; + } + + uint32_t bindingCount() const { + return m_bindingCount; + } + + private: + + uint8_t m_attributeCount; + uint8_t m_bindingCount; + + }; + + + /** + * \brief Packed vertex attribute + * + * Stores a vertex attribute description. Assumes + * that all vertex formats have numerical values + * of 127 or less (i.e. fit into 7 bits). + */ + class DxvkIlAttribute { + + public: + + DxvkIlAttribute() = default; + + DxvkIlAttribute( + uint32_t location, + uint32_t binding, + VkFormat format, + uint32_t offset) + : m_location(uint32_t(location)), + m_binding (uint32_t(binding)), + m_format (uint32_t(format)), + m_offset (uint32_t(offset)), + m_reserved(0) { } + + uint32_t location() const { + return m_location; + } + + uint32_t binding() const { + return m_binding; + } + + VkFormat format() const { + return VkFormat(m_format); + } + + uint32_t offset() const { + return m_offset; + } + + VkVertexInputAttributeDescription description() const { + VkVertexInputAttributeDescription result; + result.location = m_location; + result.binding = m_binding; + result.format = VkFormat(m_format); + result.offset = m_offset; + return result; + } + + private: + + uint32_t m_location : 5; + uint32_t m_binding : 5; + uint32_t m_format : 7; + uint32_t m_offset : 11; + uint32_t m_reserved : 4; + + }; + + + /** + * \brief Packed vertex binding + * + * Stores a vertex binding description, + * including the 32-bit divisor. + */ + class DxvkIlBinding { + + public: + + DxvkIlBinding() = default; + + DxvkIlBinding( + uint32_t binding, + uint32_t stride, + VkVertexInputRate inputRate, + uint32_t divisor) + : m_binding (uint32_t(binding)), + m_stride (uint32_t(stride)), + m_inputRate (uint32_t(inputRate)), + m_reserved (0), + m_divisor (divisor) { } + + uint32_t binding() const { + return m_binding; + } + + uint32_t stride() const { + return m_stride; + } + + VkVertexInputRate inputRate() const { + return VkVertexInputRate(m_inputRate); + } + + uint32_t divisor() const { + return m_divisor; + } + + VkVertexInputBindingDescription description() const { + VkVertexInputBindingDescription result; + result.binding = m_binding; + result.stride = m_stride; + result.inputRate = VkVertexInputRate(m_inputRate); + return result; + } + + void setStride(uint32_t stride) { + m_stride = stride; + } + + private: + + uint32_t m_binding : 5; + uint32_t m_stride : 12; + uint32_t m_inputRate : 1; + uint32_t m_reserved : 14; + uint32_t m_divisor; + + }; + + /** * \brief Packed graphics pipeline state * @@ -108,12 +264,7 @@ namespace dxvk { DxvkBindingMask bsBindingMask; DxvkIaInfo ia; - - uint32_t ilAttributeCount; - uint32_t ilBindingCount; - VkVertexInputAttributeDescription ilAttributes[DxvkLimits::MaxNumVertexAttributes]; - VkVertexInputBindingDescription ilBindings[DxvkLimits::MaxNumVertexBindings]; - uint32_t ilDivisors[DxvkLimits::MaxNumVertexBindings]; + DxvkIlInfo il; VkBool32 rsDepthClipEnable; VkBool32 rsDepthBiasEnable; @@ -141,6 +292,9 @@ namespace dxvk { VkComponentMapping omComponentMapping[MaxNumRenderTargets]; uint32_t scSpecConstants[MaxNumSpecConstants]; + + DxvkIlAttribute ilAttributes [DxvkLimits::MaxNumVertexAttributes]; + DxvkIlBinding ilBindings [DxvkLimits::MaxNumVertexBindings]; }; }