Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically fetch default FBO #1598

Merged
merged 1 commit into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libopenage/renderer/opengl/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ std::shared_ptr<QOpenGLContext> GlContext::get_raw_context() const {
return this->gl_context;
}

GLuint GlContext::get_default_framebuffer_id() {
return this->gl_context->defaultFramebufferObject();
}

gl_context_spec GlContext::get_specs() const {
return this->specs;
}
Expand Down
11 changes: 11 additions & 0 deletions libopenage/renderer/opengl/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ class GlContext {
*/
std::shared_ptr<QOpenGLContext> get_raw_context() const;

/**
* Get the ID of the default framebuffer used for displaying to
* the window.
*
* This value may change on every frame, so it should be called every
* time the default framebuffer is bound.
*
* @return ID of the default (display) framebuffer.
*/
unsigned int get_default_framebuffer_id();

/**
* Get the capabilities of this context.
*/
Expand Down
32 changes: 29 additions & 3 deletions libopenage/renderer/opengl/framebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

#include "framebuffer.h"

#include "renderer/opengl/context.h"
#include "renderer/opengl/texture.h"


namespace openage::renderer::opengl {

GlFramebuffer::GlFramebuffer(const std::shared_ptr<GlContext> &context) :
GlSimpleObject(context,
[](GLuint /*handle*/) {}),
type{gl_framebuffer_t::display} {
}

// TODO the validity of this object is contingent
// on its texture existing. use shared_ptr?
GlFramebuffer::GlFramebuffer(const std::shared_ptr<GlContext> &context,
std::vector<std::shared_ptr<GlTexture2d>> const &textures) :
GlSimpleObject(context,
[](GLuint handle) { glDeleteFramebuffers(1, &handle); }) {
[](GLuint handle) { glDeleteFramebuffers(1, &handle); }),
type{gl_framebuffer_t::textures} {
GLuint handle;
glGenFramebuffers(1, &handle);
this->handle = handle;
Expand All @@ -21,6 +29,10 @@ GlFramebuffer::GlFramebuffer(const std::shared_ptr<GlContext> &context,

std::vector<GLenum> drawBuffers;

if (textures.empty()) {
throw Error{ERR << "At least 1 texture must be assigned to texture framebuffer."};
}

size_t colorTextureCount = 0;
for (auto const &texture : textures) {
// TODO figure out attachment points from pixel formats
Expand All @@ -41,12 +53,26 @@ GlFramebuffer::GlFramebuffer(const std::shared_ptr<GlContext> &context,
}
}

gl_framebuffer_t GlFramebuffer::get_type() const {
return this->type;
}

void GlFramebuffer::bind_read() const {
glBindFramebuffer(GL_READ_FRAMEBUFFER, *this->handle);
if (this->type == gl_framebuffer_t::textures) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, *this->handle);
}
else {
glBindFramebuffer(GL_READ_FRAMEBUFFER, this->context->get_default_framebuffer_id());
}
}

void GlFramebuffer::bind_write() const {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *this->handle);
if (this->type == gl_framebuffer_t::textures) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *this->handle);
}
else {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->context->get_default_framebuffer_id());
}
}

} // namespace openage::renderer::opengl
73 changes: 59 additions & 14 deletions libopenage/renderer/opengl/framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,75 @@
#include "renderer/opengl/simple_object.h"


