Renderer: Implement renderpass attachments clear for OpenGL

This commit is contained in:
Jérôme Leclercq
2021-05-28 22:55:56 +02:00
parent 392a23eeb1
commit 299585a7de
14 changed files with 276 additions and 96 deletions

View File

@@ -5,6 +5,7 @@
#include <Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp>
#include <Nazara/Core/StackArray.hpp>
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
#include <Nazara/OpenGLRenderer/OpenGLVaoCache.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/VertexArray.hpp>
@@ -62,6 +63,8 @@ namespace Nz
for (std::size_t i = 0; i < m_maxColorBufferCount; ++i)
fboDrawBuffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i);
StackArray<std::size_t> 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<std::size_t> 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<GLfloat, 4> 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

View File

@@ -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<const OpenGLFramebuffer&>(framebuffer), renderPass, clearValues, clearValueCount);
m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), static_cast<const OpenGLRenderPass&>(renderPass), clearValues, clearValueCount);
}
void OpenGLCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset)

View File

@@ -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<RenderPass::Attachment> attachments;
std::vector<RenderPass::SubpassDescription> subpassDescriptions;
std::vector<RenderPass::SubpassDependency> 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()

View File

@@ -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 <Nazara/Renderer/RenderWindowImpl.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
RenderWindowImpl::~RenderWindowImpl() = default;
void RenderWindowImpl::BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector<RenderPass::Attachment>& attachments, std::vector<RenderPass::SubpassDescription>& subpassDescriptions, std::vector<RenderPass::SubpassDependency>& 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;
}
}
}

View File

@@ -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 <Nazara/Renderer/RenderWindowImpl.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
RenderWindowImpl::~RenderWindowImpl() = default;
}

View File

@@ -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<RenderPass::Attachment> 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<RenderPass::SubpassDescription> subpasses = {
{
{
{ colorReference },
{},
{},
std::nullopt
}
}
};
std::vector<RenderPass::SubpassDependency> subpassDependencies = {
{
RenderPass::ExternalSubpassIndex,
PipelineStage::ColorOutput,
{},
0,
PipelineStage::ColorOutput,
MemoryAccess::ColorWrite,
true //< tilable
}
};
std::optional<PixelFormat> depthStencilFormat;
if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM)
{
std::optional<PixelFormat> 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<RenderPass::Attachment> attachments;
std::vector<RenderPass::SubpassDescription> subpassDescriptions;
std::vector<RenderPass::SubpassDependency> 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;
}