1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-27 04:54:15 +01:00

[dxvk] Some more work on shader resources and resource bindings

This commit is contained in:
Philip Rebohle 2017-10-15 17:56:06 +02:00
parent 44d9bd9000
commit e433c01ad4
25 changed files with 532 additions and 105 deletions

70
src/dxvk/dxvk_barrier.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "dxvk_barrier.h"
namespace dxvk {
DxvkBarrierSet:: DxvkBarrierSet() { }
DxvkBarrierSet::~DxvkBarrierSet() { }
bool DxvkBarrierSet::hasBarriers() const {
return (m_srcFlags | m_dstFlags) != 0;
}
void DxvkBarrierSet::addMemoryBarrier(
VkPipelineStageFlags srcFlags,
VkPipelineStageFlags dstFlags,
const VkMemoryBarrier& barrier) {
m_srcFlags |= srcFlags;
m_dstFlags |= dstFlags;
m_memory.push_back(barrier);
}
void DxvkBarrierSet::addBufferBarrier(
VkPipelineStageFlags srcFlags,
VkPipelineStageFlags dstFlags,
const VkBufferMemoryBarrier& barrier) {
m_srcFlags |= srcFlags;
m_dstFlags |= dstFlags;
m_buffer.push_back(barrier);
}
void DxvkBarrierSet::addImageBarrier(
VkPipelineStageFlags srcFlags,
VkPipelineStageFlags dstFlags,
const VkImageMemoryBarrier& barrier) {
m_srcFlags |= srcFlags;
m_dstFlags |= dstFlags;
m_image.push_back(barrier);
}
void DxvkBarrierSet::recordCommands(
DxvkRecorder& recorder) {
VkPipelineStageFlags srcFlags = m_srcFlags;
VkPipelineStageFlags dstFlags = m_dstFlags;
if (srcFlags == 0) srcFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
if (dstFlags == 0) dstFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
recorder.cmdPipelineBarrier(
srcFlags, dstFlags, 0,
m_memory.size(), m_memory.data(),
m_buffer.size(), m_buffer.data(),
m_image.size(), m_image.data());
this->reset();
}
void DxvkBarrierSet::reset() {
m_srcFlags = 0;
m_dstFlags = 0;
m_memory.resize(0);
m_buffer.resize(0);
m_image .resize(0);
}
}

54
src/dxvk/dxvk_barrier.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "dxvk_recorder.h"
namespace dxvk {
/**
* \brief Barrier set
*
* Accumulates memory barriers and provides a
* method to record all those barriers into a
* command buffer at once.
*/
class DxvkBarrierSet {
public:
DxvkBarrierSet();
~DxvkBarrierSet();
bool hasBarriers() const;
void addMemoryBarrier(
VkPipelineStageFlags srcFlags,
VkPipelineStageFlags dstFlags,
const VkMemoryBarrier& barrier);
void addBufferBarrier(
VkPipelineStageFlags srcFlags,
VkPipelineStageFlags dstFlags,
const VkBufferMemoryBarrier& barrier);
void addImageBarrier(
VkPipelineStageFlags srcFlags,
VkPipelineStageFlags dstFlags,
const VkImageMemoryBarrier& barrier);
void recordCommands(
DxvkRecorder& recorder);
void reset();
private:
VkPipelineStageFlags m_srcFlags = 0;
VkPipelineStageFlags m_dstFlags = 0;
std::vector<VkMemoryBarrier> m_memory;
std::vector<VkBufferMemoryBarrier> m_buffer;
std::vector<VkImageMemoryBarrier> m_image;
};
}

View File

@ -19,6 +19,13 @@ namespace dxvk {
/// Buffer usage flags /// Buffer usage flags
VkBufferUsageFlags usage; VkBufferUsageFlags usage;
/// Pipeline stages that can access
/// the contents of the buffer.
VkPipelineStageFlags stages;
/// Allowed access patterns
VkAccessFlags access;
}; };
@ -77,4 +84,57 @@ namespace dxvk {
}; };
/**
* \brief Buffer binding
*
* Stores the buffer and the sub-range of the buffer
* to bind. Bindings are considered equal if all three
* parameters are the same.
*/
class DxvkBufferBinding {
public:
DxvkBufferBinding() { }
DxvkBufferBinding(
const Rc<DxvkBuffer>& buffer,
VkDeviceSize rangeOffset,
VkDeviceSize rangeLength)
: m_buffer(buffer),
m_offset(rangeOffset),
m_length(rangeLength) { }
Rc<DxvkResource> resource() const {
return m_buffer;
}
VkDescriptorBufferInfo descriptorInfo() const {
VkDescriptorBufferInfo info;
info.buffer = m_buffer->handle();
info.offset = m_offset;
info.range = m_length;
return info;
}
bool operator == (const DxvkBufferBinding& other) const {
return this->m_buffer == other.m_buffer
&& this->m_offset == other.m_offset
&& this->m_length == other.m_length;
}
bool operator != (const DxvkBufferBinding& other) const {
return this->m_buffer != other.m_buffer
|| this->m_offset != other.m_offset
|| this->m_length != other.m_length;
}
private:
Rc<DxvkBuffer> m_buffer = nullptr;
VkDeviceSize m_offset = 0;
VkDeviceSize m_length = 0;
};
} }

