Browse Source

Render: Make Framebuffer class more flexible

master
Riyyi 3 months ago
parent
commit
a5b7a49447
  1. 31
      src/inferno/application.cpp
  2. 5
      src/inferno/application.h
  3. 98
      src/inferno/render/framebuffer.cpp
  4. 88
      src/inferno/render/framebuffer.h

31
src/inferno/application.cpp

@ -53,10 +53,19 @@ Application::Application()
Input::initialize();
RenderCommand::initialize();
m_framebuffer = std::make_unique<Framebuffer>(
Framebuffer::Properties { .type = Framebuffer::Type::Color | Framebuffer::Type::Depth | Framebuffer::Type::Stencil,
.width = m_window->getWidth(),
.height = m_window->getHeight() });
m_framebuffer = Framebuffer::create({
.attachments = { Framebuffer::Type::Color, Framebuffer::Type::Depth },
.width = m_window->getWidth(),
.height = m_window->getHeight(),
.clearColor = { 0.2f, 0.3f, 0.3f, 1.0f },
.clearBit = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
});
m_screenFramebuffer = Framebuffer::create({
.renderToScreen = true,
.clearColor = { 1.0f, 1.0f, 1.0f, 1.0f },
.clearBit = GL_COLOR_BUFFER_BIT,
});
m_scene = std::make_shared<Scene>();
m_scene->initialize();
@ -175,10 +184,10 @@ int Application::run()
m_framebuffer->bind();
render();
RenderCommand::clearColor(m_framebuffer->clearColor());
RenderCommand::clearBit(m_framebuffer->clearBit());
RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f });
RenderCommand::clearBit(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
render();
std::pair<glm::mat4, glm::mat4> projectionView = m_scene->cameraProjectionView();
RendererCubemap::the().beginScene(projectionView.first, projectionView.second); // camera, lights, environment
@ -199,8 +208,10 @@ int Application::run()
// ---------------------------------
// Framebuffer
RenderCommand::clearColor({ 1.0f, 1.0f, 1.0f, 1.0f });
RenderCommand::clearBit(GL_COLOR_BUFFER_BIT);
m_screenFramebuffer->bind();
RenderCommand::clearColor(m_screenFramebuffer->clearColor());
RenderCommand::clearBit(m_screenFramebuffer->clearBit());
Renderer2D::the().setEnableDepthBuffer(false);
Renderer2D::the().beginScene(matIdentity, matIdentity);
@ -208,6 +219,8 @@ int Application::run()
Renderer2D::the().endScene();
Renderer2D::the().setEnableDepthBuffer(true);
m_screenFramebuffer->unbind();
m_window->render();
}

5
src/inferno/application.h

@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Riyyi
* Copyright (C) 2022,2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
@ -51,8 +51,9 @@ private:
float m_lastFrameTime { 0.0f };
std::unique_ptr<Window> m_window;
std::shared_ptr<Framebuffer> m_framebuffer;
std::shared_ptr<Framebuffer> m_screenFramebuffer;
std::shared_ptr<Scene> m_scene;
std::unique_ptr<Framebuffer> m_framebuffer;
//
std::shared_ptr<Font> m_font;

98
src/inferno/render/framebuffer.cpp

@ -14,18 +14,13 @@
namespace Inferno {
Framebuffer::Framebuffer(const Properties& init)
: m_type(init.type)
, m_width(init.width)
, m_height(init.height)
std::shared_ptr<Framebuffer> Framebuffer::create(const Properties& properties)
{
VERIFY(static_cast<int8_t>(init.type) != 0,
"malformed framebuffer type: {}", init.type);
auto result = std::shared_ptr<Framebuffer>(new Framebuffer(properties));
m_id = UINT_MAX;
glGenFramebuffers(1, &m_id);
result->createTextures();
createTextures();
return result;
}
Framebuffer::~Framebuffer()
@ -35,13 +30,6 @@ Framebuffer::~Framebuffer()
// -----------------------------------------
bool Framebuffer::check() const
{
VERIFY(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
"malformed framebuffer: {:#x}", glCheckFramebufferStatus(GL_FRAMEBUFFER));
return true;
}
void Framebuffer::bind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
@ -52,6 +40,13 @@ void Framebuffer::unbind() const
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
bool Framebuffer::check() const
{
VERIFY(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
"malformed framebuffer: {:#x}", glCheckFramebufferStatus(GL_FRAMEBUFFER));
return true;
}
void Framebuffer::resize(uint32_t width, uint32_t height)
{
if (m_width == width && m_height == height) {
@ -68,40 +63,55 @@ void Framebuffer::resize(uint32_t width, uint32_t height)
void Framebuffer::createTextures()
{
bind();
m_textures[0] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_COLOR);
m_textures[1] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_DEPTH);
m_textures[2] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_STENCIL);
m_textures[3] = AssetManager::the().remove(FRAMEBUFFER_TEXTURE_DEPTH_STENCIL);
if (m_type & Type::Color) {
// Set color attachment 0 out of 32
m_textures[0] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_COLOR, m_width, m_height, GL_RGB, GL_RGB);
m_textures[0]->bind(0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textures[0]->id(), 0);
m_textures[0]->unbind();
if (m_renderToScreen) {
return;
}
// This combined texture is required for older GPUs
if (m_type & Type::Depth && m_type & Stencil) {
m_textures[3] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_DEPTH_STENCIL, m_width, m_height, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[3]->id(), 0);
}
else if (m_type & Type::Depth) {
m_textures[1] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_DEPTH, m_width, m_height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_textures[1]->id(), 0);
if (m_id) {
glDeleteFramebuffers(1, &m_id);
m_textures.clear();
}
else if (m_type & Type::Stencil) {
m_textures[2] = AssetManager::the().load<TextureFramebuffer>(
FRAMEBUFFER_TEXTURE_STENCIL, m_width, m_height, GL_STENCIL_INDEX, GL_STENCIL_INDEX);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[2]->id(), 0);
m_id = UINT_MAX;
glGenFramebuffers(1, &m_id);
bind();
auto it = m_attachments.begin();
uint8_t color_attachment = 0;
size_t size = m_attachments.size();
m_textures.resize(size);
for (size_t i = 0; i < size; ++i) {
TypeProperties type = *(it + i);
if (type.type == Type::Color) {
// Set color attachment 0 out of 32
m_textures[i] = (TextureFramebuffer::create(
"", m_width, m_height, GL_RGB, GL_RGB));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + color_attachment, GL_TEXTURE_2D, m_textures[i]->id(), 0);
}
// This combined texture is required for older GPUs
if (type.type == Type::Depth24Stencil8) {
m_textures[i] = (TextureFramebuffer::create(
"", m_width, m_height, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_textures[i]->id(), 0);
continue;
}
if (type.type == Type::Depth32F) {
// FIXME: This isnt a 32-bit float texture
m_textures[i] = (TextureFramebuffer::create(
"", m_width, m_height, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_textures[i]->id(), 0);
continue;
}
}
VERIFY(color_attachment <= 32, "maximum color attachments was exceeded: {}/32", color_attachment);
check();
unbind();
}