namespace openage {
namespace renderer {
namespace opengl {
namespace openage::renderer::opengl {

class GlTexture2d;

/// Represents an OpenGL Framebuffer Object.
/// It is a collection of bitmap targets that can be drawn into
/// and read from.
/**
* The type of OpenGL framebuffer.
*/
enum class gl_framebuffer_t {
/**
* The actual window. This is visible to the user after swapping front and back buffers.
*/
display,
/**
* A bunch of textures. These can be color texture, depth textures, etc.
*/
textures,
};

/**
* Represents an OpenGL Framebuffer Object.
* It is a collection of bitmap targets that can be drawn into
* and read from.
*/
class GlFramebuffer final : public GlSimpleObject {
public:
/// Construct a framebuffer pointing at the given textures.
/// Texture are attached to points specific to their pixel format,
/// e.g. a depth texture will be set as the depth target.
/**
* Construct a framebuffer pointing at the default framebuffer - the window.
*
* Drawing into this framebuffer draws onto the screen.
*
* @param context OpenGL context used for drawing.
*/
GlFramebuffer(const std::shared_ptr<GlContext> &context);

/**
* Construct a framebuffer pointing at the given textures.
*
* Texture are attached to points specific to their pixel format,
* e.g. a depth texture will be set as the depth target.
*
* @param context OpenGL context used for drawing.
* @param textures Textures targeted by the framebuffer. They are automatically
* attached to the correct attachement points depending on their type.
*/
GlFramebuffer(const std::shared_ptr<GlContext> &context,
std::vector<std::shared_ptr<GlTexture2d>> const &textures);

/// Bind this framebuffer to GL_READ_FRAMEBUFFER.
/**
* Get the type of this framebuffer.
*
* @return Framebuffer type.
*/
gl_framebuffer_t get_type() const;

/**
* Bind this framebuffer to \p GL_READ_FRAMEBUFFER.
*/
void bind_read() const;

/// Bind this framebuffer to GL_DRAW_FRAMEBUFFER.
/**
* Bind this framebuffer to \p GL_DRAW_FRAMEBUFFER.
*/
void bind_write() const;

private:
/**
* Type of this framebuffer.
*/
gl_framebuffer_t type;
};

} // namespace opengl
} // namespace renderer
} // namespace openage
} // namespace openage::renderer::opengl
34 changes: 13 additions & 21 deletions libopenage/renderer/opengl/render_target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@

#include "render_target.h"

#include "error/error.h"

#include "renderer/opengl/texture.h"

