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:
parent
41fca78d27
commit
e30a8299e6
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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 };
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -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();
|
||||||
|
@ -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(
|
||||||
|
@ -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 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user