1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-20 10:54:16 +01:00

[dxvk] Refactored shader binding, client APIs must now create pipelines and pipeline layouts

This commit is contained in:
Philip Rebohle 2017-12-03 00:40:58 +01:00
parent 7ec8e727d2
commit a6bf7659b0
25 changed files with 399 additions and 500 deletions

View File

@ -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'
endian = 'little'

View File

@ -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<DxvkBindingLayout> DxgiPresenter::createBindingLayout() {
std::array<DxvkBindingInfo, 2> 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<DxvkGraphicsPipeline> DxgiPresenter::createPipeline() {
const Rc<DxvkShader> vs = this->createVertexShader();
const Rc<DxvkShader> fs = this->createFragmentShader();
return m_device->createGraphicsPipeline(
this->createBindingLayout(),
vs, nullptr, nullptr, nullptr, fs);
}
}

View File

@ -55,6 +55,10 @@ namespace dxvk {
Rc<DxvkShader> createVertexShader();
Rc<DxvkShader> createFragmentShader();
Rc<DxvkBindingLayout> createBindingLayout();
Rc<DxvkGraphicsPipeline> createPipeline();
};
}

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -3,72 +3,30 @@
namespace dxvk {
DxvkComputePipeline::DxvkComputePipeline(
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkShader>& shader)
: m_vkd(vkd), m_shader(shader) {
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& cs)
: m_vkd(vkd), m_layout(layout), m_cs(cs) {
std::vector<VkDescriptorSetLayoutBinding> 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);
}
}

View File

@ -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<vk::DeviceFn>& vkd,
const Rc<DxvkShader>& shader);
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& 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<vk::DeviceFn> m_vkd;
Rc<DxvkShader> m_shader;
Rc<DxvkBindingLayout> m_layout;
Rc<DxvkShader> 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;
};

View File

@ -4,11 +4,8 @@
namespace dxvk {
DxvkContext::DxvkContext(
const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipeMgr)
: m_device (device),
m_pipeMgr (pipeMgr) {
DxvkContext::DxvkContext(const Rc<DxvkDevice>& 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<DxvkShader>& shader) {
DxvkShaderStageState* stageState = this->getShaderStage(stage);
void DxvkContext::bindComputePipeline(
const Rc<DxvkComputePipeline>& 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<DxvkGraphicsPipeline>& 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<DxvkInputAssemblyState>& 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<DxvkInputLayout>& 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<DxvkRasterizerState>& 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<DxvkMultisampleState>& 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<DxvkDepthStencilState>& 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<DxvkBlendState>& 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<uint32_t>(stage)));
}
}
}

View File

@ -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<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipeMgr);
DxvkContext(const Rc<DxvkDevice>& 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<DxvkShader>& shader);
void bindComputePipeline(
const Rc<DxvkComputePipeline>& 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<DxvkGraphicsPipeline>& pipeline);
/**
* \brief Binds vertex buffer
@ -250,14 +255,15 @@ namespace dxvk {
private:
const Rc<DxvkDevice> m_device;
const Rc<DxvkPipelineManager> m_pipeMgr;
const Rc<DxvkDevice> m_device;
Rc<DxvkCommandList> m_cmd;
DxvkContextFlags m_flags;
DxvkContextState m_state;
DxvkBarrierSet m_barriers;
std::vector<VkWriteDescriptorSet> m_descriptorSetWrites;
void renderPassBegin();
void renderPassEnd();
@ -272,10 +278,6 @@ namespace dxvk {
void commitComputeState();
void commitGraphicsState();
DxvkShaderStageState* getShaderStage(
VkShaderStageFlagBits stage);
};
}

View File

@ -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<DxvkContextFlag>;
struct DxvkShaderStageState {
Rc<DxvkShader> shader;
};
struct DxvkVertexInputState {
DxvkBufferBinding indexBuffer;
std::array<DxvkBufferBinding,
@ -65,20 +59,13 @@ namespace dxvk {
* and constant pipeline state objects.
*/
struct DxvkContextState {
DxvkShaderStageState vs;
DxvkShaderStageState tcs;
DxvkShaderStageState tes;
DxvkShaderStageState gs;
DxvkShaderStageState fs;
DxvkShaderStageState cs;
DxvkVertexInputState vi;
DxvkViewportState vp;
DxvkOutputMergerState om;
DxvkConstantStateObjects co;
Rc<DxvkGraphicsPipeline> activeGraphicsPipeline;
Rc<DxvkComputePipeline> activeComputePipeline;
Rc<DxvkGraphicsPipeline> gp;
Rc<DxvkComputePipeline> cp;
};
}