namespace openage::renderer::opengl {

GlRenderTarget::GlRenderTarget(size_t width, size_t height) :
type(gl_render_target_t::display),
size(width, height) {}
GlRenderTarget::GlRenderTarget(const std::shared_ptr<GlContext> &context, size_t width, size_t height) :
type(gl_render_target_t::framebuffer),
size(width, height),
framebuffer(context) {}

GlRenderTarget::GlRenderTarget(const std::shared_ptr<GlContext> &context,
const std::vector<std::shared_ptr<GlTexture2d>> &textures) :
type(gl_render_target_t::textures),
type(gl_render_target_t::framebuffer),
framebuffer({context, textures}),
textures(textures) {
// TODO: Check if the textures are all the same size
Expand All @@ -21,7 +24,7 @@ GlRenderTarget::GlRenderTarget(const std::shared_ptr<GlContext> &context,

std::vector<std::shared_ptr<Texture2d>> GlRenderTarget::get_texture_targets() {
std::vector<std::shared_ptr<Texture2d>> textures{};
if (this->type == gl_render_target_t::display) {
if (this->framebuffer->get_type() == gl_framebuffer_t::display) {
return textures;
}
//else upcast pointers
Expand All @@ -33,8 +36,9 @@ std::vector<std::shared_ptr<Texture2d>> GlRenderTarget::get_texture_targets() {
}

void GlRenderTarget::resize(size_t width, size_t height) {
if (this->type != gl_render_target_t::display) {
throw Error{ERR << "Texture render target should not be resized. Create a new one instead."};
if (this->framebuffer->get_type() == gl_framebuffer_t::textures) {
throw Error{ERR << "Render target with textured framebuffer should not be resized. "
<< "Create a new one instead."};
}

this->size = std::make_pair(width, height);
Expand All @@ -46,23 +50,11 @@ void GlRenderTarget::bind_write() const {
// different sizes
glViewport(0, 0, size.first, size.second);

if (this->type == gl_render_target_t::textures) {
this->framebuffer->bind_write();
}
else {
// 0 is the default, window framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
this->framebuffer->bind_write();
}

void GlRenderTarget::bind_read() const {
if (this->type == gl_render_target_t::textures) {
this->framebuffer->bind_read();
}
else {
// 0 is the default, window framebuffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
this->framebuffer->bind_read();
}

} // namespace openage::renderer::opengl
82 changes: 62 additions & 20 deletions libopenage/renderer/opengl/render_target.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,50 +17,92 @@ namespace opengl {

class GlTexture2d;

/// The type of OpenGL render target
/**
* The type of OpenGL render target.
*/
enum class gl_render_target_t {
/// The actual window. This is visible to the user after swapping front and back buffers
display,
/// A bunch of textures
textures,
/**
* Render into a framebuffer.
*/
framebuffer,
// TODO renderbuffers mixed with textures
};

/// Represents an OpenGL target that can be drawn into.
/// It can be either a framebuffer or the display (the window).
/**
* Represents an OpenGL target that can be drawn into.
* It can be either a framebuffer with texture attachements or the display (the window).
*/
class GlRenderTarget final : public RenderTarget {
public:
/// Construct a render target pointed at the default framebuffer - the window.
GlRenderTarget(size_t width, size_t height);

/// Construct a render target pointing at the given textures.
/// Texture are attached to points specific to their pixel format,
/// e.g. a depth texture will be set as the depth target.
/**
* Construct a render target pointed at the default framebuffer - the window.
*
* @param context OpenGL context used for drawing.
* @param width Current width of the window.
* @param height Current height of the window.
*/
GlRenderTarget(const std::shared_ptr<GlContext> &context,
size_t width,
size_t height);

/**
* Construct a render target pointing at the given textures.
* Texture are attached to points specific to their pixel format,
* e.g. a depth texture will be set as the depth target.
*
* @param context OpenGL context used for drawing.
* @param textures Texture attachements.
*/
GlRenderTarget(const std::shared_ptr<GlContext> &context,
std::vector<std::shared_ptr<GlTexture2d>> const &textures);

// Get the targeted textures
/**
* Get the targeted textures.
*
* @return Textures drawn into by the render target.
*/
std::vector<std::shared_ptr<Texture2d>> get_texture_targets() override;

// Resize the render target for scaling viewport correctly.
/**
* Resize the render target to the specified dimensions.
*
* This is used to scale the viewport to the correct size when
* binding the render target with write access.
*
* @param width New width.
* @param height New height.
*/
void resize(size_t width, size_t height);

/// Bind this render target to be drawn into.
/**
* Bind this render target to be drawn into.
*/
void bind_write() const;

/// Bind this render target to be read from.
/**
* Bind this render target to be read from.
*/
void bind_read() const;

private:
/**
* Type of this render target.
*/
gl_render_target_t type;

// Size of the window or the texture target
/**
* Size of the window or the texture targets.
*/
std::pair<size_t, size_t> size;

/// For textures target type, the framebuffer.
/**
* For framebuffer target type, the framebuffer.
*/
std::optional<GlFramebuffer> framebuffer;

// target textures if the render target is an fbo
/**
* Target textures if the render target is a textured fbo.
*/
std::optional<std::vector<std::shared_ptr<GlTexture2d>>> textures;
};

Expand Down
4 changes: 3 additions & 1 deletion libopenage/renderer/opengl/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ namespace openage::renderer::opengl {
GlRenderer::GlRenderer(const std::shared_ptr<GlContext> &ctx,
const util::Vector2s &viewport_size) :
gl_context{ctx},
display{std::make_shared<GlRenderTarget>(viewport_size[0], viewport_size[1])} {
display{std::make_shared<GlRenderTarget>(ctx,
viewport_size[0],
viewport_size[1])} {
// global GL alpha blending settings
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Expand Down