1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-12 13:08:50 +01:00

[dxvk] Refactor framebuffer creation

This commit is contained in:
Philip Rebohle 2021-11-05 13:56:19 +01:00
parent f1aad6cb7b
commit 2527ea45b9
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 26 additions and 299 deletions

View File

@ -4004,7 +4004,7 @@ namespace dxvk {
const VkClearValue* clearValues) {
const DxvkFramebufferSize fbSize = framebufferInfo.size();
Rc<DxvkFramebuffer> framebuffer = m_device->createFramebuffer(framebufferInfo.attachments());
Rc<DxvkFramebuffer> framebuffer = m_device->createFramebuffer(framebufferInfo);
VkRect2D renderArea;
renderArea.offset = VkOffset2D { 0, 0 };

View File

@ -113,13 +113,8 @@ namespace dxvk {
Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
const DxvkRenderTargets& renderTargets) {
auto renderPassFormat = DxvkFramebuffer::getRenderPassFormat(renderTargets);
auto renderPassObject = m_objects.renderPassPool().getRenderPass(renderPassFormat);
return new DxvkFramebuffer(m_vkd,
renderPassObject, renderTargets,
getDefaultFramebufferSize());
const DxvkFramebufferInfo& info) {
return new DxvkFramebuffer(m_vkd, info);
}

View File

@ -270,13 +270,11 @@ namespace dxvk {
/**
* \brief Creates framebuffer for a set of render targets
*
* Automatically deduces framebuffer dimensions
* from the supplied render target views.
* \param [in] renderTargets Render targets
* \param [in] info Framebuffer info
* \returns The framebuffer object
*/
Rc<DxvkFramebuffer> createFramebuffer(
const DxvkRenderTargets& renderTargets);
const DxvkFramebufferInfo& info);
/**
* \brief Creates a buffer object

View File

@ -127,41 +127,31 @@ namespace dxvk {
DxvkFramebuffer::DxvkFramebuffer(
const Rc<vk::DeviceFn>& vkd,
DxvkRenderPass* renderPass,
const DxvkRenderTargets& renderTargets,
const DxvkFramebufferSize& defaultSize)
: m_vkd (vkd),
m_renderPass (renderPass),
m_renderTargets (renderTargets),
m_renderSize (computeRenderSize(defaultSize)) {
const DxvkFramebufferInfo& info)
: m_vkd (vkd) {
std::array<VkImageView, MaxNumRenderTargets + 1> views;
uint32_t attachmentCount = 0;
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (m_renderTargets.color[i].view != nullptr) {
views[m_attachmentCount] = m_renderTargets.color[i].view->handle();
m_attachments[m_attachmentCount] = i;
m_attachmentCount += 1;
}
if (info.getColorTarget(i).view != nullptr)
views[attachmentCount++] = info.getColorTarget(i).view->handle();
}
if (m_renderTargets.depth.view != nullptr) {
views[m_attachmentCount] = m_renderTargets.depth.view->handle();
m_attachments[m_attachmentCount] = -1;
m_attachmentCount += 1;
}
if (info.getDepthTarget().view != nullptr)
views[attachmentCount++] = info.getDepthTarget().view->handle();
VkFramebufferCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.renderPass = m_renderPass->getDefaultHandle();
info.attachmentCount = m_attachmentCount;
info.pAttachments = views.data();
info.width = m_renderSize.width;
info.height = m_renderSize.height;
info.layers = m_renderSize.layers;
VkFramebufferCreateInfo fbInfo;
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.pNext = nullptr;
fbInfo.flags = 0;
fbInfo.renderPass = info.renderPass()->getDefaultHandle();
fbInfo.attachmentCount = attachmentCount;
fbInfo.pAttachments = views.data();
fbInfo.width = info.size().width;
fbInfo.height = info.size().height;
fbInfo.layers = info.size().layers;
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_handle) != VK_SUCCESS)
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fbInfo, nullptr, &m_handle) != VK_SUCCESS)
Logger::err("DxvkFramebuffer: Failed to create framebuffer object");
}
@ -170,95 +160,4 @@ namespace dxvk {
m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_handle, nullptr);
}
int32_t DxvkFramebuffer::findAttachment(const Rc<DxvkImageView>& view) const {
for (uint32_t i = 0; i < m_attachmentCount; i++) {
if (getAttachment(i).view->matchesView(view))
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;
}
bool DxvkFramebuffer::isFullSize(const Rc<DxvkImageView>& view) const {
return m_renderSize.width == view->mipLevelExtent(0).width
&& m_renderSize.height == view->mipLevelExtent(0).height
&& m_renderSize.layers == view->info().numLayers;
}
bool DxvkFramebuffer::isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const {
VkImageAspectFlags writableAspects = vk::getWritableAspectsForLayout(getAttachment(attachmentIndex).layout);
return (writableAspects & aspects) == aspects;
}
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 {
// Some games bind render targets of a different size and
// expect it to work, so we'll compute the minimum size
DxvkFramebufferSize minSize = defaultSize;
if (m_renderTargets.depth.view != nullptr) {
DxvkFramebufferSize depthSize = this->computeRenderTargetSize(m_renderTargets.depth.view);
minSize.width = std::min(minSize.width, depthSize.width);
minSize.height = std::min(minSize.height, depthSize.height);
minSize.layers = std::min(minSize.layers, depthSize.layers);
}
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (m_renderTargets.color[i].view != nullptr) {
DxvkFramebufferSize colorSize = this->computeRenderTargetSize(m_renderTargets.color[i].view);
minSize.width = std::min(minSize.width, colorSize.width);
minSize.height = std::min(minSize.height, colorSize.height);
minSize.layers = std::min(minSize.layers, colorSize.layers);
}
}
return minSize;
}
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

@ -236,9 +236,7 @@ namespace dxvk {
DxvkFramebuffer(
const Rc<vk::DeviceFn>& vkd,
DxvkRenderPass* renderPass,
const DxvkRenderTargets& renderTargets,
const DxvkFramebufferSize& defaultSize);
const DxvkFramebufferInfo& info);
~DxvkFramebuffer();
@ -250,173 +248,10 @@ namespace dxvk {
return m_handle;
}
/**
* \brief Framebuffer size
* \returns Framebuffer size
*/
DxvkFramebufferSize size() const {
return m_renderSize;
}
/**
* \brief Framebuffer sample count
*
* Returns the sample count of the color
* and depth-stencil attachments, or 0 if
* there are no attachments.
* \returns Sample count
*/
VkSampleCountFlags getSampleCount() const {
return m_attachmentCount != 0
? m_renderPass->getSampleCount()
: 0;
}
/**
* \brief Retrieves default render pass handle
*
* 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
*/
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 Retrieves render pass
* \returns Render pass reference
*/
DxvkRenderPass* getRenderPass() const {
return m_renderPass;
}
/**
* \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 Queries color attachment index of a given attachment
* \returns The index, or -1 if the given attachment is the depth attachment
*/
const int32_t getColorAttachmentIndex(uint32_t id) const {
return m_attachments[id];
}
/**
* \brief Retrieves attachment by index
*
* \param [in] id Framebuffer attachment ID
* \returns The framebuffer attachment
*/
const DxvkAttachment& getAttachment(uint32_t id) const {
int32_t idx = getColorAttachmentIndex(id);
return idx < 0 ? m_renderTargets.depth : m_renderTargets.color[idx];
}
/**
* \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 Checks whether view and framebuffer sizes match
*
* Tests whether the size of the framebuffer is the same
* as the size of one of its views. This may be \c false
* when mixing attachments with mismatched dimensions.
* \param [in] view Image view to test
* \returns \c true if \c view has the same size as
* the framebuffer.
*/
bool isFullSize(const Rc<DxvkImageView>& view) const;
/**
* \brief Checks whether an attachment is writable
*
* Needed for certain clear optimizations.
* \param [in] attachmentIndex Attachment to check
* \param [in] aspects Aspect mask to check
* \returns \c true if all aspects can be written for the given attachment
*/
bool isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const;
/**
* \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:
const Rc<vk::DeviceFn> m_vkd;
DxvkRenderPass* m_renderPass;
const DxvkRenderTargets m_renderTargets;
const DxvkFramebufferSize m_renderSize;
uint32_t m_attachmentCount = 0;
std::array<int32_t, MaxNumRenderTargets + 1> m_attachments;
VkFramebuffer m_handle = VK_NULL_HANDLE;
DxvkFramebufferSize computeRenderSize(
const DxvkFramebufferSize& defaultSize) const;
DxvkFramebufferSize computeRenderTargetSize(
const Rc<DxvkImageView>& renderTarget) const;
Rc<vk::DeviceFn> m_vkd;
VkFramebuffer m_handle;
};