From a6bf7659b073a1fe1f0faae88423d03e5ea12b3a Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 3 Dec 2017 00:40:58 +0100 Subject: [PATCH] [dxvk] Refactored shader binding, client APIs must now create pipelines and pipeline layouts --- build-win64.txt | 4 +- src/dxgi/dxgi_presenter.cpp | 28 ++++++- src/dxgi/dxgi_presenter.h | 4 + src/dxgi/dxgi_swapchain.cpp | 1 + src/dxvk/dxvk_cmdlist.cpp | 34 --------- src/dxvk/dxvk_cmdlist.h | 7 -- src/dxvk/dxvk_compute.cpp | 56 ++------------ src/dxvk/dxvk_compute.h | 21 +++--- src/dxvk/dxvk_context.cpp | 90 ++++++++-------------- src/dxvk/dxvk_context.h | 42 ++++++----- src/dxvk/dxvk_context_state.h | 19 +---- src/dxvk/dxvk_descriptor.h | 6 -- src/dxvk/dxvk_device.cpp | 32 +++++++- src/dxvk/dxvk_device.h | 43 ++++++++++- src/dxvk/dxvk_graphics.cpp | 55 +++----------- src/dxvk/dxvk_graphics.h | 36 ++++----- src/dxvk/dxvk_image.h | 3 + src/dxvk/dxvk_pipeline.cpp | 72 ++++++++++++++++++ src/dxvk/dxvk_pipeline.h | 80 ++++++++++++++++++++ src/dxvk/dxvk_pipemgr.cpp | 63 ---------------- src/dxvk/dxvk_pipemgr.h | 119 ------------------------------ src/dxvk/dxvk_shader.h | 17 ++--- src/dxvk/dxvk_swapchain.cpp | 47 ++++++------ src/dxvk/meson.build | 2 +- tests/dxvk/test_dxvk_triangle.cpp | 18 +++-- 25 files changed, 399 insertions(+), 500 deletions(-) create mode 100644 src/dxvk/dxvk_pipeline.cpp create mode 100644 src/dxvk/dxvk_pipeline.h delete mode 100644 src/dxvk/dxvk_pipemgr.cpp delete mode 100644 src/dxvk/dxvk_pipemgr.h diff --git a/build-win64.txt b/build-win64.txt index 98ad957c..18b3c9f2 100644 --- a/build-win64.txt +++ b/build-win64.txt @@ -6,11 +6,11 @@ strip = '/usr/bin/x86_64-w64-mingw32-strip' exe_wrapper = 'wine' [properties] -cpp_args = ['-std=c++17'] +cpp_args = ['-std=c++17', '-Og', '-ggdb'] cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++'] [host_machine] system = 'windows' cpu_family = 'x86_64' cpu = 'x86_64' -endian = 'little' \ No newline at end of file +endian = 'little' diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index e7665640..a85049af 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -35,8 +35,7 @@ namespace dxvk { // Set up context state. The shader bindings and the // constant state objects will never be modified. - m_context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, createVertexShader()); - m_context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, createFragmentShader()); + m_context->bindGraphicsPipeline(createPipeline()); m_context->setInputAssemblyState( new DxvkInputAssemblyState( @@ -135,6 +134,8 @@ namespace dxvk { m_context->setViewports(1, &viewport, &scissor); // TODO bind back buffer as a shader resource +// m_context->bindSampler(0, m_sampler); +// m_context->bindSampledImage(1, view); m_context->draw(4, 1, 0, 0); m_device->submitCommandList( @@ -322,4 +323,27 @@ namespace dxvk { VK_SHADER_STAGE_FRAGMENT_BIT, module.compile()); } + + Rc DxgiPresenter::createBindingLayout() { + std::array bindings; + bindings.at(0).type = VK_DESCRIPTOR_TYPE_SAMPLER; + bindings.at(0).stages = VK_SHADER_STAGE_FRAGMENT_BIT; + + bindings.at(1).type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + bindings.at(1).stages = VK_SHADER_STAGE_FRAGMENT_BIT; + + return m_device->createBindingLayout( + bindings.size(), bindings.data()); + } + + + Rc DxgiPresenter::createPipeline() { + const Rc vs = this->createVertexShader(); + const Rc fs = this->createFragmentShader(); + + return m_device->createGraphicsPipeline( + this->createBindingLayout(), + vs, nullptr, nullptr, nullptr, fs); + } + } diff --git a/src/dxgi/dxgi_presenter.h b/src/dxgi/dxgi_presenter.h index 36d09283..4ed4dc5f 100644 --- a/src/dxgi/dxgi_presenter.h +++ b/src/dxgi/dxgi_presenter.h @@ -55,6 +55,10 @@ namespace dxvk { Rc createVertexShader(); Rc createFragmentShader(); + Rc createBindingLayout(); + + Rc createPipeline(); + }; } diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 43c16d44..250fb8d3 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -341,6 +341,7 @@ namespace dxvk { | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; if (dxvkDevice->features().geometryShader) imageInfo.stages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp index 149257f4..28e3fe30 100644 --- a/src/dxvk/dxvk_cmdlist.cpp +++ b/src/dxvk/dxvk_cmdlist.cpp @@ -91,40 +91,6 @@ namespace dxvk { } - void DxvkCommandList::bindShaderResources( - VkPipelineBindPoint pipeline, - VkPipelineLayout pipelineLayout, - VkDescriptorSetLayout descriptorLayout, - uint32_t bindingCount, - const DxvkResourceBinding* bindings) { - VkDescriptorSet dset = m_descAlloc.alloc(descriptorLayout); - - if (bindingCount > m_descriptorSetWrites.size()) - m_descriptorSetWrites.resize(bindingCount); - - for (uint32_t i = 0; i < bindingCount; i++) { - VkWriteDescriptorSet& info = m_descriptorSetWrites.at(i); - - info.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - info.pNext = nullptr; - info.dstSet = dset; - info.dstBinding = i; - info.dstArrayElement = 0; - info.descriptorCount = 1; - info.descriptorType = bindings[i].type; - info.pImageInfo = &bindings[i].image; - info.pBufferInfo = &bindings[i].buffer; - info.pTexelBufferView = nullptr; - } - - m_vkd->vkUpdateDescriptorSets(m_vkd->device(), - bindingCount, m_descriptorSetWrites.data(), 0, nullptr); - - m_vkd->vkCmdBindDescriptorSets(m_buffer, - pipeline, pipelineLayout, 0, 1, &dset, 0, nullptr); - } - - void DxvkCommandList::cmdBeginRenderPass( const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 0e107b7b..7f875772 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -76,13 +76,6 @@ namespace dxvk { */ void reset(); - void bindShaderResources( - VkPipelineBindPoint pipeline, - VkPipelineLayout pipelineLayout, - VkDescriptorSetLayout descriptorLayout, - uint32_t bindingCount, - const DxvkResourceBinding* bindings); - void cmdBeginRenderPass( const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 877512d3..487d34e3 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -3,72 +3,30 @@ namespace dxvk { DxvkComputePipeline::DxvkComputePipeline( - const Rc& vkd, - const Rc& shader) - : m_vkd(vkd), m_shader(shader) { + const Rc& vkd, + const Rc& layout, + const Rc& cs) + : m_vkd(vkd), m_layout(layout), m_cs(cs) { std::vector bindings; - - // TODO re-implement shader slots and bindings -// for (uint32_t i = 0; i < shader->slotCount(); i++) -// bindings.push_back(shader->slotBinding(0, i)); - - VkDescriptorSetLayoutCreateInfo dlayout; - dlayout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - dlayout.pNext = nullptr; - dlayout.flags = 0; - dlayout.bindingCount = bindings.size(); - dlayout.pBindings = bindings.data(); - - if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), - &dlayout, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) - throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to create descriptor set layout"); - - VkPipelineLayoutCreateInfo playout; - playout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - playout.pNext = nullptr; - playout.flags = 0; - playout.setLayoutCount = 1; - playout.pSetLayouts = &m_descriptorSetLayout; - playout.pushConstantRangeCount = 0; - playout.pPushConstantRanges = nullptr; - - if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), - &playout, nullptr, &m_pipelineLayout) != VK_SUCCESS) { - this->destroyObjects(); - throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to create pipeline layout"); - } VkComputePipelineCreateInfo info; info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; info.pNext = nullptr; info.flags = 0; - info.stage = m_shader->stageInfo(); - info.layout = m_pipelineLayout; + info.stage = cs->stageInfo(); + info.layout = this->pipelineLayout(); info.basePipelineHandle = VK_NULL_HANDLE; info.basePipelineIndex = 0; if (m_vkd->vkCreateComputePipelines(m_vkd->device(), - VK_NULL_HANDLE, 1, &info, nullptr, &m_pipeline) != VK_SUCCESS) { - this->destroyObjects(); + VK_NULL_HANDLE, 1, &info, nullptr, &m_pipeline) != VK_SUCCESS) throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to compile pipeline"); - } } DxvkComputePipeline::~DxvkComputePipeline() { - this->destroyObjects(); - } - - - void DxvkComputePipeline::destroyObjects() { if (m_pipeline != VK_NULL_HANDLE) m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeline, nullptr); - - if (m_pipelineLayout != VK_NULL_HANDLE) - m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_pipelineLayout, nullptr); - - if (m_descriptorSetLayout != VK_NULL_HANDLE) - m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_descriptorSetLayout, nullptr); } } \ No newline at end of file diff --git a/src/dxvk/dxvk_compute.h b/src/dxvk/dxvk_compute.h index 8765652a..3cbef15c 100644 --- a/src/dxvk/dxvk_compute.h +++ b/src/dxvk/dxvk_compute.h @@ -1,7 +1,8 @@ #pragma once -#include "dxvk_shader.h" +#include "dxvk_pipeline.h" #include "dxvk_resource.h" +#include "dxvk_shader.h" namespace dxvk { @@ -18,8 +19,9 @@ namespace dxvk { public: DxvkComputePipeline( - const Rc& vkd, - const Rc& shader); + const Rc& vkd, + const Rc& layout, + const Rc& cs); ~DxvkComputePipeline(); /** @@ -30,7 +32,7 @@ namespace dxvk { * \returns The descriptor set layout */ VkDescriptorSetLayout descriptorSetLayout() const { - return m_descriptorSetLayout; + return m_layout->descriptorSetLayout(); } /** @@ -41,7 +43,7 @@ namespace dxvk { * \returns The descriptor set layout */ VkPipelineLayout pipelineLayout() const { - return m_pipelineLayout; + return m_layout->pipelineLayout(); } /** @@ -55,13 +57,10 @@ namespace dxvk { private: Rc m_vkd; - Rc m_shader; + Rc m_layout; + Rc m_cs; - VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; - VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; - VkPipeline m_pipeline = VK_NULL_HANDLE; - - void destroyObjects(); + VkPipeline m_pipeline = VK_NULL_HANDLE; }; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 11baf2e8..ac900421 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -4,11 +4,8 @@ namespace dxvk { - DxvkContext::DxvkContext( - const Rc& device, - const Rc& pipeMgr) - : m_device (device), - m_pipeMgr (pipeMgr) { + DxvkContext::DxvkContext(const Rc& device) + : m_device(device) { } @@ -30,7 +27,6 @@ namespace dxvk { m_flags.set( DxvkContextFlag::GpDirtyPipeline, - DxvkContextFlag::GpDirtyPipelineState, DxvkContextFlag::GpDirtyDynamicState, DxvkContextFlag::GpDirtyResources, DxvkContextFlag::GpDirtyIndexBuffer, @@ -66,27 +62,25 @@ namespace dxvk { } - void DxvkContext::bindShader( - VkShaderStageFlagBits stage, - const Rc& shader) { - DxvkShaderStageState* stageState = this->getShaderStage(stage); + void DxvkContext::bindComputePipeline( + const Rc& pipeline) { + m_state.cp = pipeline; - if (stageState->shader != shader) { - stageState->shader = shader; - - if (stage == VK_SHADER_STAGE_COMPUTE_BIT) { - m_flags.set( - DxvkContextFlag::CpDirtyPipeline, - DxvkContextFlag::CpDirtyResources); - } else { - m_flags.set( - DxvkContextFlag::GpDirtyPipeline, - DxvkContextFlag::GpDirtyPipelineState, - DxvkContextFlag::GpDirtyResources, - DxvkContextFlag::GpDirtyVertexBuffers, - DxvkContextFlag::GpDirtyIndexBuffer); - } - } + m_flags.set( + DxvkContextFlag::CpDirtyPipeline, + DxvkContextFlag::CpDirtyResources); + } + + + void DxvkContext::bindGraphicsPipeline( + const Rc& pipeline) { + m_state.gp = pipeline; + + m_flags.set( + DxvkContextFlag::GpDirtyPipeline, + DxvkContextFlag::GpDirtyResources, + DxvkContextFlag::GpDirtyVertexBuffers, + DxvkContextFlag::GpDirtyIndexBuffer); } @@ -238,7 +232,7 @@ namespace dxvk { const VkRect2D* scissorRects) { if (m_state.vp.viewportCount != viewportCount) { m_state.vp.viewportCount = viewportCount; - m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + m_flags.set(DxvkContextFlag::GpDirtyPipeline); } for (uint32_t i = 0; i < viewportCount; i++) { @@ -254,7 +248,7 @@ namespace dxvk { const Rc& state) { if (m_state.co.inputAssemblyState != state) { m_state.co.inputAssemblyState = state; - m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + m_flags.set(DxvkContextFlag::GpDirtyPipeline); } } @@ -263,7 +257,7 @@ namespace dxvk { const Rc& state) { if (m_state.co.inputLayout != state) { m_state.co.inputLayout = state; - m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + m_flags.set(DxvkContextFlag::GpDirtyPipeline); } } @@ -272,7 +266,7 @@ namespace dxvk { const Rc& state) { if (m_state.co.rasterizerState != state) { m_state.co.rasterizerState = state; - m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + m_flags.set(DxvkContextFlag::GpDirtyPipeline); } } @@ -281,7 +275,7 @@ namespace dxvk { const Rc& state) { if (m_state.co.multisampleState != state) { m_state.co.multisampleState = state; - m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + m_flags.set(DxvkContextFlag::GpDirtyPipeline); } } @@ -290,7 +284,7 @@ namespace dxvk { const Rc& state) { if (m_state.co.depthStencilState != state) { m_state.co.depthStencilState = state; - m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + m_flags.set(DxvkContextFlag::GpDirtyPipeline); } } @@ -299,7 +293,7 @@ namespace dxvk { const Rc& state) { if (m_state.co.blendState != state) { m_state.co.blendState = state; - m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + m_flags.set(DxvkContextFlag::GpDirtyPipeline); } } @@ -350,15 +344,6 @@ namespace dxvk { if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) { m_flags.clr(DxvkContextFlag::GpDirtyPipeline); - m_state.activeGraphicsPipeline = m_pipeMgr->getGraphicsPipeline( - m_state.vs.shader, m_state.tcs.shader, m_state.tes.shader, - m_state.gs.shader, m_state.fs.shader); - } - - if (m_flags.test(DxvkContextFlag::GpDirtyPipelineState) - && m_state.activeGraphicsPipeline != nullptr) { - m_flags.clr(DxvkContextFlag::GpDirtyPipelineState); - DxvkGraphicsPipelineStateInfo gpState; gpState.inputAssemblyState = m_state.co.inputAssemblyState; gpState.inputLayout = m_state.co.inputLayout; @@ -370,8 +355,8 @@ namespace dxvk { gpState.viewportCount = m_state.vp.viewportCount; m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, - m_state.activeGraphicsPipeline->getPipelineHandle(gpState)); - m_cmd->trackResource(m_state.activeGraphicsPipeline); + m_state.gp->getPipelineHandle(gpState)); + m_cmd->trackResource(m_state.gp); } } @@ -440,21 +425,4 @@ namespace dxvk { this->updateVertexBufferBindings(); } - - DxvkShaderStageState* DxvkContext::getShaderStage(VkShaderStageFlagBits stage) { - switch (stage) { - case VK_SHADER_STAGE_VERTEX_BIT: return &m_state.vs; - case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return &m_state.tcs; - case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return &m_state.tes; - case VK_SHADER_STAGE_GEOMETRY_BIT: return &m_state.gs; - case VK_SHADER_STAGE_FRAGMENT_BIT: return &m_state.fs; - case VK_SHADER_STAGE_COMPUTE_BIT: return &m_state.cs; - - default: - throw DxvkError(str::format( - "DxvkContext::getShaderStage: Invalid stage bit: ", - static_cast(stage))); - } - } - } \ No newline at end of file diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index c5a2c142..c1836695 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -4,7 +4,6 @@ #include "dxvk_cmdlist.h" #include "dxvk_context_state.h" #include "dxvk_data.h" -#include "dxvk_pipemgr.h" #include "dxvk_util.h" namespace dxvk { @@ -20,9 +19,7 @@ namespace dxvk { public: - DxvkContext( - const Rc& device, - const Rc& pipeMgr); + DxvkContext(const Rc& device); ~DxvkContext(); /** @@ -64,18 +61,26 @@ namespace dxvk { const DxvkBufferBinding& buffer); /** - * \brief Sets shader for a given shader stage + * \brief Binds compute pipeline * - * Binds a shader to a given stage, while unbinding the - * existing one. If \c nullptr is passed as the shader - * to bind, the given shader stage will be disabled. - * When drawing, at least a vertex shader must be bound. - * \param [in] stage The shader stage - * \param [in] shader The shader to set + * Note that binding a new pipeline implicitly + * invalidates all resource bindings that are + * used by the pipeline. + * \param [in] pipeline The pipeline to bind */ - void bindShader( - VkShaderStageFlagBits stage, - const Rc& shader); + void bindComputePipeline( + const Rc& pipeline); + + /** + * \brief Binds graphics pipeline + * + * Note that binding a new pipeline implicitly + * invalidates all bindings that are used by + * the pipeline. + * \param [in] pipeline The pipeline to bind + */ + void bindGraphicsPipeline( + const Rc& pipeline); /** * \brief Binds vertex buffer @@ -250,14 +255,15 @@ namespace dxvk { private: - const Rc m_device; - const Rc m_pipeMgr; + const Rc m_device; Rc m_cmd; DxvkContextFlags m_flags; DxvkContextState m_state; DxvkBarrierSet m_barriers; + std::vector m_descriptorSetWrites; + void renderPassBegin(); void renderPassEnd(); @@ -272,10 +278,6 @@ namespace dxvk { void commitComputeState(); void commitGraphicsState(); - - DxvkShaderStageState* getShaderStage( - VkShaderStageFlagBits stage); - }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index c5ad8ea5..8f05b5bc 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -20,8 +20,7 @@ namespace dxvk { */ enum class DxvkContextFlag : uint64_t { GpRenderPassBound, ///< Render pass is currently bound - GpDirtyPipeline, ///< Graphics pipeline binding are out of date - GpDirtyPipelineState, ///< Graphics pipeline state (blending etc.) is dirty + GpDirtyPipeline, ///< Graphics pipeline binding or state is out of date GpDirtyDynamicState, ///< Dynamic state needs to be reapplied GpDirtyResources, ///< Graphics pipeline resource bindings are out of date GpDirtyVertexBuffers, ///< Vertex buffer bindings are out of date @@ -34,11 +33,6 @@ namespace dxvk { using DxvkContextFlags = Flags; - struct DxvkShaderStageState { - Rc shader; - }; - - struct DxvkVertexInputState { DxvkBufferBinding indexBuffer; std::array activeGraphicsPipeline; - Rc activeComputePipeline; + Rc gp; + Rc cp; }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_descriptor.h b/src/dxvk/dxvk_descriptor.h index 8c07c835..2ccce297 100644 --- a/src/dxvk/dxvk_descriptor.h +++ b/src/dxvk/dxvk_descriptor.h @@ -4,12 +4,6 @@ namespace dxvk { - struct DxvkResourceBinding { - VkDescriptorType type; - VkDescriptorImageInfo image; - VkDescriptorBufferInfo buffer; - }; - /** * \brief Descriptor set allocator * diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 8ed28634..6a1e03b4 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -11,8 +11,7 @@ namespace dxvk { m_vkd (vkd), m_features (features), m_memory (new DxvkMemoryAllocator(adapter, vkd)), - m_renderPassPool (new DxvkRenderPassPool (vkd)), - m_pipelineManager (new DxvkPipelineManager(vkd)) { + m_renderPassPool (new DxvkRenderPassPool (vkd)) { m_vkd->vkGetDeviceQueue(m_vkd->device(), m_adapter->graphicsQueueFamily(), 0, &m_graphicsQueue); @@ -23,7 +22,6 @@ namespace dxvk { DxvkDevice::~DxvkDevice() { - m_pipelineManager = nullptr; m_renderPassPool = nullptr; m_memory = nullptr; @@ -39,7 +37,7 @@ namespace dxvk { Rc DxvkDevice::createContext() { - return new DxvkContext(this, m_pipelineManager); + return new DxvkContext(this); } @@ -93,6 +91,32 @@ namespace dxvk { } + Rc DxvkDevice::createBindingLayout( + uint32_t bindingCount, + const DxvkBindingInfo* bindingInfos) { + return new DxvkBindingLayout(m_vkd, bindingCount, bindingInfos); + } + + + Rc DxvkDevice::createComputePipeline( + const Rc& layout, + const Rc& cs) { + return new DxvkComputePipeline(m_vkd, layout, cs); + } + + + Rc DxvkDevice::createGraphicsPipeline( + const Rc& layout, + const Rc& vs, + const Rc& tcs, + const Rc& tes, + const Rc& gs, + const Rc& fs) { + return new DxvkGraphicsPipeline(m_vkd, + layout, vs, tcs, tes, gs, fs); + } + + Rc DxvkDevice::createSwapchain( const Rc& surface, const DxvkSwapchainProperties& properties) { diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index aafe4562..957a29d5 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -8,7 +8,6 @@ #include "dxvk_framebuffer.h" #include "dxvk_image.h" #include "dxvk_memory.h" -#include "dxvk_pipemgr.h" #include "dxvk_renderpass.h" #include "dxvk_shader.h" #include "dxvk_swapchain.h" @@ -159,6 +158,47 @@ namespace dxvk { VkShaderStageFlagBits stage, const SpirvCodeBuffer& code); + /** + * \brief Creates binding layout + * + * \param [in] bindingCount Number of bindings + * \param [in] bindingInfos Binding descriptions + * \returns New binding layout + */ + Rc createBindingLayout( + uint32_t bindingCount, + const DxvkBindingInfo* bindingInfos); + + /** + * \brief Creates a compute pipeline + * + * \param [in] layout Pipeline binding layout + * \param [in] cs Compute shader + * \returns New compute pipeline + */ + Rc createComputePipeline( + const Rc& layout, + const Rc& cs); + + /** + * \brief Creates a graphics pipeline + * + * \param [in] layout Pipeline binding layout + * \param [in] vs Vertex shader + * \param [in] tcs Tessellation control shader + * \param [in] tes Tessellation evaluation shader + * \param [in] gs Geometry shader + * \param [in] fs Fragment shader + * \returns New graphics pipeline + */ + Rc createGraphicsPipeline( + const Rc& layout, + const Rc& vs, + const Rc& tcs, + const Rc& tes, + const Rc& gs, + const Rc& fs); + /** * \brief Creates a swap chain * @@ -202,7 +242,6 @@ namespace dxvk { Rc m_memory; Rc m_renderPassPool; - Rc m_pipelineManager; VkQueue m_graphicsQueue; VkQueue m_presentQueue; diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 111882b2..fde30920 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -39,47 +39,21 @@ namespace dxvk { DxvkGraphicsPipeline::DxvkGraphicsPipeline( - const Rc& vkd, - const Rc& vs, - const Rc& tcs, - const Rc& tes, - const Rc& gs, - const Rc& fs) - : m_vkd(vkd), m_vs(vs), m_tcs(tcs), - m_tes(tes), m_gs(gs), m_fs(fs) { - std::vector bindings; + const Rc& vkd, + const Rc& layout, + const Rc& vs, + const Rc& tcs, + const Rc& tes, + const Rc& gs, + const Rc& fs) + : m_vkd(vkd), m_layout(layout), + m_vs(vs), m_tcs(tcs), m_tes(tes), m_gs(gs), m_fs(fs) { - VkDescriptorSetLayoutCreateInfo dlayout; - dlayout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - dlayout.pNext = nullptr; - dlayout.flags = 0; - dlayout.bindingCount = bindings.size(); - dlayout.pBindings = bindings.data(); - - if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), - &dlayout, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) - throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to create descriptor set layout"); - - VkPipelineLayoutCreateInfo playout; - playout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - playout.pNext = nullptr; - playout.flags = 0; - playout.setLayoutCount = 1; - playout.pSetLayouts = &m_descriptorSetLayout; - playout.pushConstantRangeCount = 0; - playout.pPushConstantRanges = nullptr; - - if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), - &playout, nullptr, &m_pipelineLayout) != VK_SUCCESS) { - this->destroyObjects(); - throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to create pipeline layout"); - } } DxvkGraphicsPipeline::~DxvkGraphicsPipeline() { this->destroyPipelines(); - this->destroyObjects(); } @@ -145,7 +119,7 @@ namespace dxvk { info.pDepthStencilState = &state.depthStencilState->info(); info.pColorBlendState = &state.blendState->info(); info.pDynamicState = &dsInfo; - info.layout = m_pipelineLayout; + info.layout = this->pipelineLayout(); info.renderPass = state.renderPass; info.subpass = 0; info.basePipelineHandle = VK_NULL_HANDLE; @@ -159,15 +133,6 @@ namespace dxvk { } - void DxvkGraphicsPipeline::destroyObjects() { - if (m_pipelineLayout != VK_NULL_HANDLE) - m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_pipelineLayout, nullptr); - - if (m_descriptorSetLayout != VK_NULL_HANDLE) - m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_descriptorSetLayout, nullptr); - } - - void DxvkGraphicsPipeline::destroyPipelines() { for (const auto& pair : m_pipelines) { m_vkd->vkDestroyPipeline( diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index b7793055..67df245d 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -5,8 +5,9 @@ #include "dxvk_constant_state.h" #include "dxvk_hash.h" -#include "dxvk_shader.h" +#include "dxvk_pipeline.h" #include "dxvk_resource.h" +#include "dxvk_shader.h" namespace dxvk { @@ -48,12 +49,13 @@ namespace dxvk { public: DxvkGraphicsPipeline( - const Rc& vkd, - const Rc& vs, - const Rc& tcs, - const Rc& tes, - const Rc& gs, - const Rc& fs); + const Rc& vkd, + const Rc& layout, + const Rc& vs, + const Rc& tcs, + const Rc& tes, + const Rc& gs, + const Rc& fs); ~DxvkGraphicsPipeline(); /** @@ -64,18 +66,18 @@ namespace dxvk { * \returns The descriptor set layout */ VkDescriptorSetLayout descriptorSetLayout() const { - return m_descriptorSetLayout; + return m_layout->descriptorSetLayout(); } /** - * \brief Pipeline layout layout + * \brief Pipeline layout * * The pipeline layout for this pipeline. * Use this to bind descriptor sets. * \returns The descriptor set layout */ VkPipelineLayout pipelineLayout() const { - return m_pipelineLayout; + return m_layout->pipelineLayout(); } /** @@ -88,14 +90,13 @@ namespace dxvk { private: Rc m_vkd; - Rc m_vs; - Rc m_tcs; - Rc m_tes; - Rc m_gs; - Rc m_fs; + Rc m_layout; - VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; - VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + Rc m_vs; + Rc m_tcs; + Rc m_tes; + Rc m_gs; + Rc m_fs; std::mutex m_mutex; @@ -106,7 +107,6 @@ namespace dxvk { VkPipeline compilePipeline( const DxvkGraphicsPipelineStateInfo& state) const; - void destroyObjects(); void destroyPipelines(); }; diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index b06ae33f..57260a6d 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -42,6 +42,9 @@ namespace dxvk { /// Image tiling mode VkImageTiling tiling; + + /// Common image layout + VkImageLayout layout; }; diff --git a/src/dxvk/dxvk_pipeline.cpp b/src/dxvk/dxvk_pipeline.cpp new file mode 100644 index 00000000..7d99a018 --- /dev/null +++ b/src/dxvk/dxvk_pipeline.cpp @@ -0,0 +1,72 @@ +#include "dxvk_pipeline.h" + +namespace dxvk { + + DxvkBindingLayout::DxvkBindingLayout( + const Rc& vkd, + uint32_t bindingCount, + const DxvkBindingInfo* bindingInfos) + : m_vkd(vkd) { + + for (uint32_t i = 0; i < bindingCount; i++) { + VkDescriptorSetLayoutBinding binding; + binding.binding = i; + binding.descriptorType = bindingInfos[i].type; + binding.descriptorCount = bindingInfos[i].stages == 0 ? 0 : 1; + binding.stageFlags = bindingInfos[i].stages; + binding.pImmutableSamplers = nullptr; + m_bindings.push_back(binding); + } + + VkDescriptorSetLayoutCreateInfo dsetInfo; + dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + dsetInfo.pNext = nullptr; + dsetInfo.flags = 0; + dsetInfo.bindingCount = m_bindings.size(); + dsetInfo.pBindings = m_bindings.data(); + + if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), + &dsetInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) + throw DxvkError("DxvkBindingLayout: Failed to create descriptor set layout"); + + VkPipelineLayoutCreateInfo pipeInfo; + pipeInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeInfo.pNext = nullptr; + pipeInfo.flags = 0; + pipeInfo.setLayoutCount = 1; + pipeInfo.pSetLayouts = &m_descriptorSetLayout; + pipeInfo.pushConstantRangeCount = 0; + pipeInfo.pPushConstantRanges = nullptr; + + if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), + &pipeInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) { + m_vkd->vkDestroyDescriptorSetLayout( + m_vkd->device(), m_descriptorSetLayout, nullptr); + throw DxvkError("DxvkBindingLayout: Failed to create pipeline layout"); + } + } + + + DxvkBindingLayout::~DxvkBindingLayout() { + if (m_pipelineLayout != VK_NULL_HANDLE) { + m_vkd->vkDestroyPipelineLayout( + m_vkd->device(), m_pipelineLayout, nullptr); + } + + if (m_descriptorSetLayout != VK_NULL_HANDLE) { + m_vkd->vkDestroyDescriptorSetLayout( + m_vkd->device(), m_descriptorSetLayout, nullptr); + } + } + + + DxvkBindingInfo DxvkBindingLayout::binding(uint32_t id) const { + const VkDescriptorSetLayoutBinding& bindingInfo = m_bindings.at(id); + + DxvkBindingInfo result; + result.type = bindingInfo.descriptorType; + result.stages = bindingInfo.stageFlags; + return result; + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_pipeline.h b/src/dxvk/dxvk_pipeline.h new file mode 100644 index 00000000..1f842f27 --- /dev/null +++ b/src/dxvk/dxvk_pipeline.h @@ -0,0 +1,80 @@ +#pragma once + +#include "dxvk_include.h" + +namespace dxvk { + + /** + * \brief Shader interface binding + * + * Corresponds to a single descriptor binding in + * Vulkan. DXVK does not use descriptor arrays. + * Instead, each binding stores one descriptor. + */ + struct DxvkBindingInfo { + VkDescriptorType type; + VkShaderStageFlags stages; + }; + + + /** + * \brief Shader interface + * + * Describes shader resource bindings + * for a graphics or compute pipeline. + */ + class DxvkBindingLayout : public RcObject { + + public: + + DxvkBindingLayout( + const Rc& vkd, + uint32_t bindingCount, + const DxvkBindingInfo* bindingInfos); + + ~DxvkBindingLayout(); + + /** + * \brief Number of resource bindings + * \returns Resource binding count + */ + uint32_t numBindings() const { + return m_bindings.size(); + } + + /** + * \brief Retrieves binding info + * + * \param [in] binding ID + * \returns Binding info + */ + DxvkBindingInfo binding(uint32_t id) const; + + /** + * \brief Descriptor set layout handle + * \returns Descriptor set layout handle + */ + VkDescriptorSetLayout descriptorSetLayout() const { + return m_descriptorSetLayout; + } + + /** + * \brief Pipeline layout handle + * \returns Pipeline layout handle + */ + VkPipelineLayout pipelineLayout() const { + return m_pipelineLayout; + } + + private: + + Rc m_vkd; + + VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; + VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + + std::vector m_bindings; + + }; + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_pipemgr.cpp b/src/dxvk/dxvk_pipemgr.cpp deleted file mode 100644 index 24b95c8d..00000000 --- a/src/dxvk/dxvk_pipemgr.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "dxvk_pipemgr.h" - -namespace dxvk { - - DxvkPipelineManager::DxvkPipelineManager( - const Rc& vkd) - : m_vkd(vkd) { - - } - - - DxvkPipelineManager::~DxvkPipelineManager() { - - } - - - Rc DxvkPipelineManager::getComputePipeline(const Rc& cs) { - if (cs == nullptr) - return nullptr; - - DxvkPipelineKey<1> key; - key.setShader(0, cs); - - std::lock_guard lock(m_mutex); - - auto pair = m_computePipelines.find(key); - if (pair != m_computePipelines.end()) - return pair->second; - - Rc pipeline = new DxvkComputePipeline(m_vkd, cs); - m_computePipelines.insert(std::make_pair(key, pipeline)); - return pipeline; - } - - - Rc DxvkPipelineManager::getGraphicsPipeline( - const Rc& vs, - const Rc& tcs, - const Rc& tes, - const Rc& gs, - const Rc& fs) { - if (vs == nullptr) - return nullptr; - - DxvkPipelineKey<5> key; - key.setShader(0, vs); - key.setShader(1, tcs); - key.setShader(2, tes); - key.setShader(3, gs); - key.setShader(4, fs); - - std::lock_guard lock(m_mutex); - - auto pair = m_graphicsPipelines.find(key); - if (pair != m_graphicsPipelines.end()) - return pair->second; - - Rc pipeline = new DxvkGraphicsPipeline(m_vkd, vs, tcs, tes, gs, fs); - m_graphicsPipelines.insert(std::make_pair(key, pipeline)); - return pipeline; - } - -} \ No newline at end of file diff --git a/src/dxvk/dxvk_pipemgr.h b/src/dxvk/dxvk_pipemgr.h deleted file mode 100644 index f4f97305..00000000 --- a/src/dxvk/dxvk_pipemgr.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include -#include - -#include "dxvk_compute.h" -#include "dxvk_hash.h" -#include "dxvk_graphics.h" - -namespace dxvk { - - /** - * \brief Pipeline key - * - * Stores a fixed-size set of shaders in order - * to identify a shader pipeline object. - */ - template - class DxvkPipelineKey { - - public: - - void setShader( - size_t id, - const Rc& shader) { - m_shaders.at(id) = shader; - } - - size_t hash() const { - std::hash phash; - - DxvkHashState state; - for (size_t i = 0; i < N; i++) - state.add(phash(m_shaders[i].ptr())); - return state; - } - - bool operator == (const DxvkPipelineKey& other) const { - bool result = true; - for (size_t i = 0; (i < N) && result; i++) - result &= m_shaders[i] == other.m_shaders[i]; - return result; - } - - bool operator != (const DxvkPipelineKey& other) const { - return !this->operator == (other); - } - - private: - - std::array, N> m_shaders; - - }; - - /** - * \brief Pipeline manager - * - * Creates and manages pipeline objects - * for various combinations of shaders. - */ - class DxvkPipelineManager : public RcObject { - - public: - - DxvkPipelineManager( - const Rc& vkd); - ~DxvkPipelineManager(); - - /** - * \brief Retrieves compute pipeline - * - * Retrieves a compute pipeline object for the given - * shader. If no such pipeline object exists, a new - * one will be created. - * \param [in] cs Compute shader - * \returns Compute pipeline - */ - Rc getComputePipeline( - const Rc& cs); - - /** - * \brief Retrieves graphics pipeline - * - * Retrieves a graphics pipeline object for the given - * combination of shaders. If no such pipeline object - * exists, a new one will be created. - * \param [in] vs Vertex shader - * \param [in] tcs Tessellation control shader - * \param [in] tes Tessellation evaluation shader - * \param [in] gs Geometry shader - * \param [in] fs Fragment shader - * \returns Graphics pipeline - */ - Rc getGraphicsPipeline( - const Rc& vs, - const Rc& tcs, - const Rc& tes, - const Rc& gs, - const Rc& fs); - - private: - - Rc m_vkd; - - std::mutex m_mutex; - - std::unordered_map< - DxvkPipelineKey<1>, - Rc, - DxvkHash> m_computePipelines; - - std::unordered_map< - DxvkPipelineKey<5>, - Rc, - DxvkHash> m_graphicsPipelines; - - }; - -} \ No newline at end of file diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h index 10f40d1e..2da757f9 100644 --- a/src/dxvk/dxvk_shader.h +++ b/src/dxvk/dxvk_shader.h @@ -9,19 +9,14 @@ namespace dxvk { /** - * \brief Shader resource type + * \brief Resource slot * - * Enumerates the types of resources - * that can be accessed by shaders. + * Describes the type of a single resource + * binding that a shader can access. */ - enum class DxvkResourceType : uint32_t { - ImageSampler = VK_DESCRIPTOR_TYPE_SAMPLER, - SampledImage = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - StorageImage = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - UniformBuffer = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - StorageBuffer = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, - UniformTexelBuffer = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, - StorageTexelBuffer = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, + struct DxvkResourceSlot { + uint32_t binding; + VkDescriptorType type; }; diff --git a/src/dxvk/dxvk_swapchain.cpp b/src/dxvk/dxvk_swapchain.cpp index f55e39b8..ffdd76eb 100644 --- a/src/dxvk/dxvk_swapchain.cpp +++ b/src/dxvk/dxvk_swapchain.cpp @@ -137,28 +137,33 @@ namespace dxvk { auto swapImages = this->retrieveSwapImages(); m_framebuffers.resize(swapImages.size()); + DxvkImageCreateInfo imageInfo; + imageInfo.type = VK_IMAGE_TYPE_2D; + imageInfo.format = fmt.format; + imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; + imageInfo.extent.width = swapInfo.imageExtent.width; + imageInfo.extent.height = swapInfo.imageExtent.height; + imageInfo.extent.depth = 1; + imageInfo.numLayers = swapInfo.imageArrayLayers; + imageInfo.mipLevels = 1; + imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + imageInfo.access = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + | VK_ACCESS_MEMORY_READ_BIT; + imageInfo.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + DxvkImageViewCreateInfo viewInfo; + viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = fmt.format; + viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.minLevel = 0; + viewInfo.numLevels = 1; + viewInfo.minLayer = 0; + viewInfo.numLayers = swapInfo.imageArrayLayers; + for (size_t i = 0; i < swapImages.size(); i++) { - DxvkImageCreateInfo imageInfo; - imageInfo.type = VK_IMAGE_TYPE_2D; - imageInfo.format = fmt.format; - imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; - imageInfo.extent.width = swapInfo.imageExtent.width; - imageInfo.extent.height = swapInfo.imageExtent.height; - imageInfo.extent.depth = 1; - imageInfo.numLayers = swapInfo.imageArrayLayers; - imageInfo.mipLevels = 1; - imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - - DxvkImageViewCreateInfo viewInfo; - viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = fmt.format; - viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.minLevel = 0; - viewInfo.numLevels = 1; - viewInfo.minLayer = 0; - viewInfo.numLayers = swapInfo.imageArrayLayers; - Rc image = new DxvkImage(m_vkd, imageInfo, swapImages.at(i)); Rc iview = m_device->createImageView(image, viewInfo); diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index a06fbf47..e7350f28 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -16,7 +16,7 @@ dxvk_src = files([ 'dxvk_lifetime.cpp', 'dxvk_main.cpp', 'dxvk_memory.cpp', - 'dxvk_pipemgr.cpp', + 'dxvk_pipeline.cpp', 'dxvk_renderpass.cpp', 'dxvk_resource.cpp', 'dxvk_shader.cpp', diff --git a/tests/dxvk/test_dxvk_triangle.cpp b/tests/dxvk/test_dxvk_triangle.cpp index 0d761398..41e39a88 100644 --- a/tests/dxvk/test_dxvk_triangle.cpp +++ b/tests/dxvk/test_dxvk_triangle.cpp @@ -115,12 +115,12 @@ public: VK_SHADER_STAGE_FRAGMENT_BIT, SpirvCodeBuffer(_countof(fsCode), fsCode)); - m_dxvkContext->bindShader( - VK_SHADER_STAGE_VERTEX_BIT, - m_dxvkVertexShader); - m_dxvkContext->bindShader( - VK_SHADER_STAGE_FRAGMENT_BIT, - m_dxvkFragmentShader); + m_dxvkBindingLayout = m_dxvkDevice->createBindingLayout(0, nullptr); + + m_dxvkPipeline = m_dxvkDevice->createGraphicsPipeline(m_dxvkBindingLayout, + m_dxvkVertexShader, nullptr, nullptr, nullptr, m_dxvkFragmentShader); + + m_dxvkContext->bindGraphicsPipeline(m_dxvkPipeline); } ~TriangleApp() { @@ -194,8 +194,10 @@ private: Rc m_dxvkSwapchain; Rc m_dxvkContext; - Rc m_dxvkVertexShader; - Rc m_dxvkFragmentShader; + Rc m_dxvkVertexShader; + Rc m_dxvkFragmentShader; + Rc m_dxvkBindingLayout; + Rc m_dxvkPipeline; };