1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-19 05:52:11 +01:00

[dxvk] Refactor DxvkFramebuffer and DxvkRenderpass

This commit is contained in:
Philip Rebohle 2018-04-30 13:12:28 +02:00
parent 41fca78d27
commit e30a8299e6
13 changed files with 535 additions and 551 deletions

View File

@ -2591,20 +2591,20 @@ namespace dxvk {
// target bindings are updated. Set up the attachments. // target bindings are updated. Set up the attachments.
for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) { for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) {
if (m_state.om.renderTargetViews.at(i) != nullptr) { 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)->GetImageView(),
m_state.om.renderTargetViews.at(i)->GetRenderLayout()); m_state.om.renderTargetViews.at(i)->GetRenderLayout() };
} }
} }
if (m_state.om.depthStencilView != nullptr) { if (m_state.om.depthStencilView != nullptr) {
attachments.setDepthTarget( attachments.depth = {
m_state.om.depthStencilView->GetImageView(), m_state.om.depthStencilView->GetImageView(),
m_state.om.depthStencilView->GetRenderLayout()); m_state.om.depthStencilView->GetRenderLayout() };
} }
// Create and bind the framebuffer object to the context // Create and bind the framebuffer object to the context
EmitCs([cAttachments = attachments] (DxvkContext* ctx) { EmitCs([cAttachments = std::move(attachments)] (DxvkContext* ctx) {
ctx->bindRenderTargets(cAttachments); ctx->bindRenderTargets(cAttachments);
}); });
} }

View File

@ -169,26 +169,27 @@ namespace dxvk {
VK_FORMAT_UNDEFINED); 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); DxvkRenderTargets renderTargets;
auto framebufferSize = framebuffer->size(); renderTargets.color[0].view = swapImage;
renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
m_context->bindFramebuffer(framebuffer); m_context->bindRenderTargets(renderTargets);
VkViewport viewport; VkViewport viewport;
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = 0.0f;
viewport.width = static_cast<float>(framebufferSize.width); viewport.width = float(swapImage->imageInfo().extent.width);
viewport.height = static_cast<float>(framebufferSize.height); viewport.height = float(swapImage->imageInfo().extent.height);
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
VkRect2D scissor; VkRect2D scissor;
scissor.offset.x = 0; scissor.offset.x = 0;
scissor.offset.y = 0; scissor.offset.y = 0;
scissor.extent.width = framebufferSize.width; scissor.extent.width = swapImage->imageInfo().extent.width;
scissor.extent.height = framebufferSize.height; scissor.extent.height = swapImage->imageInfo().extent.height;
m_context->setViewports(1, &viewport, &scissor); m_context->setViewports(1, &viewport, &scissor);
@ -214,9 +215,11 @@ namespace dxvk {
m_device->submitCommandList( m_device->submitCommandList(
m_context->endRecording(), m_context->endRecording(),
sem.acquireSync, sem.presentSync); swapSemas.acquireSync,
swapSemas.presentSync);
m_swapchain->present(sem.presentSync); m_swapchain->present(
swapSemas.presentSync);
} }

View File

