diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp index 9657ceb31..6e8e8fad1 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp @@ -24,6 +24,7 @@ namespace Nz { class OpenGLCommandPool; class OpenGLFramebuffer; + class OpenGLRenderPass; class NAZARA_OPENGLRENDERER_API OpenGLCommandBuffer final : public CommandBuffer { @@ -55,7 +56,7 @@ namespace Nz inline std::size_t GetPoolIndex() const; inline const OpenGLCommandPool& GetOwner() const; - inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& renderPass, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount); + inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const OpenGLRenderPass& renderPass, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount); inline void SetScissor(Nz::Recti scissorRegion); inline void SetViewport(Nz::Recti viewportRegion); @@ -103,8 +104,8 @@ namespace Nz const OpenGLRenderPipeline* pipeline = nullptr; const OpenGLShaderBinding* shaderBindings = nullptr; UInt64 indexBufferOffset; - std::optional scissorRegion; - std::optional viewportRegion; + std::optional scissorRegion; + std::optional viewportRegion; std::vector vertexBuffers; bool shouldFlipY = false; }; @@ -135,6 +136,7 @@ namespace Nz { std::array clearValues; //< TODO: Remove hard limit? const OpenGLFramebuffer* framebuffer; + const OpenGLRenderPass* renderpass; }; using CommandData = std::variant< diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl index 84b7d3128..334b6af1f 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl @@ -135,12 +135,13 @@ namespace Nz return *m_owner; } - inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& /*renderPass*/, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount) + inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const OpenGLRenderPass& renderPass, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount) { m_maxColorBufferCount = std::max(m_maxColorBufferCount, framebuffer.GetColorBufferCount()); SetFrameBufferData setFramebuffer; setFramebuffer.framebuffer = &framebuffer; + setFramebuffer.renderpass = &renderPass; assert(clearValueCount < setFramebuffer.clearValues.size()); std::copy(clearValues, clearValues + clearValueCount, setFramebuffer.clearValues.begin()); diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp index 71443475c..01a62fd89 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp @@ -40,10 +40,10 @@ namespace Nz void Present(); private: + std::optional m_renderPass; std::size_t m_currentFrame; std::vector> m_renderImage; std::unique_ptr m_context; - OpenGLRenderPass m_renderPass; OpenGLWindowFramebuffer m_framebuffer; RenderWindow& m_owner; Vector2ui m_size; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp index db1932d1f..e80c51eec 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp @@ -134,6 +134,10 @@ namespace Nz::GL bool ProcessErrorStack() const; + inline void ResetColorWriteMasks() const; + inline void ResetDepthWriteMasks() const; + inline void ResetStencilWriteMasks() const; + void SetCurrentTextureUnit(UInt32 textureUnit) const; void SetScissorBox(GLint x, GLint y, GLsizei width, GLsizei height) const; void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) const; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.inl b/include/Nazara/OpenGLRenderer/Wrapper/Context.inl index f194afe99..6b27ce8f3 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.inl @@ -99,6 +99,35 @@ namespace Nz::GL if (m_state.boundVertexArray == vao) m_state.boundVertexArray = 0; } + + inline void Context::ResetColorWriteMasks() const + { + if (!m_state.renderStates.colorWrite) + { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + m_state.renderStates.colorWrite = true; + } + } + + inline void Context::ResetDepthWriteMasks() const + { + if (!m_state.renderStates.depthWrite) + { + glDepthMask(GL_TRUE); + m_state.renderStates.depthWrite = true; + } + } + + inline void Context::ResetStencilWriteMasks() const + { + if (m_state.renderStates.stencilBack.writeMask != 0xFFFFFFFF || m_state.renderStates.stencilFront.writeMask != 0xFFFFFFFF) + { + glStencilMaskSeparate(GL_FRONT_AND_BACK, 0xFFFFFFFF); + m_state.renderStates.stencilBack.writeMask = 0xFFFFFFFF; + m_state.renderStates.stencilFront.writeMask = 0xFFFFFFFF; + } + } + } #include diff --git a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp index 3646986e9..5058b424a 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp @@ -129,6 +129,7 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G cb(glStencilFuncSeparate, PFNGLSTENCILFUNCSEPARATEPROC) \ cb(glStencilOp, PFNGLSTENCILOPPROC) \ cb(glStencilOpSeparate, PFNGLSTENCILOPSEPARATEPROC) \ + cb(glStencilMaskSeparate, PFNGLSTENCILMASKSEPARATEPROC) \ cb(glTexImage2D, PFNGLTEXIMAGE2DPROC) \ cb(glTexImage3D, PFNGLTEXIMAGE3DPROC) \ cb(glTexParameterf, PFNGLTEXPARAMETERFPROC) \ diff --git a/include/Nazara/Renderer/RenderWindowImpl.hpp b/include/Nazara/Renderer/RenderWindowImpl.hpp index b016fbd21..2ef81f2f5 100644 --- a/include/Nazara/Renderer/RenderWindowImpl.hpp +++ b/include/Nazara/Renderer/RenderWindowImpl.hpp @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include namespace Nz { @@ -21,7 +23,6 @@ namespace Nz class Framebuffer; class RendererImpl; class RenderDevice; - class RenderPass; class RenderSurface; class NAZARA_RENDERER_API RenderWindowImpl @@ -37,6 +38,9 @@ namespace Nz virtual const Framebuffer& GetFramebuffer() const = 0; virtual const RenderPass& GetRenderPass() const = 0; + + protected: + static void BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies); }; } diff --git a/include/Nazara/Renderer/RenderWindowParameters.hpp b/include/Nazara/Renderer/RenderWindowParameters.hpp index 952333f8f..956f86a58 100644 --- a/include/Nazara/Renderer/RenderWindowParameters.hpp +++ b/include/Nazara/Renderer/RenderWindowParameters.hpp @@ -15,7 +15,7 @@ namespace Nz { struct RenderWindowParameters { - std::vector depthFormats = {Nz::PixelFormat::Depth32, Nz::PixelFormat::Depth24}; //< By order of preference + std::vector depthFormats = {Nz::PixelFormat::Depth24Stencil8, Nz::PixelFormat::Depth32, Nz::PixelFormat::Depth24}; //< By order of preference bool verticalSync = false; }; } diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp index c94b07ac0..d99c8e4a7 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,8 @@ namespace Nz for (std::size_t i = 0; i < m_maxColorBufferCount; ++i) fboDrawBuffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i); + StackArray colorIndexes = NazaraStackArrayNoInit(std::size_t, m_maxColorBufferCount); + for (const auto& commandVariant : m_commands) { std::visit([&](auto&& command) @@ -105,33 +108,128 @@ namespace Nz context = GL::Context::GetCurrentContext(); + std::size_t colorBufferCount = command.framebuffer->GetColorBufferCount(); + assert(colorBufferCount <= fboDrawBuffers.size()); + + colorIndexes.fill(0); + std::size_t colorIndex = 0; + + GLbitfield clearFields = 0; + std::optional depthStencilIndex; + + std::size_t attachmentCount = command.renderpass->GetAttachmentCount(); + + for (std::size_t i = 0; i < attachmentCount; ++i) + { + const auto& attachmentInfo = command.renderpass->GetAttachment(i); + switch (PixelFormatInfo::GetContent(attachmentInfo.format)) + { + case PixelFormatContent::ColorRGBA: + colorIndexes[colorIndex++] = i; + break; + + case PixelFormatContent::Depth: + if (!depthStencilIndex) + depthStencilIndex = i; + break; + + case PixelFormatContent::DepthStencil: + if (!depthStencilIndex) + depthStencilIndex = i; + break; + } + } + if (command.framebuffer->GetType() == OpenGLFramebuffer::Type::FBO) { - std::size_t colorBufferCount = command.framebuffer->GetColorBufferCount(); - assert(colorBufferCount <= fboDrawBuffers.size()); - context->glDrawBuffers(GLsizei(colorBufferCount), fboDrawBuffers.data()); - //FIXME: Don't clear when not needed for (std::size_t i = 0; i < colorBufferCount; ++i) { - Nz::Color color = command.clearValues[i].color; + std::size_t attachmentIndex = colorIndexes[i]; + + Nz::Color color = command.clearValues[attachmentIndex].color; std::array clearColor = { color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f }; - context->glClearBufferfv(GL_COLOR, GLint(i), clearColor.data()); + const auto& attachmentInfo = command.renderpass->GetAttachment(attachmentIndex); + if (attachmentInfo.loadOp == AttachmentLoadOp::Clear) + { + context->ResetColorWriteMasks(); + context->glClearBufferfv(GL_COLOR, GLint(i), clearColor.data()); + } } - context->glClear(GL_DEPTH_BUFFER_BIT); + if (depthStencilIndex) + { + std::size_t attachmentIndex = *depthStencilIndex; + const auto& clearValues = command.clearValues[attachmentIndex]; + + const auto& depthStencilAttachment = command.renderpass->GetAttachment(attachmentIndex); + if (depthStencilAttachment.loadOp == AttachmentLoadOp::Clear && depthStencilAttachment.stencilLoadOp == AttachmentLoadOp::Clear) + { + context->ResetDepthWriteMasks(); + context->ResetStencilWriteMasks(); + context->glClearBufferfi(GL_DEPTH_STENCIL, 0, clearValues.depth, clearValues.stencil); + } + else if (depthStencilAttachment.loadOp == AttachmentLoadOp::Clear) + { + context->ResetDepthWriteMasks(); + context->glClearBufferfv(GL_DEPTH, 0, &clearValues.depth); + } + else if (depthStencilAttachment.stencilLoadOp == AttachmentLoadOp::Clear) + { + context->ResetStencilWriteMasks(); + context->glClearBufferuiv(GL_STENCIL, 0, &clearValues.stencil); + } + } } else { GLenum buffer = GL_BACK; context->glDrawBuffers(1, &buffer); - //FIXME: Don't clear when not needed - Nz::Color color = command.clearValues[0].color; - context->glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); - context->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (colorIndex > 0) + { + std::size_t colorBufferCount = command.framebuffer->GetColorBufferCount(); + assert(colorBufferCount <= 1); + + std::size_t colorAttachmentIndex = colorIndexes.front(); + + const auto& colorAttachment = command.renderpass->GetAttachment(colorAttachmentIndex); + if (colorAttachment.loadOp == AttachmentLoadOp::Clear) + { + context->ResetColorWriteMasks(); + + Nz::Color color = command.clearValues[colorAttachmentIndex].color; + context->glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); + + clearFields |= GL_COLOR_BUFFER_BIT; + } + } + + if (depthStencilIndex) + { + std::size_t attachmentIndex = *depthStencilIndex; + const auto& clearValues = command.clearValues[attachmentIndex]; + + const auto& depthStencilAttachment = command.renderpass->GetAttachment(attachmentIndex); + if (depthStencilAttachment.loadOp == AttachmentLoadOp::Clear) + { + context->ResetDepthWriteMasks(); + context->glClearDepthf(clearValues.depth); + clearFields |= GL_DEPTH_BUFFER_BIT; + } + + if (depthStencilAttachment.stencilLoadOp == AttachmentLoadOp::Clear && PixelFormatInfo::GetContent(depthStencilAttachment.format) == PixelFormatContent::DepthStencil) + { + context->ResetStencilWriteMasks(); + context->glClearStencil(clearValues.stencil); + clearFields |= GL_STENCIL_BUFFER_BIT; + } + } + + if (clearFields) + context->glClear(clearFields); } } else diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp index 9e4a20fc0..435e2c1fe 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp @@ -21,7 +21,7 @@ namespace Nz void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti /*renderRect*/, const ClearValues* clearValues, std::size_t clearValueCount) { - m_commandBuffer.SetFramebuffer(static_cast(framebuffer), renderPass, clearValues, clearValueCount); + m_commandBuffer.SetFramebuffer(static_cast(framebuffer), static_cast(renderPass), clearValues, clearValueCount); } void OpenGLCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset) diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp index a1e95b460..1fbabd35f 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp @@ -14,7 +14,6 @@ namespace Nz { OpenGLRenderWindow::OpenGLRenderWindow(RenderWindow& owner) : m_currentFrame(0), - m_renderPass({}, {}, {}), m_framebuffer(*this), m_owner(owner) { @@ -51,6 +50,40 @@ namespace Nz m_size = m_owner.GetSize(); + // TODO: extract the exact window pixel format + PixelFormat colorFormat; + switch (contextParams.bitsPerPixel) + { + case 8: colorFormat = PixelFormat::R8; break; + case 16: colorFormat = PixelFormat::RG8; break; + case 24: colorFormat = PixelFormat::RGB8; break; + + case 32: + default: + colorFormat = PixelFormat::RGBA8; + break; + } + + // TODO: extract the exact depth-stencil format + PixelFormat depthFormat; + if (contextParams.stencilBits > 0) + depthFormat = PixelFormat::Depth24Stencil8; + else if (contextParams.depthBits > 24) + depthFormat = PixelFormat::Depth32; + else if (contextParams.depthBits > 16) + depthFormat = PixelFormat::Depth24; + else if (contextParams.depthBits > 0) + depthFormat = PixelFormat::Depth16; + else + depthFormat = PixelFormat::Undefined; + + std::vector attachments; + std::vector subpassDescriptions; + std::vector subpassDependencies; + + BuildRenderPass(colorFormat, depthFormat, attachments, subpassDescriptions, subpassDependencies); + m_renderPass.emplace(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); + constexpr std::size_t RenderImageCount = 2; m_renderImage.reserve(RenderImageCount); @@ -72,7 +105,7 @@ namespace Nz const OpenGLRenderPass& OpenGLRenderWindow::GetRenderPass() const { - return m_renderPass; + return *m_renderPass; } void OpenGLRenderWindow::Present() diff --git a/src/Nazara/Renderer/RenderWindowImpl.cpp b/src/Nazara/Renderer/RenderWindowImpl.cpp new file mode 100644 index 000000000..8e44a79a9 --- /dev/null +++ b/src/Nazara/Renderer/RenderWindowImpl.cpp @@ -0,0 +1,74 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + RenderWindowImpl::~RenderWindowImpl() = default; + + void RenderWindowImpl::BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies) + { + assert(colorFormat != PixelFormat::Undefined); + + attachments.push_back({ + colorFormat, + AttachmentLoadOp::Clear, + AttachmentLoadOp::Discard, + AttachmentStoreOp::Store, + AttachmentStoreOp::Discard, + TextureLayout::Undefined, + TextureLayout::Present + }); + + RenderPass::AttachmentReference colorReference = { + 0, + TextureLayout::ColorOutput + }; + + subpassDescriptions.push_back( + { + { colorReference }, + {}, + {}, + std::nullopt + }); + + subpassDependencies.push_back({ + RenderPass::ExternalSubpassIndex, + PipelineStage::ColorOutput, + {}, + + 0, + PipelineStage::ColorOutput, + MemoryAccess::ColorWrite, + + true //< tilable + }); + + if (depthFormat != PixelFormat::Undefined) + { + attachments.push_back({ + depthFormat, + AttachmentLoadOp::Clear, + AttachmentLoadOp::Discard, + AttachmentStoreOp::Discard, + AttachmentStoreOp::Discard, + TextureLayout::Undefined, + TextureLayout::DepthStencilReadWrite + }); + + subpassDescriptions.front().depthStencilAttachment = RenderPass::AttachmentReference{ + 1, + TextureLayout::DepthStencilReadWrite + }; + + auto& subpassDependency = subpassDependencies.front(); + subpassDependency.fromStages |= PipelineStage::FragmentTestsEarly; + subpassDependency.toStages |= PipelineStage::FragmentTestsEarly; + subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilWrite; + } + } +} diff --git a/src/Nazara/Renderer/RendererWindowImpl.cpp b/src/Nazara/Renderer/RendererWindowImpl.cpp deleted file mode 100644 index c677d8e34..000000000 --- a/src/Nazara/Renderer/RendererWindowImpl.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - RenderWindowImpl::~RenderWindowImpl() = default; -} diff --git a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp index 46aab0a8d..11dd17b7b 100644 --- a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp +++ b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp @@ -350,7 +350,7 @@ namespace Nz VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle .a; }, { // VkImageSubresourceRange subresourceRange; - VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags .aspectMask; + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, // VkImageAspectFlags .aspectMask; 0, // uint32_t .baseMipLevel; 1, // uint32_t .levelCount; 0, // uint32_t .baseArrayLayer; @@ -408,78 +408,23 @@ namespace Nz return false; } - std::vector attachments; - attachments.push_back({ - *colorFormat, - AttachmentLoadOp::Clear, - AttachmentLoadOp::Discard, - AttachmentStoreOp::Store, - AttachmentStoreOp::Discard, - TextureLayout::Undefined, - TextureLayout::Present - }); - - RenderPass::AttachmentReference colorReference = { - 0, - TextureLayout::ColorOutput - }; - - std::vector subpasses = { - { - { - { colorReference }, - {}, - {}, - std::nullopt - } - } - }; - - std::vector subpassDependencies = { - { - RenderPass::ExternalSubpassIndex, - PipelineStage::ColorOutput, - {}, - - 0, - PipelineStage::ColorOutput, - MemoryAccess::ColorWrite, - - true //< tilable - } - }; - + std::optional depthStencilFormat; if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) { - std::optional depthStencilFormat = FromVulkan(m_depthStencilFormat); + depthStencilFormat = FromVulkan(m_depthStencilFormat); if (!depthStencilFormat) { NazaraError("unhandled vulkan pixel format (0x" + NumberToString(m_depthStencilFormat, 16) + ")"); return false; } - - attachments.push_back({ - *depthStencilFormat, - AttachmentLoadOp::Clear, - AttachmentLoadOp::Discard, - AttachmentStoreOp::Discard, - AttachmentStoreOp::Discard, - TextureLayout::Undefined, - TextureLayout::DepthStencilReadWrite - }); - - subpasses.front().depthStencilAttachment = RenderPass::AttachmentReference{ - 1, - TextureLayout::DepthStencilReadWrite - }; - - auto& subpassDependency = subpassDependencies.front(); - subpassDependency.fromStages |= PipelineStage::FragmentTestsEarly; - subpassDependency.toStages |= PipelineStage::FragmentTestsEarly; - subpassDependency.toAccessFlags |= MemoryAccess::DepthStencilWrite; } - m_renderPass.emplace(*m_device, std::move(attachments), std::move(subpasses), std::move(subpassDependencies)); + std::vector attachments; + std::vector subpassDescriptions; + std::vector subpassDependencies; + + BuildRenderPass(*colorFormat, depthStencilFormat.value_or(PixelFormat::Undefined), attachments, subpassDescriptions, subpassDependencies); + m_renderPass.emplace(*m_device, std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); return true; }