1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00

[dxvk] Re-implemented pipeline creation within the backend

This commit is contained in:
Philip Rebohle 2017-12-07 09:38:31 +01:00
parent e95dc64c77
commit 19851c8432
24 changed files with 612 additions and 196 deletions

View File

@ -9,7 +9,7 @@ exe_wrapper = 'wine'
c_args = ['-Og', '-ggdb'] c_args = ['-Og', '-ggdb']
c_link_args = ['-static', '-static-libgcc'] c_link_args = ['-static', '-static-libgcc']
cpp_args = ['-std=c++17', '-Og', '-ggdb'] cpp_args = ['-std=c++17', '-Og', '-gstabs']
cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++'] cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++']
[host_machine] [host_machine]

View File

@ -55,8 +55,6 @@ namespace dxvk {
// Set up context state. The shader bindings and the // Set up context state. The shader bindings and the
// constant state objects will never be modified. // constant state objects will never be modified.
m_context->bindGraphicsPipeline(createPipeline());
m_context->setInputAssemblyState( m_context->setInputAssemblyState(
new DxvkInputAssemblyState( new DxvkInputAssemblyState(
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
@ -111,6 +109,14 @@ namespace dxvk {
new DxvkBlendState( new DxvkBlendState(
VK_FALSE, VK_LOGIC_OP_NO_OP, VK_FALSE, VK_LOGIC_OP_NO_OP,
1, &blendAttachment)); 1, &blendAttachment));
m_context->bindShader(
VK_SHADER_STAGE_VERTEX_BIT,
this->createVertexShader());
m_context->bindShader(
VK_SHADER_STAGE_FRAGMENT_BIT,
this->createFragmentShader());
} }
@ -329,7 +335,8 @@ namespace dxvk {
// Create the actual shader module // Create the actual shader module
return m_device->createShader( return m_device->createShader(
VK_SHADER_STAGE_VERTEX_BIT, module.compile()); VK_SHADER_STAGE_VERTEX_BIT,
0, nullptr, module.compile());
} }
@ -397,42 +404,24 @@ namespace dxvk {
module.opReturn(); module.opReturn();
module.functionEnd(); module.functionEnd();
// Register function entry point // Register function entry point
std::array<uint32_t, 2> interfaces = { inTexCoord, outColor }; std::array<uint32_t, 2> interfaces = { inTexCoord, outColor };
module.addEntryPoint(entryPointId, spv::ExecutionModelFragment, module.addEntryPoint(entryPointId, spv::ExecutionModelFragment,
"main", interfaces.size(), interfaces.data()); "main", interfaces.size(), interfaces.data());
// Shader resource slots
std::array<DxvkResourceSlot, 2> resourceSlots = {{
{ BindingIds::Sampler, VK_DESCRIPTOR_TYPE_SAMPLER },
{ BindingIds::Texture, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
}};
// Create the actual shader module // Create the actual shader module
return m_device->createShader( return m_device->createShader(
VK_SHADER_STAGE_FRAGMENT_BIT, module.compile()); VK_SHADER_STAGE_FRAGMENT_BIT,
} resourceSlots.size(),
resourceSlots.data(),
module.compile());
Rc<DxvkBindingLayout> DxgiPresenter::createBindingLayout() {
std::array<DxvkDescriptorSlot, 2> bindings;
bindings.at(BindingIds::Sampler).slot = BindingIds::Sampler;
bindings.at(BindingIds::Sampler).type = VK_DESCRIPTOR_TYPE_SAMPLER;
bindings.at(BindingIds::Sampler).stages = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings.at(BindingIds::Texture).slot = BindingIds::Texture;
bindings.at(BindingIds::Texture).type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
bindings.at(BindingIds::Texture).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

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

View File

@ -336,6 +336,7 @@ namespace dxvk {
DxvkImageCreateInfo imageInfo; DxvkImageCreateInfo imageInfo;
imageInfo.type = VK_IMAGE_TYPE_2D; imageInfo.type = VK_IMAGE_TYPE_2D;
imageInfo.format = bufferFormat.actual; imageInfo.format = bufferFormat.actual;
imageInfo.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
imageInfo.extent.width = m_desc.BufferDesc.Width; imageInfo.extent.width = m_desc.BufferDesc.Width;
imageInfo.extent.height = m_desc.BufferDesc.Height; imageInfo.extent.height = m_desc.BufferDesc.Height;

View File

@ -4,7 +4,7 @@
#include "dxvk_descriptor.h" #include "dxvk_descriptor.h"
#include "dxvk_lifetime.h" #include "dxvk_lifetime.h"
#include "dxvk_pipeline.h" #include "dxvk_pipelayout.h"
namespace dxvk { namespace dxvk {

View File

@ -3,17 +3,36 @@
namespace dxvk { namespace dxvk {
DxvkComputePipeline::DxvkComputePipeline( DxvkComputePipeline::DxvkComputePipeline(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& cs)
const Rc<DxvkShader>& cs) : m_vkd(vkd) {
: m_vkd(vkd), m_layout(layout), m_cs(cs) { DxvkDescriptorSlotMapping slotMapping;
cs->defineResourceSlots(slotMapping);
m_layout = new DxvkBindingLayout(vkd,
slotMapping.bindingCount(),
slotMapping.bindingInfos());
m_cs = cs->createShaderModule(slotMapping);
this->compilePipeline();
}
DxvkComputePipeline::~DxvkComputePipeline() {
if (m_pipeline != VK_NULL_HANDLE)
m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeline, nullptr);
}
void DxvkComputePipeline::compilePipeline() {
std::vector<VkDescriptorSetLayoutBinding> bindings; std::vector<VkDescriptorSetLayoutBinding> bindings;
VkComputePipelineCreateInfo info; VkComputePipelineCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
info.pNext = nullptr; info.pNext = nullptr;
info.flags = 0; info.flags = 0;
info.stage = cs->stageInfo(); info.stage = m_cs->stageInfo();
info.layout = m_layout->pipelineLayout(); info.layout = m_layout->pipelineLayout();
info.basePipelineHandle = VK_NULL_HANDLE; info.basePipelineHandle = VK_NULL_HANDLE;
info.basePipelineIndex = 0; info.basePipelineIndex = 0;
@ -23,10 +42,4 @@ namespace dxvk {
throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to compile pipeline"); throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to compile pipeline");
} }
DxvkComputePipeline::~DxvkComputePipeline() {
if (m_pipeline != VK_NULL_HANDLE)
m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeline, nullptr);
}
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "dxvk_pipeline.h" #include "dxvk_pipelayout.h"
#include "dxvk_resource.h" #include "dxvk_resource.h"
#include "dxvk_shader.h" #include "dxvk_shader.h"
@ -19,9 +19,8 @@ namespace dxvk {
public: public:
DxvkComputePipeline( DxvkComputePipeline(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& cs);
const Rc<DxvkShader>& cs);
~DxvkComputePipeline(); ~DxvkComputePipeline();
/** /**
@ -48,10 +47,12 @@ namespace dxvk {
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
Rc<DxvkBindingLayout> m_layout; Rc<DxvkBindingLayout> m_layout;
Rc<DxvkShader> m_cs; Rc<DxvkShaderModule> m_cs;
VkPipeline m_pipeline = VK_NULL_HANDLE; VkPipeline m_pipeline = VK_NULL_HANDLE;
void compilePipeline();
}; };
} }

View File

@ -53,32 +53,6 @@ namespace dxvk {
} }
void DxvkContext::bindComputePipeline(
const Rc<DxvkComputePipeline>& pipeline) {
if (m_state.cPipe != pipeline) {
m_state.cPipe = pipeline;
m_flags.set(
DxvkContextFlag::CpDirtyPipeline,
DxvkContextFlag::CpDirtyResources);
}
}
void DxvkContext::bindGraphicsPipeline(
const Rc<DxvkGraphicsPipeline>& pipeline) {
if (m_state.gPipe != pipeline) {
m_state.gPipe = pipeline;
m_flags.set(
DxvkContextFlag::GpDirtyPipeline,
DxvkContextFlag::GpDirtyResources,
DxvkContextFlag::GpDirtyVertexBuffers,
DxvkContextFlag::GpDirtyIndexBuffer);
}
}
void DxvkContext::bindIndexBuffer( void DxvkContext::bindIndexBuffer(
const DxvkBufferBinding& buffer) { const DxvkBufferBinding& buffer) {
if (m_state.vi.indexBuffer != buffer) { if (m_state.vi.indexBuffer != buffer) {
@ -178,6 +152,31 @@ namespace dxvk {
} }
void DxvkContext::bindShader(
VkShaderStageFlagBits stage,
const Rc<DxvkShader>& shader) {
DxvkShaderStage* shaderStage = nullptr;
switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT: shaderStage = &m_state.gp.vs; break;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: shaderStage = &m_state.gp.tcs; break;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: shaderStage = &m_state.gp.tes; break;
case VK_SHADER_STAGE_GEOMETRY_BIT: shaderStage = &m_state.gp.gs; break;
case VK_SHADER_STAGE_FRAGMENT_BIT: shaderStage = &m_state.gp.fs; break;
case VK_SHADER_STAGE_COMPUTE_BIT: shaderStage = &m_state.cp.cs; break;
default: return;
}
if (shaderStage->shader != shader) {
shaderStage->shader = shader;
m_flags.set(stage == VK_SHADER_STAGE_COMPUTE_BIT
? DxvkContextFlag::CpDirtyPipeline
: DxvkContextFlag::GpDirtyPipeline);
}
}
void DxvkContext::bindVertexBuffer( void DxvkContext::bindVertexBuffer(
uint32_t binding, uint32_t binding,
const DxvkBufferBinding& buffer) { const DxvkBufferBinding& buffer) {
@ -445,9 +444,12 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) { if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) {
m_flags.clr(DxvkContextFlag::CpDirtyPipeline); m_flags.clr(DxvkContextFlag::CpDirtyPipeline);
m_state.cp.pipeline = m_device->createComputePipeline(
m_state.cp.cs.shader);
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE,
m_state.cPipe->getPipelineHandle()); m_state.cp.pipeline->getPipelineHandle());
m_cmd->trackResource(m_state.cPipe); m_cmd->trackResource(m_state.cp.pipeline);
} }
} }
@ -456,6 +458,10 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) { if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
m_flags.clr(DxvkContextFlag::GpDirtyPipeline); m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
m_state.gp.pipeline = m_device->createGraphicsPipeline(
m_state.gp.vs.shader, m_state.gp.tcs.shader, m_state.gp.tes.shader,
m_state.gp.gs.shader, m_state.gp.fs.shader);
DxvkGraphicsPipelineStateInfo gpState; DxvkGraphicsPipelineStateInfo gpState;
gpState.inputAssemblyState = m_state.co.inputAssemblyState; gpState.inputAssemblyState = m_state.co.inputAssemblyState;
gpState.inputLayout = m_state.co.inputLayout; gpState.inputLayout = m_state.co.inputLayout;
@ -467,8 +473,8 @@ namespace dxvk {
gpState.viewportCount = m_state.vp.viewportCount; gpState.viewportCount = m_state.vp.viewportCount;
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
m_state.gPipe->getPipelineHandle(gpState)); m_state.gp.pipeline->getPipelineHandle(gpState));
m_cmd->trackResource(m_state.gPipe); m_cmd->trackResource(m_state.gp.pipeline);
} }
} }
@ -477,7 +483,7 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::CpDirtyResources)) { if (m_flags.test(DxvkContextFlag::CpDirtyResources)) {
m_flags.clr(DxvkContextFlag::CpDirtyResources); m_flags.clr(DxvkContextFlag::CpDirtyResources);
auto layout = m_state.cPipe->layout(); auto layout = m_state.cp.pipeline->layout();
m_cmd->bindResourceDescriptors( m_cmd->bindResourceDescriptors(
VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_COMPUTE,
@ -494,7 +500,7 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpDirtyResources)) { if (m_flags.test(DxvkContextFlag::GpDirtyResources)) {
m_flags.clr(DxvkContextFlag::GpDirtyResources); m_flags.clr(DxvkContextFlag::GpDirtyResources);
auto layout = m_state.gPipe->layout(); auto layout = m_state.gp.pipeline->layout();
m_cmd->bindResourceDescriptors( m_cmd->bindResourceDescriptors(
VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_GRAPHICS,

View File

@ -54,20 +54,6 @@ namespace dxvk {
void bindFramebuffer( void bindFramebuffer(
const Rc<DxvkFramebuffer>& fb); const Rc<DxvkFramebuffer>& fb);
/**
* \brief Binds compute pipeline
* \param [in] pipeline The pipeline to bind
*/
void bindComputePipeline(
const Rc<DxvkComputePipeline>& pipeline);
/**
* \brief Binds graphics pipeline
* \param [in] pipeline The pipeline to bind
*/
void bindGraphicsPipeline(
const Rc<DxvkGraphicsPipeline>& pipeline);
/** /**
* \brief Binds index buffer * \brief Binds index buffer
* *
@ -133,6 +119,16 @@ namespace dxvk {
uint32_t slot, uint32_t slot,
const Rc<DxvkSampler>& sampler); const Rc<DxvkSampler>& sampler);
/**
* \brief Binds a shader to a given state
*
* \param [in] stage Target shader stage
* \param [in] shader The shader to bind
*/
void bindShader(
VkShaderStageFlagBits stage,
const Rc<DxvkShader>& shader);
/** /**
* \brief Binds vertex buffer * \brief Binds vertex buffer
* *

View File

@ -7,7 +7,7 @@
#include "dxvk_graphics.h" #include "dxvk_graphics.h"
#include "dxvk_image.h" #include "dxvk_image.h"
#include "dxvk_limits.h" #include "dxvk_limits.h"
#include "dxvk_pipeline.h" #include "dxvk_pipelayout.h"
#include "dxvk_sampler.h" #include "dxvk_sampler.h"
#include "dxvk_shader.h" #include "dxvk_shader.h"
@ -54,6 +54,28 @@ namespace dxvk {
}; };
struct DxvkShaderStage {
Rc<DxvkShader> shader;
};
struct DxvkGraphicsPipelineState {
DxvkShaderStage vs;
DxvkShaderStage tcs;
DxvkShaderStage tes;
DxvkShaderStage gs;
DxvkShaderStage fs;
Rc<DxvkGraphicsPipeline> pipeline;
};
struct DxvkComputePipelineState {
DxvkShaderStage cs;
Rc<DxvkComputePipeline> pipeline;
};
/** /**
* \brief Pipeline state * \brief Pipeline state
* *
@ -66,8 +88,8 @@ namespace dxvk {
DxvkOutputMergerState om; DxvkOutputMergerState om;
DxvkConstantStateObjects co; DxvkConstantStateObjects co;
Rc<DxvkGraphicsPipeline> gPipe; DxvkGraphicsPipelineState gp;
Rc<DxvkComputePipeline> cPipe; DxvkComputePipelineState cp;
}; };
} }

View File

@ -11,7 +11,8 @@ namespace dxvk {
m_vkd (vkd), m_vkd (vkd),
m_features (features), m_features (features),
m_memory (new DxvkMemoryAllocator(adapter, vkd)), m_memory (new DxvkMemoryAllocator(adapter, vkd)),
m_renderPassPool (new DxvkRenderPassPool (vkd)) { m_renderPassPool (new DxvkRenderPassPool (vkd)),
m_pipelineManager (new DxvkPipelineManager(vkd)) {
m_vkd->vkGetDeviceQueue(m_vkd->device(), m_vkd->vkGetDeviceQueue(m_vkd->device(),
m_adapter->graphicsQueueFamily(), 0, m_adapter->graphicsQueueFamily(), 0,
&m_graphicsQueue); &m_graphicsQueue);
@ -23,6 +24,7 @@ namespace dxvk {
DxvkDevice::~DxvkDevice() { DxvkDevice::~DxvkDevice() {
m_renderPassPool = nullptr; m_renderPassPool = nullptr;
m_pipelineManager = nullptr;
m_memory = nullptr; m_memory = nullptr;
m_vkd->vkDeviceWaitIdle(m_vkd->device()); m_vkd->vkDeviceWaitIdle(m_vkd->device());
@ -92,34 +94,27 @@ namespace dxvk {
Rc<DxvkShader> DxvkDevice::createShader( Rc<DxvkShader> DxvkDevice::createShader(
VkShaderStageFlagBits stage, VkShaderStageFlagBits stage,
uint32_t slotCount,
const DxvkResourceSlot* slotInfos,
const SpirvCodeBuffer& code) { const SpirvCodeBuffer& code) {
return new DxvkShader(m_vkd, stage, code); return new DxvkShader(m_vkd, stage,
} slotCount, slotInfos, code);
Rc<DxvkBindingLayout> DxvkDevice::createBindingLayout(
uint32_t bindingCount,
const DxvkDescriptorSlot* bindingInfos) {
return new DxvkBindingLayout(m_vkd, bindingCount, bindingInfos);
} }
Rc<DxvkComputePipeline> DxvkDevice::createComputePipeline( Rc<DxvkComputePipeline> DxvkDevice::createComputePipeline(
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& cs) {
const Rc<DxvkShader>& cs) { return m_pipelineManager->createComputePipeline(cs);
return new DxvkComputePipeline(m_vkd, layout, cs);
} }
Rc<DxvkGraphicsPipeline> DxvkDevice::createGraphicsPipeline( Rc<DxvkGraphicsPipeline> DxvkDevice::createGraphicsPipeline(
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& vs, const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tcs, const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& tes, const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& gs, const Rc<DxvkShader>& fs) {
const Rc<DxvkShader>& fs) { return m_pipelineManager->createGraphicsPipeline(vs, tcs, tes, gs, fs);
return new DxvkGraphicsPipeline(m_vkd,
layout, vs, tcs, tes, gs, fs);
} }

View File

@ -8,6 +8,7 @@
#include "dxvk_framebuffer.h" #include "dxvk_framebuffer.h"
#include "dxvk_image.h" #include "dxvk_image.h"
#include "dxvk_memory.h" #include "dxvk_memory.h"
#include "dxvk_pipemanager.h"
#include "dxvk_renderpass.h" #include "dxvk_renderpass.h"
#include "dxvk_sampler.h" #include "dxvk_sampler.h"
#include "dxvk_shader.h" #include "dxvk_shader.h"
@ -166,48 +167,36 @@ namespace dxvk {
*/ */
Rc<DxvkShader> createShader( Rc<DxvkShader> createShader(
VkShaderStageFlagBits stage, VkShaderStageFlagBits stage,
uint32_t slotCount,
const DxvkResourceSlot* slotInfos,
const SpirvCodeBuffer& code); const SpirvCodeBuffer& code);
/** /**
* \brief Creates binding layout * \brief Retrieves a compute pipeline
*
* \param [in] bindingCount Number of bindings
* \param [in] bindingInfos Binding descriptions
* \returns New binding layout
*/
Rc<DxvkBindingLayout> createBindingLayout(
uint32_t bindingCount,
const DxvkDescriptorSlot* bindingInfos);
/**
* \brief Creates a compute pipeline
* *
* \param [in] layout Pipeline binding layout * \param [in] layout Pipeline binding layout
* \param [in] cs Compute shader * \param [in] cs Compute shader
* \returns New compute pipeline * \returns The compute pipeline
*/ */
Rc<DxvkComputePipeline> createComputePipeline( Rc<DxvkComputePipeline> createComputePipeline(
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& cs);
const Rc<DxvkShader>& cs);
/** /**
* \brief Creates a graphics pipeline * \brief Retrieves a graphics pipeline object
* *
* \param [in] layout Pipeline binding layout
* \param [in] vs Vertex shader * \param [in] vs Vertex shader
* \param [in] tcs Tessellation control shader * \param [in] tcs Tessellation control shader
* \param [in] tes Tessellation evaluation shader * \param [in] tes Tessellation evaluation shader
* \param [in] gs Geometry shader * \param [in] gs Geometry shader
* \param [in] fs Fragment shader * \param [in] fs Fragment shader
* \returns New graphics pipeline * \returns The graphics pipeline
*/ */
Rc<DxvkGraphicsPipeline> createGraphicsPipeline( Rc<DxvkGraphicsPipeline> createGraphicsPipeline(
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& vs, const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tcs, const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& tes, const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& gs, const Rc<DxvkShader>& fs);
const Rc<DxvkShader>& fs);
/** /**
* \brief Creates a swap chain * \brief Creates a swap chain
@ -252,6 +241,7 @@ namespace dxvk {
Rc<DxvkMemoryAllocator> m_memory; Rc<DxvkMemoryAllocator> m_memory;
Rc<DxvkRenderPassPool> m_renderPassPool; Rc<DxvkRenderPassPool> m_renderPassPool;
Rc<DxvkPipelineManager> m_pipelineManager;
VkQueue m_graphicsQueue; VkQueue m_graphicsQueue;
VkQueue m_presentQueue; VkQueue m_presentQueue;

View File

@ -39,16 +39,29 @@ namespace dxvk {
DxvkGraphicsPipeline::DxvkGraphicsPipeline( DxvkGraphicsPipeline::DxvkGraphicsPipeline(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& vs, const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tcs, const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& tes, const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& gs, const Rc<DxvkShader>& fs)
const Rc<DxvkShader>& fs) : m_vkd(vkd) {
: m_vkd(vkd), m_layout(layout), DxvkDescriptorSlotMapping slotMapping;
m_vs(vs), m_tcs(tcs), m_tes(tes), m_gs(gs), m_fs(fs) { if (vs != nullptr) vs ->defineResourceSlots(slotMapping);
if (tcs != nullptr) tcs->defineResourceSlots(slotMapping);
if (tes != nullptr) tes->defineResourceSlots(slotMapping);
if (gs != nullptr) gs ->defineResourceSlots(slotMapping);
if (fs != nullptr) fs ->defineResourceSlots(slotMapping);
m_layout = new DxvkBindingLayout(vkd,
slotMapping.bindingCount(),
slotMapping.bindingInfos());
if (vs != nullptr) m_vs = vs ->createShaderModule(slotMapping);
if (tcs != nullptr) m_tcs = tcs->createShaderModule(slotMapping);
if (tes != nullptr) m_tes = tes->createShaderModule(slotMapping);
if (gs != nullptr) m_gs = gs ->createShaderModule(slotMapping);
if (fs != nullptr) m_fs = fs ->createShaderModule(slotMapping);
} }

View File

@ -5,7 +5,7 @@
#include "dxvk_constant_state.h" #include "dxvk_constant_state.h"
#include "dxvk_hash.h" #include "dxvk_hash.h"
#include "dxvk_pipeline.h" #include "dxvk_pipelayout.h"
#include "dxvk_resource.h" #include "dxvk_resource.h"
#include "dxvk_shader.h" #include "dxvk_shader.h"
@ -49,13 +49,12 @@ namespace dxvk {
public: public:
DxvkGraphicsPipeline( DxvkGraphicsPipeline(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkBindingLayout>& layout, const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& vs, const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tcs, const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& tes, const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& gs, const Rc<DxvkShader>& fs);
const Rc<DxvkShader>& fs);
~DxvkGraphicsPipeline(); ~DxvkGraphicsPipeline();
/** /**
@ -82,11 +81,11 @@ namespace dxvk {
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
Rc<DxvkBindingLayout> m_layout; Rc<DxvkBindingLayout> m_layout;
Rc<DxvkShader> m_vs; Rc<DxvkShaderModule> m_vs;
Rc<DxvkShader> m_tcs; Rc<DxvkShaderModule> m_tcs;
Rc<DxvkShader> m_tes; Rc<DxvkShaderModule> m_tes;
Rc<DxvkShader> m_gs; Rc<DxvkShaderModule> m_gs;
Rc<DxvkShader> m_fs; Rc<DxvkShaderModule> m_fs;
std::mutex m_mutex; std::mutex m_mutex;

View File

@ -1,9 +1,44 @@
#include <cstring> #include <cstring>
#include "dxvk_pipeline.h" #include "dxvk_pipelayout.h"
namespace dxvk { namespace dxvk {
DxvkDescriptorSlotMapping:: DxvkDescriptorSlotMapping() { }
DxvkDescriptorSlotMapping::~DxvkDescriptorSlotMapping() { }
void DxvkDescriptorSlotMapping::defineSlot(
uint32_t slot,
VkDescriptorType type,
VkShaderStageFlagBits stage) {
uint32_t bindingId = this->getBindingId(slot);
if (bindingId != InvalidBinding) {
m_descriptorSlots.at(bindingId).stages |= stage;
} else {
DxvkDescriptorSlot slotInfo;
slotInfo.slot = slot;
slotInfo.type = type;
slotInfo.stages = stage;
m_descriptorSlots.push_back(slotInfo);
}
}
uint32_t DxvkDescriptorSlotMapping::getBindingId(uint32_t slot) {
// This won't win a performance competition, but the number
// of bindings used by a shader is usually much smaller than
// the number of resource slots available to the system.
for (uint32_t i = 0; i < m_descriptorSlots.size(); i++) {
if (m_descriptorSlots.at(i).slot == slot)
return i;
}
return InvalidBinding;
}
DxvkBindingLayout::DxvkBindingLayout( DxvkBindingLayout::DxvkBindingLayout(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
uint32_t bindingCount, uint32_t bindingCount,

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <vector>
#include "dxvk_include.h" #include "dxvk_include.h"
namespace dxvk { namespace dxvk {
@ -18,6 +20,69 @@ namespace dxvk {
}; };
/**
* \brief Descriptor slot mapping
*
* Convenience class that generates descriptor slot
* index to binding index mappings. This is required
* when generating Vulkan pipeline and descriptor set
* layouts.
*/
class DxvkDescriptorSlotMapping {
constexpr static uint32_t InvalidBinding = 0xFFFFFFFFu;
public:
DxvkDescriptorSlotMapping();
~DxvkDescriptorSlotMapping();
/**
* \brief Number of descriptor bindings
* \returns Descriptor binding count
*/
uint32_t bindingCount() const {
return m_descriptorSlots.size();
}
/**
* \brief Descriptor binding infos
* \returns Descriptor binding infos
*/
const DxvkDescriptorSlot* bindingInfos() const {
return m_descriptorSlots.data();
}
/**
* \brief Defines a new slot
*
* Adds a slot to the mapping. If the slot is already
* defined by another shader stage, this will extend
* the stage mask by the given stage. Otherwise, an
* entirely new binding is added.
* \param [in] slot Resource slot
* \param [in] type Resource type
* \param [in] stage Shader stage
*/
void defineSlot(
uint32_t slot,
VkDescriptorType type,
VkShaderStageFlagBits stage);
/**
* \brief Gets binding ID for a slot
*
* \param [in] slot Resource slot
* \returns Binding index, or \c InvalidBinding
*/
uint32_t getBindingId(
uint32_t slot);
private:
std::vector<DxvkDescriptorSlot> m_descriptorSlots;
};
/** /**
* \brief Shader interface * \brief Shader interface
* *

View File

@ -0,0 +1,96 @@
#include "dxvk_pipemanager.h"
namespace dxvk {
size_t DxvkPipelineKeyHash::operator () (const DxvkComputePipelineKey& key) const {
std::hash<DxvkShader*> hash;
return hash(key.cs.ptr());
}
size_t DxvkPipelineKeyHash::operator () (const DxvkGraphicsPipelineKey& key) const {
DxvkHashState state;
std::hash<DxvkShader*> hash;
state.add(hash(key.vs.ptr()));
state.add(hash(key.tcs.ptr()));
state.add(hash(key.tes.ptr()));
state.add(hash(key.gs.ptr()));
state.add(hash(key.fs.ptr()));
return state;
}
bool DxvkPipelineKeyEq::operator () (const DxvkComputePipelineKey& a, const DxvkComputePipelineKey& b) const {
return a.cs == b.cs;
}
bool DxvkPipelineKeyEq::operator () (const DxvkGraphicsPipelineKey& a, const DxvkGraphicsPipelineKey& b) const {
return a.vs == b.vs
&& a.tcs == b.tcs
&& a.tes == b.tes
&& a.gs == b.gs
&& a.fs == b.fs;
}
DxvkPipelineManager::DxvkPipelineManager(const Rc<vk::DeviceFn>& vkd)
: m_vkd(vkd) { }
DxvkPipelineManager::~DxvkPipelineManager() {
}
Rc<DxvkComputePipeline> DxvkPipelineManager::createComputePipeline(
const Rc<DxvkShader>& cs) {
if (cs == nullptr)
return nullptr;
DxvkComputePipelineKey key;
key.cs = cs;
std::lock_guard<std::mutex> lock(m_mutex);
auto pair = m_computePipelines.find(key);
if (pair != m_computePipelines.end())
return pair->second;
const Rc<DxvkComputePipeline> pipeline
= new DxvkComputePipeline(m_vkd, cs);
m_computePipelines.insert(std::make_pair(key, pipeline));
return pipeline;
}
Rc<DxvkGraphicsPipeline> DxvkPipelineManager::createGraphicsPipeline(
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;
DxvkGraphicsPipelineKey key;
key.vs = vs;
key.tcs = tcs;
key.tes = tes;
key.gs = gs;
key.fs = fs;
std::lock_guard<std::mutex> lock(m_mutex);
auto pair = m_graphicsPipelines.find(key);
if (pair != m_graphicsPipelines.end())
return pair->second;
const Rc<DxvkGraphicsPipeline> pipeline
= new DxvkGraphicsPipeline(m_vkd, vs, tcs, tes, gs, fs);
m_graphicsPipelines.insert(std::make_pair(key, pipeline));
return pipeline;
}
}

118
src/dxvk/dxvk_pipemanager.h Normal file
View File

@ -0,0 +1,118 @@
#pragma once
#include <mutex>
#include <unordered_map>
#include "dxvk_compute.h"
#include "dxvk_graphics.h"
namespace dxvk {
/**
* \brief Compute pipeline key
*
* Identifier for a compute pipeline object.
* Consists of the compute shader itself.
*/
struct DxvkComputePipelineKey {
Rc<DxvkShader> cs;
};
/**
* \brief Graphics pipeline key
*
* Identifier for a graphics pipeline object.
* Consists of all graphics pipeline shaders.
*/
struct DxvkGraphicsPipelineKey {
Rc<DxvkShader> vs;
Rc<DxvkShader> tcs;
Rc<DxvkShader> tes;
Rc<DxvkShader> gs;
Rc<DxvkShader> fs;
};
struct DxvkPipelineKeyHash {
size_t operator () (const DxvkComputePipelineKey& key) const;
size_t operator () (const DxvkGraphicsPipelineKey& key) const;
};
struct DxvkPipelineKeyEq {
bool operator () (const DxvkComputePipelineKey& a, const DxvkComputePipelineKey& b) const;
bool operator () (const DxvkGraphicsPipelineKey& a, const DxvkGraphicsPipelineKey& b) const;
};
/**
* \brief Pipeline manager
*
* Creates and stores graphics pipelines and compute
* pipelines for each combination of shaders that is
* used within the application. This is necessary
* because DXVK does not expose the concept of shader
* pipeline objects to the client API.
*/
class DxvkPipelineManager : public RcObject {
public:
DxvkPipelineManager(
const Rc<vk::DeviceFn>& vkd);
~DxvkPipelineManager();
/**
* \brief Retrieves a compute pipeline object
*
* If a pipeline for the given shader stage object
* already exists, it will be returned. Otherwise,
* a new pipeline will be created.
* \param [in] cs Compute shader
* \returns Compute pipeline object
*/
Rc<DxvkComputePipeline> createComputePipeline(
const Rc<DxvkShader>& cs);
/**
* \brief Retrieves a graphics pipeline object
*
* If a pipeline for the given shader stage objects
* already exists, it will be returned. Otherwise,
* a new pipeline 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 object
*/
Rc<DxvkGraphicsPipeline> createGraphicsPipeline(
const Rc<DxvkShader>& vs,
const Rc<DxvkShader>& tcs,
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs);
private:
const Rc<vk::DeviceFn> m_vkd;
std::mutex m_mutex;
std::unordered_map<
DxvkComputePipelineKey,
Rc<DxvkComputePipeline>,
DxvkPipelineKeyHash,
DxvkPipelineKeyEq> m_computePipelines;
std::unordered_map<
DxvkGraphicsPipelineKey,
Rc<DxvkGraphicsPipeline>,
DxvkPipelineKeyHash,
DxvkPipelineKeyEq> m_graphicsPipelines;
};
}

View File

@ -2,7 +2,7 @@
namespace dxvk { namespace dxvk {
DxvkShader::DxvkShader( DxvkShaderModule::DxvkShaderModule(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
VkShaderStageFlagBits stage, VkShaderStageFlagBits stage,
const SpirvCodeBuffer& code) const SpirvCodeBuffer& code)
@ -20,13 +20,13 @@ namespace dxvk {
} }
DxvkShader::~DxvkShader() { DxvkShaderModule::~DxvkShaderModule() {
m_vkd->vkDestroyShaderModule( m_vkd->vkDestroyShaderModule(
m_vkd->device(), m_module, nullptr); m_vkd->device(), m_module, nullptr);
} }
VkPipelineShaderStageCreateInfo DxvkShader::stageInfo() const { VkPipelineShaderStageCreateInfo DxvkShaderModule::stageInfo() const {
VkPipelineShaderStageCreateInfo info; VkPipelineShaderStageCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@ -39,4 +39,35 @@ namespace dxvk {
return info; return info;
} }
DxvkShader::DxvkShader(
const Rc<vk::DeviceFn>& vkd,
VkShaderStageFlagBits stage,
uint32_t slotCount,
const DxvkResourceSlot* slotInfos,
const SpirvCodeBuffer& code)
: m_vkd(vkd), m_stage(stage), m_code(code) {
for (uint32_t i = 0; i < slotCount; i++)
m_slots.push_back(slotInfos[i]);
}
DxvkShader::~DxvkShader() {
}
void DxvkShader::defineResourceSlots(
DxvkDescriptorSlotMapping& mapping) const {
for (const auto& slot : m_slots)
mapping.defineSlot(slot.slot, slot.type, m_stage);
}
Rc<DxvkShaderModule> DxvkShader::createShaderModule(
const DxvkDescriptorSlotMapping& mapping) const {
// TODO apply mapping
return new DxvkShaderModule(m_vkd, m_stage, m_code);
}
} }

View File

@ -3,6 +3,7 @@
#include <vector> #include <vector>
#include "dxvk_include.h" #include "dxvk_include.h"
#include "dxvk_pipelayout.h"
#include "../spirv/spirv_code_buffer.h" #include "../spirv/spirv_code_buffer.h"
@ -15,30 +16,31 @@ namespace dxvk {
* binding that a shader can access. * binding that a shader can access.
*/ */
struct DxvkResourceSlot { struct DxvkResourceSlot {
uint32_t binding; uint32_t slot;
VkDescriptorType type; VkDescriptorType type;
}; };
/** /**
* \brief Shader module * \brief Shader module object
* *
* Manages a Vulkan shader module. This will not * Manages a Vulkan shader module. This will not
* perform any sort of shader compilation. Instead, * perform any shader compilation. Instead, the
* the context will create pipeline objects on the * context will create pipeline objects on the
* fly when executing draw calls. * fly when executing draw calls.
*/ */
class DxvkShader : public RcObject { class DxvkShaderModule : public RcObject {
public: public:
DxvkShader( DxvkShaderModule(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
VkShaderStageFlagBits stage, VkShaderStageFlagBits stage,
const SpirvCodeBuffer& code); const SpirvCodeBuffer& code);
~DxvkShader();
VkShaderModule module() const { ~DxvkShaderModule();
VkShaderModule handle() const {
return m_module; return m_module;
} }
@ -52,4 +54,51 @@ namespace dxvk {
}; };
/**
* \brief Shader object
*
* Stores a SPIR-V shader and information on the
* bindings that the shader uses. In order to use
* the shader with a pipeline, a shader module
* needs to be created from he shader object.
*/
class DxvkShader : public RcObject {
public:
DxvkShader(
const Rc<vk::DeviceFn>& vkd,
VkShaderStageFlagBits stage,
uint32_t slotCount,
const DxvkResourceSlot* slotInfos,
const SpirvCodeBuffer& code);
~DxvkShader();
/**
* \brief
*/
void defineResourceSlots(
DxvkDescriptorSlotMapping& mapping) const;
/**
* \brief Creates a shader module
*
* Maps the binding slot numbers
* \param [in] mapping Resource slot mapping
* \returns The shader module
*/
Rc<DxvkShaderModule> createShaderModule(
const DxvkDescriptorSlotMapping& mapping) const;
private:
Rc<vk::DeviceFn> m_vkd;
VkShaderStageFlagBits m_stage;
SpirvCodeBuffer m_code;
std::vector<DxvkResourceSlot> m_slots;
};
} }

View File

@ -16,7 +16,8 @@ dxvk_src = files([
'dxvk_lifetime.cpp', 'dxvk_lifetime.cpp',
'dxvk_main.cpp', 'dxvk_main.cpp',
'dxvk_memory.cpp', 'dxvk_memory.cpp',
'dxvk_pipeline.cpp', 'dxvk_pipelayout.cpp',
'dxvk_pipemanager.cpp',
'dxvk_renderpass.cpp', 'dxvk_renderpass.cpp',
'dxvk_resource.cpp', 'dxvk_resource.cpp',
'dxvk_sampler.cpp', 'dxvk_sampler.cpp',

View File

@ -29,7 +29,7 @@ namespace dxvk {
*/ */
spv::Op opCode() const { spv::Op opCode() const {
return static_cast<spv::Op>( return static_cast<spv::Op>(
m_code[0] & spv::OpCodeMask); this->arg(0) & spv::OpCodeMask);
} }
/** /**
@ -37,7 +37,7 @@ namespace dxvk {
* \returns Number of DWORDs * \returns Number of DWORDs
*/ */
uint32_t length() const { uint32_t length() const {
return m_code[0] >> spv::WordCountShift; return this->arg(0) >> spv::WordCountShift;
} }
/** /**

View File

@ -113,18 +113,12 @@ public:
0, nullptr)); 0, nullptr));
m_dxvkVertexShader = m_dxvkDevice->createShader( m_dxvkVertexShader = m_dxvkDevice->createShader(
VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_VERTEX_BIT, 0, nullptr,
SpirvCodeBuffer(_countof(vsCode), vsCode)); SpirvCodeBuffer(_countof(vsCode), vsCode));
m_dxvkFragmentShader = m_dxvkDevice->createShader( m_dxvkFragmentShader = m_dxvkDevice->createShader(
VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, 0, nullptr,
SpirvCodeBuffer(_countof(fsCode), fsCode)); SpirvCodeBuffer(_countof(fsCode), fsCode));
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() { ~TriangleApp() {
@ -158,6 +152,14 @@ public:
m_dxvkContext->setViewports(1, &viewport, &scissor); m_dxvkContext->setViewports(1, &viewport, &scissor);
m_dxvkContext->bindShader(
VK_SHADER_STAGE_VERTEX_BIT,
m_dxvkVertexShader);
m_dxvkContext->bindShader(
VK_SHADER_STAGE_FRAGMENT_BIT,
m_dxvkFragmentShader);
VkClearAttachment clearAttachment; VkClearAttachment clearAttachment;
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clearAttachment.colorAttachment = 0; clearAttachment.colorAttachment = 0;
@ -198,10 +200,8 @@ private:
Rc<DxvkSwapchain> m_dxvkSwapchain; Rc<DxvkSwapchain> m_dxvkSwapchain;
Rc<DxvkContext> m_dxvkContext; Rc<DxvkContext> m_dxvkContext;
Rc<DxvkShader> m_dxvkVertexShader; Rc<DxvkShader> m_dxvkVertexShader;
Rc<DxvkShader> m_dxvkFragmentShader; Rc<DxvkShader> m_dxvkFragmentShader;
Rc<DxvkBindingLayout> m_dxvkBindingLayout;
Rc<DxvkGraphicsPipeline> m_dxvkPipeline;
}; };

View File

@ -1,6 +1,6 @@
lib_d3d11 = dxvk_compiler.find_library('d3d11') lib_d3d11 = dxvk_compiler.find_library('d3d11')
lib_dxgi = dxvk_compiler.find_library('dxgi') lib_dxgi = dxvk_compiler.find_library('dxgi')
lib_d3dcompiler_47 = dxvk_compiler.find_library('d3dcompiler_47') lib_d3dcompiler_47 = dxvk_compiler.find_library('d3dcompiler')
subdir('d3d11') subdir('d3d11')
subdir('dxbc') subdir('dxbc')