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:
parent
f1aad6cb7b
commit
2527ea45b9
@ -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 };
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 };
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user