1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-02 01:24:11 +01:00

Merge branch 'clearopt'

This commit is contained in:
Philip Rebohle 2018-05-02 00:45:17 +02:00
commit 5683422208
14 changed files with 242 additions and 97 deletions

View File

@ -42,19 +42,50 @@ namespace dxvk {
VkPipeline DxvkComputePipeline::getPipelineHandle(
const DxvkComputePipelineStateInfo& state,
DxvkStatCounters& stats) {
for (const PipelineStruct& pair : m_pipelines) {
if (pair.stateVector == state)
return pair.pipeline;
VkPipeline pipeline = VK_NULL_HANDLE;
{ std::lock_guard<sync::Spinlock> lock(m_mutex);
if (this->findPipeline(state, pipeline))
return pipeline;
}
VkPipeline pipeline = this->compilePipeline(state, m_basePipeline);
m_pipelines.push_back({ state, pipeline });
// If no pipeline exists with the given state vector,
// create a new one and add it to the pipeline set.
VkPipeline newPipeline = this->compilePipeline(state, m_basePipeline);
if (m_basePipeline == VK_NULL_HANDLE)
m_basePipeline = pipeline;
{ std::lock_guard<sync::Spinlock> lock(m_mutex);
// Discard the pipeline if another thread
// was faster compiling the same pipeline
if (this->findPipeline(state, pipeline)) {
m_vkd->vkDestroyPipeline(m_vkd->device(), newPipeline, nullptr);
return pipeline;
}
// Add new pipeline to the set
m_pipelines.push_back({ state, newPipeline });
if (m_basePipeline == VK_NULL_HANDLE)
m_basePipeline = newPipeline;
stats.addCtr(DxvkStatCounter::PipeCountCompute, 1);
return newPipeline;
}
}
bool DxvkComputePipeline::findPipeline(
const DxvkComputePipelineStateInfo& state,
VkPipeline& pipeline) const {
for (const PipelineStruct& pair : m_pipelines) {
if (pair.stateVector == state) {
pipeline = pair.pipeline;
return true;
}
}
stats.addCtr(DxvkStatCounter::PipeCountCompute, 1);
return pipeline;
return false;
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <vector>
#include "dxvk_binding.h"
#include "dxvk_pipecache.h"
#include "dxvk_pipelayout.h"
@ -76,10 +78,15 @@ namespace dxvk {
Rc<DxvkPipelineLayout> m_layout;
Rc<DxvkShaderModule> m_cs;
sync::Spinlock m_mutex;
std::vector<PipelineStruct> m_pipelines;
VkPipeline m_basePipeline = VK_NULL_HANDLE;
bool findPipeline(
const DxvkComputePipelineStateInfo& state,
VkPipeline& pipeline) const;
VkPipeline compilePipeline(
const DxvkComputePipelineStateInfo& state,
VkPipeline baseHandle) const;

View File

@ -9,10 +9,11 @@ namespace dxvk {
DxvkContext::DxvkContext(
const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineCache>& pipelineCache,
const Rc<DxvkPipelineManager>& pipelineManager,
const Rc<DxvkMetaClearObjects>& metaClearObjects)
: m_device (device),
m_pipeCache (pipelineCache),
m_pipeMgr (new DxvkPipelineManager(device.ptr())),
m_pipeMgr (pipelineManager),
m_metaClear (metaClearObjects) { }
@ -29,7 +30,8 @@ namespace dxvk {
// undefined, so we have to bind and set up everything
// before any draw or dispatch command is recorded.
m_flags.clr(
DxvkContextFlag::GpRenderPassBound);
DxvkContextFlag::GpRenderPassBound,
DxvkContextFlag::GpClearRenderTargets);
m_flags.set(
DxvkContextFlag::GpDirtyPipeline,
@ -88,7 +90,9 @@ namespace dxvk {
void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) {
m_state.om.renderTargets = targets;
// TODO execute pending clears
// If necessary, perform clears on the active render targets
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
this->startRenderPass();
// Set up default render pass ops
this->resetRenderPassOps(
@ -386,6 +390,35 @@ namespace dxvk {
const VkClearValue& clearValue) {
this->updateFramebuffer();
// Prepare attachment ops
DxvkColorAttachmentOps colorOp;
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
colorOp.loadLayout = imageView->imageInfo().layout;
colorOp.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorOp.storeLayout = imageView->imageInfo().layout;
DxvkDepthAttachmentOps depthOp;
depthOp.loadOpD = VK_ATTACHMENT_LOAD_OP_LOAD;
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
depthOp.loadLayout = imageView->imageInfo().layout;
depthOp.storeOpD = VK_ATTACHMENT_STORE_OP_STORE;
depthOp.storeOpS = VK_ATTACHMENT_STORE_OP_STORE;
depthOp.storeLayout = imageView->imageInfo().layout;
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
if (clearAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
depthOp.loadOpD = VK_ATTACHMENT_LOAD_OP_CLEAR;
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
if (clearAspects == imageView->info().aspect) {
colorOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
// Check whether the render target view is an attachment
// of the current framebuffer. If not, we need to create
// a temporary framebuffer.
@ -397,12 +430,6 @@ namespace dxvk {
if (attachmentIndex < 0) {
this->spillRenderPass();
DxvkAttachmentOps op;
op.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
op.loadLayout = imageView->imageInfo().layout;
op.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
op.storeLayout = imageView->imageInfo().layout;
// Set up and bind a temporary framebuffer
DxvkRenderTargets attachments;
DxvkRenderPassOps ops;
@ -410,37 +437,39 @@ namespace dxvk {
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
attachments.color[0].view = imageView;
attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
ops.colorOps[0] = op;
ops.colorOps[0] = colorOp;
} else {
attachments.depth.view = imageView;
attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
ops.depthOps = op;
ops.depthOps = depthOp;
}
this->renderPassBindFramebuffer(
m_device->createFramebuffer(attachments), ops);
} else {
// Make sure that the currently bound
// framebuffer can be rendered to
this->startRenderPass();
}
// Clear the attachment in quesion
VkClearAttachment clearInfo;
clearInfo.aspectMask = clearAspects;
clearInfo.colorAttachment = attachmentIndex;
clearInfo.clearValue = clearValue;
if (attachmentIndex < 0)
clearInfo.colorAttachment = 0;
m_cmd->cmdClearAttachments(
1, &clearInfo, 1, &clearRect);
// If we used a temporary framebuffer, we'll have to unbind it
// again in order to not disturb subsequent rendering commands.
if (attachmentIndex < 0)
m_device->createFramebuffer(attachments),
ops, 1, &clearValue);
this->renderPassUnbindFramebuffer();
} else if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
// Clear the attachment in quesion. For color images,
// the attachment index for the current subpass is
// equal to the render pass attachment index.
VkClearAttachment clearInfo;
clearInfo.aspectMask = clearAspects;
clearInfo.colorAttachment = attachmentIndex;
clearInfo.clearValue = clearValue;
m_cmd->cmdClearAttachments(
1, &clearInfo, 1, &clearRect);
} else {
// Perform the clear when starting the render pass
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
m_state.om.renderPassOps.colorOps[attachmentIndex] = colorOp;
if (clearAspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
m_state.om.renderPassOps.depthOps = depthOp;
m_state.om.clearValues[attachmentIndex] = clearValue;
m_flags.set(DxvkContextFlag::GpClearRenderTargets);
}
}
@ -1519,10 +1548,13 @@ namespace dxvk {
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)
&& (m_state.om.framebuffer != nullptr)) {
m_flags.set(DxvkContextFlag::GpRenderPassBound);
m_flags.clr(DxvkContextFlag::GpClearRenderTargets);
this->renderPassBindFramebuffer(
m_state.om.framebuffer,
m_state.om.renderPassOps);
m_state.om.renderPassOps,
m_state.om.clearValues.size(),
m_state.om.clearValues.data());
// Don't discard image contents if we have
// to spill the current render pass
@ -1534,7 +1566,8 @@ namespace dxvk {
void DxvkContext::spillRenderPass() {
// TODO execute pending clears
if (m_flags.test(DxvkContextFlag::GpClearRenderTargets))
this->startRenderPass();
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
@ -1545,7 +1578,9 @@ namespace dxvk {
void DxvkContext::renderPassBindFramebuffer(
const Rc<DxvkFramebuffer>& framebuffer,
const DxvkRenderPassOps& ops) {
const DxvkRenderPassOps& ops,
uint32_t clearValueCount,
const VkClearValue* clearValues) {
const DxvkFramebufferSize fbSize = framebuffer->size();
VkRect2D renderArea;
@ -1558,8 +1593,8 @@ namespace dxvk {
info.renderPass = framebuffer->getRenderPassHandle(ops);
info.framebuffer = framebuffer->handle();
info.renderArea = renderArea;
info.clearValueCount = 0;
info.pClearValues = nullptr;
info.clearValueCount = clearValueCount;
info.pClearValues = clearValues;
m_cmd->cmdBeginRenderPass(&info,
VK_SUBPASS_CONTENTS_INLINE);
@ -1577,17 +1612,23 @@ namespace dxvk {
const DxvkRenderTargets& renderTargets,
DxvkRenderPassOps& renderPassOps) {
renderPassOps.depthOps = renderTargets.depth.view != nullptr
? DxvkAttachmentOps {
VK_ATTACHMENT_LOAD_OP_LOAD, renderTargets.depth.view->imageInfo().layout,
VK_ATTACHMENT_STORE_OP_STORE, renderTargets.depth.view->imageInfo().layout }
: DxvkAttachmentOps { };
? DxvkDepthAttachmentOps {
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_LOAD_OP_LOAD,
renderTargets.depth.view->imageInfo().layout,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_STORE_OP_STORE,
renderTargets.depth.view->imageInfo().layout }
: DxvkDepthAttachmentOps { };
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
renderPassOps.colorOps[i] = renderTargets.color[i].view != nullptr
? DxvkAttachmentOps {
VK_ATTACHMENT_LOAD_OP_LOAD, renderTargets.color[i].view->imageInfo().layout,
VK_ATTACHMENT_STORE_OP_STORE, renderTargets.color[i].view->imageInfo().layout }
: DxvkAttachmentOps { };
? DxvkColorAttachmentOps {
VK_ATTACHMENT_LOAD_OP_LOAD,
renderTargets.color[i].view->imageInfo().layout,
VK_ATTACHMENT_STORE_OP_STORE,
renderTargets.color[i].view->imageInfo().layout }
: DxvkColorAttachmentOps { };
}
// TODO provide a sane alternative for this

View File

@ -30,6 +30,7 @@ namespace dxvk {
DxvkContext(
const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineCache>& pipelineCache,
const Rc<DxvkPipelineManager>& pipelineManager,
const Rc<DxvkMetaClearObjects>& metaClearObjects);
~DxvkContext();
@ -644,7 +645,9 @@ namespace dxvk {
void renderPassBindFramebuffer(
const Rc<DxvkFramebuffer>& framebuffer,
const DxvkRenderPassOps& ops);
const DxvkRenderPassOps& ops,
uint32_t clearValueCount,
const VkClearValue* clearValues);
void renderPassUnbindFramebuffer();

View File

@ -16,12 +16,13 @@ namespace dxvk {
/**
* \brief Graphics pipeline state flags
*
* Stores some information on which state of the
* graphics pipeline has changed and/or needs to
* be updated.
* Stores some information on which state
* of the graphics and compute pipelines
* has changed and/or needs to be updated.
*/
enum class DxvkContextFlag : uint64_t {
GpRenderPassBound, ///< Render pass is currently bound
GpClearRenderTargets, ///< Render targets need to be cleared
GpDirtyFramebuffer, ///< Framebuffer binding is out of date
GpDirtyPipeline, ///< Graphics pipeline binding is out of date
GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled
@ -54,7 +55,7 @@ namespace dxvk {
struct DxvkOutputMergerState {
std::array<VkClearValue, MaxNumRenderTargets + 1> clearValue;
std::array<VkClearValue, MaxNumRenderTargets + 1> clearValues = { };
DxvkRenderTargets renderTargets;
DxvkRenderPassOps renderPassOps;

View File

@ -16,6 +16,7 @@ namespace dxvk {
m_memory (new DxvkMemoryAllocator (adapter, vkd)),
m_renderPassPool (new DxvkRenderPassPool (vkd)),
m_pipelineCache (new DxvkPipelineCache (vkd)),
m_pipelineManager (new DxvkPipelineManager (this)),
m_metaClearObjects(new DxvkMetaClearObjects (vkd)),
m_unboundResources(this),
m_submissionQueue (this) {
@ -106,6 +107,7 @@ namespace dxvk {
Rc<DxvkContext> DxvkDevice::createContext() {
return new DxvkContext(this,
m_pipelineCache,
m_pipelineManager,
m_metaClearObjects);
}

View File

@ -355,6 +355,7 @@ namespace dxvk {
Rc<DxvkMemoryAllocator> m_memory;
Rc<DxvkRenderPassPool> m_renderPassPool;
Rc<DxvkPipelineCache> m_pipelineCache;
Rc<DxvkPipelineManager> m_pipelineManager;
Rc<DxvkMetaClearObjects> m_metaClearObjects;
DxvkUnboundResources m_unboundResources;

View File

@ -13,20 +13,18 @@ namespace dxvk {
m_renderSize (computeRenderSize(defaultSize)) {
std::array<VkImageView, MaxNumRenderTargets + 1> views;
uint32_t viewId = 0;
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (m_renderTargets.color[i].view != nullptr) {
views[viewId] = m_renderTargets.color[i].view->handle();
m_attachments[viewId] = &m_renderTargets.color[i];
viewId += 1;
views[m_attachmentCount] = m_renderTargets.color[i].view->handle();
m_attachments[m_attachmentCount] = &m_renderTargets.color[i];
m_attachmentCount += 1;
}
}
if (m_renderTargets.depth.view != nullptr) {
views[viewId] = m_renderTargets.depth.view->handle();
m_attachments[viewId] = &m_renderTargets.depth;
viewId += 1;
views[m_attachmentCount] = m_renderTargets.depth.view->handle();
m_attachments[m_attachmentCount] = &m_renderTargets.depth;
m_attachmentCount += 1;
}
VkFramebufferCreateInfo info;
@ -34,7 +32,7 @@ namespace dxvk {
info.pNext = nullptr;
info.flags = 0;
info.renderPass = m_renderPass->getDefaultHandle();
info.attachmentCount = viewId;
info.attachmentCount = m_attachmentCount;
info.pAttachments = views.data();
info.width = m_renderSize.width;
info.height = m_renderSize.height;

View File

@ -78,23 +78,52 @@ namespace dxvk {
VkPipeline DxvkGraphicsPipeline::getPipelineHandle(
const DxvkGraphicsPipelineStateInfo& state,
DxvkStatCounters& stats) {
VkPipeline pipeline = VK_NULL_HANDLE;
for (const PipelineStruct& pair : m_pipelines) {
if (pair.stateVector == state)
return pair.pipeline;
{ std::lock_guard<sync::Spinlock> lock(m_mutex);
if (this->findPipeline(state, pipeline))
return pipeline;
}
VkPipeline pipeline = this->validatePipelineState(state)
// If no pipeline exists with the given state vector,
// create a new one and add it to the pipeline set.
VkPipeline newPipeline = this->validatePipelineState(state)
? this->compilePipeline(state, m_basePipeline)
: VK_NULL_HANDLE;
m_pipelines.push_back({ state, pipeline });
{ std::lock_guard<sync::Spinlock> lock(m_mutex);
// Discard the pipeline if another thread
// was faster compiling the same pipeline
if (this->findPipeline(state, pipeline)) {
m_vkd->vkDestroyPipeline(m_vkd->device(), newPipeline, nullptr);
return pipeline;
}
// Add new pipeline to the set
m_pipelines.push_back({ state, newPipeline });
if (m_basePipeline == VK_NULL_HANDLE)
m_basePipeline = newPipeline;
stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1);
return newPipeline;
}
}
bool DxvkGraphicsPipeline::findPipeline(
const DxvkGraphicsPipelineStateInfo& state,
VkPipeline& pipeline) const {
for (const PipelineStruct& pair : m_pipelines) {
if (pair.stateVector == state) {
pipeline = pair.pipeline;
return true;
}
}
if (m_basePipeline == VK_NULL_HANDLE)
m_basePipeline = pipeline;
stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1);
return pipeline;
return false;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <vector>
#include <mutex>
#include "dxvk_binding.h"
#include "dxvk_constant_state.h"
@ -160,10 +160,15 @@ namespace dxvk {
DxvkGraphicsCommonPipelineStateInfo m_common;
sync::Spinlock m_mutex;
std::vector<PipelineStruct> m_pipelines;
VkPipeline m_basePipeline = VK_NULL_HANDLE;
bool findPipeline(
const DxvkGraphicsPipelineStateInfo& state,
VkPipeline& pipeline) const;
VkPipeline compilePipeline(
const DxvkGraphicsPipelineStateInfo& state,
VkPipeline baseHandle) const;

View File

@ -21,17 +21,19 @@ namespace dxvk {
}
bool DxvkPipelineKeyEq::operator () (const DxvkComputePipelineKey& a, const DxvkComputePipelineKey& b) const {
bool DxvkPipelineKeyEq::operator () (
const DxvkComputePipelineKey& a,
const DxvkComputePipelineKey& b) const {
return a.cs == b.cs;
}
bool DxvkPipelineKeyEq::operator () (const DxvkGraphicsPipelineKey& a, const DxvkGraphicsPipelineKey& b) const {
return a.vs == b.vs
&& a.tcs == b.tcs
&& a.tes == b.tes
&& a.gs == b.gs
&& a.fs == b.fs;
bool DxvkPipelineKeyEq::operator () (
const DxvkGraphicsPipelineKey& a,
const DxvkGraphicsPipelineKey& b) const {
return a.vs == b.vs && a.tcs == b.tcs
&& a.tes == b.tes && a.gs == b.gs
&& a.fs == b.fs;
}
@ -52,6 +54,8 @@ namespace dxvk {
if (cs == nullptr)
return nullptr;
std::lock_guard<std::mutex> lock(m_mutex);
DxvkComputePipelineKey key;
key.cs = cs;
@ -77,6 +81,8 @@ namespace dxvk {
if (vs == nullptr)
return nullptr;
std::lock_guard<std::mutex> lock(m_mutex);
DxvkGraphicsPipelineKey key;
key.vs = vs;
key.tcs = tcs;

View File

@ -1,5 +1,6 @@
#pragma once
#include <mutex>
#include <unordered_map>
#include "dxvk_compute.h"
@ -99,6 +100,8 @@ namespace dxvk {
const DxvkDevice* m_device;
std::mutex m_mutex;
std::unordered_map<
DxvkComputePipelineKey,
Rc<DxvkComputePipeline>,

View File

@ -89,10 +89,10 @@ namespace dxvk {
desc.flags = 0;
desc.format = m_format.depth.format;
desc.samples = m_format.sampleCount;
desc.loadOp = ops.depthOps.loadOp;
desc.storeOp = ops.depthOps.storeOp;
desc.stencilLoadOp = ops.depthOps.loadOp;
desc.stencilStoreOp = ops.depthOps.storeOp;
desc.loadOp = ops.depthOps.loadOpD;
desc.storeOp = ops.depthOps.storeOpD;
desc.stencilLoadOp = ops.depthOps.loadOpS;
desc.stencilStoreOp = ops.depthOps.storeOpS;
desc.initialLayout = ops.depthOps.loadLayout;
desc.finalLayout = ops.depthOps.storeLayout;
@ -179,9 +179,11 @@ namespace dxvk {
bool DxvkRenderPass::compareOps(
const DxvkRenderPassOps& a,
const DxvkRenderPassOps& b) {
bool eq = a.depthOps.loadOp == b.depthOps.loadOp
bool eq = a.depthOps.loadOpD == b.depthOps.loadOpD
&& a.depthOps.loadOpS == b.depthOps.loadOpS
&& a.depthOps.loadLayout == b.depthOps.loadLayout
&& a.depthOps.storeOp == b.depthOps.storeOp
&& a.depthOps.storeOpD == b.depthOps.storeOpD
&& a.depthOps.storeOpS == b.depthOps.storeOpS
&& a.depthOps.storeLayout == b.depthOps.storeLayout;
for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {

View File

@ -35,12 +35,12 @@ namespace dxvk {
/**
* \brief Attachment transitions
* \brief Color attachment transitions
*
* Stores the load/store ops and the initial
* and final layout of a single attachment.
*/
struct DxvkAttachmentOps {
struct DxvkColorAttachmentOps {
VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
VkImageLayout loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@ -48,6 +48,22 @@ namespace dxvk {
};
/**
* \brief Depth attachment transitions
*
* Stores the load/store ops and the initial and
* final layout of the depth-stencil attachment.
*/
struct DxvkDepthAttachmentOps {
VkAttachmentLoadOp loadOpD = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
VkAttachmentLoadOp loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
VkImageLayout loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkAttachmentStoreOp storeOpD = VK_ATTACHMENT_STORE_OP_STORE;
VkAttachmentStoreOp storeOpS = VK_ATTACHMENT_STORE_OP_STORE;
VkImageLayout storeLayout = VK_IMAGE_LAYOUT_GENERAL;
};
/**
* \brief Render pass transitions
*
@ -56,8 +72,8 @@ namespace dxvk {
* from a group of render passes with the same format.
*/
struct DxvkRenderPassOps {
DxvkAttachmentOps depthOps;
DxvkAttachmentOps colorOps[MaxNumRenderTargets];
DxvkDepthAttachmentOps depthOps;
DxvkColorAttachmentOps colorOps[MaxNumRenderTargets];
};