From 6353307898cd397e2bcde13e2448a8a678a60004 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 13 Sep 2021 19:42:24 +0300 Subject: [PATCH] Redesign framebuffer attachment management Framebuffers now have an immutable format to which attachments must conform. --- source/core/deviceinfo.cpp | 1 + source/core/deviceinfo.h | 1 + source/core/framebuffer.cpp | 139 +++++++++++++++--------- source/core/framebuffer.h | 56 ++++++---- source/core/frameformat.cpp | 137 ++++++++++++++++++++++++ source/core/frameformat.h | 84 +++++++++++++++ source/core/texture.h | 2 + source/core/texture2dmultisample.h | 1 + source/effects/ambientocclusion.cpp | 4 +- source/effects/bloom.cpp | 6 +- source/effects/environmentmap.cpp | 11 +- source/effects/shadowmap.cpp | 1 + source/effects/sky.cpp | 4 +- source/materials/pbrmaterial.cpp | 4 +- source/render/rendertarget.cpp | 159 ++++------------------------ source/render/rendertarget.h | 50 +-------- source/render/sequence.cpp | 8 +- 17 files changed, 396 insertions(+), 272 deletions(-) create mode 100644 source/core/frameformat.cpp create mode 100644 source/core/frameformat.h diff --git a/source/core/deviceinfo.cpp b/source/core/deviceinfo.cpp index 54cb88b4..93297a79 100644 --- a/source/core/deviceinfo.cpp +++ b/source/core/deviceinfo.cpp @@ -12,6 +12,7 @@ Limits::Limits() glGetIntegerv(GL_MAX_CLIP_PLANES, reinterpret_cast(&max_clip_planes)); glGetIntegerv(GL_MAX_SAMPLES, reinterpret_cast(&max_samples)); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast(&uniform_buffer_alignment)); + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, reinterpret_cast(&max_color_attachments)); } const Limits &Limits::get_global() diff --git a/source/core/deviceinfo.h b/source/core/deviceinfo.h index 9ea239b1..1eb120ff 100644 --- a/source/core/deviceinfo.h +++ b/source/core/deviceinfo.h @@ -12,6 +12,7 @@ struct Limits unsigned max_clip_planes; unsigned max_samples; unsigned uniform_buffer_alignment; + unsigned max_color_attachments; Limits(); diff --git a/source/core/framebuffer.cpp b/source/core/framebuffer.cpp index 93a72686..05cd27f0 100644 --- a/source/core/framebuffer.cpp +++ b/source/core/framebuffer.cpp @@ -77,14 +77,32 @@ Framebuffer::Framebuffer(unsigned i): height = view[3]; } -Framebuffer::Framebuffer(): - width(0), - height(0), - status(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT), - dirty(0) +Framebuffer::Framebuffer() +{ + init(); +} + +Framebuffer::Framebuffer(FrameAttachment fa) +{ + init(); + set_format(fa); +} + +Framebuffer::Framebuffer(const FrameFormat &f) +{ + init(); + set_format(f); +} + +void Framebuffer::init() { static Require _req(EXT_framebuffer_object); + width = 0; + height = 0; + status = FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + dirty = 0; + if(ARB_direct_state_access) glCreateFramebuffers(1, &id); else @@ -97,44 +115,57 @@ Framebuffer::~Framebuffer() glDeleteFramebuffers(1, &id); } +void Framebuffer::set_format(const FrameFormat &fmt) +{ + if(!format.empty()) + throw invalid_operation("Framebuffer::set_format"); + if(fmt.empty()) + throw invalid_argument("Framebuffer::set_format"); + + format = fmt; + attachments.resize(format.size()); +} + void Framebuffer::update() const { vector color_bufs; - color_bufs.reserve(attachments.size()); - for(unsigned i=0; i(*j)); if(dirty&(1<get_target(); if(ARB_direct_state_access) { if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE || attch.layer<0) - glNamedFramebufferTexture(id, attch.attachment, attch.tex->get_id(), attch.level); + glNamedFramebufferTexture(id, gl_attach_point, attch.tex->get_id(), attch.level); else - glNamedFramebufferTextureLayer(id, attch.attachment, attch.tex->get_id(), attch.level, attch.layer); + glNamedFramebufferTextureLayer(id, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer); } else if(type==GL_TEXTURE_2D || type==GL_TEXTURE_2D_MULTISAMPLE) - glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, type, attch.tex->get_id(), attch.level); + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level); else if(attch.layer<0) - glFramebufferTexture(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level); + glFramebufferTexture(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level); else if(type==GL_TEXTURE_2D_ARRAY) - glFramebufferTextureLayer(GL_FRAMEBUFFER, attch.attachment, attch.tex->get_id(), attch.level, attch.layer); + glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attach_point, attch.tex->get_id(), attch.level, attch.layer); else if(type==GL_TEXTURE_3D) - glFramebufferTexture3D(GL_FRAMEBUFFER, attch.attachment, type, attch.tex->get_id(), attch.level, attch.layer); + glFramebufferTexture3D(GL_FRAMEBUFFER, gl_attach_point, type, attch.tex->get_id(), attch.level, attch.layer); else if(type==GL_TEXTURE_CUBE_MAP) - glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level); + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, TextureCube::enumerate_faces(attch.layer), attch.tex->get_id(), attch.level); } else if(ARB_direct_state_access) - glNamedFramebufferTexture(id, attch.attachment, 0, 0); + glNamedFramebufferTexture(id, gl_attach_point, 0, 0); else - glFramebufferTexture2D(GL_FRAMEBUFFER, attch.attachment, GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attach_point, GL_TEXTURE_2D, 0, 0); } - if(attch.attachment>=COLOR_ATTACHMENT0 && attch.attachment<=COLOR_ATTACHMENT3) - color_bufs.push_back(attch.attachment); + if(gl_attach_point!=GL_DEPTH_ATTACHMENT && gl_attach_point!=GL_STENCIL_ATTACHMENT) + color_bufs.push_back(gl_attach_point); } if(color_bufs.size()>1) @@ -198,74 +229,79 @@ void Framebuffer::check_size() } break; } -} -unsigned Framebuffer::get_attachment_index(FramebufferAttachment attch) -{ - for(unsigned i=0; i1 && samples!=format.get_samples()) || (format.get_samples()==1 && samples)) + throw incompatible_data("Framebuffer::attach"); + + unsigned i = 0; + for(const UInt16 *j=format.begin(); j!=format.end(); ++j, ++i) + if(*j==attch) + { + attachments[i].set(tex, level, layer); + dirty |= 1<=0) + { + attachments[i].clear(); + dirty |= 1< +#include "frameformat.h" #include "gl.h" #include "texturecube.h" #include @@ -18,16 +19,6 @@ class Texture2DMultisample; class Texture3D; class WindowView; -enum FramebufferAttachment -{ - COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0, - COLOR_ATTACHMENT1 = GL_COLOR_ATTACHMENT1, - COLOR_ATTACHMENT2 = GL_COLOR_ATTACHMENT2, - COLOR_ATTACHMENT3 = GL_COLOR_ATTACHMENT3, - DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT, - STENCIL_ATTACHMENT = GL_STENCIL_ATTACHMENT -}; - enum FramebufferStatus { FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, @@ -74,17 +65,17 @@ class Framebuffer private: struct Attachment { - FramebufferAttachment attachment; Texture *tex; unsigned level; int layer; - Attachment(FramebufferAttachment); + Attachment(); void set(Texture &, unsigned, int); void clear(); }; unsigned id; + FrameFormat format; std::vector attachments; unsigned width; unsigned height; @@ -93,25 +84,48 @@ private: Framebuffer(unsigned); public: + /** Creates an empty framebuffer. Format must be set before textures can + be attached. */ Framebuffer(); + + /** Creates a framebuffer and sets its format to a single attachment. */ + Framebuffer(FrameAttachment); + + /** Creates a framebuffer and sets its format. */ + Framebuffer(const FrameFormat &); + +private: + void init(); +public: ~Framebuffer(); + /** Sets the format of the framebuffer. Once the format is set, it can't + be changed. */ + void set_format(const FrameFormat &); + + const FrameFormat &get_format() const { return format; } + unsigned get_width() const { return width; } unsigned get_height() const { return height; } private: void update() const; void check_size(); - unsigned get_attachment_index(FramebufferAttachment); - void set_attachment(FramebufferAttachment, Texture &, unsigned, int); + void set_attachment(FrameAttachment, Texture &, unsigned, int, unsigned); public: - void attach(FramebufferAttachment attch, Texture2D &tex, unsigned level = 0); - void attach(FramebufferAttachment attch, Texture2DMultisample &tex); - void attach(FramebufferAttachment attch, Texture3D &tex, unsigned layer, unsigned level = 0); - void attach(FramebufferAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level = 0); - void attach_layered(FramebufferAttachment attch, Texture3D &tex, unsigned level = 0); - void attach_layered(FramebufferAttachment attch, TextureCube &tex, unsigned level = 0); - void detach(FramebufferAttachment attch); + + /** Attaches a texture to the framebuffer. Only the attachment point + portion of attch is considered; pixel format is ignored. The framebuffer + must have a format and the format of the texture must match that defined + in the framebuffer for this attachment point. */ + void attach(FrameAttachment attch, Texture2D &tex, unsigned level = 0); + + void attach(FrameAttachment attch, Texture2DMultisample &tex); + void attach(FrameAttachment attch, Texture3D &tex, unsigned layer, unsigned level = 0); + void attach(FrameAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level = 0); + void attach_layered(FrameAttachment attch, Texture3D &tex, unsigned level = 0); + void attach_layered(FrameAttachment attch, TextureCube &tex, unsigned level = 0); + void detach(FrameAttachment attch); void resize(const WindowView &); diff --git a/source/core/frameformat.cpp b/source/core/frameformat.cpp new file mode 100644 index 00000000..30d7a47f --- /dev/null +++ b/source/core/frameformat.cpp @@ -0,0 +1,137 @@ +#include "deviceinfo.h" +#include "error.h" +#include "frameformat.h" + +using namespace std; + +namespace Msp { +namespace GL { + +FrameFormat::FrameFormat(): + count(0), + samples(1) +{ } + +FrameFormat::FrameFormat(FrameAttachment fa): + count(1), + samples(1) +{ + attachments[0] = fa; +} + +FrameFormat FrameFormat::operator,(FrameAttachment fa) const +{ + if(count>=MAX_ATTACHMENTS) + throw invalid_operation("FrameFormat::operator,"); + + FrameFormat result = *this; + result.attachments[result.count++] = fa; + + return result; +} + +FrameFormat FrameFormat::operator,(PixelFormat pf) const +{ + if(!count) + throw invalid_operation("FrameFormat::operator,"); + + FrameFormat r = *this; + UInt16 &fa = r.attachments[r.count-1]; + fa = make_typed_attachment(static_cast(fa), pf); + + return r; +} + +FrameFormat FrameFormat::operator,(unsigned index) const +{ + if(!count) + throw invalid_operation("FrameFormat::operator,"); + + FrameFormat r = *this; + UInt16 &fa = r.attachments[r.count-1]; + fa = make_indexed_attachment(static_cast(fa), index); + + return r; +} + +FrameFormat &FrameFormat::set_samples(unsigned s) +{ + samples = s; + return *this; +} + +int FrameFormat::index(FrameAttachment fa) const +{ + for(unsigned i=0; i((fa&0xFC00) | (is_float(type)*0x80) | get_type_size(type)<<4 | get_component_count(comp)); +} + +FrameAttachment make_indexed_attachment(FrameAttachment fa, unsigned i) +{ + if(get_attach_point(fa)==get_attach_point(COLOR_ATTACHMENT)) + { + if(i>61) + throw out_of_range("make_indexed_attachment"); + return static_cast(fa+(i<<10)); + } + else + throw invalid_argument("make_indexed_attachment"); +} + +PixelFormat get_attachment_pixelformat(UInt16 fa) +{ + PixelComponents comp; + if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT)) + comp = DEPTH_COMPONENT; + else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT)) + comp = STENCIL_INDEX; + else + comp = static_cast(fa&7); + + DataType type; + if(fa&0x80) + type = static_cast((fa&0x70)>>4 | 0x300); + else + type = static_cast((fa&0x70)>>4); + + return make_pixelformat(comp, type); +} + +GLenum get_gl_attachment(FrameAttachment fa) +{ + if(get_attach_point(fa)==get_attach_point(DEPTH_ATTACHMENT)) + return GL_DEPTH_ATTACHMENT; + else if(get_attach_point(fa)==get_attach_point(STENCIL_ATTACHMENT)) + return GL_STENCIL_ATTACHMENT; + else + return GL_COLOR_ATTACHMENT0+get_attach_point(fa); +} + +} // namespace GL +} // namespace Msp diff --git a/source/core/frameformat.h b/source/core/frameformat.h new file mode 100644 index 00000000..45ea9198 --- /dev/null +++ b/source/core/frameformat.h @@ -0,0 +1,84 @@ +#ifndef MSP_GL_FRAMEFORMAT_H_ +#define MSP_GL_FRAMEFORMAT_H_ + +#include +#include "pixelformat.h" + +namespace Msp { +namespace GL { + +/** +Describes a single attachment of a framebuffer. The values are bitfields laid +as follows: + +nnnn nn__ fsss _ccc + │ │ │ └╴Number of components + │ │ └─────╴Size of one component + │ └────────╴Floating-point flag + └────────────╴Attachment index + +This information is presented for internal documentation purposes only; it is +inadvisable for programs to rely on it. +*/ +enum FrameAttachment +{ + COLOR_ATTACHMENT = 0x0014, + DEPTH_ATTACHMENT = 0xF8C1, + STENCIL_ATTACHMENT = 0xFC11 +}; + +/** +Describes the complete format of a framebuffer. It can hold multiple +attachments (currently up to seven) as well as a sample count. +*/ +class FrameFormat +{ +private: + enum { MAX_ATTACHMENTS = 7 }; + + UInt8 count; + UInt8 samples; + UInt16 attachments[MAX_ATTACHMENTS]; + +public: + FrameFormat(); + FrameFormat(FrameAttachment); + + FrameFormat operator,(FrameAttachment) const; + FrameFormat operator,(PixelFormat) const; + FrameFormat operator,(unsigned) const; + + FrameFormat &set_samples(unsigned); + unsigned get_samples() const { return samples; } + + unsigned size() const { return count; } + bool empty() const { return !count; } + const UInt16 *begin() const { return attachments; } + const UInt16 *end() const { return attachments+count; } + int index(FrameAttachment) const; +}; + +inline FrameFormat operator,(FrameAttachment fa1, FrameAttachment fa2) +{ return (FrameFormat(fa1), fa2); } + +FrameAttachment make_typed_attachment(FrameAttachment, PixelFormat); + +inline FrameAttachment operator,(FrameAttachment fa, PixelFormat pf) +{ return make_typed_attachment(fa, pf); } + +FrameAttachment make_indexed_attachment(FrameAttachment, unsigned); + +inline FrameAttachment operator,(FrameAttachment fa, unsigned i) +{ return make_indexed_attachment(fa, i); } + +inline unsigned get_attach_point(UInt16 fa) +{ return fa>>10; } + +PixelFormat get_attachment_pixelformat(UInt16); + +GLenum get_gl_attachment(FrameAttachment); + +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/core/texture.h b/source/core/texture.h index 58e22d35..e3697d2e 100644 --- a/source/core/texture.h +++ b/source/core/texture.h @@ -86,6 +86,8 @@ protected: void set_parameter_i(GLenum, int) const; public: + PixelFormat get_format() const { return format; } + static bool can_generate_mipmap(); void generate_mipmap(); diff --git a/source/core/texture2dmultisample.h b/source/core/texture2dmultisample.h index cb086f0d..1abacfaa 100644 --- a/source/core/texture2dmultisample.h +++ b/source/core/texture2dmultisample.h @@ -22,6 +22,7 @@ public: unsigned get_width() const { return width; } unsigned get_height() const { return height; } + unsigned get_samples() const { return samples; } virtual AsyncLoader *load(IO::Seekable &, const Resources * = 0) { return 0; } virtual UInt64 get_data_size() const; diff --git a/source/effects/ambientocclusion.cpp b/source/effects/ambientocclusion.cpp index 6ba51853..1b3626a9 100644 --- a/source/effects/ambientocclusion.cpp +++ b/source/effects/ambientocclusion.cpp @@ -13,7 +13,7 @@ namespace GL { AmbientOcclusion::AmbientOcclusion(unsigned w, unsigned h, float): rotate_lookup(get_or_create_rotate_lookup()), - occlude_target(w, h, (RENDER_COLOR,R8)), + occlude_target(w, h, (COLOR_ATTACHMENT,R8)), occlude_shader(Resources::get_global().get("_ambientocclusion_occlude.glsl.shader")), combine_shader(Resources::get_global().get("_ambientocclusion_combine.glsl.shader")), quad(Resources::get_global().get("_fullscreen_quad.mesh")), @@ -104,7 +104,7 @@ void AmbientOcclusion::render(Renderer &renderer, const Texture2D &color, const Renderer::Push push(renderer); renderer.set_texture("source", &color, &nearest_clamp_sampler); renderer.set_texture("depth", &depth, &nearest_clamp_sampler); - renderer.set_texture("occlusion", &occlude_target.get_target_texture(RENDER_COLOR), &linear_sampler); + renderer.set_texture("occlusion", &occlude_target.get_target_texture(COLOR_ATTACHMENT), &linear_sampler); renderer.set_texture("rotate", &rotate_lookup, &nearest_sampler); renderer.set_shader_program(&occlude_shader, &shdata); diff --git a/source/effects/bloom.cpp b/source/effects/bloom.cpp index 8b973b30..fc087d4c 100644 --- a/source/effects/bloom.cpp +++ b/source/effects/bloom.cpp @@ -23,7 +23,7 @@ Bloom::Bloom(unsigned w, unsigned h): blur_shdata[1].uniform("delta", 0.0f, 1.0f/h); for(unsigned i=0; i<2; ++i) - target[i] = new RenderTarget(w, h, (RENDER_COLOR,RGB16F)); + target[i] = new RenderTarget(w, h, (COLOR_ATTACHMENT,RGB16F)); set_radius(2.0f); set_strength(0.2f); @@ -69,13 +69,13 @@ void Bloom::render(Renderer &renderer, const Texture2D &src, const Texture2D &) { Renderer::Push push2(renderer); renderer.set_framebuffer(&target[i]->get_framebuffer()); - renderer.set_texture("source", (i ? &target[0]->get_target_texture(RENDER_COLOR) : &src), &nearest_sampler); + renderer.set_texture("source", (i ? &target[0]->get_target_texture(COLOR_ATTACHMENT) : &src), &nearest_sampler); renderer.add_shader_data(blur_shdata[i]); quad.draw(renderer); } renderer.set_texture("source", &src, &nearest_sampler); - renderer.set_texture("blurred", &target[1]->get_target_texture(RENDER_COLOR), &linear_sampler); + renderer.set_texture("blurred", &target[1]->get_target_texture(COLOR_ATTACHMENT), &linear_sampler); renderer.set_shader_program(&combine_shader); quad.draw(renderer); } diff --git a/source/effects/environmentmap.cpp b/source/effects/environmentmap.cpp index 5002e0f8..ced4a104 100644 --- a/source/effects/environmentmap.cpp +++ b/source/effects/environmentmap.cpp @@ -61,7 +61,8 @@ void EnvironmentMap::init(unsigned s, PixelFormat f, unsigned l) for(unsigned i=0; i<6; ++i) { TextureCubeFace face = TextureCube::enumerate_faces(i); - faces[i].fbo.attach(COLOR_ATTACHMENT0, env_tex, face, 0); + faces[i].fbo.set_format((COLOR_ATTACHMENT,f, DEPTH_ATTACHMENT,DEPTH_COMPONENT32F)); + faces[i].fbo.attach(COLOR_ATTACHMENT, env_tex, face, 0); faces[i].fbo.attach(DEPTH_ATTACHMENT, depth_buf); faces[i].camera.set_look_direction(TextureCube::get_face_direction(face)); faces[i].camera.set_up_direction(TextureCube::get_t_direction(face)); @@ -71,13 +72,17 @@ void EnvironmentMap::init(unsigned s, PixelFormat f, unsigned l) } irradiance.storage(f, size/4, 1); - irradiance_fbo.attach_layered(COLOR_ATTACHMENT0, irradiance); + irradiance_fbo.set_format((COLOR_ATTACHMENT,f)); + irradiance_fbo.attach_layered(COLOR_ATTACHMENT, irradiance); if(l>1) { specular_fbos.resize(l-1); for(unsigned i=1; i face_matrices[6]; for(unsigned i=0; i<6; ++i) diff --git a/source/effects/shadowmap.cpp b/source/effects/shadowmap.cpp index 35e851cd..bcdb0c9f 100644 --- a/source/effects/shadowmap.cpp +++ b/source/effects/shadowmap.cpp @@ -38,6 +38,7 @@ void ShadowMap::init(unsigned s) rendered = false; depth_buf.storage(DEPTH_COMPONENT32F, size, size, 1); + fbo.set_format((DEPTH_ATTACHMENT,DEPTH_COMPONENT32F)); fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0); depth_test.enabled = true; diff --git a/source/effects/sky.cpp b/source/effects/sky.cpp index 23819db3..d9c95b3b 100644 --- a/source/effects/sky.cpp +++ b/source/effects/sky.cpp @@ -15,10 +15,10 @@ namespace GL { Sky::Sky(Renderable &r, Light &s): Effect(r), sun(s), - transmittance_lookup(128, 64, (RENDER_COLOR, RGB16F)), + transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGB16F)), transmittance_shprog(Resources::get_global().get("_sky_transmittance.glsl.shader")), transmittance_lookup_dirty(true), - distant(256, 128, (RENDER_COLOR, RGB16F)), + distant(256, 128, (COLOR_ATTACHMENT,RGB16F)), distant_shprog(Resources::get_global().get("_sky_distant.glsl.shader")), fullscreen_mesh(Resources::get_global().get("_fullscreen_quad.mesh")), backdrop_shprog(Resources::get_global().get("_sky_backdrop.glsl.shader")), diff --git a/source/materials/pbrmaterial.cpp b/source/materials/pbrmaterial.cpp index 5dc1b55c..ad36159a 100644 --- a/source/materials/pbrmaterial.cpp +++ b/source/materials/pbrmaterial.cpp @@ -52,8 +52,8 @@ const Texture2D &PbrMaterial::get_or_create_fresnel_lookup() shdata.uniform("roughness", 0.0f); const Mesh &mesh = resources.get("_fullscreen_quad.mesh"); - Framebuffer fresnel_lookup_fbo; - fresnel_lookup_fbo.attach(COLOR_ATTACHMENT0, *fresnel_lookup); + Framebuffer fresnel_lookup_fbo((COLOR_ATTACHMENT,RG8)); + fresnel_lookup_fbo.attach(COLOR_ATTACHMENT, *fresnel_lookup); Renderer renderer; renderer.set_framebuffer(&fresnel_lookup_fbo); renderer.set_shader_program(&shprog, &shdata); diff --git a/source/render/rendertarget.cpp b/source/render/rendertarget.cpp index 426b2d52..6a114285 100644 --- a/source/render/rendertarget.cpp +++ b/source/render/rendertarget.cpp @@ -10,146 +10,30 @@ using namespace std; namespace Msp { namespace GL { -RenderTargetFormat::RenderTargetFormat(): - count(0) -{ } - -RenderTargetFormat::RenderTargetFormat(RenderOutput o): - count(1) -{ - outputs[0] = o; -} - -RenderTargetFormat RenderTargetFormat::operator,(RenderOutput o) const +RenderTarget::RenderTarget(unsigned w, unsigned h, const FrameFormat &f): + width(w), + height(h), + fbo(f) { - if(count>=MAX_OUTPUTS) - throw invalid_operation("RenderTargetFormat::operator,"); - - RenderTargetFormat result = *this; - result.outputs[result.count++] = o; - - return result; -} - -RenderTargetFormat RenderTargetFormat::operator,(PixelFormat f) const -{ - if(!count) - throw invalid_operation("RenderTargetFormat::operator,"); - - PixelComponents comp = get_components(f); - DataType type = get_component_type(f); - unsigned size = 0; - unsigned char out = outputs[count-1]; - if(get_output_type(out)>=get_output_type(RENDER_DEPTH)) + textures.reserve(f.size()); + unsigned samples = f.get_samples(); + for(const UInt16 *i=f.begin(); i!=f.end(); ++i) { - if(comp!=DEPTH_COMPONENT) - throw invalid_argument("RenderTargetFormat::operator,"); - switch(type) - { - case UNSIGNED_SHORT: size = 0; break; - case UNSIGNED_INT: size = 2; break; - case FLOAT: size = 3; break; - default: throw invalid_argument("RenderTargetFormat::operator,"); - } - } - else - { - if(comp!=RED && comp!=RG && comp!=RGB && comp!=RGBA) - throw invalid_argument("RenderTargetformat::operator,"); - switch(type) - { - case UNSIGNED_BYTE: size = 0; break; - case HALF_FLOAT: size = 2; break; - case FLOAT: size = 3; break; - default: throw invalid_argument("RenderTargetFormat::operator,"); - } - } - - out = (out&~15) | (size<<2) | (get_component_count(f)-1); - RenderTargetFormat result = *this; - result.outputs[result.count-1] = out; - - return result; -} - -int RenderTargetFormat::index(RenderOutput o) const -{ - unsigned type = get_output_type(o); - unsigned i = 0; - for(const unsigned char *j=begin(); j!=end(); ++j, ++i) - if(get_output_type(*j)==type) - return i; - return -1; -} - - -PixelFormat get_output_pixelformat(unsigned char o) -{ - PixelComponents comp; - DataType type; - if(get_output_type(o)>=get_output_type(RENDER_DEPTH)) - { - static DataType types[4] = { UNSIGNED_SHORT, UNSIGNED_SHORT, UNSIGNED_INT, FLOAT }; - comp = DEPTH_COMPONENT; - type = types[(o>>2)&3]; - } - else - { - static PixelComponents components[4] = { RED, RG, RGB, RGBA }; - static DataType types[4] = { UNSIGNED_BYTE, UNSIGNED_SHORT, HALF_FLOAT, FLOAT }; - comp = components[o&3]; - type = types[(o>>2)&3]; - } - - return make_pixelformat(comp, type); -} - - -RenderTarget::RenderTarget(unsigned w, unsigned h, RenderOutput o) -{ - init(w, h, 0, o); -} - -RenderTarget::RenderTarget(unsigned w, unsigned h, const RenderTargetFormat &f) -{ - init(w, h, 0, f); -} - -RenderTarget::RenderTarget(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f) -{ - init(w, h, s, f); -} - -void RenderTarget::init(unsigned w, unsigned h, unsigned s, const RenderTargetFormat &f) -{ - width = w; - height = h; - samples = s; - format = f; - - for(const unsigned char *i=format.begin(); i!=format.end(); ++i) - { - unsigned type = get_output_type(*i); - FramebufferAttachment att; - if(type>=get_output_type(RENDER_DEPTH)) - att = DEPTH_ATTACHMENT; - else - att = static_cast(COLOR_ATTACHMENT0+type); - - PixelFormat pf = get_output_pixelformat(*i); + FrameAttachment fa = static_cast(*i); + PixelFormat pf = get_attachment_pixelformat(*i); - if(samples) + if(samples>1) { Texture2DMultisample *tex2d_ms = new Texture2DMultisample; tex2d_ms->storage(pf, width, height, samples); - fbo.attach(att, *tex2d_ms); + fbo.attach(fa, *tex2d_ms); textures.push_back(tex2d_ms); } else { Texture2D *tex2d = new Texture2D; tex2d->storage(pf, width, height, 1); - fbo.attach(att, *tex2d); + fbo.attach(fa, *tex2d); textures.push_back(tex2d); } } @@ -165,17 +49,17 @@ const Texture2D &RenderTarget::get_target_texture(unsigned i) const { if(i>=textures.size()) throw out_of_range("RenderTarget::get_target_texture"); - if(samples) + if(fbo.get_format().get_samples()>1) throw invalid_operation("RenderTarget::get_target_texture"); return *static_cast(textures[i]); } -const Texture2D &RenderTarget::get_target_texture(RenderOutput o) const +const Texture2D &RenderTarget::get_target_texture(FrameAttachment fa) const { - int index = format.index(o); + int index = fbo.get_format().index(fa); if(index<0) - throw key_error(o); + throw key_error(fa); return get_target_texture(index); } @@ -184,16 +68,19 @@ void RenderTarget::set_debug_name(const string &name) { #ifdef DEBUG fbo.set_debug_name(name+" [FBO]"); + const FrameFormat &fmt = fbo.get_format(); unsigned i = 0; - for(const unsigned char *j=format.begin(); j!=format.end(); ++i, ++j) + for(const UInt16 *j=fmt.begin(); j!=fmt.end(); ++i, ++j) { - unsigned type = get_output_type(*j); + unsigned attach_pt = get_attach_point(static_cast(*j)); string tex_name; - if(type>=get_output_type(RENDER_DEPTH)) + if(attach_pt==get_attach_point(DEPTH_ATTACHMENT)) tex_name = name+"/depth"; + else if(attach_pt==get_attach_point(STENCIL_ATTACHMENT)) + tex_name = name+"/stencil"; else - tex_name = Msp::format("%s/color%d", name, type); + tex_name = Msp::format("%s/color%d", name, attach_pt); textures[i]->set_debug_name(tex_name+".tex2d"); } diff --git a/source/render/rendertarget.h b/source/render/rendertarget.h index f13d23d9..bad7845c 100644 --- a/source/render/rendertarget.h +++ b/source/render/rendertarget.h @@ -9,72 +9,28 @@ namespace GL { class Texture; class Texture2D; -enum RenderOutput -{ - RENDER_COLOR = 0|3, - RENDER_DEPTH = 192|12 -}; - -class RenderTargetFormat -{ -private: - enum { MAX_OUTPUTS = 7 }; - - unsigned char count; - unsigned char outputs[MAX_OUTPUTS]; - -public: - RenderTargetFormat(); - RenderTargetFormat(RenderOutput); - - RenderTargetFormat operator,(RenderOutput) const; - RenderTargetFormat operator,(PixelFormat) const; - - bool empty() const { return !count; } - const unsigned char *begin() const { return outputs; } - const unsigned char *end() const { return outputs+count; } - int index(RenderOutput) const; -}; - -inline RenderTargetFormat operator,(RenderOutput o1, RenderOutput o2) -{ return (RenderTargetFormat(o1), o2); } - -inline RenderTargetFormat operator,(RenderOutput o, PixelFormat f) -{ return (RenderTargetFormat(o), f); } - -inline unsigned get_output_type(unsigned char o) -{ return o>>4; } - -PixelFormat get_output_pixelformat(unsigned char); - - class RenderTarget { private: unsigned width; unsigned height; - unsigned samples; - RenderTargetFormat format; std::vector textures; Framebuffer fbo; public: - RenderTarget(unsigned, unsigned, RenderOutput); - RenderTarget(unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH)); - RenderTarget(unsigned, unsigned, unsigned, const RenderTargetFormat & = (RENDER_COLOR, RENDER_DEPTH)); + RenderTarget(unsigned, unsigned, const FrameFormat & = (COLOR_ATTACHMENT, DEPTH_ATTACHMENT)); private: RenderTarget(const RenderTarget &); RenderTarget &operator=(const RenderTarget &); - void init(unsigned, unsigned, unsigned, const RenderTargetFormat &); public: ~RenderTarget(); unsigned get_width() const { return width; } unsigned get_height() const { return height; } - const RenderTargetFormat &get_format() const { return format; } + const FrameFormat &get_format() const { return fbo.get_format(); } Framebuffer &get_framebuffer() { return fbo; } const Texture2D &get_target_texture(unsigned) const; - const Texture2D &get_target_texture(RenderOutput) const; + const Texture2D &get_target_texture(FrameAttachment) const; void set_debug_name(const std::string &); }; diff --git a/source/render/sequence.cpp b/source/render/sequence.cpp index aaa1ef12..e27ebf18 100644 --- a/source/render/sequence.cpp +++ b/source/render/sequence.cpp @@ -197,8 +197,8 @@ void Sequence::render(Renderer &renderer, Tag tag) const { unsigned j = i%2; renderer.set_framebuffer(i+1get_framebuffer() : out_fbo); - const Texture2D &color = target[j]->get_target_texture(RENDER_COLOR); - const Texture2D &depth = target[j]->get_target_texture(RENDER_DEPTH); + const Texture2D &color = target[j]->get_target_texture(COLOR_ATTACHMENT); + const Texture2D &depth = target[j]->get_target_texture(DEPTH_ATTACHMENT); postproc[i].postproc->render(renderer, color, depth); } } @@ -220,7 +220,7 @@ void Sequence::create_targets(unsigned recreate) } PixelFormat color_pf = (hdr ? (alpha ? RGBA16F : RGB16F) : (alpha ? RGBA8 : RGB8)); - RenderTargetFormat fmt = (RENDER_COLOR,color_pf, RENDER_DEPTH); + FrameFormat fmt = (COLOR_ATTACHMENT,color_pf, DEPTH_ATTACHMENT); if(!postproc.empty() || samples) { if(!target[0]) @@ -230,7 +230,7 @@ void Sequence::create_targets(unsigned recreate) } if(!target_ms && samples) - target_ms = new RenderTarget(width, height, samples, fmt); + target_ms = new RenderTarget(width, height, fmt.set_samples(samples)); #ifdef DEBUG if(!debug_name.empty()) -- 2.45.2