[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.
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);
});
}

View File

@ -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);
}

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) {
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();
}
@ -1524,12 +1519,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();
@ -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();
VkRect2D renderArea;
@ -1547,7 +1555,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;
@ -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() {
m_flags.set(
DxvkContextFlag::CpDirtyPipeline,
@ -1724,7 +1757,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);
@ -1836,8 +1869,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);

View File

@ -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();

View File

@ -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 };

View File

@ -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);
}

View File

@ -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 };
}
}

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 {
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;
};

View File

@ -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;
}
}

View File

@ -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);
};
}

View File

@ -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();

View File

@ -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(

View File

@ -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 };
}