88
src/inferno/render/framebuffer.h

@ -6,67 +6,95 @@
#pragma once
#include <cstdint> // int8_t
#include <memory> // std::shared_ptr
#include <cstddef> //size_t
#include <cstdint> // uint8_t
#include <initializer_list>
#include <memory> // std::shared_ptr
#include "inferno/asset/texture.h"
#include "ruc/meta/core.h"
#include "glm/ext/vector_float4.hpp" // glm::vec4
// AssetManager paths to the global framebuffer textures
#define FRAMEBUFFER_TEXTURE_COLOR "@framebuffer-color"
#define FRAMEBUFFER_TEXTURE_DEPTH "@framebuffer-depth"
#define FRAMEBUFFER_TEXTURE_STENCIL "@framebuffer-stencil"
#define FRAMEBUFFER_TEXTURE_DEPTH_STENCIL "@framebuffer-depth-stencil"
#include "inferno/asset/texture.h"
#include "ruc/format/log.h"
namespace Inferno {
class Framebuffer final { // Frame Buffer Object, FBO
public:
enum Type : int8_t {
enum Type : uint8_t {
None = 0,
Color = BIT(0),
Depth = BIT(1),
Stencil = BIT(2),
// Color
RGBA8 = 1,
// Depth/stencil
Depth32F = 2,
Depth24Stencil8 = 3,
// Defaults
Color = RGBA8,
Depth = Depth24Stencil8,
};
struct TypeProperties {
TypeProperties() = default;
TypeProperties(Type type)
: type(type)
{
}
~TypeProperties() {};
Type type;
};
struct Properties {
Type type { None };
std::initializer_list<TypeProperties> attachments {};
bool renderToScreen { false }; // (dummy framebuffer)
uint32_t width { 1280 };
uint32_t height { 720 };
glm::vec4 clearColor { 1.0f, 0.0f, 1.0f, 1.0f }; // magenta
uint32_t clearBit { 0 };
};
Framebuffer(const Properties& init);
~Framebuffer();
bool check() const;
// Factory function
static std::shared_ptr<Framebuffer> create(const Properties& properties);
void bind() const;
void unbind() const;
bool check() const;
void resize(uint32_t width, uint32_t height);
Type type() const { return m_type; }
uint32_t id() const { return m_id; }
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
uint32_t id() const { return m_id; }
std::shared_ptr<TextureFramebuffer> texture(uint8_t index) const { return m_textures[index]; }
uint32_t clearBit() const { return m_clearBit; }
glm::vec4 clearColor() const { return m_clearColor; }
const std::vector<TypeProperties>& attachments() const { return m_attachments; }
std::shared_ptr<TextureFramebuffer> texture(size_t index) const { return m_textures[index]; }
private:
Framebuffer(const Properties& properties)
: m_renderToScreen(properties.renderToScreen)
, m_width(properties.width)
, m_height(properties.height)
, m_clearBit(properties.clearBit)
, m_clearColor(properties.clearColor)
, m_attachments(properties.attachments)
{
}
void createTextures();
private:
Type m_type { None };
bool m_renderToScreen { false };
uint32_t m_id { 0 };
uint32_t m_width { 0 };
uint32_t m_height { 0 };
uint32_t m_id { 0 };
std::shared_ptr<TextureFramebuffer> m_textures[4] { nullptr, nullptr, nullptr, nullptr };
uint32_t m_clearBit { 0 };
glm::vec4 m_clearColor;
std::vector<TypeProperties> m_attachments;
std::vector<std::shared_ptr<TextureFramebuffer>> m_textures;
};
// Make bitwise OR '|' return the enum type instead of int
inline Framebuffer::Type operator|(Framebuffer::Type lhs, Framebuffer::Type rhs)
{
return static_cast<Framebuffer::Type>(
static_cast<int8_t>(lhs) | static_cast<int8_t>(rhs));
}
} // namespace Inferno

Loading…
Cancel
Save