View File

@ -138,4 +138,22 @@ namespace dxvk {
m_vkd->vkCmdEndRenderPass(m_buffer); m_vkd->vkCmdEndRenderPass(m_buffer);
} }
void DxvkCommandList::cmdPipelineBarrier(
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
uint32_t memoryBarrierCount,
const VkMemoryBarrier* pMemoryBarriers,
uint32_t bufferMemoryBarrierCount,
const VkBufferMemoryBarrier* pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier* pImageMemoryBarriers) {
m_vkd->vkCmdPipelineBarrier(m_buffer,
dstStageMask, srcStageMask, dependencyFlags,
memoryBarrierCount, pMemoryBarriers,
bufferMemoryBarrierCount, pBufferMemoryBarriers,
imageMemoryBarrierCount, pImageMemoryBarriers);
}
} }

View File

@ -104,6 +104,17 @@ namespace dxvk {
void cmdEndRenderPass() final; void cmdEndRenderPass() final;
void cmdPipelineBarrier(
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
uint32_t memoryBarrierCount,
const VkMemoryBarrier* pMemoryBarriers,
uint32_t bufferMemoryBarrierCount,
const VkBufferMemoryBarrier* pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier* pImageMemoryBarriers) final;
private: private:
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;

View File

@ -6,6 +6,7 @@ namespace dxvk {
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkShader>& shader) const Rc<DxvkShader>& shader)
: m_vkd(vkd) { : m_vkd(vkd) {
TRACE(this, shader);
std::vector<VkDescriptorSetLayoutBinding> bindings; std::vector<VkDescriptorSetLayoutBinding> bindings;
@ -80,6 +81,7 @@ namespace dxvk {
DxvkComputePipeline::~DxvkComputePipeline() { DxvkComputePipeline::~DxvkComputePipeline() {
TRACE(this);
this->destroyObjects(); this->destroyObjects();
} }

View File

@ -4,8 +4,11 @@
namespace dxvk { namespace dxvk {
DxvkContext::DxvkContext(const Rc<DxvkDevice>& device) DxvkContext::DxvkContext(
: m_device(device) { const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipeMgr)
: m_device (device),
m_pipeMgr (pipeMgr) {
TRACE(this, device); TRACE(this, device);
} }
@ -53,6 +56,57 @@ namespace dxvk {
} }
void DxvkContext::bindFramebuffer(
const Rc<DxvkFramebuffer>& fb) {
TRACE(this, fb);
if (m_state.g.fb != fb) {
m_state.g.fb = fb;
if (m_state.g.flags.test(
DxvkGraphicsPipelineBit::RenderPassBound))
this->endRenderPass();
}
}
void DxvkContext::bindShader(
VkShaderStageFlagBits stage,
const Rc<DxvkShader>& shader) {
TRACE(this, stage, shader);
DxvkShaderState* state = this->getShaderState(stage);
if (state->shader != shader) {
state->shader = shader;
this->setPipelineDirty(stage);
}
}
void DxvkContext::bindStorageBuffer(
VkShaderStageFlagBits stage,
uint32_t slot,
const Rc<DxvkBuffer>& buffer,
VkDeviceSize offset,
VkDeviceSize length) {
TRACE(this, stage, slot);
DxvkBufferBinding binding(buffer, offset, length);
DxvkShaderState* state = this->getShaderState(stage);
// TODO investigate whether it is worth checking whether
// the shader actually uses the resource. However, if the
// application is not completely retarded, always setting
// the 'resources dirty' flag should be the best option.
if (state->boundStorageBuffers.at(slot) != binding) {
state->boundStorageBuffers.at(slot) = binding;
this->setResourcesDirty(stage);
m_cmd->trackResource(binding.resource());
}
}
void DxvkContext::clearRenderTarget( void DxvkContext::clearRenderTarget(
const VkClearAttachment& attachment, const VkClearAttachment& attachment,
const VkClearRect& clearArea) { const VkClearRect& clearArea) {
@ -67,6 +121,8 @@ namespace dxvk {
uint32_t wgCountX, uint32_t wgCountX,
uint32_t wgCountY, uint32_t wgCountY,
uint32_t wgCountZ) { uint32_t wgCountZ) {
TRACE(this, wgCountX, wgCountY, wgCountZ);
this->endRenderPass();
this->flushComputeState(); this->flushComputeState();
m_cmd->cmdDispatch( m_cmd->cmdDispatch(
@ -79,6 +135,8 @@ namespace dxvk {
uint32_t instanceCount, uint32_t instanceCount,
uint32_t firstVertex, uint32_t firstVertex,
uint32_t firstInstance) { uint32_t firstInstance) {
TRACE(this, vertexCount, instanceCount,
firstVertex, firstInstance);
this->flushGraphicsState(); this->flushGraphicsState();
m_cmd->cmdDraw( m_cmd->cmdDraw(
@ -93,6 +151,8 @@ namespace dxvk {
uint32_t firstIndex, uint32_t firstIndex,
uint32_t vertexOffset, uint32_t vertexOffset,
uint32_t firstInstance) { uint32_t firstInstance) {
TRACE(this, indexCount, instanceCount,
firstIndex, vertexOffset, firstInstance);
this->flushGraphicsState(); this->flushGraphicsState();
m_cmd->cmdDrawIndexed( m_cmd->cmdDrawIndexed(
@ -102,49 +162,15 @@ namespace dxvk {
} }
void DxvkContext::setFramebuffer(
const Rc<DxvkFramebuffer>& fb) {
TRACE(this, fb);
if (m_state.g.fb != fb) {
m_state.g.fb = fb;
if (m_state.g.flags.test(
DxvkGraphicsPipelineBit::RenderPassBound))
this->endRenderPass();
}
}
void DxvkContext::setShader(
VkShaderStageFlagBits stage,
const Rc<DxvkShader>& shader) {
TRACE(this, stage, shader);
DxvkShaderState* state = this->getShaderState(stage);
if (state->shader != shader) {
state->shader = shader;
if (stage == VK_SHADER_STAGE_COMPUTE_BIT) {
m_state.c.flags.set(
DxvkComputePipelineBit::PipelineDirty,
DxvkComputePipelineBit::DirtyResources);
} else {
m_state.g.flags.set(
DxvkGraphicsPipelineBit::PipelineDirty,
DxvkGraphicsPipelineBit::DirtyResources);
}
}
}
void DxvkContext::flushComputeState() { void DxvkContext::flushComputeState() {
if (m_state.c.flags.test(DxvkComputePipelineBit::PipelineDirty) if (m_state.c.flags.test(DxvkComputePipelineBit::PipelineDirty)) {
&& m_state.c.pipeline != nullptr) { m_state.c.pipeline = m_pipeMgr->getComputePipeline(m_state.c.cs.shader);
m_cmd->cmdBindPipeline(
VK_PIPELINE_BIND_POINT_COMPUTE, if (m_state.c.pipeline != nullptr) {
m_state.c.pipeline->getPipelineHandle()); m_cmd->cmdBindPipeline(
VK_PIPELINE_BIND_POINT_COMPUTE,
m_state.c.pipeline->getPipelineHandle());
}
} }
m_state.c.flags.clr( m_state.c.flags.clr(
@ -187,6 +213,27 @@ namespace dxvk {
} }
void DxvkContext::setPipelineDirty(VkShaderStageFlagBits stage) {
if (stage == VK_SHADER_STAGE_COMPUTE_BIT) {
m_state.c.flags.set(
DxvkComputePipelineBit::PipelineDirty,
DxvkComputePipelineBit::DirtyResources);
} else {
m_state.g.flags.set(
DxvkGraphicsPipelineBit::PipelineDirty,
DxvkGraphicsPipelineBit::DirtyResources);
}
}
void DxvkContext::setResourcesDirty(VkShaderStageFlagBits stage) {
if (stage == VK_SHADER_STAGE_COMPUTE_BIT)
m_state.c.flags.set(DxvkComputePipelineBit::DirtyResources);
else
m_state.g.flags.set(DxvkGraphicsPipelineBit::DirtyResources);
}
DxvkShaderState* DxvkContext::getShaderState(VkShaderStageFlagBits stage) { DxvkShaderState* DxvkContext::getShaderState(VkShaderStageFlagBits stage) {
switch (stage) { switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT: case VK_SHADER_STAGE_VERTEX_BIT:

View File

@ -1,8 +1,11 @@
#pragma once #pragma once
#include "dxvk_barrier.h"
#include "dxvk_cmdlist.h" #include "dxvk_cmdlist.h"
#include "dxvk_context_state.h" #include "dxvk_context_state.h"
#include "dxvk_deferred.h" #include "dxvk_deferred.h"
#include "dxvk_pipemgr.h"
#include "dxvk_util.h"
namespace dxvk { namespace dxvk {
@ -18,7 +21,8 @@ namespace dxvk {
public: public:
DxvkContext( DxvkContext(
const Rc<DxvkDevice>& device); const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipeMgr);
~DxvkContext(); ~DxvkContext();
/** /**
@ -51,6 +55,41 @@ namespace dxvk {
*/ */
bool endRecording(); bool endRecording();
/**
* \brief Sets framebuffer
* \param [in] fb Framebuffer
*/
void bindFramebuffer(
const Rc<DxvkFramebuffer>& fb);
/**
* \brief Sets shader for a given shader stage
*
* 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
*/
void bindShader(
VkShaderStageFlagBits stage,
const Rc<DxvkShader>& shader);
/**
* \brief Binds a storage buffer
*
* \param [in] stage Shader stage for this binding
* \param [in] slot Binding slot index
* \param [in] buffer Buffer binding info
*/
void bindStorageBuffer(
VkShaderStageFlagBits stage,
uint32_t slot,
const Rc<DxvkBuffer>& buffer,
VkDeviceSize offset,
VkDeviceSize length);
/** /**
* \brief Clears an active render target * \brief Clears an active render target
* *
@ -103,30 +142,10 @@ namespace dxvk {
uint32_t vertexOffset, uint32_t vertexOffset,
uint32_t firstInstance); uint32_t firstInstance);
/**
* \brief Sets framebuffer
* \param [in] fb Framebuffer
*/
void setFramebuffer(
const Rc<DxvkFramebuffer>& fb);
/**
* \brief Sets shader for a given shader stage
*
* 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
*/
void setShader(
VkShaderStageFlagBits stage,
const Rc<DxvkShader>& shader);
private: private:
const Rc<DxvkDevice> m_device; const Rc<DxvkDevice> m_device;
const Rc<DxvkPipelineManager> m_pipeMgr;
Rc<DxvkRecorder> m_cmd; Rc<DxvkRecorder> m_cmd;
DxvkContextState m_state; DxvkContextState m_state;
@ -137,9 +156,19 @@ namespace dxvk {
void beginRenderPass(); void beginRenderPass();
void endRenderPass(); void endRenderPass();
void setPipelineDirty(VkShaderStageFlagBits stage);
void setResourcesDirty(VkShaderStageFlagBits stage);
void shaderResourceBarriers(
DxvkBarrierSet& barriers,
VkShaderStageFlagBits stage);
DxvkShaderState* getShaderState( DxvkShaderState* getShaderState(
VkShaderStageFlagBits stage); VkShaderStageFlagBits stage);
VkPipelineStageFlags pipelineStage(
VkShaderStageFlags shaderStage) const;
}; };
} }

View File

@ -1,7 +1,9 @@
#pragma once #pragma once
#include "dxvk_buffer.h"
#include "dxvk_compute.h" #include "dxvk_compute.h"
#include "dxvk_framebuffer.h" #include "dxvk_framebuffer.h"
#include "dxvk_image.h"
#include "dxvk_limits.h" #include "dxvk_limits.h"
#include "dxvk_shader.h" #include "dxvk_shader.h"
@ -48,7 +50,10 @@ namespace dxvk {
* buffers, storage buffers and storage images. * buffers, storage buffers and storage images.
*/ */
struct DxvkShaderState { struct DxvkShaderState {
Rc<DxvkShader> shader; Rc<DxvkShader> shader;
std::array<DxvkBufferBinding, MaxNumStorageBuffers> boundStorageBuffers;
std::array<DxvkBufferBinding, MaxNumUniformBuffers> boundUniformBuffers;
}; };

View File

@ -6,10 +6,11 @@ namespace dxvk {
DxvkDevice::DxvkDevice( DxvkDevice::DxvkDevice(
const Rc<DxvkAdapter>& adapter, const Rc<DxvkAdapter>& adapter,
const Rc<vk::DeviceFn>& vkd) const Rc<vk::DeviceFn>& vkd)
: m_adapter (adapter), : m_adapter (adapter),
m_vkd (vkd), m_vkd (vkd),
m_memory (adapter, vkd), m_memory (new DxvkMemoryAllocator(adapter, vkd)),
m_renderPassPool(vkd) { m_renderPassPool (new DxvkRenderPassPool (vkd)),
m_pipelineManager (new DxvkPipelineManager(vkd)) {
TRACE(this, adapter); TRACE(this, adapter);
m_vkd->vkGetDeviceQueue(m_vkd->device(), m_vkd->vkGetDeviceQueue(m_vkd->device(),
@ -23,6 +24,10 @@ namespace dxvk {
DxvkDevice::~DxvkDevice() { DxvkDevice::~DxvkDevice() {
TRACE(this); TRACE(this);
m_pipelineManager = nullptr;
m_renderPassPool = nullptr;
m_memory = nullptr;
m_vkd->vkDeviceWaitIdle(m_vkd->device()); m_vkd->vkDeviceWaitIdle(m_vkd->device());
m_vkd->vkDestroyDevice(m_vkd->device(), nullptr); m_vkd->vkDestroyDevice(m_vkd->device(), nullptr);
} }
@ -35,14 +40,14 @@ namespace dxvk {
Rc<DxvkContext> DxvkDevice::createContext() { Rc<DxvkContext> DxvkDevice::createContext() {
return new DxvkContext(this); return new DxvkContext(this, m_pipelineManager);
} }
Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer( Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
const DxvkRenderTargets& renderTargets) { const DxvkRenderTargets& renderTargets) {
auto format = renderTargets.renderPassFormat(); auto format = renderTargets.renderPassFormat();
auto renderPass = m_renderPassPool.getRenderPass(format); auto renderPass = m_renderPassPool->getRenderPass(format);
return new DxvkFramebuffer(m_vkd, renderPass, renderTargets); return new DxvkFramebuffer(m_vkd, renderPass, renderTargets);
} }
@ -51,7 +56,7 @@ namespace dxvk {
const DxvkBufferCreateInfo& createInfo, const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType) { VkMemoryPropertyFlags memoryType) {
return new DxvkBuffer(m_vkd, return new DxvkBuffer(m_vkd,
createInfo, m_memory, memoryType); createInfo, *m_memory, memoryType);
} }

View File

@ -6,6 +6,7 @@
#include "dxvk_context.h" #include "dxvk_context.h"
#include "dxvk_framebuffer.h" #include "dxvk_framebuffer.h"
#include "dxvk_memory.h" #include "dxvk_memory.h"
#include "dxvk_pipemgr.h"
#include "dxvk_renderpass.h" #include "dxvk_renderpass.h"
#include "dxvk_shader.h" #include "dxvk_shader.h"
#include "dxvk_swapchain.h" #include "dxvk_swapchain.h"
@ -179,13 +180,13 @@ namespace dxvk {
Rc<DxvkAdapter> m_adapter; Rc<DxvkAdapter> m_adapter;
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
DxvkMemoryAllocator m_memory; Rc<DxvkMemoryAllocator> m_memory;
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

@ -2,17 +2,17 @@
namespace dxvk { namespace dxvk {
size_t DxvkGraphicsPipelineState::hash() const { size_t DxvkGraphicsPipelineStateInfo::hash() const {
// TODO implement // TODO implement
} }
bool DxvkGraphicsPipelineState::operator == (const DxvkGraphicsPipelineState& other) const { bool DxvkGraphicsPipelineStateInfo::operator == (const DxvkGraphicsPipelineStateInfo& other) const {
// TODO implement // TODO implement
} }
bool DxvkGraphicsPipelineState::operator != (const DxvkGraphicsPipelineState& other) const { bool DxvkGraphicsPipelineStateInfo::operator != (const DxvkGraphicsPipelineStateInfo& other) const {
return !this->operator == (other); return !this->operator == (other);
} }
@ -36,7 +36,7 @@ namespace dxvk {
VkPipeline DxvkGraphicsPipeline::getPipelineHandle( VkPipeline DxvkGraphicsPipeline::getPipelineHandle(
const DxvkGraphicsPipelineState& state) { const DxvkGraphicsPipelineStateInfo& state) {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
auto pair = m_pipelines.find(state); auto pair = m_pipelines.find(state);
@ -50,7 +50,7 @@ namespace dxvk {
VkPipeline DxvkGraphicsPipeline::compilePipeline( VkPipeline DxvkGraphicsPipeline::compilePipeline(
const DxvkGraphicsPipelineState& state) const { const DxvkGraphicsPipelineStateInfo& state) const {
} }

View File

@ -9,13 +9,13 @@
namespace dxvk { namespace dxvk {
struct DxvkGraphicsPipelineState { struct DxvkGraphicsPipelineStateInfo {
VkRenderPass renderPass; VkRenderPass renderPass;
size_t hash() const; size_t hash() const;
bool operator == (const DxvkGraphicsPipelineState& other) const; bool operator == (const DxvkGraphicsPipelineStateInfo& other) const;
bool operator != (const DxvkGraphicsPipelineState& other) const; bool operator != (const DxvkGraphicsPipelineStateInfo& other) const;
}; };
/** /**
@ -43,7 +43,7 @@ namespace dxvk {
} }
VkPipeline getPipelineHandle( VkPipeline getPipelineHandle(
const DxvkGraphicsPipelineState& state); const DxvkGraphicsPipelineStateInfo& state);
private: private:
@ -60,11 +60,11 @@ namespace dxvk {
std::mutex m_mutex; std::mutex m_mutex;
std::unordered_map< std::unordered_map<
DxvkGraphicsPipelineState, DxvkGraphicsPipelineStateInfo,
VkPipeline, DxvkHash> m_pipelines; VkPipeline, DxvkHash> m_pipelines;
VkPipeline compilePipeline( VkPipeline compilePipeline(
const DxvkGraphicsPipelineState& state) const; const DxvkGraphicsPipelineStateInfo& state) const;
}; };

View File

@ -68,7 +68,7 @@ namespace dxvk {
* Allocates device memory for Vulkan resources. * Allocates device memory for Vulkan resources.
* Memory objects will be destroyed automatically. * Memory objects will be destroyed automatically.
*/ */
class DxvkMemoryAllocator { class DxvkMemoryAllocator : public RcObject {
friend class DxvkMemory; friend class DxvkMemory;
public: public:

View File

@ -14,8 +14,9 @@ namespace dxvk {
} }
Rc<DxvkComputePipeline> DxvkPipelineManager::getComputePipeline( Rc<DxvkComputePipeline> DxvkPipelineManager::getComputePipeline(const Rc<DxvkShader>& cs) {
const Rc<DxvkShader>& cs) { if (cs == nullptr)
return nullptr;
DxvkPipelineKey<1> key; DxvkPipelineKey<1> key;
key.setShader(0, cs); key.setShader(0, cs);
@ -38,6 +39,8 @@ namespace dxvk {
const Rc<DxvkShader>& tes, const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs, const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs) { const Rc<DxvkShader>& fs) {
if (vs == nullptr)
return nullptr;
DxvkPipelineKey<5> key; DxvkPipelineKey<5> key;
key.setShader(0, vs); key.setShader(0, vs);

View File

@ -73,6 +73,7 @@ namespace dxvk {
* shader. If no such pipeline object exists, a new * shader. If no such pipeline object exists, a new
* one will be created. * one will be created.
* \param [in] cs Compute shader * \param [in] cs Compute shader
* \returns Compute pipeline
*/ */
Rc<DxvkComputePipeline> getComputePipeline( Rc<DxvkComputePipeline> getComputePipeline(
const Rc<DxvkShader>& cs); const Rc<DxvkShader>& cs);

View File

@ -61,6 +61,17 @@ namespace dxvk {
virtual void cmdEndRenderPass() = 0; virtual void cmdEndRenderPass() = 0;
virtual void cmdPipelineBarrier(
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
uint32_t memoryBarrierCount,
const VkMemoryBarrier* pMemoryBarriers,
uint32_t bufferMemoryBarrierCount,
const VkBufferMemoryBarrier* pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier* pImageMemoryBarriers) = 0;
}; };
} }

View File

@ -140,7 +140,7 @@ namespace dxvk {
* Thread-safe class that manages the render pass * Thread-safe class that manages the render pass
* objects that are used within an application. * objects that are used within an application.
*/ */
class DxvkRenderPassPool { class DxvkRenderPassPool : public RcObject {
public: public:

View File

@ -8,6 +8,19 @@
namespace dxvk { namespace dxvk {
/**
* \brief Resource access mode
*
* Defines whether a resource will be
* used for reading, writing, or both.
*/
enum class DxvkResourceModeBit : uint32_t {
Read = 0,
Write = 1,
};
using DxvkResourceMode = Flags<DxvkResourceModeBit>;
/** /**
* \brief Shader resource type * \brief Shader resource type
* *
@ -27,6 +40,7 @@ namespace dxvk {
* \brief Resource slot * \brief Resource slot
*/ */
struct DxvkResourceSlot{ struct DxvkResourceSlot{
DxvkResourceMode mode;
DxvkResourceType type; DxvkResourceType type;
uint32_t slot; uint32_t slot;
}; };

23
src/dxvk/dxvk_util.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "dxvk_util.h"
namespace dxvk::util {
VkPipelineStageFlags pipelineStages(
VkShaderStageFlags shaderStages) {
VkPipelineStageFlags result = 0;
if (shaderStages & VK_SHADER_STAGE_COMPUTE_BIT)
result |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
if (shaderStages & VK_SHADER_STAGE_VERTEX_BIT)
result |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
if (shaderStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
result |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
if (shaderStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
result |= VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
if (shaderStages & VK_SHADER_STAGE_GEOMETRY_BIT)
result |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
if (shaderStages & VK_SHADER_STAGE_FRAGMENT_BIT)
result |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
return result;
}
}

16
src/dxvk/dxvk_util.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "dxvk_include.h"
namespace dxvk::util {
/**
* \brief Gets pipeline stage flags for shader stages
*
* \param [in] shaderStages Shader stage flags
* \returns Corresponding pipeline stage flags
*/
VkPipelineStageFlags pipelineStages(
VkShaderStageFlags shaderStages);
}

View File

@ -1,5 +1,6 @@
dxvk_src = files([ dxvk_src = files([
'dxvk_adapter.cpp', 'dxvk_adapter.cpp',
'dxvk_barrier.cpp',
'dxvk_buffer.cpp', 'dxvk_buffer.cpp',
'dxvk_cmdlist.cpp', 'dxvk_cmdlist.cpp',
'dxvk_compute.cpp', 'dxvk_compute.cpp',
@ -21,6 +22,7 @@ dxvk_src = files([
'dxvk_surface.cpp', 'dxvk_surface.cpp',
'dxvk_swapchain.cpp', 'dxvk_swapchain.cpp',
'dxvk_sync.cpp', 'dxvk_sync.cpp',
'dxvk_util.cpp',
'spirv/dxvk_spirv_code_buffer.cpp', 'spirv/dxvk_spirv_code_buffer.cpp',

View File

@ -9,11 +9,20 @@ namespace dxvk {
DxvkSpirvCodeBuffer::~DxvkSpirvCodeBuffer() { } DxvkSpirvCodeBuffer::~DxvkSpirvCodeBuffer() { }
DxvkSpirvCodeBuffer::DxvkSpirvCodeBuffer( DxvkSpirvCodeBuffer::DxvkSpirvCodeBuffer(std::istream&& stream) {
std::basic_istream<uint32_t>& stream) stream.ignore(std::numeric_limits<std::streamsize>::max());
: m_code( std::streamsize length = stream.gcount();
std::istreambuf_iterator<uint32_t>(stream), stream.clear();
std::istreambuf_iterator<uint32_t>()) { } stream.seekg(0, std::ios_base::beg);
std::vector<char> buffer(length);
stream.read(buffer.data(), length);
buffer.resize(stream.gcount());
m_code.resize(buffer.size() / sizeof(uint32_t));
std::memcpy(reinterpret_cast<char*>(m_code.data()),
buffer.data(), m_code.size() * sizeof(uint32_t));
}
void DxvkSpirvCodeBuffer::append(const DxvkSpirvCodeBuffer& other) { void DxvkSpirvCodeBuffer::append(const DxvkSpirvCodeBuffer& other) {
@ -100,8 +109,10 @@ namespace dxvk {
} }
void DxvkSpirvCodeBuffer::store(std::basic_ostream<uint32_t>& stream) const { void DxvkSpirvCodeBuffer::store(std::ostream&& stream) const {
stream.write(m_code.data(), m_code.size()); stream.write(
reinterpret_cast<const char*>(m_code.data()),
sizeof(uint32_t) * m_code.size());
} }
} }

View File

@ -21,8 +21,7 @@ namespace dxvk {
public: public:
DxvkSpirvCodeBuffer(); DxvkSpirvCodeBuffer();
DxvkSpirvCodeBuffer( DxvkSpirvCodeBuffer(std::istream&& stream);
std::basic_istream<uint32_t>& stream);
~DxvkSpirvCodeBuffer(); ~DxvkSpirvCodeBuffer();
/** /**
@ -38,7 +37,7 @@ namespace dxvk {
* \returns Code size, in bytes * \returns Code size, in bytes
*/ */
size_t size() const { size_t size() const {
return m_code.size(); return m_code.size() * sizeof(uint32_t);
} }
/** /**
@ -120,7 +119,7 @@ namespace dxvk {
* exists mostly for debugging purposes. * exists mostly for debugging purposes.
* \param [in] stream Output stream * \param [in] stream Output stream
*/ */
void store(std::basic_ostream<uint32_t>& stream) const; void store(std::ostream&& stream) const;
private: private:

View File

@ -3,6 +3,9 @@
#include <dxvk_main.h> #include <dxvk_main.h>
#include <dxvk_surface.h> #include <dxvk_surface.h>
#include <cstring>
#include <fstream>
#include <windows.h> #include <windows.h>
#include <windowsx.h> #include <windowsx.h>
@ -26,6 +29,37 @@ public:
m_dxvkContext (m_dxvkDevice->createContext()), m_dxvkContext (m_dxvkDevice->createContext()),
m_dxvkCommandList (m_dxvkDevice->createCommandList()) { m_dxvkCommandList (m_dxvkDevice->createCommandList()) {
DxvkBufferCreateInfo bufferInfo;
bufferInfo.size = sizeof(m_testData);
bufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
bufferInfo.stages = VK_PIPELINE_STAGE_HOST_BIT
| VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
bufferInfo.access = VK_ACCESS_HOST_WRITE_BIT
| VK_ACCESS_HOST_READ_BIT
| VK_ACCESS_SHADER_WRITE_BIT
| VK_ACCESS_SHADER_READ_BIT;
m_testBuffer = m_dxvkDevice->createBuffer(bufferInfo,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
for (size_t i = 0; i < 64; i++)
m_testData[i] = static_cast<int>(i);
std::memcpy(m_testBuffer->mapPtr(),
m_testData, sizeof(m_testData));
DxvkResourceSlot computeBufferSlot;
computeBufferSlot.mode.set(
DxvkResourceModeBit::Read,
DxvkResourceModeBit::Write);
computeBufferSlot.type = DxvkResourceType::StorageBuffer;
computeBufferSlot.slot = 0;
DxvkSpirvCodeBuffer code(std::ifstream("comp.spv", std::ios::binary));
code.store(std::ofstream("comp.2.spv", std::ios::binary));
m_compShader = m_dxvkDevice->createShader(
VK_SHADER_STAGE_COMPUTE_BIT, std::move(code),
1, &computeBufferSlot);
} }
~TriangleApp() { ~TriangleApp() {
@ -40,7 +74,7 @@ public:
auto fbSize = fb->size(); auto fbSize = fb->size();
m_dxvkContext->beginRecording(m_dxvkCommandList); m_dxvkContext->beginRecording(m_dxvkCommandList);
m_dxvkContext->setFramebuffer(fb); m_dxvkContext->bindFramebuffer(fb);
VkClearAttachment clearAttachment; VkClearAttachment clearAttachment;
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -58,6 +92,13 @@ public:
m_dxvkContext->clearRenderTarget( m_dxvkContext->clearRenderTarget(
clearAttachment, clearAttachment,
clearArea); clearArea);
m_dxvkContext->bindShader(
VK_SHADER_STAGE_COMPUTE_BIT,
m_compShader);
m_dxvkContext->bindStorageBuffer(
VK_SHADER_STAGE_COMPUTE_BIT, 0,
m_testBuffer, 0, sizeof(m_testData));
m_dxvkContext->dispatch(1, 1, 1);
m_dxvkContext->endRecording(); m_dxvkContext->endRecording();
auto fence = m_dxvkDevice->submitCommandList( auto fence = m_dxvkDevice->submitCommandList(
@ -76,9 +117,13 @@ private:
Rc<DxvkContext> m_dxvkContext; Rc<DxvkContext> m_dxvkContext;
Rc<DxvkCommandList> m_dxvkCommandList; Rc<DxvkCommandList> m_dxvkCommandList;
Rc<DxvkBuffer> m_testBuffer;
Rc<DxvkShader> m_compShader;
Rc<DxvkShader> m_vertShader; Rc<DxvkShader> m_vertShader;
Rc<DxvkShader> m_fragShader; Rc<DxvkShader> m_fragShader;
int m_testData[64];
}; };
LRESULT CALLBACK WindowProc(HWND hWnd, LRESULT CALLBACK WindowProc(HWND hWnd,