diff --git a/CloneSource.cpp b/CloneSource.cpp index da6fbed..be22f95 100644 --- a/CloneSource.cpp +++ b/CloneSource.cpp @@ -66,7 +66,7 @@ void CloneSource::init() if (origin_ && origin_->ready_ && origin_->mode_ > Source::UNINITIALIZED && origin_->renderbuffer_) { // create render Frame buffer matching size of images - FrameBuffer *renderbuffer = new FrameBuffer( origin_->frame()->resolution(), origin_->frame()->use_alpha() ); + FrameBuffer *renderbuffer = new FrameBuffer( origin_->frame()->resolution(), origin_->frame()->flags() ); // set the renderbuffer of the source and attach rendering nodes attach(renderbuffer); diff --git a/DelayFilter.cpp b/DelayFilter.cpp index 86b8c2b..ad720c0 100644 --- a/DelayFilter.cpp +++ b/DelayFilter.cpp @@ -54,8 +54,8 @@ void DelayFilter::update (float dt) if ( frames_.empty() || now_ - elapsed_.front() < delay_ + ( double(dt) * 0.002) ) { // create a FBO if none can be reused (from above) and test for RAM in GPU - if (temp_frame_ == nullptr && ( frames_.empty() || Rendering::shouldHaveEnoughMemory(input_->resolution(), input_->use_alpha()) ) ){ - temp_frame_ = new FrameBuffer( input_->resolution(), input_->use_alpha() ); + if (temp_frame_ == nullptr && ( frames_.empty() || Rendering::shouldHaveEnoughMemory(input_->resolution(), input_->flags()) ) ){ + temp_frame_ = new FrameBuffer( input_->resolution(), input_->flags() ); } // image available if (temp_frame_ != nullptr) { diff --git a/FrameBuffer.cpp b/FrameBuffer.cpp index 288aade..9d483ed 100644 --- a/FrameBuffer.cpp +++ b/FrameBuffer.cpp @@ -75,22 +75,24 @@ glm::ivec2 FrameBuffer::getParametersFromResolution(glm::vec3 res) return p; } -FrameBuffer::FrameBuffer(glm::vec3 resolution, bool useAlpha, bool multiSampling): - textureid_(0), intermediate_textureid_(0), framebufferid_(0), intermediate_framebufferid_(0), - use_alpha_(useAlpha), use_multi_sampling_(multiSampling) +FrameBuffer::FrameBuffer(glm::vec3 resolution, FrameBufferFlags flags): flags_(flags), + textureid_(0), multisampling_textureid_(0), framebufferid_(0), multisampling_framebufferid_(0) { attrib_.viewport = glm::ivec2(resolution); setProjectionArea(glm::vec2(1.f, 1.f)); attrib_.clear_color = glm::vec4(0.f, 0.f, 0.f, 0.f); + for(int i=0; i 0; +#ifdef FRAMEBUFFER_DEBUG + g_printerr("New FBO %d (%d x %d)\n", framebufferid_, attrib_.viewport.x, attrib_.viewport.y); +#endif - if (use_multi_sampling_){ + // take settings into account: no multisampling if application multisampling is level 0 + if ( Settings::application.render.multisampling < 1 ) + flags_ &= ~FrameBuffer_multisampling; + + if (flags_ & FrameBuffer_multisampling){ // create a multisample texture - glGenTextures(1, &intermediate_textureid_); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, intermediate_textureid_); + glGenTextures(1, &multisampling_textureid_); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampling_textureid_); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, Settings::application.render.multisampling, - use_alpha_ ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y, GL_TRUE); + (flags_ & FrameBuffer_alpha) ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y, GL_TRUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -126,28 +141,34 @@ void FrameBuffer::init() glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); // attach the multisampled texture to FBO (framebufferid_ currently binded) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, intermediate_textureid_, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampling_textureid_, 0); // create an intermediate FBO : this is the FBO to use for reading - glGenFramebuffers(1, &intermediate_framebufferid_); - glBindFramebuffer(GL_FRAMEBUFFER, intermediate_framebufferid_); - - // attach the 2D texture to intermediate FBO (intermediate_framebufferid_) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0); + glGenFramebuffers(1, &multisampling_framebufferid_); + glBindFramebuffer(GL_FRAMEBUFFER, multisampling_framebufferid_); #ifdef FRAMEBUFFER_DEBUG - g_printerr("New FBO %d Multi Sampling\n", framebufferid_); + g_printerr(" - with Multi Sampling (%d) \n", Settings::application.render.multisampling); #endif } - else { - // direct attach the 2D texture to FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0); + // attach the 2D texture to latest binded FBO + // (i.e. the multisampling_framebufferid_ FBO if enabled, default framebufferid_ otherwise) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0); + + if (flags_ & FrameBuffer_mipmap) { + + glGenFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_); + for(int i=0; i < MIPMAP_LEVEL; ++i) { + + glBindFramebuffer(GL_FRAMEBUFFER, mipmap_framebufferid_[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, i + 1); + + } #ifdef FRAMEBUFFER_DEBUG - g_printerr("New FBO %d Single Sampling\n", framebufferid_); + g_printerr(" - with Mipmap (%d)\n", MIPMAP_LEVEL); #endif - } checkFramebufferStatus(); @@ -159,15 +180,17 @@ FrameBuffer::~FrameBuffer() { if (framebufferid_) glDeleteFramebuffers(1, &framebufferid_); - if (intermediate_framebufferid_) - glDeleteFramebuffers(1, &intermediate_framebufferid_); + if (multisampling_framebufferid_) + glDeleteFramebuffers(1, &multisampling_framebufferid_); + if (mipmap_framebufferid_[0]) + glDeleteFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_); if (textureid_) glDeleteTextures(1, &textureid_); - if (intermediate_textureid_) - glDeleteTextures(1, &intermediate_textureid_); + if (multisampling_textureid_) + glDeleteTextures(1, &multisampling_textureid_); #ifdef FRAMEBUFFER_DEBUG - GLint framebufferMemoryInKB = ( width() * height() * (use_alpha_?4:3) ) / 1024; + GLint framebufferMemoryInKB = ( width() * height() * (flags_ & FrameBuffer_alpha?4:3) ) / 1024; g_printerr("Framebuffer deleted %d x %d, ~%d kB freed\n", width(), height(), framebufferMemoryInKB); #endif } @@ -213,15 +236,22 @@ void FrameBuffer::resize(int width, int height) glDeleteFramebuffers(1, &framebufferid_); framebufferid_ = 0; - if (intermediate_framebufferid_) - glDeleteFramebuffers(1, &intermediate_framebufferid_); - intermediate_framebufferid_ = 0; + if (multisampling_framebufferid_) + glDeleteFramebuffers(1, &multisampling_framebufferid_); + multisampling_framebufferid_ = 0; + + if (mipmap_framebufferid_[0]) + glDeleteFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_); + for(int i=0; iuse_alpha_) ){ + if (!framebufferid_ || !destination || (flags_ & FrameBuffer_alpha) != (destination->flags_ & FrameBuffer_alpha) ){ #ifdef FRAMEBUFFER_DEBUG g_printerr("FrameBuffer blit failed\n"); #endif @@ -299,8 +349,8 @@ bool FrameBuffer::blit(FrameBuffer *destination) if (!destination->framebufferid_) destination->init(); - if (use_multi_sampling_) - glBindFramebuffer(GL_READ_FRAMEBUFFER, intermediate_framebufferid_); + if (flags_ & FrameBuffer_multisampling) + glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampling_framebufferid_); else glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_); @@ -310,6 +360,8 @@ bool FrameBuffer::blit(FrameBuffer *destination) 0, 0, destination->width(), destination->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_FRAMEBUFFER, 0); + // TODO : verify blit onto FBO with mipmapping ? + return true; } @@ -353,7 +405,7 @@ void FrameBuffer::checkFramebufferStatus() { // approximation of RAM needed for this FBO - GLint framebufferMemoryInKB = ( width() * height() * (use_alpha_?4:3) * (use_multi_sampling_?2:1) ) / 1024; + GLint framebufferMemoryInKB = ( width() * height() * (flags_ & FrameBuffer_alpha?4:3) * (flags_ & FrameBuffer_multisampling?2:1) ) / 1024; // test available memory if created buffer is big (more than 8MB) if ( framebufferMemoryInKB > 8000 ) { @@ -463,7 +515,7 @@ FrameBufferImage *FrameBuffer::image(){ return img; // only compatible for RGB FrameBuffers - if (use_alpha_ || use_multi_sampling_) + if (flags_ & FrameBuffer_alpha || flags_ & FrameBuffer_multisampling) return img; // allocate image @@ -482,7 +534,7 @@ bool FrameBuffer::fill(FrameBufferImage *image) init(); // only compatible for RGB FrameBuffers - if (use_alpha_ || use_multi_sampling_) + if (flags_ & FrameBuffer_alpha || flags_ & FrameBuffer_multisampling) return false; // invalid image diff --git a/FrameBuffer.h b/FrameBuffer.h index a44673d..22f4200 100644 --- a/FrameBuffer.h +++ b/FrameBuffer.h @@ -4,6 +4,7 @@ #include "RenderingManager.h" #define FBI_JPEG_QUALITY 90 +#define MIPMAP_LEVEL 6 /** * @brief The FrameBufferImage class stores an RGB image in RAM @@ -45,8 +46,17 @@ public: static glm::vec3 getResolutionFromParameters(int ar, int h); static glm::ivec2 getParametersFromResolution(glm::vec3 res); - FrameBuffer(glm::vec3 resolution, bool useAlpha = false, bool multiSampling = false); - FrameBuffer(uint width, uint height, bool useAlpha = false, bool multiSampling = false); + enum FrameBufferCreationFlags_ + { + FrameBuffer_rgb = 0, + FrameBuffer_alpha = 1 << 1, + FrameBuffer_multisampling = 1 << 2, + FrameBuffer_mipmap = 1 << 3 + }; + typedef int FrameBufferFlags; + + FrameBuffer(glm::vec3 resolution, FrameBufferFlags flags = FrameBuffer_rgb); + FrameBuffer(uint width, uint height, FrameBufferFlags flags = FrameBuffer_rgb); FrameBuffer(FrameBuffer const&) = delete; ~FrameBuffer(); @@ -81,8 +91,7 @@ public: // internal pixel format inline uint opengl_id() const { return framebufferid_; } - inline bool use_alpha() const { return use_alpha_; } - inline bool use_multisampling() const { return use_multi_sampling_; } + inline FrameBufferFlags flags() const { return flags_; } // index for texturing uint texture() const; @@ -95,12 +104,12 @@ private: void init(); void checkFramebufferStatus(); + FrameBufferFlags flags_; RenderingAttrib attrib_; glm::mat4 projection_; glm::vec2 projection_area_; - uint textureid_, intermediate_textureid_; - uint framebufferid_, intermediate_framebufferid_; - bool use_alpha_, use_multi_sampling_; + uint textureid_, multisampling_textureid_; + uint framebufferid_, multisampling_framebufferid_, mipmap_framebufferid_[MIPMAP_LEVEL] = {}; }; diff --git a/FrameBufferFilter.cpp b/FrameBufferFilter.cpp index d6c264f..d1dc8ce 100644 --- a/FrameBufferFilter.cpp +++ b/FrameBufferFilter.cpp @@ -6,7 +6,7 @@ #include "FrameBufferFilter.h" const char* FrameBufferFilter::type_label[FrameBufferFilter::FILTER_INVALID] = { - "None", "Delay", "Custom" + "None", "Delay", "Shader code" }; FrameBufferFilter::FrameBufferFilter() : enabled_(true), input_(nullptr) diff --git a/FrameBufferFilter.h b/FrameBufferFilter.h index 6810276..f02050f 100644 --- a/FrameBufferFilter.h +++ b/FrameBufferFilter.h @@ -1,6 +1,7 @@ #ifndef FRAMEBUFFERFILTER_H #define FRAMEBUFFERFILTER_H +#include #include class Visitor; diff --git a/FrameGrabber.cpp b/FrameGrabber.cpp index 69cad79..3506eaa 100644 --- a/FrameGrabber.cpp +++ b/FrameGrabber.cpp @@ -138,12 +138,12 @@ void FrameGrabbing::grabFrame(FrameBuffer *frame_buffer) // if different frame buffer from previous frame if ( frame_buffer->width() != width_ || frame_buffer->height() != height_ || - frame_buffer->use_alpha() != use_alpha_) { + (frame_buffer->flags() & FrameBuffer::FrameBuffer_alpha) != use_alpha_) { // define stream properties width_ = frame_buffer->width(); height_ = frame_buffer->height(); - use_alpha_ = frame_buffer->use_alpha(); + use_alpha_ = (frame_buffer->flags() & FrameBuffer::FrameBuffer_alpha); size_ = width_ * height_ * (use_alpha_ ? 4 : 3); // first time initialization diff --git a/ImageFilter.cpp b/ImageFilter.cpp index 1ca1509..c75589b 100644 --- a/ImageFilter.cpp +++ b/ImageFilter.cpp @@ -374,7 +374,9 @@ void ImageFilter::draw (FrameBuffer *input) // (re)create framebuffer for result of first-pass if (buffers_.first != nullptr) delete buffers_.first; - buffers_.first = new FrameBuffer( input_->resolution(), input_->use_alpha() ); + // FBO with mipmapping + FrameBuffer::FrameBufferFlags f = input_->flags() | FrameBuffer::FrameBuffer_mipmap; + buffers_.first = new FrameBuffer( input_->resolution(), f ); // enforce framebuffer if first-pass is created now, filled with input framebuffer input_->blit( buffers_.first ); // create second-pass surface and shader, taking as texture the first-pass framebuffer @@ -383,7 +385,7 @@ void ImageFilter::draw (FrameBuffer *input) // (re)create framebuffer for result of second-pass if (buffers_.second != nullptr) delete buffers_.second; - buffers_.second = new FrameBuffer( buffers_.first->resolution(), buffers_.first->use_alpha() ); + buffers_.second = new FrameBuffer( buffers_.first->resolution(), buffers_.first->flags() ); } if ( enabled() ) diff --git a/InfoVisitor.cpp b/InfoVisitor.cpp index 27b40fb..99cbee5 100644 --- a/InfoVisitor.cpp +++ b/InfoVisitor.cpp @@ -206,13 +206,13 @@ void InfoVisitor::visit (RenderSource& s) if (s.frame()){ if (brief_) { - oss << (s.frame()->use_alpha() ? "RGBA, " : "RGB, "); + oss << (s.frame()->flags() & FrameBuffer::FrameBuffer_alpha ? "RGBA, " : "RGB, "); oss << s.frame()->width() << " x " << s.frame()->height(); } else { oss << "Rendering Output ("; oss << RenderSource::rendering_provenance_label[s.renderingProvenance()] << ") " << std::endl; - oss << (s.frame()->use_alpha() ? "RGBA" : "RGB") << std::endl; + oss << (s.frame()->flags() & FrameBuffer::FrameBuffer_alpha ? "RGBA" : "RGB") << std::endl; oss << s.frame()->width() << " x " << s.frame()->height(); } } @@ -230,13 +230,13 @@ void InfoVisitor::visit (CloneSource& s) if (s.frame()){ if (brief_) { - oss << (s.frame()->use_alpha() ? "RGBA, " : "RGB, "); + oss << (s.frame()->flags() & FrameBuffer::FrameBuffer_alpha ? "RGBA, " : "RGB, "); oss << s.frame()->width() << " x " << s.frame()->height(); } else { if (s.origin()) oss << "Clone of '" << s.origin()->name() << "' " << std::endl; - oss << (s.frame()->use_alpha() ? "RGBA, " : "RGB, "); + oss << (s.frame()->flags() & FrameBuffer::FrameBuffer_alpha ? "RGBA, " : "RGB, "); oss << FrameBufferFilter::type_label[s.filter()->type()] << " filter" << std::endl; oss << s.frame()->width() << " x " << s.frame()->height(); } diff --git a/MediaSource.cpp b/MediaSource.cpp index 27c8bca..ccabf7e 100644 --- a/MediaSource.cpp +++ b/MediaSource.cpp @@ -106,7 +106,7 @@ void MediaSource::init() // create Frame buffer matching size of media player float height = float(mediaplayer_->width()) / mediaplayer_->aspectRatio(); - FrameBuffer *renderbuffer = new FrameBuffer(mediaplayer_->width(), (uint)height, true); + FrameBuffer *renderbuffer = new FrameBuffer(mediaplayer_->width(), (uint)height, FrameBuffer::FrameBuffer_alpha); // icon in mixing view if (mediaplayer_->isImage()) diff --git a/RenderSource.cpp b/RenderSource.cpp index 9eac440..d6b8e25 100644 --- a/RenderSource.cpp +++ b/RenderSource.cpp @@ -78,9 +78,14 @@ void RenderSource::init() // rendered_surface_ = new Surface; // rendered_surface_->setTextureIndex( fb->texture() ); + // use same flags than session frame, without multisampling + FrameBuffer::FrameBufferFlags flag = fb->flags(); + flag &= ~FrameBuffer::FrameBuffer_multisampling; + // create the frame buffer displayed by the source (all modes) - rendered_output_ = new FrameBuffer( fb->resolution(), fb->use_alpha() ); - // needs a first initialization + rendered_output_ = new FrameBuffer( fb->resolution(), flag ); + + // needs a first initialization (to get texture) fb->blit(rendered_output_); // set the texture index from internal framebuffer, apply it to the source texture surface diff --git a/RenderView.cpp b/RenderView.cpp index a9f30fe..6bf1c67 100644 --- a/RenderView.cpp +++ b/RenderView.cpp @@ -77,9 +77,13 @@ void RenderView::setResolution(glm::vec3 resolution, bool useAlpha) frame_buffer_ = nullptr; } - if (!frame_buffer_) + if (!frame_buffer_) { // output frame is an RBG Multisamples FrameBuffer - frame_buffer_ = new FrameBuffer(resolution, useAlpha, true); + FrameBuffer::FrameBufferFlags flag = FrameBuffer::FrameBuffer_multisampling; + if (useAlpha) + flag |= FrameBuffer::FrameBuffer_alpha; + frame_buffer_ = new FrameBuffer(resolution, flag); + } // reset fading setFading(); diff --git a/RenderingManager.cpp b/RenderingManager.cpp index dd6e160..8349e50 100644 --- a/RenderingManager.cpp +++ b/RenderingManager.cpp @@ -522,12 +522,13 @@ glm::ivec2 Rendering::getGPUMemoryInformation() } -bool Rendering::shouldHaveEnoughMemory(glm::vec3 resolution, bool useAlpha, bool multiSampling) +bool Rendering::shouldHaveEnoughMemory(glm::vec3 resolution, int flags) { glm::ivec2 RAM = getGPUMemoryInformation(); // approximation of RAM needed for such FBO - GLint framebufferMemoryInKB = ( resolution.x * resolution.x * (useAlpha?4:3) * (multiSampling?2:1) ) / 1024; + GLint framebufferMemoryInKB = ( resolution.x * resolution.x * + ((flags & FrameBuffer::FrameBuffer_alpha)?4:3) * ((flags & FrameBuffer::FrameBuffer_multisampling)?2:1) ) / 1024; return ( RAM.x > framebufferMemoryInKB * 3 ); } diff --git a/RenderingManager.h b/RenderingManager.h index b9e295a..2ced133 100644 --- a/RenderingManager.h +++ b/RenderingManager.h @@ -149,7 +149,7 @@ public: // memory management static glm::ivec2 getGPUMemoryInformation(); - static bool shouldHaveEnoughMemory(glm::vec3 resolution, bool useAlpha = false, bool multiSampling = false); + static bool shouldHaveEnoughMemory(glm::vec3 resolution, int flags); #ifdef USE_GST_OPENGL_SYNC_HANDLER // for opengl pipeline in gstreamer diff --git a/StreamSource.cpp b/StreamSource.cpp index c1ba807..23742c9 100644 --- a/StreamSource.cpp +++ b/StreamSource.cpp @@ -124,7 +124,7 @@ void StreamSource::init() // create Frame buffer matching size of media player float height = float(stream_->width()) / stream_->aspectRatio(); - FrameBuffer *renderbuffer = new FrameBuffer(stream_->width(), (uint)height, true); + FrameBuffer *renderbuffer = new FrameBuffer(stream_->width(), (uint)height, FrameBuffer::FrameBuffer_alpha); // set the renderbuffer of the source and attach rendering nodes attach(renderbuffer);