[dxvk] Added shader stub, improved state tracking code

This commit is contained in:
Philip Rebohle 2017-10-13 03:19:23 +02:00
parent 94af8140d2
commit 764220db98
8 changed files with 276 additions and 53 deletions

17
src/dxvk/dxvk_compute.cpp Normal file
View File

@ -0,0 +1,17 @@
#include "dxvk_compute.h"
namespace dxvk {
DxvkComputePipeline::DxvkComputePipeline(
const Rc<vk::DeviceFn>& vkd)
: m_vkd(vkd) {
// TODO implement
}
DxvkComputePipeline::~DxvkComputePipeline() {
m_vkd->vkDestroyPipeline(
m_vkd->device(), m_pipeline, nullptr);
}
}

34
src/dxvk/dxvk_compute.h Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include "dxvk_shader.h"
namespace dxvk {
/**
* \brief Compute pipeline
*
* Stores a pipeline object
*/
class DxvkComputePipeline : public RcObject {
public:
DxvkComputePipeline(const Rc<vk::DeviceFn>& vkd);
~DxvkComputePipeline();
/**
* \brief Pipeline handle
* \returns Pipeline handle
*/
VkPipeline handle() const {
return m_pipeline;
}
private:
Rc<vk::DeviceFn> m_vkd;
VkPipeline m_pipeline;
};
}

View File

