mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-11-30 04:24:11 +01:00
[dxvk] Refactor DxvkFramebuffer and DxvkRenderpass
This commit is contained in:
parent
a32050374c
commit
1bbfe77013
@ -2591,20 +2591,20 @@ namespace dxvk {
|
||||
// target bindings are updated. Set up the attachments.
|
||||
for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) {
|
||||
if (m_state.om.renderTargetViews.at(i) != nullptr) {
|
||||
attachments.setColorTarget(i,
|
||||
attachments.color[i] = {
|
||||
m_state.om.renderTargetViews.at(i)->GetImageView(),
|
||||
m_state.om.renderTargetViews.at(i)->GetRenderLayout());
|
||||
m_state.om.renderTargetViews.at(i)->GetRenderLayout() };
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state.om.depthStencilView != nullptr) {
|
||||
attachments.setDepthTarget(
|
||||
attachments.depth = {
|
||||
m_state.om.depthStencilView->GetImageView(),
|
||||
m_state.om.depthStencilView->GetRenderLayout());
|
||||
m_state.om.depthStencilView->GetRenderLayout() };
|
||||
}
|
||||
|
||||
// Create and bind the framebuffer object to the context
|
||||
EmitCs([cAttachments = attachments] (DxvkContext* ctx) {
|
||||
EmitCs([cAttachments = std::move(attachments)] (DxvkContext* ctx) {
|
||||
ctx->bindRenderTargets(cAttachments);
|
||||
});
|
||||
}
|
||||
|
@ -169,26 +169,27 @@ namespace dxvk {
|
||||
VK_FORMAT_UNDEFINED);
|
||||
}
|
||||
|
||||
const DxvkSwapSemaphores sem = m_swapchain->getSemaphorePair();
|
||||
auto swapSemas = m_swapchain->getSemaphorePair();
|
||||
auto swapImage = m_swapchain->getImageView(swapSemas.acquireSync);
|
||||
|
||||
auto framebuffer = m_swapchain->getFramebuffer(sem.acquireSync);
|
||||
auto framebufferSize = framebuffer->size();
|
||||
|
||||
m_context->bindFramebuffer(framebuffer);
|
||||
DxvkRenderTargets renderTargets;
|
||||
renderTargets.color[0].view = swapImage;
|
||||
renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
m_context->bindRenderTargets(renderTargets);
|
||||
|
||||
VkViewport viewport;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(framebufferSize.width);
|
||||
viewport.height = static_cast<float>(framebufferSize.height);
|
||||
viewport.width = float(swapImage->imageInfo().extent.width);
|
||||
viewport.height = float(swapImage->imageInfo().extent.height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D scissor;
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
scissor.extent.width = framebufferSize.width;
|
||||
scissor.extent.height = framebufferSize.height;
|
||||
scissor.extent.width = swapImage->imageInfo().extent.width;
|
||||
scissor.extent.height = swapImage->imageInfo().extent.height;
|
||||
|
||||
m_context->setViewports(1, &viewport, &scissor);
|
||||
|
||||
@ -214,9 +215,11 @@ namespace dxvk {
|
||||
|
||||
m_device->submitCommandList(
|
||||
m_context->endRecording(),
|
||||
sem.acquireSync, sem.presentSync);
|
||||
swapSemas.acquireSync,
|
||||
swapSemas.presentSync);
|
||||
|
||||
m_swapchain->present(sem.presentSync);
|
||||
m_swapchain->present(
|
||||
swapSemas.presentSync);
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,31 +85,17 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::bindFramebuffer(const Rc<DxvkFramebuffer>& fb) {
|
||||
if (m_state.om.framebuffer != fb) {
|
||||
this->spillRenderPass();
|
||||
|
||||
if (fb != nullptr) {
|
||||
m_state.gp.state.msSampleCount = fb->sampleCount();
|
||||
m_state.gp.state.omRenderPass = fb->renderPass();
|
||||
|
||||
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
||||
}
|
||||
|
||||
m_state.om.framebuffer = fb;
|
||||
}
|
||||
|
||||
m_state.om.renderTargets = fb != nullptr
|
||||
? fb->renderTargets()
|
||||
: DxvkRenderTargets();
|
||||
m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) {
|
||||
m_state.om.renderTargets = targets;
|
||||
|
||||
if (m_state.om.framebuffer == nullptr || !m_state.om.framebuffer->renderTargets().matches(targets)) {
|
||||
// TODO execute pending clears
|
||||
|
||||
// Set up default render pass ops
|
||||
this->resetRenderPassOps(
|
||||
m_state.om.renderTargets,
|
||||
m_state.om.renderPassOps);
|
||||
|
||||
if (m_state.om.framebuffer == nullptr || !m_state.om.framebuffer->hasTargets(targets)) {
|
||||
// Create a new framebuffer object next
|
||||
// time we start rendering something
|
||||
m_flags.set(DxvkContextFlag::GpDirtyFramebuffer);
|
||||
@ -403,27 +389,36 @@ namespace dxvk {
|
||||
// Check whether the render target view is an attachment
|
||||
// of the current framebuffer. If not, we need to create
|
||||
// a temporary framebuffer.
|
||||
uint32_t attachmentIndex = MaxNumRenderTargets;
|
||||
int32_t attachmentIndex = -1;
|
||||
|
||||
if (m_state.om.framebuffer != nullptr)
|
||||
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
|
||||
|
||||
if (attachmentIndex == MaxNumRenderTargets) {
|
||||
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;
|
||||
|
||||
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
attachments.setColorTarget(0, imageView,
|
||||
imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
|
||||
attachments.color[0].view = imageView;
|
||||
attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
ops.colorOps[0] = op;
|
||||
} else {
|
||||
attachments.setDepthTarget(imageView,
|
||||
imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
|
||||
attachments.depth.view = imageView;
|
||||
attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
ops.depthOps = op;
|
||||
}
|
||||
|
||||
this->renderPassBindFramebuffer(
|
||||
m_device->createFramebuffer(attachments));
|
||||
m_device->createFramebuffer(attachments), ops);
|
||||
} else {
|
||||
// Make sure that the currently bound
|
||||
// framebuffer can be rendered to
|
||||
@ -436,7 +431,7 @@ namespace dxvk {
|
||||
clearInfo.colorAttachment = attachmentIndex;
|
||||
clearInfo.clearValue = clearValue;
|
||||
|
||||
if (attachmentIndex == MaxNumRenderTargets)
|
||||
if (attachmentIndex < 0)
|
||||
clearInfo.colorAttachment = 0;
|
||||
|
||||
m_cmd->cmdClearAttachments(
|
||||
@ -444,7 +439,7 @@ namespace dxvk {
|
||||
|
||||
// If we used a temporary framebuffer, we'll have to unbind it
|
||||
// again in order to not disturb subsequent rendering commands.
|
||||
if (attachmentIndex == MaxNumRenderTargets)
|
||||
if (attachmentIndex < 0)
|
||||
this->renderPassUnbindFramebuffer();
|
||||
}
|
||||
|
||||
@ -1520,12 +1515,23 @@ namespace dxvk {
|
||||
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)
|
||||
&& (m_state.om.framebuffer != nullptr)) {
|
||||
m_flags.set(DxvkContextFlag::GpRenderPassBound);
|
||||
this->renderPassBindFramebuffer(m_state.om.framebuffer);
|
||||
|
||||
this->renderPassBindFramebuffer(
|
||||
m_state.om.framebuffer,
|
||||
m_state.om.renderPassOps);
|
||||
|
||||
// Don't discard image contents if we have
|
||||
// to spill the current render pass
|
||||
this->resetRenderPassOps(
|
||||
m_state.om.renderTargets,
|
||||
m_state.om.renderPassOps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::spillRenderPass() {
|
||||
// TODO execute pending clears
|
||||
|
||||
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
|
||||
m_flags.clr(DxvkContextFlag::GpRenderPassBound);
|
||||
this->renderPassUnbindFramebuffer();
|
||||
@ -1533,7 +1539,9 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::renderPassBindFramebuffer(const Rc<DxvkFramebuffer>& framebuffer) {
|
||||
void DxvkContext::renderPassBindFramebuffer(
|
||||
const Rc<DxvkFramebuffer>& framebuffer,
|
||||
const DxvkRenderPassOps& ops) {
|
||||
const DxvkFramebufferSize fbSize = framebuffer->size();
|
||||
|
||||
VkRect2D renderArea;
|
||||
@ -1543,7 +1551,7 @@ namespace dxvk {
|
||||
VkRenderPassBeginInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.renderPass = framebuffer->renderPass();
|
||||
info.renderPass = framebuffer->getRenderPassHandle(ops);
|
||||
info.framebuffer = framebuffer->handle();
|
||||
info.renderArea = renderArea;
|
||||
info.clearValueCount = 0;
|
||||
@ -1561,6 +1569,31 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::resetRenderPassOps(
|
||||
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 { };
|
||||
|
||||
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 { };
|
||||
}
|
||||
|
||||
// TODO provide a sane alternative for this
|
||||
if (renderPassOps.colorOps[0].loadLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
|
||||
renderPassOps.colorOps[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
renderPassOps.colorOps[0].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::unbindComputePipeline() {
|
||||
m_flags.set(
|
||||
DxvkContextFlag::CpDirtyPipeline,
|
||||
@ -1720,7 +1753,7 @@ namespace dxvk {
|
||||
DxvkAttachment depthAttachment;
|
||||
|
||||
if (bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS && m_state.om.framebuffer != nullptr)
|
||||
depthAttachment = m_state.om.framebuffer->renderTargets().getDepthTarget();
|
||||
depthAttachment = m_state.om.framebuffer->getDepthTarget();
|
||||
|
||||
for (uint32_t i = 0; i < layout->bindingCount(); i++) {
|
||||
const auto& binding = layout->binding(i);
|
||||
@ -1832,8 +1865,8 @@ namespace dxvk {
|
||||
|
||||
auto fb = m_device->createFramebuffer(m_state.om.renderTargets);
|
||||
|
||||
m_state.gp.state.msSampleCount = fb->sampleCount();
|
||||
m_state.gp.state.omRenderPass = fb->renderPass();
|
||||
m_state.gp.state.msSampleCount = fb->getSampleCount();
|
||||
m_state.gp.state.omRenderPass = fb->getDefaultRenderPassHandle();
|
||||
m_state.om.framebuffer = fb;
|
||||
|
||||
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
|
||||
|
@ -71,13 +71,6 @@ namespace dxvk {
|
||||
void endQuery(
|
||||
const DxvkQueryRevision& query);
|
||||
|
||||
/**
|
||||
* \brief Sets framebuffer
|
||||
* \param [in] fb Framebuffer
|
||||
*/
|
||||
void bindFramebuffer(
|
||||
const Rc<DxvkFramebuffer>& fb);
|
||||
|
||||
/**
|
||||
* \brief Sets render targets
|
||||
*
|
||||
@ -650,9 +643,15 @@ namespace dxvk {
|
||||
void spillRenderPass();
|
||||
|
||||
void renderPassBindFramebuffer(
|
||||
const Rc<DxvkFramebuffer>& framebuffer);
|
||||
const Rc<DxvkFramebuffer>& framebuffer,
|
||||
const DxvkRenderPassOps& ops);
|
||||
|
||||
void renderPassUnbindFramebuffer();
|
||||
|
||||
void resetRenderPassOps(
|
||||
const DxvkRenderTargets& renderTargets,
|
||||
DxvkRenderPassOps& renderPassOps);
|
||||
|
||||
void unbindComputePipeline();
|
||||
|
||||
void updateComputePipeline();
|
||||
|
@ -54,7 +54,10 @@ namespace dxvk {
|
||||
|
||||
|
||||
struct DxvkOutputMergerState {
|
||||
std::array<VkClearValue, MaxNumRenderTargets + 1> clearValue;
|
||||
|
||||
DxvkRenderTargets renderTargets;
|
||||
DxvkRenderPassOps renderPassOps;
|
||||
Rc<DxvkFramebuffer> framebuffer = nullptr;
|
||||
|
||||
DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
@ -117,11 +117,11 @@ namespace dxvk {
|
||||
m_properties.limits.maxFramebufferHeight,
|
||||
m_properties.limits.maxFramebufferLayers };
|
||||
|
||||
auto format = renderTargets.renderPassFormat();
|
||||
auto renderPass = m_renderPassPool->getRenderPass(format);
|
||||
auto renderPassFormat = DxvkFramebuffer::getRenderPassFormat(renderTargets);
|
||||
auto renderPassObject = m_renderPassPool->getRenderPass(renderPassFormat);
|
||||
|
||||
return new DxvkFramebuffer(m_vkd,
|
||||
renderPass, renderTargets, defaultSize);
|
||||
renderPassObject, renderTargets, defaultSize);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,142 +2,117 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkRenderTargets:: DxvkRenderTargets() { }
|
||||
DxvkRenderTargets::~DxvkRenderTargets() { }
|
||||
|
||||
|
||||
DxvkRenderPassFormat DxvkRenderTargets::renderPassFormat() const {
|
||||
DxvkRenderPassFormat result;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
if (m_colorTargets.at(i).view != nullptr) {
|
||||
result.setColorFormat(i, DxvkRenderTargetFormat {
|
||||
m_colorTargets.at(i).view->info().format,
|
||||
m_colorTargets.at(i).view->imageInfo().layout,
|
||||
m_colorTargets.at(i).view->imageInfo().layout,
|
||||
m_colorTargets.at(i).layout });
|
||||
result.setSampleCount(m_colorTargets.at(i).view->imageInfo().sampleCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_depthTarget.view != nullptr) {
|
||||
result.setDepthFormat(DxvkRenderTargetFormat {
|
||||
m_depthTarget.view->info().format,
|
||||
m_depthTarget.view->imageInfo().layout,
|
||||
m_depthTarget.view->imageInfo().layout,
|
||||
m_depthTarget.layout });
|
||||
result.setSampleCount(m_depthTarget.view->imageInfo().sampleCount);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkRenderTargets::getAttachments(VkImageView* viewHandles) const {
|
||||
uint32_t numViews = 0;
|
||||
|
||||
if (m_depthTarget.view != nullptr)
|
||||
viewHandles[numViews++] = m_depthTarget.view->handle();
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
if (m_colorTargets.at(i).view != nullptr)
|
||||
viewHandles[numViews++] = m_colorTargets.at(i).view->handle();
|
||||
}
|
||||
|
||||
return numViews;
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebufferSize DxvkRenderTargets::getImageSize(
|
||||
const DxvkFramebufferSize& defaultSize) const {
|
||||
if (m_depthTarget.view != nullptr)
|
||||
return this->renderTargetSize(m_depthTarget.view);
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
if (m_colorTargets.at(i).view != nullptr)
|
||||
return this->renderTargetSize(m_colorTargets.at(i).view);
|
||||
}
|
||||
|
||||
return defaultSize;
|
||||
}
|
||||
|
||||
|
||||
bool DxvkRenderTargets::hasAttachments() const {
|
||||
bool result = m_depthTarget.view != nullptr;
|
||||
|
||||
for (uint32_t i = 0; (i < MaxNumRenderTargets) && !result; i++)
|
||||
result |= m_colorTargets.at(i).view != nullptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool DxvkRenderTargets::matches(const DxvkRenderTargets& other) const {
|
||||
bool equal = m_depthTarget.view == other.m_depthTarget.view
|
||||
&& m_depthTarget.layout == other.m_depthTarget.layout;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets && equal; i++) {
|
||||
equal &= m_colorTargets.at(i).view == other.m_colorTargets.at(i).view
|
||||
&& m_colorTargets.at(i).layout == other.m_colorTargets.at(i).layout;
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebufferSize DxvkRenderTargets::renderTargetSize(
|
||||
const Rc<DxvkImageView>& renderTarget) const {
|
||||
auto extent = renderTarget->mipLevelExtent(0);
|
||||
auto layers = renderTarget->info().numLayers;
|
||||
return DxvkFramebufferSize { extent.width, extent.height, layers };
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebuffer::DxvkFramebuffer(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const Rc<DxvkRenderPass>& renderPass,
|
||||
const DxvkRenderTargets& renderTargets,
|
||||
const DxvkFramebufferSize& defaultSize)
|
||||
: m_vkd (vkd),
|
||||
m_renderPass (renderPass),
|
||||
m_renderTargets (renderTargets),
|
||||
m_framebufferSize (renderTargets.getImageSize(defaultSize)) {
|
||||
: m_vkd (vkd),
|
||||
m_renderPass (renderPass),
|
||||
m_renderTargets (renderTargets),
|
||||
m_renderSize (computeRenderSize(defaultSize)) {
|
||||
std::array<VkImageView, MaxNumRenderTargets + 1> views;
|
||||
uint32_t viewCount = renderTargets.getAttachments(views.data());
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_renderTargets.depth.view != nullptr) {
|
||||
views[viewId] = m_renderTargets.depth.view->handle();
|
||||
m_attachments[viewId] = &m_renderTargets.depth;
|
||||
viewId += 1;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.renderPass = renderPass->handle();
|
||||
info.attachmentCount = viewCount;
|
||||
info.renderPass = m_renderPass->getDefaultHandle();
|
||||
info.attachmentCount = viewId;
|
||||
info.pAttachments = views.data();
|
||||
info.width = m_framebufferSize.width;
|
||||
info.height = m_framebufferSize.height;
|
||||
info.layers = m_framebufferSize.layers;
|
||||
info.width = m_renderSize.width;
|
||||
info.height = m_renderSize.height;
|
||||
info.layers = m_renderSize.layers;
|
||||
|
||||
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_framebuffer) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkFramebuffer: Failed to create framebuffer object");
|
||||
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_handle) != VK_SUCCESS)
|
||||
Logger::err("DxvkFramebuffer: Failed to create framebuffer object");
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebuffer::~DxvkFramebuffer() {
|
||||
m_vkd->vkDestroyFramebuffer(
|
||||
m_vkd->device(), m_framebuffer, nullptr);
|
||||
m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_handle, nullptr);
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkFramebuffer::findAttachment(
|
||||
const Rc<DxvkImageView>& view) const {
|
||||
if (m_renderTargets.getDepthTarget().view == view)
|
||||
return 0;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
if (m_renderTargets.getColorTarget(i).view == view)
|
||||
return i;
|
||||
int32_t DxvkFramebuffer::findAttachment(const Rc<DxvkImageView>& view) const {
|
||||
for (uint32_t i = 0; i < m_attachmentCount; i++) {
|
||||
if (m_attachments[i]->view == view)
|
||||
return int32_t(i);
|
||||
}
|
||||
|
||||
return MaxNumRenderTargets;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
bool DxvkFramebuffer::hasTargets(const DxvkRenderTargets& renderTargets) {
|
||||
bool eq = m_renderTargets.depth.view == renderTargets.depth.view
|
||||
&& m_renderTargets.depth.layout == renderTargets.depth.layout;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
|
||||
eq &= m_renderTargets.color[i].view == renderTargets.color[i].view
|
||||
&& m_renderTargets.color[i].layout == renderTargets.color[i].layout;
|
||||
}
|
||||
|
||||
return eq;
|
||||
}
|
||||
|
||||
|
||||
DxvkRenderPassFormat DxvkFramebuffer::getRenderPassFormat(const DxvkRenderTargets& renderTargets) {
|
||||
DxvkRenderPassFormat format;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
if (renderTargets.color[i].view != nullptr) {
|
||||
format.sampleCount = renderTargets.color[i].view->imageInfo().sampleCount;
|
||||
format.color[i].format = renderTargets.color[i].view->info().format;
|
||||
format.color[i].layout = renderTargets.color[i].layout;
|
||||
}
|
||||
}
|
||||
|
||||
if (renderTargets.depth.view != nullptr) {
|
||||
format.sampleCount = renderTargets.depth.view->imageInfo().sampleCount;
|
||||
format.depth.format = renderTargets.depth.view->info().format;
|
||||
format.depth.layout = renderTargets.depth.layout;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebufferSize DxvkFramebuffer::computeRenderSize(
|
||||
const DxvkFramebufferSize& defaultSize) const {
|
||||
if (m_renderTargets.depth.view != nullptr)
|
||||
return this->computeRenderTargetSize(m_renderTargets.depth.view);
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
if (m_renderTargets.color[i].view != nullptr)
|
||||
return this->computeRenderTargetSize(m_renderTargets.color[i].view);
|
||||
}
|
||||
|
||||
return defaultSize;
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebufferSize DxvkFramebuffer::computeRenderTargetSize(
|
||||
const Rc<DxvkImageView>& renderTarget) const {
|
||||
auto extent = renderTarget->mipLevelExtent(0);
|
||||
auto layers = renderTarget->info().numLayers;
|
||||
return DxvkFramebufferSize { extent.width, extent.height, layers };
|
||||
}
|
||||
|
||||
}
|
@ -19,6 +19,12 @@ namespace dxvk {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Framebuffer attachment
|
||||
*
|
||||
* Stores an attachment, as well as the image layout
|
||||
* that will be used for rendering to the attachment.
|
||||
*/
|
||||
struct DxvkAttachment {
|
||||
Rc<DxvkImageView> view = nullptr;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
@ -26,127 +32,23 @@ namespace dxvk {
|
||||
|
||||
|
||||
/**
|
||||
* \brief Render target description
|
||||
* \brief Render targets
|
||||
*
|
||||
* Stores render targets for a framebuffer object
|
||||
* and provides methods to query the render pass
|
||||
* format. Note that all render target views must
|
||||
* have the same size and number of array layers.
|
||||
* Stores all depth-stencil and color
|
||||
* attachments attached to a framebuffer.
|
||||
*/
|
||||
class DxvkRenderTargets {
|
||||
|
||||
public:
|
||||
|
||||
DxvkRenderTargets();
|
||||
~DxvkRenderTargets();
|
||||
|
||||
/**
|
||||
* \brief Retrieves color target
|
||||
*
|
||||
* \param [in] id Color attachment ID
|
||||
* \returns Render target view
|
||||
*/
|
||||
DxvkAttachment getColorTarget(uint32_t id) const {
|
||||
return m_colorTargets.at(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves depth-stencil target
|
||||
* \returns Depth-stencil target view
|
||||
*/
|
||||
DxvkAttachment getDepthTarget() const {
|
||||
return m_depthTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets color target
|
||||
*
|
||||
* \param [in] id Color attachment ID
|
||||
* \param [in] view Render target view
|
||||
* \param [in] layout Layout to use for rendering
|
||||
*/
|
||||
void setColorTarget(
|
||||
uint32_t id,
|
||||
const Rc<DxvkImageView>& view,
|
||||
VkImageLayout layout) {
|
||||
m_colorTargets.at(id) = { view, layout };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets depth-stencil target
|
||||
*
|
||||
* \param [in] layout Layout to use for rendering
|
||||
* \param [in] view Depth-stencil target view
|
||||
*/
|
||||
void setDepthTarget(
|
||||
const Rc<DxvkImageView>& view,
|
||||
VkImageLayout layout) {
|
||||
m_depthTarget = { view, layout };
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Render pass format
|
||||
*
|
||||
* Computes the render pass format based on
|
||||
* the color and depth-stencil attachments.
|
||||
* \returns Render pass format
|
||||
*/
|
||||
DxvkRenderPassFormat renderPassFormat() const;
|
||||
|
||||
/**
|
||||
* \brief Creates attachment list
|
||||
*
|
||||
* \param [out] viewHandles Attachment handles
|
||||
* \returns Framebuffer attachment count
|
||||
*/
|
||||
uint32_t getAttachments(VkImageView* viewHandles) const;
|
||||
|
||||
/**
|
||||
* \brief Framebuffer size
|
||||
*
|
||||
* The width, height and layer count of the
|
||||
* attached render targets.
|
||||
* \param [in] defaultSize Size to use when
|
||||
* there are no framebuffer attachments.
|
||||
* \returns Framebuffer size
|
||||
*/
|
||||
DxvkFramebufferSize getImageSize(
|
||||
const DxvkFramebufferSize& defaultSize) const;
|
||||
|
||||
/**
|
||||
* \brief Checks whether any attachments are defined
|
||||
* \returns \c false if no attachments are defined
|
||||
*/
|
||||
bool hasAttachments() const;
|
||||
|
||||
/**
|
||||
* \brief Compares two sets of render targets
|
||||
*
|
||||
* Checks whether two sets of render targets
|
||||
* are identical, including the image layout.
|
||||
* \param [in] other Render target set to compare to
|
||||
* \returns \c true if the render targets are the same
|
||||
*/
|
||||
bool matches(const DxvkRenderTargets& other) const;
|
||||
|
||||
private:
|
||||
|
||||
std::array<DxvkAttachment, MaxNumRenderTargets> m_colorTargets;
|
||||
DxvkAttachment m_depthTarget;
|
||||
|
||||
DxvkFramebufferSize renderTargetSize(
|
||||
const Rc<DxvkImageView>& renderTarget) const;
|
||||
|
||||
struct DxvkRenderTargets {
|
||||
DxvkAttachment depth;
|
||||
DxvkAttachment color[MaxNumRenderTargets];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK framebuffer
|
||||
* \brief Framebuffer
|
||||
*
|
||||
* A framebuffer either stores a set of image views
|
||||
* that will be used as render targets, or in case
|
||||
* no render targets are being used, fixed viewport
|
||||
* dimensions.
|
||||
* no render targets are attached, fixed dimensions.
|
||||
*/
|
||||
class DxvkFramebuffer : public DxvkResource {
|
||||
|
||||
@ -157,6 +59,7 @@ namespace dxvk {
|
||||
const Rc<DxvkRenderPass>& renderPass,
|
||||
const DxvkRenderTargets& renderTargets,
|
||||
const DxvkFramebufferSize& defaultSize);
|
||||
|
||||
~DxvkFramebuffer();
|
||||
|
||||
/**
|
||||
@ -164,15 +67,7 @@ namespace dxvk {
|
||||
* \returns Framebuffer handle
|
||||
*/
|
||||
VkFramebuffer handle() const {
|
||||
return m_framebuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Render pass handle
|
||||
* \returns Render pass handle
|
||||
*/
|
||||
VkRenderPass renderPass() const {
|
||||
return m_renderPass->handle();
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,45 +75,124 @@ namespace dxvk {
|
||||
* \returns Framebuffer size
|
||||
*/
|
||||
DxvkFramebufferSize size() const {
|
||||
return m_framebufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Render target info
|
||||
* \returns Render target info
|
||||
*/
|
||||
const DxvkRenderTargets& renderTargets() const {
|
||||
return m_renderTargets;
|
||||
return m_renderSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sample count
|
||||
* \returns Sample count
|
||||
*/
|
||||
VkSampleCountFlagBits sampleCount() const {
|
||||
return m_renderPass->sampleCount();
|
||||
VkSampleCountFlagBits getSampleCount() const {
|
||||
return m_renderPass->getSampleCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves index of a given attachment
|
||||
* \brief Retrieves default render pass handle
|
||||
*
|
||||
* \param [in] view The image view to look up
|
||||
* \returns The attachment index, or \c 0 for a depth-stencil
|
||||
* attachment, or \c MaxNumRenderTargets if the given
|
||||
* view is not a framebuffer attachment.
|
||||
* Retrieves the render pass handle that was used
|
||||
* to create the Vulkan framebuffer object with,
|
||||
* and that should be used to create pipelines.
|
||||
* \returns The default render pass handle
|
||||
*/
|
||||
uint32_t findAttachment(
|
||||
const Rc<DxvkImageView>& view) const;
|
||||
VkRenderPass getDefaultRenderPassHandle() const {
|
||||
return m_renderPass->getDefaultHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves render pass handle
|
||||
*
|
||||
* Retrieves a render pass handle that can
|
||||
* be used to begin a render pass instance.
|
||||
* \param [in] ops Render pass ops
|
||||
* \returns The render pass handle
|
||||
*/
|
||||
VkRenderPass getRenderPassHandle(const DxvkRenderPassOps& ops) const {
|
||||
return m_renderPass->getHandle(ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Depth-stencil target
|
||||
* \returns Depth-stencil target
|
||||
*/
|
||||
const DxvkAttachment& getDepthTarget() const {
|
||||
return m_renderTargets.depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Color target
|
||||
*
|
||||
* \param [in] id Target Index
|
||||
* \returns The color target
|
||||
*/
|
||||
const DxvkAttachment& getColorTarget(uint32_t id) const {
|
||||
return m_renderTargets.color[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Number of framebuffer attachment
|
||||
* \returns Total attachment count
|
||||
*/
|
||||
uint32_t numAttachments() const {
|
||||
return m_attachmentCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves attachment by index
|
||||
*
|
||||
* \param [in] id Framebuffer attachment ID
|
||||
* \returns The framebuffer attachment
|
||||
*/
|
||||
const DxvkAttachment& getAttachment(uint32_t id) const {
|
||||
return *m_attachments[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Finds attachment index by view
|
||||
*
|
||||
* Color attachments start at 0
|
||||
* \param [in] view Image view
|
||||
* \returns Attachment index
|
||||
*/
|
||||
int32_t findAttachment(const Rc<DxvkImageView>& view) const;
|
||||
|
||||
/**
|
||||
* \brief Checks whether the framebuffer's targets match
|
||||
*
|
||||
* \param [in] renderTargets Render targets to check
|
||||
* \returns \c true if the render targets are the same
|
||||
* as the ones used for this framebuffer object.
|
||||
*/
|
||||
bool hasTargets(
|
||||
const DxvkRenderTargets& renderTargets);
|
||||
|
||||
/**
|
||||
* \brief Generatess render pass format
|
||||
*
|
||||
* This render pass format can be used to
|
||||
* look up a compatible render pass.
|
||||
* \param [in] renderTargets Render targets
|
||||
* \returns The render pass format
|
||||
*/
|
||||
static DxvkRenderPassFormat getRenderPassFormat(
|
||||
const DxvkRenderTargets& renderTargets);
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
Rc<DxvkRenderPass> m_renderPass;
|
||||
const Rc<vk::DeviceFn> m_vkd;
|
||||
const Rc<DxvkRenderPass> m_renderPass;
|
||||
const DxvkRenderTargets m_renderTargets;
|
||||
const DxvkFramebufferSize m_renderSize;
|
||||
|
||||
DxvkRenderTargets m_renderTargets;
|
||||
DxvkFramebufferSize m_framebufferSize = { 0, 0, 0 };
|
||||
uint32_t m_attachmentCount = 0;
|
||||
std::array<const DxvkAttachment*, MaxNumRenderTargets + 1> m_attachments;
|
||||
|
||||
VkFramebuffer m_framebuffer = VK_NULL_HANDLE;
|
||||
VkFramebuffer m_handle = VK_NULL_HANDLE;
|
||||
|
||||
DxvkFramebufferSize computeRenderSize(
|
||||
const DxvkFramebufferSize& defaultSize) const;
|
||||
|
||||
DxvkFramebufferSize computeRenderTargetSize(
|
||||
const Rc<DxvkImageView>& renderTarget) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -4,29 +4,56 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
bool DxvkRenderPassFormat::matchesFormat(const DxvkRenderPassFormat& other) const {
|
||||
bool equal = m_samples == other.m_samples;
|
||||
DxvkRenderPass::DxvkRenderPass(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkRenderPassFormat& fmt)
|
||||
: m_vkd(vkd), m_format(fmt),
|
||||
m_default(createRenderPass(DxvkRenderPassOps())) {
|
||||
|
||||
equal &= m_depth.format == other.m_depth.format
|
||||
&& m_depth.initialLayout == other.m_depth.initialLayout
|
||||
&& m_depth.finalLayout == other.m_depth.finalLayout
|
||||
&& m_depth.renderLayout == other.m_depth.renderLayout;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets && equal; i++) {
|
||||
equal &= m_color[i].format == other.m_color[i].format
|
||||
&& m_color[i].initialLayout == other.m_color[i].initialLayout
|
||||
&& m_color[i].finalLayout == other.m_color[i].finalLayout
|
||||
&& m_color[i].renderLayout == other.m_color[i].renderLayout;
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
|
||||
DxvkRenderPass::DxvkRenderPass(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkRenderPassFormat& fmt)
|
||||
: m_vkd(vkd), m_format(fmt) {
|
||||
DxvkRenderPass::~DxvkRenderPass() {
|
||||
m_vkd->vkDestroyRenderPass(m_vkd->device(), m_default, nullptr);
|
||||
|
||||
for (const auto& i : m_instances) {
|
||||
m_vkd->vkDestroyRenderPass(
|
||||
m_vkd->device(), i.handle, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DxvkRenderPass::hasCompatibleFormat(
|
||||
const DxvkRenderPassFormat& fmt) const {
|
||||
bool eq = m_format.sampleCount == fmt.sampleCount;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
|
||||
eq &= m_format.color[i].format == fmt.color[i].format
|
||||
&& m_format.color[i].layout == fmt.color[i].layout;
|
||||
}
|
||||
|
||||
eq &= m_format.depth.format == fmt.depth.format
|
||||
&& m_format.depth.layout == fmt.depth.layout;
|
||||
|
||||
return eq;
|
||||
}
|
||||
|
||||
|
||||
VkRenderPass DxvkRenderPass::getHandle(const DxvkRenderPassOps& ops) {
|
||||
std::lock_guard<sync::Spinlock> lock(m_mutex);
|
||||
|
||||
for (const auto& i : m_instances) {
|
||||
if (compareOps(i.ops, ops))
|
||||
return i.handle;
|
||||
}
|
||||
|
||||
VkRenderPass handle = this->createRenderPass(ops);
|
||||
m_instances.push_back({ ops, handle });
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
VkRenderPass DxvkRenderPass::createRenderPass(const DxvkRenderPassOps& ops) {
|
||||
std::vector<VkAttachmentDescription> attachments;
|
||||
|
||||
VkAttachmentReference depthRef;
|
||||
@ -34,51 +61,47 @@ namespace dxvk {
|
||||
|
||||
// Render passes may not require the previous
|
||||
// contents of the attachments to be preserved.
|
||||
const DxvkRenderTargetFormat depthFmt = fmt.getDepthFormat();
|
||||
|
||||
if (depthFmt.format != VK_FORMAT_UNDEFINED) {
|
||||
VkAttachmentDescription desc;
|
||||
desc.flags = 0;
|
||||
desc.format = depthFmt.format;
|
||||
desc.samples = fmt.getSampleCount();
|
||||
desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
desc.initialLayout = depthFmt.initialLayout;
|
||||
desc.finalLayout = depthFmt.finalLayout;
|
||||
|
||||
depthRef.attachment = attachments.size();
|
||||
depthRef.layout = depthFmt.renderLayout;
|
||||
|
||||
attachments.push_back(desc);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
const DxvkRenderTargetFormat colorFmt = fmt.getColorFormat(i);
|
||||
|
||||
colorRef[i].attachment = VK_ATTACHMENT_UNUSED;
|
||||
colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
if (colorFmt.format != VK_FORMAT_UNDEFINED) {
|
||||
if (m_format.color[i].format != VK_FORMAT_UNDEFINED) {
|
||||
VkAttachmentDescription desc;
|
||||
desc.flags = 0;
|
||||
desc.format = colorFmt.format;
|
||||
desc.samples = fmt.getSampleCount();
|
||||
desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
desc.format = m_format.color[i].format;
|
||||
desc.samples = m_format.sampleCount;
|
||||
desc.loadOp = ops.colorOps[i].loadOp;
|
||||
desc.storeOp = ops.colorOps[i].storeOp;
|
||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
desc.initialLayout = colorFmt.initialLayout;
|
||||
desc.finalLayout = colorFmt.finalLayout;
|
||||
desc.initialLayout = ops.colorOps[i].loadLayout;
|
||||
desc.finalLayout = ops.colorOps[i].storeLayout;
|
||||
|
||||
colorRef[i].attachment = attachments.size();
|
||||
colorRef[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
colorRef[i].layout = m_format.color[i].layout;
|
||||
|
||||
attachments.push_back(desc);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_format.depth.format != VK_FORMAT_UNDEFINED) {
|
||||
VkAttachmentDescription desc;
|
||||
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.initialLayout = ops.depthOps.loadLayout;
|
||||
desc.finalLayout = ops.depthOps.storeLayout;
|
||||
|
||||
depthRef.attachment = attachments.size();
|
||||
depthRef.layout = m_format.depth.layout;
|
||||
|
||||
attachments.push_back(desc);
|
||||
}
|
||||
|
||||
VkSubpassDescription subpass;
|
||||
subpass.flags = 0;
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
@ -87,11 +110,14 @@ namespace dxvk {
|
||||
subpass.colorAttachmentCount = colorRef.size();
|
||||
subpass.pColorAttachments = colorRef.data();
|
||||
subpass.pResolveAttachments = nullptr;
|
||||
subpass.pDepthStencilAttachment = depthFmt.format != VK_FORMAT_UNDEFINED ? &depthRef : nullptr;
|
||||
subpass.pDepthStencilAttachment = &depthRef;
|
||||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = nullptr;
|
||||
|
||||
std::array<VkSubpassDependency, 2> subpassDeps = {{
|
||||
if (m_format.depth.format == VK_FORMAT_UNDEFINED)
|
||||
subpass.pDepthStencilAttachment = nullptr;
|
||||
|
||||
const std::array<VkSubpassDependency, 2> subpassDeps = {{
|
||||
{ VK_SUBPASS_EXTERNAL, 0,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
@ -139,14 +165,33 @@ namespace dxvk {
|
||||
info.dependencyCount = subpassDeps.size();
|
||||
info.pDependencies = subpassDeps.data();
|
||||
|
||||
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &m_renderPass) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkRenderPass::DxvkRenderPass: Failed to create render pass object");
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
|
||||
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &renderPass) != VK_SUCCESS) {
|
||||
Logger::err("DxvkRenderPass: Failed to create render pass object");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
|
||||
DxvkRenderPass::~DxvkRenderPass() {
|
||||
m_vkd->vkDestroyRenderPass(
|
||||
m_vkd->device(), m_renderPass, nullptr);
|
||||
bool DxvkRenderPass::compareOps(
|
||||
const DxvkRenderPassOps& a,
|
||||
const DxvkRenderPassOps& b) {
|
||||
bool eq = a.depthOps.loadOp == b.depthOps.loadOp
|
||||
&& a.depthOps.loadLayout == b.depthOps.loadLayout
|
||||
&& a.depthOps.storeOp == b.depthOps.storeOp
|
||||
&& a.depthOps.storeLayout == b.depthOps.storeLayout;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
|
||||
eq &= a.colorOps[i].loadOp == b.colorOps[i].loadOp
|
||||
&& a.colorOps[i].loadLayout == b.colorOps[i].loadLayout
|
||||
&& a.colorOps[i].storeOp == b.colorOps[i].storeOp
|
||||
&& a.colorOps[i].storeLayout == b.colorOps[i].storeLayout;
|
||||
}
|
||||
|
||||
return eq;
|
||||
}
|
||||
|
||||
|
||||
@ -161,29 +206,17 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkRenderPass> DxvkRenderPassPool::getRenderPass(
|
||||
const DxvkRenderPassFormat& fmt) {
|
||||
Rc<DxvkRenderPass> DxvkRenderPassPool::getRenderPass(const DxvkRenderPassFormat& fmt) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
Rc<DxvkRenderPass> renderPass = nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < m_renderPasses.size() && renderPass == nullptr; i++) {
|
||||
if (m_renderPasses[i]->matchesFormat(fmt))
|
||||
renderPass = m_renderPasses[i];
|
||||
for (const auto& r : m_renderPasses) {
|
||||
if (r->hasCompatibleFormat(fmt))
|
||||
return r;
|
||||
}
|
||||
|
||||
if (renderPass != nullptr)
|
||||
return renderPass;
|
||||
|
||||
renderPass = this->createRenderPass(fmt);
|
||||
m_renderPasses.push_back(renderPass);
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkRenderPass> DxvkRenderPassPool::createRenderPass(
|
||||
const DxvkRenderPassFormat& fmt) {
|
||||
return new DxvkRenderPass(m_vkd, fmt);
|
||||
Rc<DxvkRenderPass> rp = new DxvkRenderPass(m_vkd, fmt);
|
||||
m_renderPasses.push_back(rp);
|
||||
return rp;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "dxvk_hash.h"
|
||||
#include "dxvk_include.h"
|
||||
@ -10,50 +10,84 @@
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Format and layout info for a sigle render target
|
||||
* \brief Format and layout for a render target
|
||||
*
|
||||
* Stores the format, initial layout and
|
||||
* final layout of a render target.
|
||||
* Stores the image format of the attachment and
|
||||
* the image layout that is used while rendering.
|
||||
*/
|
||||
struct DxvkRenderTargetFormat {
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkImageLayout renderLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
struct DxvkAttachmentFormat {
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Render pass format
|
||||
*
|
||||
* Stores the formats of all render targets
|
||||
* that are used by a framebuffer object.
|
||||
* Stores the attachment formats for all depth and
|
||||
* color attachments, as well as the sample count.
|
||||
*/
|
||||
class DxvkRenderPassFormat {
|
||||
struct DxvkRenderPassFormat {
|
||||
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
DxvkAttachmentFormat depth;
|
||||
DxvkAttachmentFormat color[MaxNumRenderTargets];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Attachment transitions
|
||||
*
|
||||
* Stores the load/store ops and the initial
|
||||
* and final layout of a single attachment.
|
||||
*/
|
||||
struct DxvkAttachmentOps {
|
||||
VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
VkImageLayout loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
VkImageLayout storeLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Render pass transitions
|
||||
*
|
||||
* Stores transitions for all depth and color attachments.
|
||||
* This is used to select a specific render pass object
|
||||
* from a group of render passes with the same format.
|
||||
*/
|
||||
struct DxvkRenderPassOps {
|
||||
DxvkAttachmentOps depthOps;
|
||||
DxvkAttachmentOps colorOps[MaxNumRenderTargets];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Render pass object
|
||||
*
|
||||
* Manages a set of compatible render passes, i.e.
|
||||
* render passes which share the same format but
|
||||
* may differ in their attachment operations.
|
||||
*/
|
||||
class DxvkRenderPass : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Retrieves color target format
|
||||
*
|
||||
* If the color target has not been defined,
|
||||
* this will return \c VK_FORMAT_UNDEFINED.
|
||||
* \param [in] id Color target index
|
||||
* \returns Color target format
|
||||
*/
|
||||
DxvkRenderTargetFormat getColorFormat(uint32_t id) const {
|
||||
return m_color.at(id);
|
||||
}
|
||||
DxvkRenderPass(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkRenderPassFormat& fmt);
|
||||
|
||||
~DxvkRenderPass();
|
||||
|
||||
/**
|
||||
* \brief Retrieves depth-stencil format
|
||||
* \brief Checks whether a format is compatible
|
||||
*
|
||||
* If the color target has not been defined,
|
||||
* this will return \c VK_FORMAT_UNDEFINED.
|
||||
* Two render pass formats are considered compatible
|
||||
* if all the relevant attachment formats match.
|
||||
* \param [in] fmt The render pass format to check
|
||||
* \returns \c true if this render pass is compatible.
|
||||
*/
|
||||
DxvkRenderTargetFormat getDepthFormat() const {
|
||||
return m_depth;
|
||||
}
|
||||
bool hasCompatibleFormat(
|
||||
const DxvkRenderPassFormat& fmt) const;
|
||||
|
||||
/**
|
||||
* \brief Retrieves sample count
|
||||
@ -63,103 +97,53 @@ namespace dxvk {
|
||||
* \returns Sample count
|
||||
*/
|
||||
VkSampleCountFlagBits getSampleCount() const {
|
||||
return m_samples;
|
||||
return m_format.sampleCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets color target format
|
||||
* \brief Returns handle of default render pass
|
||||
*
|
||||
* \param [in] id Color target index
|
||||
* \param [in] fmt Color target format
|
||||
* The default render pass handle should be used to
|
||||
* create pipelines and framebuffer objects. It can
|
||||
* \e not be used for \c vkCmdBeginRenderPass calls.
|
||||
* \returns The default render pass handle
|
||||
*/
|
||||
void setColorFormat(uint32_t id, DxvkRenderTargetFormat fmt) {
|
||||
m_color.at(id) = fmt;
|
||||
VkRenderPass getDefaultHandle() const {
|
||||
return m_default;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets depth-stencil format
|
||||
* \param [in] fmt Depth-stencil format
|
||||
*/
|
||||
void setDepthFormat(DxvkRenderTargetFormat fmt) {
|
||||
m_depth = fmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets sample count
|
||||
* \param [in] samples Sample count
|
||||
*/
|
||||
void setSampleCount(VkSampleCountFlagBits samples) {
|
||||
m_samples = samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether two render pass formats are compatible
|
||||
* \brief Returns handle to a specialized render pass
|
||||
*
|
||||
* \param [in] other The render pass format to compare to
|
||||
* \returns \c true if the render pass formats are compatible
|
||||
*/
|
||||
bool matchesFormat(const DxvkRenderPassFormat& other) const;
|
||||
|
||||
private:
|
||||
|
||||
std::array<DxvkRenderTargetFormat, MaxNumRenderTargets> m_color;
|
||||
DxvkRenderTargetFormat m_depth;
|
||||
VkSampleCountFlagBits m_samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK render pass
|
||||
*
|
||||
* Render pass objects are used internally to identify render
|
||||
* target formats and
|
||||
*/
|
||||
class DxvkRenderPass : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkRenderPass(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkRenderPassFormat& fmt);
|
||||
~DxvkRenderPass();
|
||||
|
||||
/**
|
||||
* \brief Render pass handle
|
||||
*
|
||||
* Internal use only.
|
||||
* Returns a handle to a render pass with the given
|
||||
* set of parameters. This should be used for calls
|
||||
* to \c vkCmdBeginRenderPass.
|
||||
* \param [in] ops Attachment ops
|
||||
* \returns Render pass handle
|
||||
*/
|
||||
VkRenderPass handle() const {
|
||||
return m_renderPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Render pass sample count
|
||||
* \returns Render pass sample count
|
||||
*/
|
||||
VkSampleCountFlagBits sampleCount() const {
|
||||
return m_format.getSampleCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks render pass format compatibility
|
||||
*
|
||||
* This render pass object can be used with compatible render
|
||||
* pass formats. Two render pass formats are compatible if the
|
||||
* used attachments match in image format and layout.
|
||||
* \param [in] format The render pass format to test
|
||||
* \returns \c true if the formats match
|
||||
*/
|
||||
bool matchesFormat(const DxvkRenderPassFormat& format) const {
|
||||
return m_format.matchesFormat(format);
|
||||
}
|
||||
VkRenderPass getHandle(
|
||||
const DxvkRenderPassOps& ops);
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
DxvkRenderPassFormat m_format;
|
||||
VkRenderPass m_renderPass;
|
||||
struct Instance {
|
||||
DxvkRenderPassOps ops;
|
||||
VkRenderPass handle;
|
||||
};
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
DxvkRenderPassFormat m_format;
|
||||
VkRenderPass m_default;
|
||||
|
||||
sync::Spinlock m_mutex;
|
||||
std::vector<Instance> m_instances;
|
||||
|
||||
VkRenderPass createRenderPass(
|
||||
const DxvkRenderPassOps& ops);
|
||||
|
||||
static bool compareOps(
|
||||
const DxvkRenderPassOps& a,
|
||||
const DxvkRenderPassOps& b);
|
||||
|
||||
};
|
||||
|
||||
@ -167,35 +151,35 @@ namespace dxvk {
|
||||
/**
|
||||
* \brief Render pass pool
|
||||
*
|
||||
* Thread-safe class that manages the render pass
|
||||
* objects that are used within an application.
|
||||
* Manages render pass objects. For each render
|
||||
* pass format, a new render pass object will
|
||||
* be created, but no two render pass objects
|
||||
* will have the same format.
|
||||
*/
|
||||
class DxvkRenderPassPool : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkRenderPassPool(const Rc<vk::DeviceFn>& vkd);
|
||||
DxvkRenderPassPool(
|
||||
const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkRenderPassPool();
|
||||
|
||||
/**
|
||||
* \brief Retrieves a render pass object
|
||||
*
|
||||
* \param [in] fmt Render target formats
|
||||
* \returns Compatible render pass object
|
||||
* \param [in] fmt The render pass format
|
||||
* \returns Matching render pass object
|
||||
*/
|
||||
Rc<DxvkRenderPass> getRenderPass(
|
||||
const DxvkRenderPassFormat& fmt);
|
||||
const DxvkRenderPassFormat& fmt);
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
const Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::vector<Rc<DxvkRenderPass>> m_renderPasses;
|
||||
|
||||
Rc<DxvkRenderPass> createRenderPass(
|
||||
const DxvkRenderPassFormat& fmt);
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -34,7 +34,7 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkFramebuffer> DxvkSwapchain::getFramebuffer(
|
||||
Rc<DxvkImageView> DxvkSwapchain::getImageView(
|
||||
const Rc<DxvkSemaphore>& wakeSync) {
|
||||
VkResult status = this->acquireNextImage(wakeSync);
|
||||
|
||||
@ -136,17 +136,6 @@ namespace dxvk {
|
||||
if (m_vkd->vkCreateSwapchainKHR(m_vkd->device(), &swapInfo, nullptr, &m_handle) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSwapchain: Failed to recreate swap chain");
|
||||
|
||||
// Create the render pass object
|
||||
DxvkRenderPassFormat renderTargetFormat;
|
||||
|
||||
renderTargetFormat.setColorFormat(0,
|
||||
DxvkRenderTargetFormat { fmt.format,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR });
|
||||
|
||||
m_renderPass = new DxvkRenderPass(
|
||||
m_vkd, renderTargetFormat);
|
||||
|
||||
// Retrieve swap images
|
||||
auto swapImages = this->retrieveSwapImages();
|
||||
|
||||
@ -181,16 +170,8 @@ namespace dxvk {
|
||||
viewInfo.numLayers = swapInfo.imageArrayLayers;
|
||||
|
||||
for (size_t i = 0; i < swapImages.size(); i++) {
|
||||
Rc<DxvkImage> image = new DxvkImage(m_vkd, imageInfo, swapImages.at(i));
|
||||
Rc<DxvkImageView> iview = m_device->createImageView(image, viewInfo);
|
||||
|
||||
DxvkRenderTargets renderTargets;
|
||||
renderTargets.setColorTarget(0, iview,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
m_framebuffers.at(i) = new DxvkFramebuffer(
|
||||
m_vkd, m_renderPass, renderTargets,
|
||||
DxvkFramebufferSize());
|
||||
m_framebuffers.at(i) = m_device->createImageView(
|
||||
new DxvkImage(m_vkd, imageInfo, swapImages.at(i)), viewInfo);
|
||||
|
||||
m_semaphoreSet.at(i).acquireSync = m_device->createSemaphore();
|
||||
m_semaphoreSet.at(i).presentSync = m_device->createSemaphore();
|
||||
|
@ -53,20 +53,20 @@ namespace dxvk {
|
||||
*
|
||||
* Retrieves a set of semaphores for the acquire
|
||||
* and present operations. This must be called
|
||||
* \e before \c getFramebuffer.
|
||||
* \e before \c getImageView.
|
||||
* \returns Semaphore pair
|
||||
*/
|
||||
DxvkSwapSemaphores getSemaphorePair();
|
||||
|
||||
/**
|
||||
* \brief Retrieves the framebuffer for the current frame
|
||||
* \brief Retrieves the image view for the current frame
|
||||
*
|
||||
* If necessary, this will automatically recreate the
|
||||
* underlying swapchain object and framebuffer objects.
|
||||
* underlying swapchain object and image view objects.
|
||||
* \param [in] wakeSync Semaphore to signal
|
||||
* \returns The framebuffer object
|
||||
* \returns The image view object
|
||||
*/
|
||||
Rc<DxvkFramebuffer> getFramebuffer(
|
||||
Rc<DxvkImageView> getImageView(
|
||||
const Rc<DxvkSemaphore>& wakeSync);
|
||||
|
||||
/**
|
||||
@ -83,7 +83,7 @@ namespace dxvk {
|
||||
/**
|
||||
* \brief Changes swapchain properties
|
||||
*
|
||||
* This must not be called between \ref getFramebuffer
|
||||
* This must not be called between \ref getImageView
|
||||
* and \ref present as this method may recreate the swap
|
||||
* chain and framebuffer objects immediately.
|
||||
* \param [in] props New swapchain properties
|
||||
@ -102,8 +102,7 @@ namespace dxvk {
|
||||
uint32_t m_imageIndex = 0;
|
||||
uint32_t m_frameIndex = 0;
|
||||
|
||||
Rc<DxvkRenderPass> m_renderPass;
|
||||
std::vector<Rc<DxvkFramebuffer>> m_framebuffers;
|
||||
std::vector<Rc<DxvkImageView>> m_framebuffers;
|
||||
std::vector<DxvkSwapSemaphores> m_semaphoreSet;
|
||||
|
||||
VkResult acquireNextImage(
|
||||
|
@ -170,8 +170,8 @@ namespace dxvk::hud {
|
||||
viewInfo.numLayers = 1;
|
||||
|
||||
m_renderTargetView = m_device->createImageView(m_renderTarget, viewInfo);
|
||||
m_renderTargetInfo.setColorTarget(0, m_renderTargetView,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
m_renderTargetInfo.color[0] = { m_renderTargetView,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user