// @(#)root/gl:$Id$ // Author: Matevz Tadel, Aug 2009 /************************************************************************* * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #include "TGLFBO.h" #include #include #include #include #include //______________________________________________________________________________ // // Frame-buffer object. // // Requires GL-1.5. // // Taken from Gled project, see: // http://www.gled.org/cgi-bin/viewcvs.cgi/trunk/libsets/GledCore/Pupils/ // See also: // http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt ClassImp(TGLFBO); Bool_t TGLFBO::fgRescaleToPow2 = kTRUE; // For ATI. Bool_t TGLFBO::fgMultiSampleNAWarned = kFALSE; TGLFBO::TGLFBO() : fFrameBuffer (0), fColorTexture (0), fDepthBuffer (0), fMSFrameBuffer(0), fMSColorBuffer(0), fW (-1), fH (-1), fMSSamples (0), fMSCoverageSamples (0), fWScale (1), fHScale (1), fIsRescaled (kFALSE) { // Constructor. } //______________________________________________________________________________ TGLFBO::~TGLFBO() { // Destructor. Release(); } //______________________________________________________________________________ void TGLFBO::Init(int w, int h, int ms_samples) { // Acquire GL resources for given width, height and number of // multi-sampling samples. static const std::string eh("TGLFBO::Init "); // Should be replaced with ARB_framebuffer_object (SLC6). if (!GLEW_EXT_framebuffer_object) { throw std::runtime_error(eh + "GL_EXT_framebuffer_object extension required for FBO."); } fIsRescaled = kFALSE; if (fgRescaleToPow2) { Int_t nw = 1 << TMath::CeilNint(TMath::Log2(w)); Int_t nh = 1 << TMath::CeilNint(TMath::Log2(h)); if (nw != w || nh != h) { fWScale = ((Float_t)w) / nw; fHScale = ((Float_t)h) / nh; w = nw; h = nh; fIsRescaled = kTRUE; } } if (ms_samples > 0 && ! GLEW_EXT_framebuffer_multisample) { if (!fgMultiSampleNAWarned) { Info(eh.c_str(), "GL implementation does not support multi-sampling for FBOs."); fgMultiSampleNAWarned = kTRUE; } ms_samples = 0; } if (fFrameBuffer != 0) { if (fW == w && fH == h && fMSSamples == ms_samples) return; Release(); } Int_t maxSize; glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &maxSize); if (w > maxSize || h > maxSize) { throw std::runtime_error(eh + Form("maximum size supported by GL implementation is %d.", maxSize)); } fW = w; fH = h; fMSSamples = ms_samples; if (fMSSamples > 0) { if (GLEW_NV_framebuffer_multisample_coverage) { GLint n_modes; glGetIntegerv(GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV, &n_modes); GLint *modes = new GLint[2*n_modes]; glGetIntegerv(GL_MULTISAMPLE_COVERAGE_MODES_NV, modes); for (int i = 0; i < n_modes; ++i) { if (modes[i*2+1] == fMSSamples && modes[i*2] > fMSCoverageSamples) fMSCoverageSamples = modes[i*2]; } delete [] modes; } if (gDebug > 0) { Info(eh.c_str(), "InitMultiSample coverage_samples=%d, color_samples=%d.", fMSCoverageSamples, fMSSamples); } InitMultiSample(); } else { if (gDebug > 0) { Info(eh.c_str(), "InitStandard (no multi-sampling)."); } InitStandard(); } GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); glBindTexture (GL_TEXTURE_2D, 0); switch (status) { case GL_FRAMEBUFFER_COMPLETE_EXT: if (gDebug > 0) printf("%sConstructed TGLFBO ... all fine.\n", eh.c_str()); break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: Release(); throw std::runtime_error(eh + "Constructed TGLFBO not supported, choose different formats."); break; default: Release(); throw std::runtime_error(eh + "Constructed TGLFBO is not complete, unexpected error."); break; } } //______________________________________________________________________________ void TGLFBO::Release() { // Release the allocated GL resources. glDeleteFramebuffersEXT (1, &fFrameBuffer); glDeleteRenderbuffersEXT(1, &fDepthBuffer); if (fMSFrameBuffer) glDeleteFramebuffersEXT (1, &fMSFrameBuffer); if (fMSColorBuffer) glDeleteRenderbuffersEXT(1, &fMSColorBuffer); if (fColorTexture) glDeleteTextures (1, &fColorTexture); fW = fH = -1; fMSSamples = fMSCoverageSamples = 0; fFrameBuffer = fColorTexture = fDepthBuffer = fMSFrameBuffer = fMSColorBuffer = 0; } //______________________________________________________________________________ void TGLFBO::Bind() { // Bind the frame-buffer object. if (fMSSamples > 0) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fMSFrameBuffer); // On by default // glEnable(GL_MULTISAMPLE); // Experimenting: // glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); // glEnable(GL_SAMPLE_COVERAGE_ARB); } else { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer); } } //______________________________________________________________________________ void TGLFBO::Unbind() { // Unbind the frame-buffer object. if (fMSSamples > 0) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fMSFrameBuffer); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fFrameBuffer); glBlitFramebufferEXT(0, 0, fW, fH, 0, 0, fW, fH, GL_COLOR_BUFFER_BIT, GL_NEAREST); } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } //______________________________________________________________________________ void TGLFBO::BindTexture() { // Bind texture. glPushAttrib(GL_TEXTURE_BIT); glBindTexture(GL_TEXTURE_2D, fColorTexture); glEnable(GL_TEXTURE_2D); if (fIsRescaled) { glMatrixMode(GL_TEXTURE); glPushMatrix(); glScalef(fWScale, fHScale, 1); glMatrixMode(GL_MODELVIEW); } } //______________________________________________________________________________ void TGLFBO::UnbindTexture() { // Unbind texture. if (fIsRescaled) { glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } glPopAttrib(); } //______________________________________________________________________________ void TGLFBO::SetAsReadBuffer() { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fFrameBuffer); } //============================================================================== //______________________________________________________________________________ void TGLFBO::InitStandard() { glGenFramebuffersEXT(1, &fFrameBuffer); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer); fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT); fColorTexture = CreateAndAttachColorTexture(); } //______________________________________________________________________________ void TGLFBO::InitMultiSample() { glGenFramebuffersEXT(1, &fMSFrameBuffer); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fMSFrameBuffer); fMSColorBuffer = CreateAndAttachRenderBuffer(GL_RGBA8, GL_COLOR_ATTACHMENT0); fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT); // fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL_ATTACHMENT); glGenFramebuffersEXT(1, &fFrameBuffer); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer); fColorTexture = CreateAndAttachColorTexture(); } //______________________________________________________________________________ UInt_t TGLFBO::CreateAndAttachRenderBuffer(Int_t format, Int_t type) { UInt_t id = 0; glGenRenderbuffersEXT(1, &id); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id); if (fMSSamples > 0) { if (fMSCoverageSamples > 0) glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, fMSCoverageSamples, fMSSamples, format, fW, fH); else glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, fMSSamples, format, fW, fH); } else { glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fW, fH); } glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, type, GL_RENDERBUFFER_EXT, id); return id; } //______________________________________________________________________________ UInt_t TGLFBO::CreateAndAttachColorTexture() { // Initialize color-texture and attach it to current FB. UInt_t id = 0; glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, fW, fH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, id, 0); return id; }