@ -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) { void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) {
m_state.om.renderTargets = 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 // Create a new framebuffer object next
// time we start rendering something // time we start rendering something
m_flags.set(DxvkContextFlag::GpDirtyFramebuffer); m_flags.set(DxvkContextFlag::GpDirtyFramebuffer);
@ -403,27 +389,36 @@ namespace dxvk {
// Check whether the render target view is an attachment // Check whether the render target view is an attachment
// of the current framebuffer. If not, we need to create // of the current framebuffer. If not, we need to create
// a temporary framebuffer. // a temporary framebuffer.
uint32_t attachmentIndex = MaxNumRenderTargets; int32_t attachmentIndex = -1;
if (m_state.om.framebuffer != nullptr) if (m_state.om.framebuffer != nullptr)
attachmentIndex = m_state.om.framebuffer->findAttachment(imageView); attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
if (attachmentIndex == MaxNumRenderTargets) { if (attachmentIndex < 0) {
this->spillRenderPass(); 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 // Set up and bind a temporary framebuffer
DxvkRenderTargets attachments; DxvkRenderTargets attachments;
DxvkRenderPassOps ops;
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) { if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
attachments.setColorTarget(0, imageView, attachments.color[0].view = imageView;
imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
ops.colorOps[0] = op;
} else { } else {
attachments.setDepthTarget(imageView, attachments.depth.view = imageView;
imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
ops.depthOps = op;
} }
this->renderPassBindFramebuffer( this->renderPassBindFramebuffer(
m_device->createFramebuffer(attachments)); m_device->createFramebuffer(attachments), ops);
} else { } else {
// Make sure that the currently bound // Make sure that the currently bound
// framebuffer can be rendered to // framebuffer can be rendered to
@ -436,7 +431,7 @@ namespace dxvk {
clearInfo.colorAttachment = attachmentIndex; clearInfo.colorAttachment = attachmentIndex;
clearInfo.clearValue = clearValue; clearInfo.clearValue = clearValue;
if (attachmentIndex == MaxNumRenderTargets) if (attachmentIndex < 0)
clearInfo.colorAttachment = 0; clearInfo.colorAttachment = 0;
m_cmd->cmdClearAttachments( m_cmd->cmdClearAttachments(
@ -444,7 +439,7 @@ namespace dxvk {
// If we used a temporary framebuffer, we'll have to unbind it // If we used a temporary framebuffer, we'll have to unbind it
// again in order to not disturb subsequent rendering commands. // again in order to not disturb subsequent rendering commands.
if (attachmentIndex == MaxNumRenderTargets) if (attachmentIndex < 0)
this->renderPassUnbindFramebuffer(); this->renderPassUnbindFramebuffer();
} }
@ -1524,12 +1519,23 @@ namespace dxvk {
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound) if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)
&& (m_state.om.framebuffer != nullptr)) { && (m_state.om.framebuffer != nullptr)) {
m_flags.set(DxvkContextFlag::GpRenderPassBound); 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() { void DxvkContext::spillRenderPass() {
// TODO execute pending clears
if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
m_flags.clr(DxvkContextFlag::GpRenderPassBound); m_flags.clr(DxvkContextFlag::GpRenderPassBound);
this->renderPassUnbindFramebuffer(); this->renderPassUnbindFramebuffer();
@ -1537,7 +1543,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(); const DxvkFramebufferSize fbSize = framebuffer->size();
VkRect2D renderArea; VkRect2D renderArea;
@ -1547,7 +1555,7 @@ namespace dxvk {
VkRenderPassBeginInfo info; VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr; info.pNext = nullptr;
info.renderPass = framebuffer->renderPass(); info.renderPass = framebuffer->getRenderPassHandle(ops);
info.framebuffer = framebuffer->handle(); info.framebuffer = framebuffer->handle();
info.renderArea = renderArea; info.renderArea = renderArea;
info.clearValueCount = 0; info.clearValueCount = 0;
@ -1565,6 +1573,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() { void DxvkContext::unbindComputePipeline() {
m_flags.set( m_flags.set(
DxvkContextFlag::CpDirtyPipeline, DxvkContextFlag::CpDirtyPipeline,
@ -1724,7 +1757,7 @@ namespace dxvk {
DxvkAttachment depthAttachment; DxvkAttachment depthAttachment;
if (bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS && m_state.om.framebuffer != nullptr) 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++) { for (uint32_t i = 0; i < layout->bindingCount(); i++) {
const auto& binding = layout->binding(i); const auto& binding = layout->binding(i);
@ -1836,8 +1869,8 @@ namespace dxvk {
auto fb = m_device->createFramebuffer(m_state.om.renderTargets); auto fb = m_device->createFramebuffer(m_state.om.renderTargets);
m_state.gp.state.msSampleCount = fb->sampleCount(); m_state.gp.state.msSampleCount = fb->getSampleCount();
m_state.gp.state.omRenderPass = fb->renderPass(); m_state.gp.state.omRenderPass = fb->getDefaultRenderPassHandle();
m_state.om.framebuffer = fb; m_state.om.framebuffer = fb;
m_flags.set(DxvkContextFlag::GpDirtyPipelineState); m_flags.set(DxvkContextFlag::GpDirtyPipelineState);

View File

@ -71,13 +71,6 @@ namespace dxvk {
void endQuery( void endQuery(
const DxvkQueryRevision& query); const DxvkQueryRevision& query);
/**
* \brief Sets framebuffer
* \param [in] fb Framebuffer
*/
void bindFramebuffer(
const Rc<DxvkFramebuffer>& fb);
/** /**
* \brief Sets render targets * \brief Sets render targets
* *
@ -650,9 +643,15 @@ namespace dxvk {
void spillRenderPass(); void spillRenderPass();
void renderPassBindFramebuffer( void renderPassBindFramebuffer(
const Rc<DxvkFramebuffer>& framebuffer); const Rc<DxvkFramebuffer>& framebuffer,
const DxvkRenderPassOps& ops);
void renderPassUnbindFramebuffer(); void renderPassUnbindFramebuffer();
void resetRenderPassOps(
const DxvkRenderTargets& renderTargets,
DxvkRenderPassOps& renderPassOps);
void unbindComputePipeline(); void unbindComputePipeline();
void updateComputePipeline(); void updateComputePipeline();

View File

@ -54,7 +54,10 @@ namespace dxvk {
struct DxvkOutputMergerState { struct DxvkOutputMergerState {
std::array<VkClearValue, MaxNumRenderTargets + 1> clearValue;
DxvkRenderTargets renderTargets; DxvkRenderTargets renderTargets;
DxvkRenderPassOps renderPassOps;
Rc<DxvkFramebuffer> framebuffer = nullptr; Rc<DxvkFramebuffer> framebuffer = nullptr;
DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }; DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f };

View File

@ -117,11 +117,11 @@ namespace dxvk {
m_properties.limits.maxFramebufferHeight, m_properties.limits.maxFramebufferHeight,
m_properties.limits.maxFramebufferLayers }; m_properties.limits.maxFramebufferLayers };
auto format = renderTargets.renderPassFormat(); auto renderPassFormat = DxvkFramebuffer::getRenderPassFormat(renderTargets);
auto renderPass = m_renderPassPool->getRenderPass(format); auto renderPassObject = m_renderPassPool->getRenderPass(renderPassFormat);
return new DxvkFramebuffer(m_vkd, return new DxvkFramebuffer(m_vkd,
renderPass, renderTargets, defaultSize); renderPassObject, renderTargets, defaultSize);
} }

View File

@ -2,97 +2,6 @@
namespace dxvk { 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( DxvkFramebuffer::DxvkFramebuffer(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkRenderPass>& renderPass, const Rc<DxvkRenderPass>& renderPass,
@ -101,43 +10,109 @@ namespace dxvk {
: m_vkd (vkd), : m_vkd (vkd),
m_renderPass (renderPass), m_renderPass (renderPass),
m_renderTargets (renderTargets), m_renderTargets (renderTargets),
m_framebufferSize (renderTargets.getImageSize(defaultSize)) { m_renderSize (computeRenderSize(defaultSize)) {
std::array<VkImageView, MaxNumRenderTargets + 1> views; 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; VkFramebufferCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.pNext = nullptr; info.pNext = nullptr;
info.flags = 0; info.flags = 0;
info.renderPass = renderPass->handle(); info.renderPass = m_renderPass->getDefaultHandle();
info.attachmentCount = viewCount; info.attachmentCount = viewId;
info.pAttachments = views.data(); info.pAttachments = views.data();
info.width = m_framebufferSize.width; info.width = m_renderSize.width;
info.height = m_framebufferSize.height; info.height = m_renderSize.height;
info.layers = m_framebufferSize.layers; info.layers = m_renderSize.layers;
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_framebuffer) != VK_SUCCESS) if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_handle) != VK_SUCCESS)
throw DxvkError("DxvkFramebuffer: Failed to create framebuffer object"); Logger::err("DxvkFramebuffer: Failed to create framebuffer object");
} }
DxvkFramebuffer::~DxvkFramebuffer() { DxvkFramebuffer::~DxvkFramebuffer() {
m_vkd->vkDestroyFramebuffer( m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_handle, nullptr);
m_vkd->device(), m_framebuffer, nullptr);
} }
uint32_t DxvkFramebuffer::findAttachment( int32_t DxvkFramebuffer::findAttachment(const Rc<DxvkImageView>& view) const {
const Rc<DxvkImageView>& view) const { for (uint32_t i = 0; i < m_attachmentCount; i++) {
if (m_renderTargets.getDepthTarget().view == view) if (m_attachments[i]->view == view)
return 0; return int32_t(i);
}
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++) { for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (m_renderTargets.getColorTarget(i).view == view) if (renderTargets.color[i].view != nullptr) {
return i; 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;
}
} }
return MaxNumRenderTargets; 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 };
} }
} }

View File

@ -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 { struct DxvkAttachment {
Rc<DxvkImageView> view = nullptr; Rc<DxvkImageView> view = nullptr;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; 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 * Stores all depth-stencil and color
* and provides methods to query the render pass * attachments attached to a framebuffer.
* format. Note that all render target views must
* have the same size and number of array layers.
*/ */
class DxvkRenderTargets { struct DxvkRenderTargets {
DxvkAttachment depth;
public: DxvkAttachment color[MaxNumRenderTargets];
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;
}; };
/** /**
* \brief DXVK framebuffer * \brief Framebuffer
* *
* A framebuffer either stores a set of image views * A framebuffer either stores a set of image views
* that will be used as render targets, or in case * that will be used as render targets, or in case
* no render targets are being used, fixed viewport * no render targets are attached, fixed dimensions.
* dimensions.
*/ */
class DxvkFramebuffer : public DxvkResource { class DxvkFramebuffer : public DxvkResource {
@ -157,6 +59,7 @@ namespace dxvk {
const Rc<DxvkRenderPass>& renderPass, const Rc<DxvkRenderPass>& renderPass,
const DxvkRenderTargets& renderTargets, const DxvkRenderTargets& renderTargets,
const DxvkFramebufferSize& defaultSize); const DxvkFramebufferSize& defaultSize);
~DxvkFramebuffer(); ~DxvkFramebuffer();
/** /**
@ -164,15 +67,7 @@ namespace dxvk {
* \returns Framebuffer handle * \returns Framebuffer handle
*/ */
VkFramebuffer handle() const { VkFramebuffer handle() const {
return m_framebuffer; return m_handle;
}
/**
* \brief Render pass handle
* \returns Render pass handle
*/
VkRenderPass renderPass() const {
return m_renderPass->handle();
} }
/** /**
@ -180,45 +75,124 @@ namespace dxvk {
* \returns Framebuffer size * \returns Framebuffer size
*/ */
DxvkFramebufferSize size() const { DxvkFramebufferSize size() const {
return m_framebufferSize; return m_renderSize;
}
/**
* \brief Render target info
* \returns Render target info
*/
const DxvkRenderTargets& renderTargets() const {
return m_renderTargets;
} }
/** /**
* \brief Sample count * \brief Sample count
* \returns Sample count * \returns Sample count
*/ */
VkSampleCountFlagBits sampleCount() const { VkSampleCountFlagBits getSampleCount() const {
return m_renderPass->sampleCount(); 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 * Retrieves the render pass handle that was used
* \returns The attachment index, or \c 0 for a depth-stencil * to create the Vulkan framebuffer object with,
* attachment, or \c MaxNumRenderTargets if the given * and that should be used to create pipelines.
* view is not a framebuffer attachment. * \returns The default render pass handle
*/ */
uint32_t findAttachment( VkRenderPass getDefaultRenderPassHandle() const {
const Rc<DxvkImageView>& view) 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: private:
Rc<vk::DeviceFn> m_vkd; const Rc<vk::DeviceFn> m_vkd;
Rc<DxvkRenderPass> m_renderPass; const Rc<DxvkRenderPass> m_renderPass;
const DxvkRenderTargets m_renderTargets;
const DxvkFramebufferSize m_renderSize;
DxvkRenderTargets m_renderTargets; uint32_t m_attachmentCount = 0;
DxvkFramebufferSize m_framebufferSize = { 0, 0, 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;
}; };

View File

@ -4,29 +4,56 @@
namespace dxvk { namespace dxvk {
bool DxvkRenderPassFormat::matchesFormat(const DxvkRenderPassFormat& other) const {
bool equal = m_samples == other.m_samples;
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( DxvkRenderPass::DxvkRenderPass(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const DxvkRenderPassFormat& fmt) const DxvkRenderPassFormat& fmt)
: m_vkd(vkd), m_format(fmt) { : m_vkd(vkd), m_format(fmt),
m_default(createRenderPass(DxvkRenderPassOps())) {
}
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; std::vector<VkAttachmentDescription> attachments;
VkAttachmentReference depthRef; VkAttachmentReference depthRef;
@ -34,51 +61,47 @@ namespace dxvk {
// Render passes may not require the previous // Render passes may not require the previous
// contents of the attachments to be preserved. // 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++) { for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
const DxvkRenderTargetFormat colorFmt = fmt.getColorFormat(i);
colorRef[i].attachment = VK_ATTACHMENT_UNUSED; colorRef[i].attachment = VK_ATTACHMENT_UNUSED;
colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED; colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
if (colorFmt.format != VK_FORMAT_UNDEFINED) { if (m_format.color[i].format != VK_FORMAT_UNDEFINED) {
VkAttachmentDescription desc; VkAttachmentDescription desc;
desc.flags = 0; desc.flags = 0;
desc.format = colorFmt.format; desc.format = m_format.color[i].format;
desc.samples = fmt.getSampleCount(); desc.samples = m_format.sampleCount;
desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; desc.loadOp = ops.colorOps[i].loadOp;
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; desc.storeOp = ops.colorOps[i].storeOp;
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc.initialLayout = colorFmt.initialLayout; desc.initialLayout = ops.colorOps[i].loadLayout;
desc.finalLayout = colorFmt.finalLayout; desc.finalLayout = ops.colorOps[i].storeLayout;
colorRef[i].attachment = attachments.size(); 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); 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; VkSubpassDescription subpass;
subpass.flags = 0; subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
@ -87,11 +110,14 @@ namespace dxvk {
subpass.colorAttachmentCount = colorRef.size(); subpass.colorAttachmentCount = colorRef.size();
subpass.pColorAttachments = colorRef.data(); subpass.pColorAttachments = colorRef.data();
subpass.pResolveAttachments = nullptr; subpass.pResolveAttachments = nullptr;
subpass.pDepthStencilAttachment = depthFmt.format != VK_FORMAT_UNDEFINED ? &depthRef : nullptr; subpass.pDepthStencilAttachment = &depthRef;
subpass.preserveAttachmentCount = 0; subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr; 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_SUBPASS_EXTERNAL, 0,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
@ -139,14 +165,33 @@ namespace dxvk {
info.dependencyCount = subpassDeps.size(); info.dependencyCount = subpassDeps.size();
info.pDependencies = subpassDeps.data(); info.pDependencies = subpassDeps.data();
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &m_renderPass) != VK_SUCCESS) VkRenderPass renderPass = VK_NULL_HANDLE;
throw DxvkError("DxvkRenderPass::DxvkRenderPass: Failed to create render pass object");
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() { bool DxvkRenderPass::compareOps(
m_vkd->vkDestroyRenderPass( const DxvkRenderPassOps& a,
m_vkd->device(), m_renderPass, nullptr); 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( Rc<DxvkRenderPass> DxvkRenderPassPool::getRenderPass(const DxvkRenderPassFormat& fmt) {
const DxvkRenderPassFormat& fmt) {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
Rc<DxvkRenderPass> renderPass = nullptr; for (const auto& r : m_renderPasses) {
if (r->hasCompatibleFormat(fmt))
for (uint32_t i = 0; i < m_renderPasses.size() && renderPass == nullptr; i++) { return r;
if (m_renderPasses[i]->matchesFormat(fmt))
renderPass = m_renderPasses[i];
} }
if (renderPass != nullptr) Rc<DxvkRenderPass> rp = new DxvkRenderPass(m_vkd, fmt);
return renderPass; m_renderPasses.push_back(rp);
return rp;
renderPass = this->createRenderPass(fmt);
m_renderPasses.push_back(renderPass);
return renderPass;
}
Rc<DxvkRenderPass> DxvkRenderPassPool::createRenderPass(
const DxvkRenderPassFormat& fmt) {
return new DxvkRenderPass(m_vkd, fmt);
} }
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <unordered_map> #include <vector>
#include "dxvk_hash.h" #include "dxvk_hash.h"
#include "dxvk_include.h" #include "dxvk_include.h"
@ -10,50 +10,84 @@
namespace dxvk { 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 * Stores the image format of the attachment and
* final layout of a render target. * the image layout that is used while rendering.
*/ */
struct DxvkRenderTargetFormat { struct DxvkAttachmentFormat {
VkFormat format = VK_FORMAT_UNDEFINED; VkFormat format = VK_FORMAT_UNDEFINED;
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageLayout renderLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}; };
/** /**
* \brief Render pass format * \brief Render pass format
* *
* Stores the formats of all render targets * Stores the attachment formats for all depth and
* that are used by a framebuffer object. * 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: public:
/** DxvkRenderPass(
* \brief Retrieves color target format const Rc<vk::DeviceFn>& vkd,
* const DxvkRenderPassFormat& fmt);
* If the color target has not been defined,
* this will return \c VK_FORMAT_UNDEFINED. ~DxvkRenderPass();
* \param [in] id Color target index
* \returns Color target format
*/
DxvkRenderTargetFormat getColorFormat(uint32_t id) const {
return m_color.at(id);
}
/** /**
* \brief Retrieves depth-stencil format * \brief Checks whether a format is compatible
* *
* If the color target has not been defined, * Two render pass formats are considered compatible
* this will return \c VK_FORMAT_UNDEFINED. * 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 { bool hasCompatibleFormat(
return m_depth; const DxvkRenderPassFormat& fmt) const;
}
/** /**
* \brief Retrieves sample count * \brief Retrieves sample count
@ -63,103 +97,53 @@ namespace dxvk {
* \returns Sample count * \returns Sample count
*/ */
VkSampleCountFlagBits getSampleCount() const { 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 * The default render pass handle should be used to
* \param [in] fmt Color target format * 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) { VkRenderPass getDefaultHandle() const {
m_color.at(id) = fmt; return m_default;
} }
/** /**
* \brief Sets depth-stencil format * \brief Returns handle to a specialized render pass
* \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
* *
* \param [in] other The render pass format to compare to * Returns a handle to a render pass with the given
* \returns \c true if the render pass formats are compatible * set of parameters. This should be used for calls
*/ * to \c vkCmdBeginRenderPass.
bool matchesFormat(const DxvkRenderPassFormat& other) const; * \param [in] ops Attachment ops
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 Render pass handle * \returns Render pass handle
*/ */
VkRenderPass handle() const { VkRenderPass getHandle(
return m_renderPass; const DxvkRenderPassOps& ops);
}
/**
* \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);
}
private: private:
struct Instance {
DxvkRenderPassOps ops;
VkRenderPass handle;
};
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
DxvkRenderPassFormat m_format; DxvkRenderPassFormat m_format;
VkRenderPass m_renderPass; 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 * \brief Render pass pool
* *
* Thread-safe class that manages the render pass * Manages render pass objects. For each render
* objects that are used within an application. * 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 { class DxvkRenderPassPool : public RcObject {
public: public:
DxvkRenderPassPool(const Rc<vk::DeviceFn>& vkd); DxvkRenderPassPool(
const Rc<vk::DeviceFn>& vkd);
~DxvkRenderPassPool(); ~DxvkRenderPassPool();
/** /**
* \brief Retrieves a render pass object * \brief Retrieves a render pass object
* *
* \param [in] fmt Render target formats * \param [in] fmt The render pass format
* \returns Compatible render pass object * \returns Matching render pass object
*/ */
Rc<DxvkRenderPass> getRenderPass( Rc<DxvkRenderPass> getRenderPass(
const DxvkRenderPassFormat& fmt); const DxvkRenderPassFormat& fmt);
private: private:
Rc<vk::DeviceFn> m_vkd; const Rc<vk::DeviceFn> m_vkd;
std::mutex m_mutex; std::mutex m_mutex;
std::vector<Rc<DxvkRenderPass>> m_renderPasses; std::vector<Rc<DxvkRenderPass>> m_renderPasses;
Rc<DxvkRenderPass> createRenderPass(
const DxvkRenderPassFormat& fmt);
}; };
} }

View File

@ -34,7 +34,7 @@ namespace dxvk {
} }
Rc<DxvkFramebuffer> DxvkSwapchain::getFramebuffer( Rc<DxvkImageView> DxvkSwapchain::getImageView(
const Rc<DxvkSemaphore>& wakeSync) { const Rc<DxvkSemaphore>& wakeSync) {
VkResult status = this->acquireNextImage(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) if (m_vkd->vkCreateSwapchainKHR(m_vkd->device(), &swapInfo, nullptr, &m_handle) != VK_SUCCESS)
throw DxvkError("DxvkSwapchain: Failed to recreate swap chain"); 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 // Retrieve swap images
auto swapImages = this->retrieveSwapImages(); auto swapImages = this->retrieveSwapImages();
@ -181,16 +170,8 @@ namespace dxvk {
viewInfo.numLayers = swapInfo.imageArrayLayers; viewInfo.numLayers = swapInfo.imageArrayLayers;
for (size_t i = 0; i < swapImages.size(); i++) { for (size_t i = 0; i < swapImages.size(); i++) {
Rc<DxvkImage> image = new DxvkImage(m_vkd, imageInfo, swapImages.at(i)); m_framebuffers.at(i) = m_device->createImageView(
Rc<DxvkImageView> iview = m_device->createImageView(image, viewInfo); new DxvkImage(m_vkd, imageInfo, swapImages.at(i)), 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_semaphoreSet.at(i).acquireSync = m_device->createSemaphore(); m_semaphoreSet.at(i).acquireSync = m_device->createSemaphore();
m_semaphoreSet.at(i).presentSync = m_device->createSemaphore(); m_semaphoreSet.at(i).presentSync = m_device->createSemaphore();

View File

@ -53,20 +53,20 @@ namespace dxvk {
* *
* Retrieves a set of semaphores for the acquire * Retrieves a set of semaphores for the acquire
* and present operations. This must be called * and present operations. This must be called
* \e before \c getFramebuffer. * \e before \c getImageView.
* \returns Semaphore pair * \returns Semaphore pair
*/ */
DxvkSwapSemaphores getSemaphorePair(); 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 * 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 * \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); const Rc<DxvkSemaphore>& wakeSync);
/** /**
@ -83,7 +83,7 @@ namespace dxvk {
/** /**
* \brief Changes swapchain properties * \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 * and \ref present as this method may recreate the swap
* chain and framebuffer objects immediately. * chain and framebuffer objects immediately.
* \param [in] props New swapchain properties * \param [in] props New swapchain properties
@ -102,8 +102,7 @@ namespace dxvk {
uint32_t m_imageIndex = 0; uint32_t m_imageIndex = 0;
uint32_t m_frameIndex = 0; uint32_t m_frameIndex = 0;
Rc<DxvkRenderPass> m_renderPass; std::vector<Rc<DxvkImageView>> m_framebuffers;
std::vector<Rc<DxvkFramebuffer>> m_framebuffers;
std::vector<DxvkSwapSemaphores> m_semaphoreSet; std::vector<DxvkSwapSemaphores> m_semaphoreSet;
VkResult acquireNextImage( VkResult acquireNextImage(

View File

@ -170,8 +170,8 @@ namespace dxvk::hud {
viewInfo.numLayers = 1; viewInfo.numLayers = 1;
m_renderTargetView = m_device->createImageView(m_renderTarget, viewInfo); m_renderTargetView = m_device->createImageView(m_renderTarget, viewInfo);
m_renderTargetInfo.setColorTarget(0, m_renderTargetView, m_renderTargetInfo.color[0] = { m_renderTargetView,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
} }