View File

@ -4,12 +4,6 @@
namespace dxvk {
struct DxvkResourceBinding {
VkDescriptorType type;
VkDescriptorImageInfo image;
VkDescriptorBufferInfo buffer;
};
/**
* \brief Descriptor set allocator
*

View File

@ -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<DxvkContext> DxvkDevice::createContext() {
return new DxvkContext(this, m_pipelineManager);
return new DxvkContext(this);
}
@ -93,6 +91,32 @@ namespace dxvk {
}
Rc<DxvkBindingLayout> DxvkDevice::createBindingLayout(
uint32_t bindingCount,
const DxvkBindingInfo* bindingInfos) {
return new DxvkBindingLayout(m_vkd, bindingCount, bindingInfos);
}
Rc<DxvkComputePipeline> DxvkDevice::createComputePipeline(
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& cs) {
return new DxvkComputePipeline(m_vkd, layout, cs);
}
Rc<DxvkGraphicsPipeline> DxvkDevice::createGraphicsPipeline(
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs) {
return new DxvkGraphicsPipeline(m_vkd,
layout, vs, tcs, tes, gs, fs);
}
Rc<DxvkSwapchain> DxvkDevice::createSwapchain(
const Rc<DxvkSurface>& surface,
const DxvkSwapchainProperties& properties) {

View File

@ -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<DxvkBindingLayout> 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<DxvkComputePipeline> createComputePipeline(
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& 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<DxvkGraphicsPipeline> createGraphicsPipeline(
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs);
/**
* \brief Creates a swap chain
*
@ -202,7 +242,6 @@ namespace dxvk {
Rc<DxvkMemoryAllocator> m_memory;
Rc<DxvkRenderPassPool> m_renderPassPool;
Rc<DxvkPipelineManager> m_pipelineManager;
VkQueue m_graphicsQueue;
VkQueue m_presentQueue;

View File

@ -39,47 +39,21 @@ namespace dxvk {
DxvkGraphicsPipeline::DxvkGraphicsPipeline(
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs)
: m_vkd(vkd), m_vs(vs), m_tcs(tcs),
m_tes(tes), m_gs(gs), m_fs(fs) {
std::vector<VkDescriptorSetLayoutBinding> bindings;
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& 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(

View File

@ -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<vk::DeviceFn>& vkd,
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs);
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout,
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& 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<vk::DeviceFn> m_vkd;
Rc<DxvkShader> m_vs;
Rc<DxvkShader> m_tcs;
Rc<DxvkShader> m_tes;
Rc<DxvkShader> m_gs;
Rc<DxvkShader> m_fs;
Rc<DxvkBindingLayout> m_layout;
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
Rc<DxvkShader> m_vs;
Rc<DxvkShader> m_tcs;
Rc<DxvkShader> m_tes;
Rc<DxvkShader> m_gs;
Rc<DxvkShader> m_fs;
std::mutex m_mutex;
@ -106,7 +107,6 @@ namespace dxvk {
VkPipeline compilePipeline(
const DxvkGraphicsPipelineStateInfo& state) const;
void destroyObjects();
void destroyPipelines();
};

View File

@ -42,6 +42,9 @@ namespace dxvk {
/// Image tiling mode
VkImageTiling tiling;
/// Common image layout
VkImageLayout layout;
};

View File

@ -0,0 +1,72 @@
#include "dxvk_pipeline.h"
namespace dxvk {
DxvkBindingLayout::DxvkBindingLayout(
const Rc<vk::DeviceFn>& 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;
}
}

80
src/dxvk/dxvk_pipeline.h Normal file
View File

@ -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<vk::DeviceFn>& 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<vk::DeviceFn> m_vkd;
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
std::vector<VkDescriptorSetLayoutBinding> m_bindings;
};
}

View File

@ -1,63 +0,0 @@
#include "dxvk_pipemgr.h"
namespace dxvk {
DxvkPipelineManager::DxvkPipelineManager(
const Rc<vk::DeviceFn>& vkd)
: m_vkd(vkd) {
}
DxvkPipelineManager::~DxvkPipelineManager() {
}
Rc<DxvkComputePipeline> DxvkPipelineManager::getComputePipeline(const Rc<DxvkShader>& cs) {
if (cs == nullptr)
return nullptr;
DxvkPipelineKey<1> key;
key.setShader(0, cs);
std::lock_guard<std::mutex> lock(m_mutex);
auto pair = m_computePipelines.find(key);
if (pair != m_computePipelines.end())
return pair->second;
Rc<DxvkComputePipeline> pipeline = new DxvkComputePipeline(m_vkd, cs);
m_computePipelines.insert(std::make_pair(key, pipeline));
return pipeline;
}
Rc<DxvkGraphicsPipeline> DxvkPipelineManager::getGraphicsPipeline(
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& 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<std::mutex> lock(m_mutex);
auto pair = m_graphicsPipelines.find(key);
if (pair != m_graphicsPipelines.end())
return pair->second;
Rc<DxvkGraphicsPipeline> pipeline = new DxvkGraphicsPipeline(m_vkd, vs, tcs, tes, gs, fs);
m_graphicsPipelines.insert(std::make_pair(key, pipeline));
return pipeline;
}
}

View File

@ -1,119 +0,0 @@
#pragma once
#include <mutex>
#include <unordered_map>
#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<size_t N>
class DxvkPipelineKey {
public:
void setShader(
size_t id,
const Rc<DxvkShader>& shader) {
m_shaders.at(id) = shader;
}
size_t hash() const {
std::hash<DxvkShader*> 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<Rc<DxvkShader>, N> m_shaders;
};
/**
* \brief Pipeline manager
*
* Creates and manages pipeline objects
* for various combinations of shaders.
*/
class DxvkPipelineManager : public RcObject {
public:
DxvkPipelineManager(
const Rc<vk::DeviceFn>& 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<DxvkComputePipeline> getComputePipeline(
const Rc<DxvkShader>& 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<DxvkGraphicsPipeline> getGraphicsPipeline(
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs);
private:
Rc<vk::DeviceFn> m_vkd;
std::mutex m_mutex;
std::unordered_map<
DxvkPipelineKey<1>,
Rc<DxvkComputePipeline>,
DxvkHash> m_computePipelines;
std::unordered_map<
DxvkPipelineKey<5>,
Rc<DxvkGraphicsPipeline>,
DxvkHash> m_graphicsPipelines;
};
}

View File

@ -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;
};

View File

@ -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<DxvkImage> image = new DxvkImage(m_vkd, imageInfo, swapImages.at(i));
Rc<DxvkImageView> iview = m_device->createImageView(image, viewInfo);

View File

@ -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',

View File

@ -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<DxvkSwapchain> m_dxvkSwapchain;
Rc<DxvkContext> m_dxvkContext;
Rc<DxvkShader> m_dxvkVertexShader;
Rc<DxvkShader> m_dxvkFragmentShader;
Rc<DxvkShader> m_dxvkVertexShader;
Rc<DxvkShader> m_dxvkFragmentShader;
Rc<DxvkBindingLayout> m_dxvkBindingLayout;
Rc<DxvkGraphicsPipeline> m_dxvkPipeline;
};