Renderer: Implement Framebuffers
This commit is contained in:
@@ -106,18 +106,19 @@ namespace Nz
|
||||
for (std::size_t i = 0; i < colorBufferCount; ++i)
|
||||
{
|
||||
Nz::Color color = command.clearValues[i].color;
|
||||
std::array<GLuint, 4> clearColor = { color.r, color.g, color.b, color.a };
|
||||
std::array<GLfloat, 4> clearColor = { color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f };
|
||||
|
||||
context->glClearBufferuiv(GL_COLOR, GLint(i), clearColor.data());
|
||||
context->glClearBufferfv(GL_COLOR, GLint(i), clearColor.data());
|
||||
}
|
||||
|
||||
context->glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
Nz::Color color = command.clearValues[0].color;
|
||||
context->glClearColor(color.r, color.g, color.b, color.a);
|
||||
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);
|
||||
}
|
||||
|
||||
context->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
else
|
||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||
@@ -131,6 +132,8 @@ namespace Nz
|
||||
states.shaderBindings->Apply(context);
|
||||
states.pipeline->Apply(context);
|
||||
|
||||
states.pipeline->FlipY(states.shouldFlipY);
|
||||
|
||||
if (states.scissorRegion)
|
||||
context.SetScissorBox(states.scissorRegion->x, states.scissorRegion->y, states.scissorRegion->width, states.scissorRegion->height);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Nz
|
||||
m_commandBuffer.BeginDebugRegion(regionName, color);
|
||||
}
|
||||
|
||||
void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list<ClearValues> clearValues)
|
||||
void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti /*renderRect*/, std::initializer_list<ClearValues> clearValues)
|
||||
{
|
||||
m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), renderPass, clearValues);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <Nazara/Renderer/CommandPool.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLBuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLShaderStage.hpp>
|
||||
@@ -58,6 +60,16 @@ namespace Nz
|
||||
return std::make_shared<OpenGLCommandPool>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Framebuffer> OpenGLDevice::InstantiateFramebuffer(unsigned int /*width*/, unsigned int /*height*/, const std::shared_ptr<RenderPass>& /*renderPass*/, const std::vector<std::shared_ptr<Texture>>& attachments)
|
||||
{
|
||||
return std::make_shared<OpenGLFboFramebuffer>(*this, attachments);
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderPass> OpenGLDevice::InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies)
|
||||
{
|
||||
return std::make_shared<OpenGLRenderPass>(std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies));
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderPipeline> OpenGLDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo)
|
||||
{
|
||||
return std::make_shared<OpenGLRenderPipeline>(*this, std::move(pipelineInfo));
|
||||
|
||||
92
src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp
Normal file
92
src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - OpenGL Renderer"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
|
||||
#include <Nazara/OpenGLRenderer/OpenGLTexture.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/OpenGLRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector<std::shared_ptr<Texture>>& attachments) :
|
||||
OpenGLFramebuffer(OpenGLFramebuffer::Type::FBO)
|
||||
{
|
||||
if (!m_framebuffer.Create(device))
|
||||
throw std::runtime_error("failed to create framebuffer object");
|
||||
|
||||
std::size_t colorAttachmentCount = 0;
|
||||
bool hasDepth = false;
|
||||
bool hasStencil = false;
|
||||
|
||||
for (std::size_t i = 0; i < attachments.size(); ++i)
|
||||
{
|
||||
assert(attachments[i]);
|
||||
const OpenGLTexture& glTexture = static_cast<const OpenGLTexture&>(*attachments[i]);
|
||||
|
||||
PixelFormat textureFormat = glTexture.GetFormat();
|
||||
|
||||
GLenum attachment;
|
||||
switch (PixelFormatInfo::GetContent(textureFormat))
|
||||
{
|
||||
case PixelFormatContent_ColorRGBA:
|
||||
attachment = GL_COLOR_ATTACHMENT0 + colorAttachmentCount;
|
||||
colorAttachmentCount++;
|
||||
break;
|
||||
|
||||
case PixelFormatContent_Depth:
|
||||
if (hasDepth)
|
||||
throw std::runtime_error("a framebuffer can only have one depth attachment");
|
||||
|
||||
attachment = GL_DEPTH_ATTACHMENT;
|
||||
hasDepth = true;
|
||||
break;
|
||||
|
||||
case PixelFormatContent_DepthStencil:
|
||||
if (hasDepth)
|
||||
throw std::runtime_error("a framebuffer can only have one depth attachment");
|
||||
|
||||
if (hasStencil)
|
||||
throw std::runtime_error("a framebuffer can only have one stencil attachment");
|
||||
|
||||
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
hasDepth = true;
|
||||
hasStencil = true;
|
||||
break;
|
||||
|
||||
case PixelFormatContent_Stencil:
|
||||
if (hasStencil)
|
||||
throw std::runtime_error("a framebuffer can only have one stencil attachment");
|
||||
|
||||
attachment = GL_STENCIL_ATTACHMENT;
|
||||
hasStencil = true;
|
||||
break;
|
||||
|
||||
case PixelFormatContent_Undefined:
|
||||
default:
|
||||
throw std::runtime_error("unhandled pixel format " + PixelFormatInfo::GetName(textureFormat));
|
||||
}
|
||||
|
||||
m_framebuffer.Texture2D(attachment, ToOpenGL(OpenGLTexture::ToTextureTarget(glTexture.GetType())), glTexture.GetTexture().GetObjectId());
|
||||
}
|
||||
|
||||
GLenum status = m_framebuffer.Check();
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
throw std::runtime_error("invalid framebuffer: 0x" + NumberToString(status, 16));
|
||||
|
||||
m_colorAttachmentCount = colorAttachmentCount;
|
||||
}
|
||||
|
||||
void OpenGLFboFramebuffer::Activate() const
|
||||
{
|
||||
const GL::Context& context = m_framebuffer.EnsureDeviceContext();
|
||||
|
||||
context.BindFramebuffer(GL::FramebufferTarget::Draw, m_framebuffer.GetObjectId());
|
||||
}
|
||||
|
||||
std::size_t OpenGLFboFramebuffer::GetColorBufferCount() const
|
||||
{
|
||||
return m_colorAttachmentCount;
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace Nz
|
||||
const TextureBinding& texBinding = std::get<TextureBinding>(binding.content);
|
||||
|
||||
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, resourceIndex);
|
||||
textureDescriptor.bindingIndex = binding.bindingIndex;
|
||||
textureDescriptor.bindingIndex = UInt32(binding.bindingIndex);
|
||||
|
||||
if (OpenGLTexture* glTexture = static_cast<OpenGLTexture*>(texBinding.texture))
|
||||
{
|
||||
@@ -79,29 +79,7 @@ namespace Nz
|
||||
else
|
||||
textureDescriptor.sampler = 0;
|
||||
|
||||
switch (glTexture->GetType())
|
||||
{
|
||||
case ImageType_2D:
|
||||
textureDescriptor.textureTarget = GL::TextureTarget::Target2D;
|
||||
break;
|
||||
|
||||
case ImageType_2D_Array:
|
||||
textureDescriptor.textureTarget = GL::TextureTarget::Target2D_Array;
|
||||
break;
|
||||
|
||||
case ImageType_3D:
|
||||
textureDescriptor.textureTarget = GL::TextureTarget::Target3D;
|
||||
break;
|
||||
|
||||
case ImageType_Cubemap:
|
||||
textureDescriptor.textureTarget = GL::TextureTarget::Cubemap;
|
||||
break;
|
||||
|
||||
case ImageType_1D:
|
||||
case ImageType_1D_Array:
|
||||
default:
|
||||
throw std::runtime_error("unsupported texture type");
|
||||
}
|
||||
textureDescriptor.textureTarget = OpenGLTexture::ToTextureTarget(glTexture->GetType());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -419,7 +419,7 @@ namespace Nz
|
||||
|
||||
RenderPass::AttachmentReference colorReference = {
|
||||
0,
|
||||
TextureLayout::ColorInput
|
||||
TextureLayout::ColorOutput
|
||||
};
|
||||
|
||||
std::vector<RenderPass::SubpassDescription> subpasses = {
|
||||
@@ -475,12 +475,12 @@ namespace Nz
|
||||
AttachmentStoreOp::Discard,
|
||||
AttachmentStoreOp::Discard,
|
||||
TextureLayout::Undefined,
|
||||
TextureLayout::DepthStencilInput
|
||||
TextureLayout::DepthStencilOutput
|
||||
});
|
||||
|
||||
subpasses.front().depthStencilAttachment = RenderPass::AttachmentReference{
|
||||
1,
|
||||
TextureLayout::DepthStencilInput
|
||||
TextureLayout::DepthStencilOutput
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanShaderStage.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanTexture.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanTextureSampler.hpp>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
@@ -25,6 +27,16 @@ namespace Nz
|
||||
return std::make_shared<VulkanCommandPool>(*this, queueType);
|
||||
}
|
||||
|
||||
std::shared_ptr<Framebuffer> VulkanDevice::InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments)
|
||||
{
|
||||
return std::make_shared<VulkanSingleFramebuffer>(*this, width, height, renderPass, attachments);
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderPass> VulkanDevice::InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies)
|
||||
{
|
||||
return std::make_shared<VulkanRenderPass>(*this, std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies));
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderPipeline> VulkanDevice::InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo)
|
||||
{
|
||||
return std::make_shared<VulkanRenderPipeline>(*this, std::move(pipelineInfo));
|
||||
|
||||
@@ -76,9 +76,9 @@ namespace Nz
|
||||
VkSubpassDescriptionFlags(0),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
UInt32(subpassInfo.inputAttachments.size()),
|
||||
&vkAttachmentReferences[inputAttachmentIndex],
|
||||
(!subpassInfo.inputAttachments.empty()) ? &vkAttachmentReferences[inputAttachmentIndex] : nullptr,
|
||||
UInt32(subpassInfo.colorAttachment.size()),
|
||||
&vkAttachmentReferences[colorAttachmentIndex],
|
||||
(!subpassInfo.colorAttachment.empty()) ? &vkAttachmentReferences[colorAttachmentIndex] : nullptr,
|
||||
nullptr,
|
||||
(subpassInfo.depthStencilAttachment) ? &vkAttachmentReferences[depthStencilAttachmentIndex] : nullptr,
|
||||
0,
|
||||
|
||||
@@ -3,8 +3,42 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/VulkanRenderer/VulkanSingleFramebuffer.hpp>
|
||||
#include <Nazara/Core/StackArray.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
|
||||
#include <Nazara/VulkanRenderer/VulkanTexture.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/VulkanRenderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
VulkanSingleFramebuffer::VulkanSingleFramebuffer(Vk::Device& device, unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments) :
|
||||
VulkanFramebuffer(Type::Single)
|
||||
{
|
||||
assert(renderPass);
|
||||
const VulkanRenderPass& vkRenderPass = static_cast<const VulkanRenderPass&>(*renderPass);
|
||||
|
||||
StackArray<VkImageView> imageViews = NazaraStackArrayNoInit(VkImageView, attachments.size());
|
||||
for (std::size_t i = 0; i < attachments.size(); ++i)
|
||||
{
|
||||
assert(attachments[i]);
|
||||
|
||||
const VulkanTexture& vkTexture = static_cast<const VulkanTexture&>(*attachments[i]);
|
||||
imageViews[i] = vkTexture.GetImageView();
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo createInfo = {
|
||||
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
vkRenderPass.GetRenderPass(),
|
||||
UInt32(imageViews.size()),
|
||||
imageViews.data(),
|
||||
UInt32(width),
|
||||
UInt32(height),
|
||||
1
|
||||
};
|
||||
|
||||
if (!m_framebuffer.Create(device, createInfo))
|
||||
throw std::runtime_error("failed to instantiate Vulkan framebuffer: " + TranslateVulkanError(m_framebuffer.GetLastErrorCode()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user