[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
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);
}
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 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:
Rc<vk::DeviceFn> m_vkd;

View File

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

View File

@ -4,8 +4,11 @@
namespace dxvk {
DxvkContext::DxvkContext(const Rc<DxvkDevice>& device)
: m_device(device) {
DxvkContext::DxvkContext(
const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipeMgr)
: m_device (device),
m_pipeMgr (pipeMgr) {
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(
const VkClearAttachment& attachment,
const VkClearRect& clearArea) {
@ -67,6 +121,8 @@ namespace dxvk {
uint32_t wgCountX,
uint32_t wgCountY,
uint32_t wgCountZ) {
TRACE(this, wgCountX, wgCountY, wgCountZ);
this->endRenderPass();
this->flushComputeState();
m_cmd->cmdDispatch(
@ -79,6 +135,8 @@ namespace dxvk {
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance) {
TRACE(this, vertexCount, instanceCount,
firstVertex, firstInstance);
this->flushGraphicsState();
m_cmd->cmdDraw(
@ -93,6 +151,8 @@ namespace dxvk {
uint32_t firstIndex,
uint32_t vertexOffset,
uint32_t firstInstance) {
TRACE(this, indexCount, instanceCount,
firstIndex, vertexOffset, firstInstance);
this->flushGraphicsState();
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() {
if (m_state.c.flags.test(DxvkComputePipelineBit::PipelineDirty)
&& m_state.c.pipeline != nullptr) {
m_cmd->cmdBindPipeline(
VK_PIPELINE_BIND_POINT_COMPUTE,
m_state.c.pipeline->getPipelineHandle());
if (m_state.c.flags.test(DxvkComputePipelineBit::PipelineDirty)) {
m_state.c.pipeline = m_pipeMgr->getComputePipeline(m_state.c.cs.shader);
if (m_state.c.pipeline != nullptr) {
m_cmd->cmdBindPipeline(
VK_PIPELINE_BIND_POINT_COMPUTE,
m_state.c.pipeline->getPipelineHandle());
}
}
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) {
switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT:

View File

@ -1,8 +1,11 @@
#pragma once
#include "dxvk_barrier.h"
#include "dxvk_cmdlist.h"
#include "dxvk_context_state.h"
#include "dxvk_deferred.h"
#include "dxvk_pipemgr.h"
#include "dxvk_util.h"
namespace dxvk {
@ -18,7 +21,8 @@ namespace dxvk {
public:
DxvkContext(
const Rc<DxvkDevice>& device);
const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipeMgr);
~DxvkContext();
/**
@ -51,6 +55,41 @@ namespace dxvk {
*/
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
*
@ -103,30 +142,10 @@ namespace dxvk {
uint32_t vertexOffset,
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:
const Rc<DxvkDevice> m_device;
const Rc<DxvkDevice> m_device;
const Rc<DxvkPipelineManager> m_pipeMgr;
Rc<DxvkRecorder> m_cmd;
DxvkContextState m_state;
@ -137,9 +156,19 @@ namespace dxvk {
void beginRenderPass();
void endRenderPass();
void setPipelineDirty(VkShaderStageFlagBits stage);
void setResourcesDirty(VkShaderStageFlagBits stage);
void shaderResourceBarriers(
DxvkBarrierSet& barriers,
VkShaderStageFlagBits stage);
DxvkShaderState* getShaderState(
VkShaderStageFlagBits stage);
VkPipelineStageFlags pipelineStage(
VkShaderStageFlags shaderStage) const;
};
}

View File

@ -1,7 +1,9 @@
#pragma once
#include "dxvk_buffer.h"
#include "dxvk_compute.h"
#include "dxvk_framebuffer.h"
#include "dxvk_image.h"
#include "dxvk_limits.h"
#include "dxvk_shader.h"
@ -48,7 +50,10 @@ namespace dxvk {
* buffers, storage buffers and storage images.
*/
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(
const Rc<DxvkAdapter>& adapter,
const Rc<vk::DeviceFn>& vkd)
: m_adapter (adapter),
m_vkd (vkd),
m_memory (adapter, vkd),
m_renderPassPool(vkd) {
: m_adapter (adapter),
m_vkd (vkd),
m_memory (new DxvkMemoryAllocator(adapter, vkd)),
m_renderPassPool (new DxvkRenderPassPool (vkd)),
m_pipelineManager (new DxvkPipelineManager(vkd)) {
TRACE(this, adapter);
m_vkd->vkGetDeviceQueue(m_vkd->device(),
@ -23,6 +24,10 @@ namespace dxvk {
DxvkDevice::~DxvkDevice() {
TRACE(this);
m_pipelineManager = nullptr;
m_renderPassPool = nullptr;
m_memory = nullptr;
m_vkd->vkDeviceWaitIdle(m_vkd->device());
m_vkd->vkDestroyDevice(m_vkd->device(), nullptr);
}
@ -35,14 +40,14 @@ namespace dxvk {
Rc<DxvkContext> DxvkDevice::createContext() {
return new DxvkContext(this);
return new DxvkContext(this, m_pipelineManager);
}
Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
const DxvkRenderTargets& renderTargets) {
auto format = renderTargets.renderPassFormat();
auto renderPass = m_renderPassPool.getRenderPass(format);
auto renderPass = m_renderPassPool->getRenderPass(format);
return new DxvkFramebuffer(m_vkd, renderPass, renderTargets);
}
@ -51,7 +56,7 @@ namespace dxvk {
const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType) {
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_framebuffer.h"
#include "dxvk_memory.h"
#include "dxvk_pipemgr.h"
#include "dxvk_renderpass.h"
#include "dxvk_shader.h"
#include "dxvk_swapchain.h"
@ -179,13 +180,13 @@ namespace dxvk {
Rc<DxvkAdapter> m_adapter;
Rc<vk::DeviceFn> m_vkd;
DxvkMemoryAllocator m_memory;
DxvkRenderPassPool m_renderPassPool;
Rc<DxvkMemoryAllocator> m_memory;
Rc<DxvkRenderPassPool> m_renderPassPool;
Rc<DxvkPipelineManager> m_pipelineManager;
VkQueue m_graphicsQueue;
VkQueue m_presentQueue;
};
}

View File

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

View File

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

View File

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

View File

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

View File

@ -73,6 +73,7 @@ namespace dxvk {
* 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);

View File

@ -61,6 +61,17 @@ namespace dxvk {
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
* objects that are used within an application.
*/
class DxvkRenderPassPool {
class DxvkRenderPassPool : public RcObject {
public:

View File

@ -8,6 +8,19 @@
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
*
@ -27,6 +40,7 @@ namespace dxvk {
* \brief Resource slot
*/
struct DxvkResourceSlot{
DxvkResourceMode mode;
DxvkResourceType type;
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_adapter.cpp',
'dxvk_barrier.cpp',
'dxvk_buffer.cpp',
'dxvk_cmdlist.cpp',
'dxvk_compute.cpp',
@ -21,6 +22,7 @@ dxvk_src = files([
'dxvk_surface.cpp',
'dxvk_swapchain.cpp',
'dxvk_sync.cpp',
'dxvk_util.cpp',
'spirv/dxvk_spirv_code_buffer.cpp',

View File

@ -9,11 +9,20 @@ namespace dxvk {
DxvkSpirvCodeBuffer::~DxvkSpirvCodeBuffer() { }
DxvkSpirvCodeBuffer::DxvkSpirvCodeBuffer(
std::basic_istream<uint32_t>& stream)
: m_code(
std::istreambuf_iterator<uint32_t>(stream),
std::istreambuf_iterator<uint32_t>()) { }
DxvkSpirvCodeBuffer::DxvkSpirvCodeBuffer(std::istream&& stream) {
stream.ignore(std::numeric_limits<std::streamsize>::max());
std::streamsize length = stream.gcount();
stream.clear();
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) {
@ -100,8 +109,10 @@ namespace dxvk {
}
void DxvkSpirvCodeBuffer::store(std::basic_ostream<uint32_t>& stream) const {
stream.write(m_code.data(), m_code.size());
void DxvkSpirvCodeBuffer::store(std::ostream&& stream) const {
stream.write(
reinterpret_cast<const char*>(m_code.data()),
sizeof(uint32_t) * m_code.size());
}
}

View File

@ -21,8 +21,7 @@ namespace dxvk {
public:
DxvkSpirvCodeBuffer();
DxvkSpirvCodeBuffer(
std::basic_istream<uint32_t>& stream);
DxvkSpirvCodeBuffer(std::istream&& stream);
~DxvkSpirvCodeBuffer();
/**
@ -38,7 +37,7 @@ namespace dxvk {
* \returns Code size, in bytes
*/
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.
* \param [in] stream Output stream
*/
void store(std::basic_ostream<uint32_t>& stream) const;
void store(std::ostream&& stream) const;
private:

View File

@ -3,6 +3,9 @@
#include <dxvk_main.h>
#include <dxvk_surface.h>
#include <cstring>
#include <fstream>
#include <windows.h>
#include <windowsx.h>
@ -26,6 +29,37 @@ public:
m_dxvkContext (m_dxvkDevice->createContext()),
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() {
@ -40,7 +74,7 @@ public:
auto fbSize = fb->size();
m_dxvkContext->beginRecording(m_dxvkCommandList);
m_dxvkContext->setFramebuffer(fb);
m_dxvkContext->bindFramebuffer(fb);
VkClearAttachment clearAttachment;
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -58,6 +92,13 @@ public:
m_dxvkContext->clearRenderTarget(
clearAttachment,
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();
auto fence = m_dxvkDevice->submitCommandList(
@ -76,9 +117,13 @@ private:
Rc<DxvkContext> m_dxvkContext;
Rc<DxvkCommandList> m_dxvkCommandList;
Rc<DxvkBuffer> m_testBuffer;
Rc<DxvkShader> m_compShader;
Rc<DxvkShader> m_vertShader;
Rc<DxvkShader> m_fragShader;
int m_testData[64];
};
LRESULT CALLBACK WindowProc(HWND hWnd,