@ -19,13 +19,30 @@ namespace dxvk {
TRACE(this, cmdList);
m_commandList = cmdList;
m_commandList->beginRecording();
// Make sure that we apply the current context state
// to the command buffer when recording draw commands.
m_state.g.flags.clr(
DxvkGraphicsPipelineBit::RenderPassBound);
m_state.g.flags.set(
DxvkGraphicsPipelineBit::PipelineDirty,
DxvkGraphicsPipelineBit::PipelineStateDirty,
DxvkGraphicsPipelineBit::DirtyResources,
DxvkGraphicsPipelineBit::DirtyVertexBuffers,
DxvkGraphicsPipelineBit::DirtyIndexBuffer);
m_state.c.flags.set(
DxvkComputePipelineBit::PipelineDirty,
DxvkComputePipelineBit::DirtyResources);
}
bool DxvkContext::endRecording() {
TRACE(this);
if (m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
// Any currently active render pass must be
// ended before finalizing the command buffer.
if (m_state.g.flags.test(DxvkGraphicsPipelineBit::RenderPassBound))
this->endRenderPass();
// Finalize the command list
@ -38,8 +55,7 @@ namespace dxvk {
void DxvkContext::clearRenderTarget(
const VkClearAttachment& attachment,
const VkClearRect& clearArea) {
if (!m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
this->beginRenderPass();
this->flushGraphicsState();
m_vkd->vkCmdClearAttachments(
m_commandList->handle(),
@ -48,12 +64,25 @@ namespace dxvk {
}
void DxvkContext::dispatch(
uint32_t wgCountX,
uint32_t wgCountY,
uint32_t wgCountZ) {
this->flushComputeState();
m_vkd->vkCmdDispatch(
m_commandList->handle(),
wgCountX, wgCountY, wgCountZ);
}
void DxvkContext::draw(
uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance) {
this->prepareDraw();
this->flushGraphicsState();
m_vkd->vkCmdDraw(
m_commandList->handle(),
vertexCount,
@ -69,7 +98,8 @@ namespace dxvk {
uint32_t firstIndex,
uint32_t vertexOffset,
uint32_t firstInstance) {
this->prepareDraw();
this->flushGraphicsState();
m_vkd->vkCmdDrawIndexed(
m_commandList->handle(),
indexCount,
@ -84,37 +114,57 @@ namespace dxvk {
const Rc<DxvkFramebuffer>& fb) {
TRACE(this, fb);
// When changing the framebuffer binding, we end the
// current render pass, but beginning the new render
// pass is deferred until a draw command is called.
if (m_state.fb.framebuffer != fb) {
if (m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
this->endRenderPass();
if (m_state.g.fb != fb) {
m_state.g.fb = fb;
m_state.fb.framebuffer = fb;
m_commandList->trackResource(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() {
VkCommandBuffer cmd = m_commandList->handle();
if (m_state.c.flags.test(DxvkComputePipelineBit::PipelineDirty)
&& m_state.c.pipeline != nullptr) {
m_vkd->vkCmdBindPipeline(cmd,
VK_PIPELINE_BIND_POINT_COMPUTE,
m_state.c.pipeline->handle());
}
m_state.c.flags.clr(
DxvkComputePipelineBit::PipelineDirty,
DxvkComputePipelineBit::DirtyResources);
}
void DxvkContext::flushGraphicsState() {
}
void DxvkContext::prepareDraw() {
this->flushGraphicsState();
if (!m_state.fb.flags.test(DxvkFbStateFlags::InsideRenderPass))
if (!m_state.g.flags.test(DxvkGraphicsPipelineBit::RenderPassBound))
this->beginRenderPass();
}
@ -122,22 +172,20 @@ namespace dxvk {
void DxvkContext::beginRenderPass() {
TRACE(this);
const DxvkFramebufferSize fbsize
= m_state.fb.framebuffer->size();
DxvkFramebufferSize fbsize
= m_state.g.fb->size();
VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr;
info.renderPass = m_state.fb.framebuffer->renderPass();
info.framebuffer = m_state.fb.framebuffer->handle();
info.renderPass = m_state.g.fb->renderPass();
info.framebuffer = m_state.g.fb->handle();
info.renderArea = VkRect2D { { 0, 0 }, { fbsize.width, fbsize.height } };
info.clearValueCount = 0;
info.pClearValues = nullptr;
m_vkd->vkCmdBeginRenderPass(
m_commandList->handle(),
&info, VK_SUBPASS_CONTENTS_INLINE);
m_state.fb.flags.set(DxvkFbStateFlags::InsideRenderPass);
m_vkd->vkCmdBeginRenderPass(m_commandList->handle(), &info, VK_SUBPASS_CONTENTS_INLINE);
m_state.g.flags.set(DxvkGraphicsPipelineBit::RenderPassBound);
}
@ -145,7 +193,33 @@ namespace dxvk {
TRACE(this);
m_vkd->vkCmdEndRenderPass(m_commandList->handle());
m_state.fb.flags.clr(DxvkFbStateFlags::InsideRenderPass);
m_state.g.flags.clr(DxvkGraphicsPipelineBit::RenderPassBound);
}
DxvkShaderState* DxvkContext::getShaderState(VkShaderStageFlagBits stage) {
switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT:
return &m_state.g.vs;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
return &m_state.g.tcs;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
return &m_state.g.tes;
case VK_SHADER_STAGE_GEOMETRY_BIT:
return &m_state.g.gs;
case VK_SHADER_STAGE_FRAGMENT_BIT:
return &m_state.g.fs;
case VK_SHADER_STAGE_COMPUTE_BIT:
return &m_state.c.cs;
default:
return nullptr;
}
}
}

View File

@ -1,7 +1,5 @@
#pragma once
#define DXVK_ERROR_CHECKING 1
#include "dxvk_cmdlist.h"
#include "dxvk_context_state.h"
@ -61,6 +59,18 @@ namespace dxvk {
const VkClearAttachment& attachment,
const VkClearRect& clearArea);
/**
* \brief Dispatches compute operations
*
* \param [in] wgCountX Number of X work groups
* \param [in] wgCountY Number of Y work groups
* \param [in] wgCountZ Number of Z work groups
*/
void dispatch(
uint32_t wgCountX,
uint32_t wgCountY,
uint32_t wgCountZ);
/**
* \brief Draws primitive without using an index buffer
*
@ -118,20 +128,15 @@ namespace dxvk {
Rc<DxvkCommandList> m_commandList;
DxvkContextState m_state;
/**
* \brief Forces a graphics pipeline state flush
*
* Applies current shader bindings, resource bindings
* etc. to the command buffer so that draw calls can
* be executed. Called whenever the need arises.
*/
void flushComputeState();
void flushGraphicsState();
void prepareDraw();
void beginRenderPass();
void endRenderPass();
DxvkShaderState* getShaderState(
VkShaderStageFlagBits stage);
};
}

View File

@ -1,21 +1,113 @@
#pragma once
#include "dxvk_compute.h"
#include "dxvk_framebuffer.h"
#include "dxvk_shader.h"
namespace dxvk {
enum class DxvkFbStateFlags : uint32_t {
InsideRenderPass = 0,
/**
* \brief Limits of the DXVK API
*
* Stores the number of binding slots
* available for all resource types.
*/
enum DxvkLimits : size_t {
MaxNumRenderTargets = 8,
MaxNumUniformBuffers = 16,
MaxNumSampledImages = 16,
MaxNumStorageBuffers = 128,
MaxNumStorageImages = 128,
MaxNumVertexBuffers = 32,
MaxNumOutputStreams = 4,
};
struct DxvkFramebufferState {
Rc<DxvkFramebuffer> framebuffer;
Flags<DxvkFbStateFlags> flags;
/**
* \brief Graphics pipeline state flags
*
* Stores some information on which state of the
* graphics pipeline has changed and/or needs to
* be updated.
*/
enum class DxvkGraphicsPipelineBit : uint64_t {
RenderPassBound = 0, ///< If set, a render pass instance is currently active
PipelineDirty = 1, ///< If set, the shader pipeline binding is out of date
PipelineStateDirty = 2, ///< If set, another pipeline variant needs to be bound
DirtyResources = 3, ///< If set, the descriptor set must be updated
DirtyVertexBuffers = 4, ///< If set, the vertex buffer bindings need to be updated
DirtyIndexBuffer = 5, ///< If set, the index buffer binding needs to be updated
};
using DxvkGraphicsPipelineFlags = Flags<DxvkGraphicsPipelineBit>;
/**
* \brief Compute pipeline state flags
*
* Stores information on whether the compute shader
* or any of its resource bindings have been updated.
*/
enum class DxvkComputePipelineBit : uint64_t {
PipelineDirty = 0, ///< If set, the shader pipeline binding is out of date
DirtyResources = 1, ///< If set, the descriptor set must be updated
};
using DxvkComputePipelineFlags = Flags<DxvkComputePipelineBit>;
/**
* \brief Shader state
*
* Stores the active shader and resources for a single
* shader stage. This includes sampled textures, uniform
* buffers, storage buffers and storage images.
*/
struct DxvkShaderState {
Rc<DxvkShader> shader;
};
/**
* \brief Graphics pipeline state
*
* Stores everything related to graphics
* operations, including bound resources.
*/
struct DxvkGraphicsPipelineState {
DxvkShaderState vs;
DxvkShaderState tcs;
DxvkShaderState tes;
DxvkShaderState gs;
DxvkShaderState fs;
Rc<DxvkFramebuffer> fb;
DxvkGraphicsPipelineFlags flags;
};
/**
* \brief Compute pipeline state
*
* Stores the active compute pipeline and
* resources bound to the compute shader.
*/
struct DxvkComputePipelineState {
DxvkShaderState cs;
Rc<DxvkComputePipeline> pipeline;
DxvkComputePipelineFlags flags;
};
/**
* \brief DXVK context state
*
* Stores all graphics pipeline state known
* to DXVK. As in Vulkan, graphics and compute
* pipeline states are strictly separated.
*/
struct DxvkContextState {
DxvkFramebufferState fb; ///< Framebuffer and render pass
DxvkGraphicsPipelineState g;
DxvkComputePipelineState c;
};
}

View File

@ -8,13 +8,13 @@ namespace dxvk {
void DxvkLifetimeTracker::trackResource(const Rc<DxvkResource>& rc) {
if (m_resources.insert(rc).second)
rc->incUseCount();
rc->acquire();
}
void DxvkLifetimeTracker::reset() {
for (auto i = m_resources.cbegin(); i != m_resources.cend(); i++)
(*i)->decUseCount();
(*i)->release();
m_resources.clear();
}

View File

@ -21,8 +21,8 @@ namespace dxvk {
return m_useCount != 0;
}
void incUseCount() { m_useCount += 1; }
void decUseCount() { m_useCount -= 1; }
void acquire() { m_useCount += 1; }
void release() { m_useCount -= 1; }
private:

View File

@ -1,6 +1,7 @@
dxvk_src = files([
'dxvk_adapter.cpp',
'dxvk_cmdlist.cpp',
'dxvk_compute.cpp',
'dxvk_context.cpp',
'dxvk_device.cpp',
'dxvk_framebuffer.cpp',