diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index 0705d905..780bf358 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -109,6 +109,18 @@ namespace dxvk { return m_buffer; } + VkBuffer bufferHandle() const { + return m_buffer->handle(); + } + + size_t bufferOffset() const { + return m_offset; + } + + size_t bufferRange() const { + return m_length; + } + VkDescriptorBufferInfo descriptorInfo() const { VkDescriptorBufferInfo info; info.buffer = m_buffer->handle(); diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp index 8b68aefd..3d8c2717 100644 --- a/src/dxvk/dxvk_cmdlist.cpp +++ b/src/dxvk/dxvk_cmdlist.cpp @@ -119,6 +119,15 @@ namespace dxvk { } + void DxvkCommandList::cmdBindIndexBuffer( + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType) { + m_vkd->vkCmdBindIndexBuffer(m_buffer, + buffer, offset, indexType); + } + + void DxvkCommandList::cmdBindPipeline( VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index e5ca18a7..ef59f2bf 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -82,6 +82,11 @@ namespace dxvk { const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) final; + void cmdBindIndexBuffer( + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType) final; + void cmdBindPipeline( VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) final; diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 92d420c3..dd4f13e1 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -76,7 +76,7 @@ namespace dxvk { if (m_vkd->vkCreateComputePipelines(m_vkd->device(), VK_NULL_HANDLE, 1, &info, nullptr, &m_pipeline) != VK_SUCCESS) { this->destroyObjects(); - throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to compipe pipeline"); + throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to compile pipeline"); } } diff --git a/src/dxvk/dxvk_constant_state.cpp b/src/dxvk/dxvk_constant_state.cpp new file mode 100644 index 00000000..1a960d02 --- /dev/null +++ b/src/dxvk/dxvk_constant_state.cpp @@ -0,0 +1,137 @@ +#include "dxvk_constant_state.h" + +namespace dxvk { + + DxvkInputAssemblyState::DxvkInputAssemblyState( + VkPrimitiveTopology primitiveTopology, + VkBool32 primitiveRestart) { + m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + m_info.pNext = nullptr; + m_info.flags = 0; + m_info.topology = primitiveTopology; + m_info.primitiveRestartEnable = primitiveRestart; + } + + + DxvkRasterizerState::DxvkRasterizerState( + VkBool32 enableDepthClamp, + VkBool32 enableDiscard, + VkPolygonMode polygonMode, + VkCullModeFlags cullMode, + VkFrontFace frontFace, + VkBool32 depthBiasEnable, + float depthBiasConstant, + float depthBiasClamp, + float depthBiasSlope, + float lineWidth) { + m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + m_info.pNext = nullptr; + m_info.flags = 0; + m_info.depthClampEnable = enableDepthClamp; + m_info.rasterizerDiscardEnable= enableDiscard; + m_info.polygonMode = polygonMode; + m_info.cullMode = cullMode; + m_info.frontFace = frontFace; + m_info.depthBiasEnable = depthBiasEnable; + m_info.depthBiasConstantFactor= depthBiasConstant; + m_info.depthBiasClamp = depthBiasClamp; + m_info.depthBiasSlopeFactor = depthBiasSlope; + m_info.lineWidth = lineWidth; + } + + + DxvkMultisampleState::DxvkMultisampleState( + VkSampleCountFlagBits sampleCount, + uint32_t sampleMask, + VkBool32 enableAlphaToCoverage, + VkBool32 enableAlphaToOne, + VkBool32 enableSampleShading, + float minSampleShading) { + m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + m_info.pNext = nullptr; + m_info.flags = 0; + m_info.rasterizationSamples = sampleCount; + m_info.sampleShadingEnable = enableSampleShading; + m_info.minSampleShading = minSampleShading; + m_info.pSampleMask = &m_mask; + m_info.alphaToCoverageEnable = enableAlphaToCoverage; + m_info.alphaToOneEnable = enableAlphaToOne; + + m_mask = sampleMask; + } + + + DxvkDepthStencilState::DxvkDepthStencilState( + VkBool32 enableDepthTest, + VkBool32 enableDepthWrite, + VkBool32 enableDepthBounds, + VkBool32 enableStencilTest, + VkCompareOp depthCompareOp, + VkStencilOpState stencilOpFront, + VkStencilOpState stencilOpBack, + float depthBoundsMin, + float depthBoundsMax) { + m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + m_info.pNext = nullptr; + m_info.flags = 0; + m_info.depthTestEnable = enableDepthTest; + m_info.depthWriteEnable = enableDepthWrite; + m_info.depthCompareOp = depthCompareOp; + m_info.depthBoundsTestEnable = enableDepthBounds; + m_info.stencilTestEnable = enableStencilTest; + m_info.front = stencilOpFront; + m_info.back = stencilOpBack; + m_info.minDepthBounds = depthBoundsMin; + m_info.maxDepthBounds = depthBoundsMax; + } + + + DxvkBlendState::DxvkBlendState( + VkBool32 enableLogicOp, + VkLogicOp logicOp, + uint32_t attachmentCount, + const VkPipelineColorBlendAttachmentState* attachmentState) { + m_attachments.resize(attachmentCount); + + for (uint32_t i = 0; i < attachmentCount; i++) + m_attachments.at(i) = attachmentState[i]; + + m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + m_info.pNext = nullptr; + m_info.flags = 0; + m_info.logicOpEnable = enableLogicOp; + m_info.logicOp = logicOp; + m_info.attachmentCount = m_attachments.size(); + m_info.pAttachments = m_attachments.data(); + + for (uint32_t i = 0; i < 4; i++) + m_info.blendConstants[i] = 0.0f; + } + + + DxvkInputLayout::DxvkInputLayout( + uint32_t attributeCount, + const VkVertexInputAttributeDescription* attributeInfo, + uint32_t bindingCount, + const VkVertexInputBindingDescription* bindingInfo) { + // Copy vertex attribute info to a persistent array + m_attributes.resize(attributeCount); + for (uint32_t i = 0; i < attributeCount; i++) + m_attributes.at(i) = attributeInfo[i]; + + // Copy vertex binding info to a persistent array + m_bindings.resize(bindingCount); + for (uint32_t i = 0; i < bindingCount; i++) + m_bindings.at(i) = bindingInfo[i]; + + // Create info structure referencing those arrays + m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + m_info.pNext = nullptr; + m_info.flags = 0; + m_info.vertexBindingDescriptionCount = m_bindings.size(); + m_info.pVertexBindingDescriptions = m_bindings.data(); + m_info.vertexAttributeDescriptionCount = m_attributes.size(); + m_info.pVertexAttributeDescriptions = m_attributes.data(); + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_constant_state.h b/src/dxvk/dxvk_constant_state.h new file mode 100644 index 00000000..db02cdf2 --- /dev/null +++ b/src/dxvk/dxvk_constant_state.h @@ -0,0 +1,202 @@ +#pragma once + +#include "dxvk_buffer.h" +#include "dxvk_framebuffer.h" +#include "dxvk_limits.h" +#include "dxvk_resource.h" +#include "dxvk_shader.h" + +namespace dxvk { + + /** + * \brief Input assembly state + * + * Stores the primitive topology and + * whether or not primitive restart + * is enabled. + */ + class DxvkInputAssemblyState : public RcObject { + + public: + + DxvkInputAssemblyState( + VkPrimitiveTopology primitiveTopology, + VkBool32 primitiveRestart); + + const VkPipelineInputAssemblyStateCreateInfo& info() const { + return m_info; + } + + private: + + VkPipelineInputAssemblyStateCreateInfo m_info; + + }; + + + /** + * \brief Rasterizer state + * + * Stores the operating mode of the + * rasterizer, including the depth bias. + */ + class DxvkRasterizerState : public RcObject { + + public: + + DxvkRasterizerState( + VkBool32 enableDepthClamp, + VkBool32 enableDiscard, + VkPolygonMode polygonMode, + VkCullModeFlags cullMode, + VkFrontFace frontFace, + VkBool32 depthBiasEnable, + float depthBiasConstant, + float depthBiasClamp, + float depthBiasSlope, + float lineWidth); + + const VkPipelineRasterizationStateCreateInfo& info() const { + return m_info; + } + + private: + + VkPipelineRasterizationStateCreateInfo m_info; + + }; + + + /** + * \brief Multisample state + * + * Defines details on how to handle + * multisampling, including the alpha + * coverage mode. + */ + class DxvkMultisampleState : public RcObject { + + public: + + DxvkMultisampleState( + VkSampleCountFlagBits sampleCount, + uint32_t sampleMask, + VkBool32 enableAlphaToCoverage, + VkBool32 enableAlphaToOne, + VkBool32 enableSampleShading, + float minSampleShading); + + const VkPipelineMultisampleStateCreateInfo& info() const { + return m_info; + } + + private: + + VkPipelineMultisampleStateCreateInfo m_info; + uint32_t m_mask; + + }; + + + /** + * \brief Depth-stencil state + * + * Defines the depth test and stencil + * operations for the graphics pipeline. + */ + class DxvkDepthStencilState : public RcObject { + + public: + + DxvkDepthStencilState( + VkBool32 enableDepthTest, + VkBool32 enableDepthWrite, + VkBool32 enableDepthBounds, + VkBool32 enableStencilTest, + VkCompareOp depthCompareOp, + VkStencilOpState stencilOpFront, + VkStencilOpState stencilOpBack, + float depthBoundsMin, + float depthBoundsMax); + + const VkPipelineDepthStencilStateCreateInfo& info() const { + return m_info; + } + + private: + + VkPipelineDepthStencilStateCreateInfo m_info; + + }; + + + /** + * \brief Blend state + * + * Stores the color blend state for each + * available framebuffer attachment. + */ + class DxvkBlendState : public RcObject { + + public: + + DxvkBlendState( + VkBool32 enableLogicOp, + VkLogicOp logicOp, + uint32_t attachmentCount, + const VkPipelineColorBlendAttachmentState* attachmentState); + + const VkPipelineColorBlendStateCreateInfo& info() const { + return m_info; + } + + private: + + std::vector m_attachments; + + VkPipelineColorBlendStateCreateInfo m_info; + + }; + + + /** + * \brief Input layout + * + * Stores the attributes and vertex buffer binding + * descriptions that the vertex shader will take + * its input values from. + */ + class DxvkInputLayout : public RcObject { + + public: + + DxvkInputLayout( + uint32_t attributeCount, + const VkVertexInputAttributeDescription* attributeInfo, + uint32_t bindingCount, + const VkVertexInputBindingDescription* bindingInfo); + + const VkPipelineVertexInputStateCreateInfo& info() const { + return m_info; + } + + private: + + std::vector m_attributes; + std::vector m_bindings; + + VkPipelineVertexInputStateCreateInfo m_info; + + }; + + + struct DxvkConstantStateObjects { + Rc inputAssembly; + Rc inputLayout; + Rc rasterizerState; + Rc multisampleState; + Rc depthStencilState; + Rc blendState; + }; + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 48c00aa4..e2f05d16 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -34,6 +34,7 @@ namespace dxvk { m_state.flags.set( DxvkContextFlag::GpDirtyPipeline, DxvkContextFlag::GpDirtyPipelineState, + DxvkContextFlag::GpDirtyDynamicState, DxvkContextFlag::GpDirtyResources, DxvkContextFlag::GpDirtyIndexBuffer, DxvkContextFlag::GpDirtyVertexBuffers, @@ -63,6 +64,15 @@ namespace dxvk { } + void DxvkContext::bindIndexBuffer( + const DxvkBufferBinding& buffer) { + if (m_state.vi.indexBuffer != buffer) { + m_state.vi.indexBuffer = buffer; + m_state.flags.set(DxvkContextFlag::GpDirtyIndexBuffer); + } + } + + void DxvkContext::bindShader( VkShaderStageFlagBits stage, const Rc& shader) { @@ -89,6 +99,16 @@ namespace dxvk { } + void DxvkContext::bindVertexBuffer( + uint32_t binding, + const DxvkBufferBinding& buffer) { + if (m_state.vi.vertexBuffers.at(binding) != buffer) { + m_state.vi.vertexBuffers.at(binding) = buffer; + m_state.flags.set(DxvkContextFlag::GpDirtyVertexBuffers); + } + } + + void DxvkContext::clearRenderTarget( const VkClearAttachment& attachment, const VkClearRect& clearArea) { @@ -174,7 +194,7 @@ namespace dxvk { m_state.flags.clr(DxvkContextFlag::GpDirtyPipelineState); DxvkGraphicsPipelineStateInfo gpState; - gpState.renderPass = m_state.om.framebuffer->renderPass(); + // TODO fill state object m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, m_state.activeGraphicsPipeline->getPipelineHandle(gpState)); @@ -182,9 +202,44 @@ namespace dxvk { } + void DxvkContext::bindDynamicState() { + if (m_state.flags.test(DxvkContextFlag::GpDirtyDynamicState)) { + m_state.flags.clr(DxvkContextFlag::GpDirtyDynamicState); + + // TODO implement + } + } + + + void DxvkContext::bindIndexBuffer() { + if (m_state.flags.test(DxvkContextFlag::GpDirtyIndexBuffer)) { + m_state.flags.clr(DxvkContextFlag::GpDirtyIndexBuffer); + + m_cmd->cmdBindIndexBuffer( + m_state.vi.indexBuffer.bufferHandle(), + m_state.vi.indexBuffer.bufferOffset(), + VK_INDEX_TYPE_UINT32); + m_cmd->trackResource( + m_state.vi.indexBuffer.resource()); + } + } + + + void DxvkContext::bindVertexBuffers() { + if (m_state.flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) { + m_state.flags.clr(DxvkContextFlag::GpDirtyVertexBuffers); + + // TODO implement + } + } + + void DxvkContext::flushGraphicsState() { this->renderPassBegin(); this->bindGraphicsPipeline(); + this->bindDynamicState(); + this->bindIndexBuffer(); + this->bindVertexBuffers(); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 7fc36983..df5953bb 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -55,6 +55,13 @@ namespace dxvk { void bindFramebuffer( const Rc& fb); + /** + * \brief Binds index buffer + * \param [in] buffer New index buffer + */ + void bindIndexBuffer( + const DxvkBufferBinding& buffer); + /** * \brief Sets shader for a given shader stage * @@ -69,6 +76,16 @@ namespace dxvk { VkShaderStageFlagBits stage, const Rc& shader); + /** + * \brief Binds vertex buffer + * + * \param [in] binding Vertex buffer binding + * \param [in] buffer New vertex buffer + */ + void bindVertexBuffer( + uint32_t binding, + const DxvkBufferBinding& buffer); + /** * \brief Clears an active render target * @@ -118,10 +135,12 @@ namespace dxvk { DxvkContextState m_state; void renderPassBegin(); - void renderPassEnd(); void bindGraphicsPipeline(); + void bindDynamicState(); + void bindIndexBuffer(); + void bindVertexBuffers(); void flushGraphicsState(); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 12836e7f..dcd7075f 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -2,6 +2,7 @@ #include "dxvk_buffer.h" #include "dxvk_compute.h" +#include "dxvk_constant_state.h" #include "dxvk_framebuffer.h" #include "dxvk_graphics.h" #include "dxvk_image.h" @@ -21,6 +22,7 @@ namespace dxvk { GpRenderPassBound, ///< Render pass is currently bound GpDirtyPipeline, ///< Graphics pipeline binding are out of date GpDirtyPipelineState, ///< Graphics pipeline state (blending etc.) is dirty + GpDirtyDynamicState, ///< Dynamic state needs to be reapplied GpDirtyResources, ///< Graphics pipeline resource bindings are out of date GpDirtyVertexBuffers, ///< Vertex buffer bindings are out of date GpDirtyIndexBuffer, ///< Index buffer binding are out of date @@ -32,58 +34,25 @@ namespace dxvk { using DxvkContextFlags = Flags; - /** - * \brief Shader state - * - * Stores the active shader and resources - * for a single shader stage. All stages - * support the same types of resources. - */ struct DxvkShaderStageState { Rc shader; }; - /** - * \brief Input assembly state - * - * Stores the primitive topology - * and the vertex input layout. - */ - struct DxvkInputAssemblyState { - VkPrimitiveTopology primitiveTopology; - VkBool32 primitiveRestart; - - uint32_t numVertexBindings = 0; - uint32_t numVertexAttributes = 0; - - std::array vertexBindings; - - std::array vertexAttributes; - }; - - - /** - * \brief Vertex input state - * - * Stores the currently bound index - * buffer and vertex buffers. - */ struct DxvkVertexInputState { - Rc indexBuffer; - std::array, - DxvkLimits::MaxNumVertexBuffers> vertexBuffers; + DxvkBufferBinding indexBuffer; + std::array vertexBuffers; + }; + + + struct DxvkViewportState { + uint32_t viewportCount = 0; + std::array viewports; + std::array scissorRects; }; - /** - * \brief Output merger state - * - * Stores the active framebuffer and the current - * blend state, as well as the depth stencil state. - */ struct DxvkOutputMergerState { Rc framebuffer; }; @@ -103,9 +72,10 @@ namespace dxvk { DxvkShaderStageState fs; DxvkShaderStageState cs; - DxvkInputAssemblyState ia; DxvkVertexInputState vi; + DxvkViewportState vp; DxvkOutputMergerState om; + DxvkConstantStateObjects co; Rc activeGraphicsPipeline; Rc activeComputePipeline; diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 9656d322..316b24ff 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -2,13 +2,34 @@ namespace dxvk { + template + size_t hashPtr(T* ptr) { + return reinterpret_cast(ptr); + } + size_t DxvkGraphicsPipelineStateInfo::hash() const { - // TODO implement + DxvkHashState state; + state.add(hashPtr(this->inputAssembly.ptr())); + state.add(hashPtr(this->inputLayout.ptr())); + state.add(hashPtr(this->rasterizerState.ptr())); + state.add(hashPtr(this->multisampleState.ptr())); + state.add(hashPtr(this->depthStencilState.ptr())); + state.add(hashPtr(this->blendState.ptr())); + state.add(std::hash()(this->renderPass)); + state.add(viewportCount); + return state; } bool DxvkGraphicsPipelineStateInfo::operator == (const DxvkGraphicsPipelineStateInfo& other) const { - return this->renderPass == other.renderPass; + return this->inputAssembly == other.inputAssembly + && this->inputLayout == other.inputLayout + && this->rasterizerState == other.rasterizerState + && this->multisampleState == other.multisampleState + && this->depthStencilState == other.depthStencilState + && this->blendState == other.blendState + && this->renderPass == other.renderPass + && this->viewportCount == other.viewportCount; } diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 49847ea1..92b0cc05 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -3,6 +3,7 @@ #include #include +#include "dxvk_constant_state.h" #include "dxvk_hash.h" #include "dxvk_shader.h" #include "dxvk_resource.h" @@ -12,10 +13,21 @@ namespace dxvk { /** * \brief Graphics pipeline state info * - * + * Stores all information that is required to create + * a graphics pipeline, except the shader objects + * themselves. Also used to identify pipelines using + * the current pipeline state vector. */ struct DxvkGraphicsPipelineStateInfo { - VkRenderPass renderPass; + Rc inputAssembly; + Rc inputLayout; + Rc rasterizerState; + Rc multisampleState; + Rc depthStencilState; + Rc blendState; + + VkRenderPass renderPass; + uint32_t viewportCount; size_t hash() const; diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index 8fef38b5..3380f0cd 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -133,7 +133,6 @@ namespace dxvk { DxvkImageViewCreateInfo m_info; VkImageView m_view; - }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_limits.h b/src/dxvk/dxvk_limits.h index 5896660a..b9e3bea5 100644 --- a/src/dxvk/dxvk_limits.h +++ b/src/dxvk/dxvk_limits.h @@ -1,11 +1,15 @@ #pragma once +#include "dxvk_include.h" + namespace dxvk { enum DxvkLimits : size_t { MaxNumRenderTargets = 8, - MaxNumVertexBuffers = 32, + MaxNumVertexAttributes = 32, + MaxNumVertexBindings = 32, MaxNumOutputStreams = 4, + MaxNumViewports = 16, }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_recorder.h b/src/dxvk/dxvk_recorder.h index e47d9513..05c42f36 100644 --- a/src/dxvk/dxvk_recorder.h +++ b/src/dxvk/dxvk_recorder.h @@ -39,6 +39,11 @@ namespace dxvk { const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) = 0; + virtual void cmdBindIndexBuffer( + VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType) = 0; + virtual void cmdBindPipeline( VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) = 0; diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 7f32640f..61fed846 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -4,6 +4,7 @@ dxvk_src = files([ 'dxvk_buffer.cpp', 'dxvk_cmdlist.cpp', 'dxvk_compute.cpp', + 'dxvk_constant_state.cpp', 'dxvk_context.cpp', 'dxvk_deferred.cpp', 'dxvk_descriptor.cpp',