mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-30 02:52:10 +01:00
[dxvk] Restructured state tracker again
This commit is contained in:
parent
b367f6af55
commit
a84e2eabc2
@ -37,98 +37,19 @@ namespace dxvk {
|
||||
|
||||
virtual ~DxbcCodeGen();
|
||||
|
||||
/**
|
||||
* \brief Declares temporary registers
|
||||
* \param [in] n Number of temp registers
|
||||
*/
|
||||
void dclTemps(uint32_t n);
|
||||
|
||||
/**
|
||||
* \brief Declares an interface variable
|
||||
*
|
||||
* \param [in] regType Register type
|
||||
* \param [in] regId Interface register index
|
||||
* \param [in] regDim Array dimension of interface variable
|
||||
* \param [in] regMask Component mask for this declaration
|
||||
* \param [in] sv System value to map to the given components
|
||||
*/
|
||||
virtual void dclInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcComponentMask regMask,
|
||||
DxbcSystemValue sv) = 0;
|
||||
|
||||
/**
|
||||
* \brief Defines 32-bit constant
|
||||
*
|
||||
* The constant will be declared as a 32-bit
|
||||
* unsigned integer. Cast the resulting value
|
||||
* to the required type.
|
||||
* \param [in] v Constant value
|
||||
* \returns The constant value ID
|
||||
*/
|
||||
DxbcValue defConstScalar(uint32_t v);
|
||||
|
||||
/**
|
||||
* \brief Defines 32-bit constant vector
|
||||
*
|
||||
* Defines a four-component vector of 32-bit
|
||||
* unsigned integer values. Cast the resulting
|
||||
* value to the required type as needed.
|
||||
* \param [in] x First vector component
|
||||
* \param [in] y Second vector component
|
||||
* \param [in] z Third vector component
|
||||
* \param [in] w Fourth vector component
|
||||
* \returns The constant value ID
|
||||
*/
|
||||
DxbcValue defConstVector(
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t z, uint32_t w);
|
||||
|
||||
/**
|
||||
* \brief Returns from function
|
||||
*/
|
||||
void fnReturn();
|
||||
|
||||
/**
|
||||
* \brief Retrieves temporary register pointer
|
||||
*
|
||||
* Provides access to a temporary register.
|
||||
* \param [in] regId Register index
|
||||
* \returns Register pointer
|
||||
*/
|
||||
DxbcPointer ptrTempReg(
|
||||
uint32_t regId);
|
||||
|
||||
/**
|
||||
* \brief Pointer to an interface variable
|
||||
*
|
||||
* Provides access to an interface variable.
|
||||
* \param [in] regType Register type
|
||||
* \param [in] regId Register index
|
||||
* \returns Register pointer
|
||||
*/
|
||||
virtual DxbcPointer ptrInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId) = 0;
|
||||
|
||||
/**
|
||||
* \brief Pointer to an interface variable
|
||||
*
|
||||
* Provides access to an indexed interface variable.
|
||||
* Some shader types may have indexed input or output
|
||||
* variables that can be accesswed via an array index.
|
||||
* \param [in] regType Register type
|
||||
* \param [in] regId Register index
|
||||
* \param [in] index Array index
|
||||
* \returns Register pointer
|
||||
*/
|
||||
virtual DxbcPointer ptrInterfaceVarIndexed(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
const DxbcValue& index) = 0;
|
||||
|
||||
DxbcValue opAbs(
|
||||
const DxbcValue& src);
|
||||
|
||||
@ -146,99 +67,50 @@ namespace dxvk {
|
||||
DxbcValue opSaturate(
|
||||
const DxbcValue& src);
|
||||
|
||||
/**
|
||||
* \brief Casts register value to another type
|
||||
*
|
||||
* Type cast that does not change the bit pattern
|
||||
* of the value. This is required as DXBC values
|
||||
* are not statically typed, but SPIR-V is.
|
||||
* \param [in] src Source value
|
||||
* \param [in] type Destination type
|
||||
* \returns Resulting register value
|
||||
*/
|
||||
DxbcValue regCast(
|
||||
const DxbcValue& src,
|
||||
const DxbcValueType& type);
|
||||
|
||||
/**
|
||||
* \brief Extracts vector components
|
||||
*
|
||||
* Extracts the given set of components.
|
||||
* \param [in] src Source vector
|
||||
* \param [in] mask Component mask
|
||||
* \returns Resulting register value
|
||||
*/
|
||||
DxbcValue regExtract(
|
||||
const DxbcValue& src,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
/**
|
||||
* \brief Swizzles a vector register
|
||||
*
|
||||
* Swizzles the vector and extracts
|
||||
* the given set of vector components.
|
||||
* \param [in] src Source vector to swizzle
|
||||
* \param [in] swizzle The component swizzle
|
||||
* \param [in] mask Components to extract
|
||||
* \returns Resulting register value
|
||||
*/
|
||||
DxbcValue regSwizzle(
|
||||
const DxbcValue& src,
|
||||
const DxbcComponentSwizzle& swizzle,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
/**
|
||||
* \brief Writes to parts of a vector register
|
||||
*
|
||||
* Note that the source value must have the same
|
||||
* number of components as the write mask.
|
||||
* \param [in] dst Destination value ID
|
||||
* \param [in] src Source value ID
|
||||
* \param [in] mask Write mask
|
||||
* \returns New destination value ID
|
||||
*/
|
||||
DxbcValue regInsert(
|
||||
const DxbcValue& dst,
|
||||
const DxbcValue& src,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
/**
|
||||
* \brief Loads register
|
||||
*
|
||||
* \param [in] ptr Register pointer
|
||||
* \returns The register value ID
|
||||
*/
|
||||
DxbcValue regLoad(
|
||||
const DxbcPointer& ptr);
|
||||
|
||||
/**
|
||||
* \brief Stores register
|
||||
*
|
||||
* \param [in] ptr Register pointer
|
||||
* \param [in] val Value ID to store
|
||||
* \param [in] mask Write mask
|
||||
*/
|
||||
void regStore(
|
||||
const DxbcPointer& ptr,
|
||||
const DxbcValue& val,
|
||||
DxbcComponentMask mask);
|
||||
|
||||
/**
|
||||
* \brief Finalizes shader
|
||||
*
|
||||
* Depending on the shader stage, this may generate
|
||||
* additional code to set up input variables, output
|
||||
* variables, and execute shader phases.
|
||||
* \returns DXVK shader module
|
||||
*/
|
||||
virtual void dclInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
uint32_t regDim,
|
||||
DxbcComponentMask regMask,
|
||||
DxbcSystemValue sv) = 0;
|
||||
|
||||
virtual DxbcPointer ptrInterfaceVar(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId) = 0;
|
||||
|
||||
virtual DxbcPointer ptrInterfaceVarIndexed(
|
||||
DxbcOperandType regType,
|
||||
uint32_t regId,
|
||||
const DxbcValue& index) = 0;
|
||||
|
||||
virtual Rc<DxvkShader> finalize() = 0;
|
||||
|
||||
/**
|
||||
* \brief Creates code generator for a given program type
|
||||
*
|
||||
* \param [in] version Program version
|
||||
* \returns The code generator
|
||||
*/
|
||||
static Rc<DxbcCodeGen> create(
|
||||
const DxbcProgramVersion& version);
|
||||
|
||||
|
@ -21,38 +21,34 @@ namespace dxvk {
|
||||
void DxvkContext::beginRecording(
|
||||
const Rc<DxvkRecorder>& recorder) {
|
||||
TRACE(this, recorder);
|
||||
|
||||
m_cmd = recorder;
|
||||
m_cmd->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);
|
||||
// The current state of the internal command buffer is
|
||||
// undefined, so we have to bind and set up everything
|
||||
// before any draw or dispatch command is recorded.
|
||||
m_state.flags.clr(
|
||||
DxvkContextFlag::GpRenderPassBound);
|
||||
|
||||
m_state.c.flags.set(
|
||||
DxvkComputePipelineBit::PipelineDirty,
|
||||
DxvkComputePipelineBit::DirtyResources);
|
||||
m_state.flags.set(
|
||||
DxvkContextFlag::GpDirtyPipeline,
|
||||
DxvkContextFlag::GpDirtyPipelineState,
|
||||
DxvkContextFlag::GpDirtyResources,
|
||||
DxvkContextFlag::GpDirtyIndexBuffers,
|
||||
DxvkContextFlag::GpDirtyVertexBuffers,
|
||||
DxvkContextFlag::CpDirtyPipeline,
|
||||
DxvkContextFlag::CpDirtyResources);
|
||||
}
|
||||
|
||||
|
||||
bool DxvkContext::endRecording() {
|
||||
void DxvkContext::endRecording() {
|
||||
TRACE(this);
|
||||
|
||||
// Any currently active render pass must be
|
||||
// ended before finalizing the command buffer.
|
||||
if (m_state.g.flags.test(DxvkGraphicsPipelineBit::RenderPassBound))
|
||||
this->endRenderPass();
|
||||
this->renderPassEnd();
|
||||
|
||||
// Finalize the command list
|
||||
m_cmd->endRecording();
|
||||
m_cmd = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -60,12 +56,9 @@ namespace dxvk {
|
||||
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();
|
||||
if (m_state.om.framebuffer != fb) {
|
||||
m_state.om.framebuffer = fb;
|
||||
this->renderPassEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,34 +68,23 @@ namespace dxvk {
|
||||
const Rc<DxvkShader>& shader) {
|
||||
TRACE(this, stage, shader);
|
||||
|
||||
DxvkShaderState* state = this->getShaderState(stage);
|
||||
DxvkShaderStageState* stageState = this->getShaderStage(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());
|
||||
if (stageState->shader != shader) {
|
||||
stageState->shader = shader;
|
||||
|
||||
if (stage == VK_SHADER_STAGE_COMPUTE_BIT) {
|
||||
m_state.flags.set(
|
||||
DxvkContextFlag::CpDirtyPipeline,
|
||||
DxvkContextFlag::CpDirtyResources);
|
||||
} else {
|
||||
m_state.flags.set(
|
||||
DxvkContextFlag::GpDirtyPipeline,
|
||||
DxvkContextFlag::GpDirtyPipelineState,
|
||||
DxvkContextFlag::GpDirtyResources,
|
||||
DxvkContextFlag::GpDirtyVertexBuffers,
|
||||
DxvkContextFlag::GpDirtyIndexBuffers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,28 +92,18 @@ namespace dxvk {
|
||||
void DxvkContext::clearRenderTarget(
|
||||
const VkClearAttachment& attachment,
|
||||
const VkClearRect& clearArea) {
|
||||
this->flushGraphicsState();
|
||||
TRACE(this);
|
||||
|
||||
// We only need the framebuffer to be bound. Flushing the
|
||||
// entire pipeline state is not required and might actually
|
||||
// cause problems if the current pipeline state is invalid.
|
||||
this->renderPassBegin();
|
||||
|
||||
m_cmd->cmdClearAttachments(
|
||||
1, &attachment, 1, &clearArea);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::dispatch(
|
||||
uint32_t wgCountX,
|
||||
uint32_t wgCountY,
|
||||
uint32_t wgCountZ) {
|
||||
TRACE(this, wgCountX, wgCountY, wgCountZ);
|
||||
this->endRenderPass();
|
||||
this->flushComputeState();
|
||||
|
||||
m_cmd->cmdDispatch(
|
||||
wgCountX, wgCountY, wgCountZ);
|
||||
|
||||
// TODO resource barriers
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::draw(
|
||||
uint32_t vertexCount,
|
||||
uint32_t instanceCount,
|
||||
@ -139,11 +111,6 @@ namespace dxvk {
|
||||
uint32_t firstInstance) {
|
||||
TRACE(this, vertexCount, instanceCount,
|
||||
firstVertex, firstInstance);
|
||||
this->flushGraphicsState();
|
||||
|
||||
m_cmd->cmdDraw(
|
||||
vertexCount, instanceCount,
|
||||
firstVertex, firstInstance);
|
||||
}
|
||||
|
||||
|
||||
@ -155,162 +122,86 @@ namespace dxvk {
|
||||
uint32_t firstInstance) {
|
||||
TRACE(this, indexCount, instanceCount,
|
||||
firstIndex, vertexOffset, firstInstance);
|
||||
this->flushGraphicsState();
|
||||
|
||||
m_cmd->cmdDrawIndexed(
|
||||
indexCount, instanceCount,
|
||||
firstIndex, vertexOffset,
|
||||
firstInstance);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::flushComputeState() {
|
||||
if (m_state.c.flags.test(DxvkComputePipelineBit::PipelineDirty)) {
|
||||
m_state.c.pipeline = m_pipeMgr->getComputePipeline(m_state.c.cs.shader);
|
||||
void DxvkContext::renderPassBegin() {
|
||||
if (!m_state.flags.test(DxvkContextFlag::GpRenderPassBound)
|
||||
&& (m_state.om.framebuffer != nullptr)) {
|
||||
m_state.flags.set(DxvkContextFlag::GpRenderPassBound);
|
||||
|
||||
if (m_state.c.pipeline != nullptr) {
|
||||
m_cmd->cmdBindPipeline(
|
||||
VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||
m_state.c.pipeline->getPipelineHandle());
|
||||
}
|
||||
const DxvkFramebufferSize fbSize
|
||||
= m_state.om.framebuffer->size();
|
||||
|
||||
VkRect2D renderArea;
|
||||
renderArea.offset = VkOffset2D { 0, 0 };
|
||||
renderArea.extent = VkExtent2D { fbSize.width, fbSize.height };
|
||||
|
||||
VkRenderPassBeginInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.renderPass = m_state.om.framebuffer->renderPass();
|
||||
info.framebuffer = m_state.om.framebuffer->handle();
|
||||
info.renderArea = renderArea;
|
||||
info.clearValueCount = 0;
|
||||
info.pClearValues = nullptr;
|
||||
|
||||
m_cmd->cmdBeginRenderPass(&info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::renderPassEnd() {
|
||||
if (m_state.flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||
m_state.flags.clr(DxvkContextFlag::GpRenderPassBound);
|
||||
m_cmd->cmdEndRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::bindGraphicsPipeline() {
|
||||
if (m_state.flags.test(DxvkContextFlag::GpDirtyPipeline)) {
|
||||
m_state.flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
||||
|
||||
m_state.activeGraphicsPipeline = m_pipeMgr->getGraphicsPipeline(
|
||||
m_state.vs.shader, m_state.tcs.shader, m_state.tes.shader,
|
||||
m_state.gs.shader, m_state.fs.shader);
|
||||
}
|
||||
|
||||
if (m_state.c.flags.test(DxvkComputePipelineBit::DirtyResources)
|
||||
&& m_state.c.pipeline != nullptr) {
|
||||
std::vector<DxvkResourceBinding> bindings;
|
||||
this->addResourceBindingInfo(bindings, m_state.c.cs);
|
||||
if (m_state.flags.test(DxvkContextFlag::GpDirtyPipelineState)
|
||||
&& m_state.activeGraphicsPipeline != nullptr) {
|
||||
m_state.flags.clr(DxvkContextFlag::GpDirtyPipelineState);
|
||||
|
||||
m_cmd->bindShaderResources(
|
||||
VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||
m_state.c.pipeline->pipelineLayout(),
|
||||
m_state.c.pipeline->descriptorSetLayout(),
|
||||
bindings.size(), bindings.data());
|
||||
DxvkGraphicsPipelineStateInfo gpState;
|
||||
gpState.renderPass = m_state.om.framebuffer->renderPass();
|
||||
|
||||
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_state.activeGraphicsPipeline->getPipelineHandle(gpState));
|
||||
}
|
||||
|
||||
m_state.c.flags.clr(
|
||||
DxvkComputePipelineBit::PipelineDirty,
|
||||
DxvkComputePipelineBit::DirtyResources);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::flushGraphicsState() {
|
||||
if (!m_state.g.flags.test(DxvkGraphicsPipelineBit::RenderPassBound))
|
||||
this->beginRenderPass();
|
||||
this->renderPassBegin();
|
||||
this->bindGraphicsPipeline();
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::beginRenderPass() {
|
||||
TRACE(this);
|
||||
|
||||
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.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_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
m_state.g.flags.set(DxvkGraphicsPipelineBit::RenderPassBound);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::endRenderPass() {
|
||||
TRACE(this);
|
||||
|
||||
m_cmd->cmdEndRenderPass();
|
||||
m_state.g.flags.clr(DxvkGraphicsPipelineBit::RenderPassBound);
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
DxvkShaderStageState* DxvkContext::getShaderStage(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_VERTEX_BIT: return &m_state.vs;
|
||||
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return &m_state.tcs;
|
||||
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return &m_state.tes;
|
||||
case VK_SHADER_STAGE_GEOMETRY_BIT: return &m_state.gs;
|
||||
case VK_SHADER_STAGE_FRAGMENT_BIT: return &m_state.fs;
|
||||
case VK_SHADER_STAGE_COMPUTE_BIT: return &m_state.cs;
|
||||
|
||||
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;
|
||||
throw DxvkError(str::format(
|
||||
"DxvkContext::getShaderStage: Invalid stage bit: ",
|
||||
static_cast<uint32_t>(stage)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkContext::addResourceBindingInfo(
|
||||
std::vector<DxvkResourceBinding>& bindings,
|
||||
const DxvkShaderState& stageInfo) const {
|
||||
const uint32_t slotCount = stageInfo.shader->slotCount();
|
||||
|
||||
for (uint32_t i = 0; i < slotCount; i++) {
|
||||
DxvkResourceSlot slot = stageInfo.shader->slot(i);
|
||||
DxvkResourceBinding binding;
|
||||
|
||||
switch (slot.type) {
|
||||
case DxvkResourceType::ImageSampler:
|
||||
binding.type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||
break;
|
||||
|
||||
case DxvkResourceType::SampledImage:
|
||||
binding.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||
break;
|
||||
|
||||
case DxvkResourceType::StorageImage:
|
||||
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
break;
|
||||
|
||||
case DxvkResourceType::UniformBuffer:
|
||||
binding.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
binding.buffer = stageInfo.boundUniformBuffers.at(slot.slot).descriptorInfo();
|
||||
break;
|
||||
|
||||
case DxvkResourceType::StorageBuffer:
|
||||
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
binding.buffer = stageInfo.boundStorageBuffers.at(slot.slot).descriptorInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
bindings.push_back(binding);
|
||||
}
|
||||
|
||||
return slotCount;
|
||||
}
|
||||
|
||||
}
|
@ -43,17 +43,10 @@ namespace dxvk {
|
||||
* The command list can then be submitted to
|
||||
* the device.
|
||||
*
|
||||
* The return value of this method can be used to
|
||||
* determine whether the command list needs to be
|
||||
* submitted. In case the command list is empty,
|
||||
* \c false will be returned and it shall not be
|
||||
* submitted to the device.
|
||||
*
|
||||
* This will not change any context state
|
||||
* other than the active command list.
|
||||
* \returns \c true if any commands were recorded
|
||||
*/
|
||||
bool endRecording();
|
||||
void endRecording();
|
||||
|
||||
/**
|
||||
* \brief Sets framebuffer
|
||||
@ -76,20 +69,6 @@ namespace dxvk {
|
||||
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
|
||||
*
|
||||
@ -100,18 +79,6 @@ 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
|
||||
*
|
||||
@ -150,25 +117,16 @@ namespace dxvk {
|
||||
Rc<DxvkRecorder> m_cmd;
|
||||
DxvkContextState m_state;
|
||||
|
||||
void flushComputeState();
|
||||
void renderPassBegin();
|
||||
|
||||
void renderPassEnd();
|
||||
|
||||
void bindGraphicsPipeline();
|
||||
|
||||
void flushGraphicsState();
|
||||
|
||||
void beginRenderPass();
|
||||
void endRenderPass();
|
||||
|
||||
void setPipelineDirty(VkShaderStageFlagBits stage);
|
||||
void setResourcesDirty(VkShaderStageFlagBits stage);
|
||||
|
||||
void shaderResourceBarriers(
|
||||
DxvkBarrierSet& barriers,
|
||||
VkShaderStageFlagBits stage);
|
||||
|
||||
DxvkShaderState* getShaderState(
|
||||
VkShaderStageFlagBits stage);
|
||||
|
||||
uint32_t addResourceBindingInfo(
|
||||
std::vector<DxvkResourceBinding>& bindings,
|
||||
const DxvkShaderState& stageInfo) const;
|
||||
DxvkShaderStageState* getShaderStage(
|
||||
VkShaderStageFlagBits stage);
|
||||
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "dxvk_buffer.h"
|
||||
#include "dxvk_compute.h"
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_graphics.h"
|
||||
#include "dxvk_image.h"
|
||||
#include "dxvk_limits.h"
|
||||
#include "dxvk_shader.h"
|
||||
@ -16,87 +17,64 @@ namespace dxvk {
|
||||
* 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
|
||||
enum class DxvkContextFlag : uint64_t {
|
||||
GpRenderPassBound, ///< Render pass is currently bound
|
||||
GpDirtyPipeline, ///< Graphics pipeline binding are out of date
|
||||
GpDirtyPipelineState, ///< Graphics pipeline state (blending etc.) is dirty
|
||||
GpDirtyResources, ///< Graphics pipeline resource bindings are out of date
|
||||
GpDirtyVertexBuffers, ///< Vertex buffer bindings are out of date
|
||||
GpDirtyIndexBuffers, ///< Index buffer binding are out of date
|
||||
|
||||
CpDirtyPipeline, ///< Compute pipeline binding are out of date
|
||||
CpDirtyResources, ///< Compute pipeline resource bindings are out of date
|
||||
};
|
||||
|
||||
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>;
|
||||
using DxvkContextFlags = Flags<DxvkContextFlag>;
|
||||
|
||||
|
||||
/**
|
||||
* \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.
|
||||
* Stores the active shader and resources
|
||||
* for a single shader stage. All stages
|
||||
* support the same types of resources.
|
||||
*/
|
||||
struct DxvkShaderState {
|
||||
Rc<DxvkShader> shader;
|
||||
|
||||
std::array<DxvkBufferBinding, MaxNumStorageBuffers> boundStorageBuffers;
|
||||
std::array<DxvkBufferBinding, MaxNumUniformBuffers> boundUniformBuffers;
|
||||
struct DxvkShaderStageState {
|
||||
Rc<DxvkShader> shader;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Graphics pipeline state
|
||||
* \brief Output merger state
|
||||
*
|
||||
* Stores everything related to graphics
|
||||
* operations, including bound resources.
|
||||
* Stores the active framebuffer and the current
|
||||
* blend state, as well as the depth stencil state.
|
||||
*/
|
||||
struct DxvkGraphicsPipelineState {
|
||||
DxvkShaderState vs;
|
||||
DxvkShaderState tcs;
|
||||
DxvkShaderState tes;
|
||||
DxvkShaderState gs;
|
||||
DxvkShaderState fs;
|
||||
Rc<DxvkFramebuffer> fb;
|
||||
DxvkGraphicsPipelineFlags flags;
|
||||
struct DxvkOutputMergerState {
|
||||
Rc<DxvkFramebuffer> framebuffer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Compute pipeline state
|
||||
* \brief 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.
|
||||
* Stores all bound shaders, resources,
|
||||
* and constant pipeline state objects.
|
||||
*/
|
||||
struct DxvkContextState {
|
||||
DxvkGraphicsPipelineState g;
|
||||
DxvkComputePipelineState c;
|
||||
DxvkShaderStageState vs;
|
||||
DxvkShaderStageState tcs;
|
||||
DxvkShaderStageState tes;
|
||||
DxvkShaderStageState gs;
|
||||
DxvkShaderStageState fs;
|
||||
DxvkShaderStageState cs;
|
||||
|
||||
DxvkOutputMergerState om;
|
||||
|
||||
Rc<DxvkGraphicsPipeline> activeGraphicsPipeline;
|
||||
Rc<DxvkComputePipeline> activeComputePipeline;
|
||||
|
||||
DxvkContextFlags flags;
|
||||
};
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ namespace dxvk {
|
||||
|
||||
|
||||
bool DxvkGraphicsPipelineStateInfo::operator == (const DxvkGraphicsPipelineStateInfo& other) const {
|
||||
// TODO implement
|
||||
return this->renderPass == other.renderPass;
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,6 +9,11 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Graphics pipeline state info
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct DxvkGraphicsPipelineStateInfo {
|
||||
VkRenderPass renderPass;
|
||||
|
||||
@ -18,6 +23,7 @@ namespace dxvk {
|
||||
bool operator != (const DxvkGraphicsPipelineStateInfo& other) const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Graphics pipeline
|
||||
*
|
||||
|
@ -28,38 +28,6 @@ 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;
|
||||
|
||||
SpirvCodeBuffer code(std::ifstream("comp.spv", std::ios::binary));
|
||||
code.store(std::ofstream("comp.2.spv", std::ios::binary));
|
||||
|
||||
m_compShader = new DxvkShader(
|
||||
VK_SHADER_STAGE_COMPUTE_BIT, std::move(code),
|
||||
1, &computeBufferSlot);
|
||||
}
|
||||
|
||||
~TriangleApp() {
|
||||
@ -92,22 +60,12 @@ 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(
|
||||
m_dxvkCommandList, sync1, sync2);
|
||||
m_dxvkSwapchain->present(sync2);
|
||||
m_dxvkDevice->waitForIdle();
|
||||
|
||||
std::memcpy(m_testData, m_testBuffer->mapPtr(), sizeof(m_testData));
|
||||
std::cout << m_testData[0] << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -120,13 +78,6 @@ 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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user