Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLFBO.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Matevz Tadel, Aug 2009
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TGLFBO.h"
13 #include "TGLIncludes.h"
14 #include <TMath.h>
15 #include <TString.h>
16 #include <TError.h>
17 
18 #include <stdexcept>
19 
20 /** \class TGLFBO
21 \ingroup opengl
22 Frame-buffer object.
23 
24 Requires GL-1.5.
25 
26 Taken from Gled project, see:
27 
28  http://www.gled.org/cgi-bin/viewcvs.cgi/trunk/libsets/GledCore/Pupils/
29 
30 See also:
31 
32  http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt
33 */
34 
35 ClassImp(TGLFBO);
36 
37 Bool_t TGLFBO::fgRescaleToPow2 = kTRUE; // For ATI.
38 Bool_t TGLFBO::fgMultiSampleNAWarned = kFALSE;
39 
40 ////////////////////////////////////////////////////////////////////////////////
41 /// Constructor.
42 
43 TGLFBO::TGLFBO() :
44  fFrameBuffer (0),
45  fColorTexture (0),
46  fDepthBuffer (0),
47  fMSFrameBuffer(0),
48  fMSColorBuffer(0),
49  fW (-1),
50  fH (-1),
51  fReqW (-1),
52  fReqH (-1),
53  fMSSamples (0),
54  fMSCoverageSamples (0),
55  fWScale (1),
56  fHScale (1),
57  fIsRescaled (kFALSE)
58 {
59 }
60 
61 ////////////////////////////////////////////////////////////////////////////////
62 /// Destructor.
63 
64 TGLFBO::~TGLFBO()
65 {
66  Release();
67 }
68 
69 ////////////////////////////////////////////////////////////////////////////////
70 /// Acquire GL resources for given width, height and number of
71 /// multi-sampling samples.
72 
73 void TGLFBO::Init(int w, int h, int ms_samples)
74 {
75  static const std::string eh("TGLFBO::Init ");
76 
77  // Should be replaced with ARB_framebuffer_object (SLC6).
78  if (!GLEW_EXT_framebuffer_object)
79  {
80  throw std::runtime_error(eh + "GL_EXT_framebuffer_object extension required for FBO.");
81  }
82 
83  fReqW = w; fReqH = h;
84 
85  fIsRescaled = kFALSE;
86  if (fgRescaleToPow2)
87  {
88  Int_t nw = 1 << TMath::CeilNint(TMath::Log2(w));
89  Int_t nh = 1 << TMath::CeilNint(TMath::Log2(h));
90  if (nw != w || nh != h)
91  {
92  fWScale = ((Float_t)w) / nw;
93  fHScale = ((Float_t)h) / nh;
94  w = nw; h = nh;
95  fIsRescaled = kTRUE;
96  }
97  }
98 
99  if (ms_samples > 0 && ! GLEW_EXT_framebuffer_multisample)
100  {
101  if (!fgMultiSampleNAWarned)
102  {
103  Info(eh.c_str(), "GL implementation does not support multi-sampling for FBOs.");
104  fgMultiSampleNAWarned = kTRUE;
105  }
106  ms_samples = 0;
107  }
108 
109  if (fFrameBuffer != 0)
110  {
111  if (fW == w && fH == h && fMSSamples == ms_samples)
112  return;
113  Release();
114  }
115 
116  Int_t maxSize;
117  glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &maxSize);
118  if (w > maxSize || h > maxSize)
119  {
120  throw std::runtime_error(eh + Form("maximum size supported by GL implementation is %d.", maxSize));
121  }
122 
123  fW = w; fH = h; fMSSamples = ms_samples;
124 
125  if (fMSSamples > 0)
126  {
127  if (GLEW_NV_framebuffer_multisample_coverage)
128  {
129  GLint n_modes;
130  glGetIntegerv(GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV, &n_modes);
131  GLint *modes = new GLint[2*n_modes];
132  glGetIntegerv(GL_MULTISAMPLE_COVERAGE_MODES_NV, modes);
133 
134  for (int i = 0; i < n_modes; ++i)
135  {
136  if (modes[i*2+1] == fMSSamples && modes[i*2] > fMSCoverageSamples)
137  fMSCoverageSamples = modes[i*2];
138  }
139 
140  delete [] modes;
141  }
142  if (gDebug > 0) {
143  Info(eh.c_str(), "InitMultiSample coverage_samples=%d, color_samples=%d.", fMSCoverageSamples, fMSSamples);
144  }
145  InitMultiSample();
146  }
147  else
148  {
149  if (gDebug > 0) {
150  Info(eh.c_str(), "InitStandard (no multi-sampling).");
151  }
152  InitStandard();
153  }
154 
155  GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
156 
157  glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
158  glBindTexture (GL_TEXTURE_2D, 0);
159 
160  switch (status)
161  {
162  case GL_FRAMEBUFFER_COMPLETE_EXT:
163  if (gDebug > 0)
164  printf("%sConstructed TGLFBO ... all fine.\n", eh.c_str());
165  break;
166  case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
167  Release();
168  throw std::runtime_error(eh + "Constructed TGLFBO not supported, choose different formats.");
169  break;
170  default:
171  Release();
172  throw std::runtime_error(eh + "Constructed TGLFBO is not complete, unexpected error.");
173  break;
174  }
175 }
176 
177 ////////////////////////////////////////////////////////////////////////////////
178 /// Release the allocated GL resources.
179 
180 void TGLFBO::Release()
181 {
182  glDeleteFramebuffersEXT (1, &fFrameBuffer);
183  glDeleteRenderbuffersEXT(1, &fDepthBuffer);
184 
185  if (fMSFrameBuffer) glDeleteFramebuffersEXT (1, &fMSFrameBuffer);
186  if (fMSColorBuffer) glDeleteRenderbuffersEXT(1, &fMSColorBuffer);
187  if (fColorTexture) glDeleteTextures (1, &fColorTexture);
188 
189  fW = fH = -1; fMSSamples = fMSCoverageSamples = 0;
190  fFrameBuffer = fColorTexture = fDepthBuffer = fMSFrameBuffer = fMSColorBuffer = 0;
191 
192 }
193 
194 ////////////////////////////////////////////////////////////////////////////////
195 /// Bind the frame-buffer object.
196 
197 void TGLFBO::Bind()
198 {
199  if (fMSSamples > 0) {
200  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fMSFrameBuffer);
201  // On by default
202  // glEnable(GL_MULTISAMPLE);
203  // Experimenting:
204  // glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
205  // glEnable(GL_SAMPLE_COVERAGE_ARB);
206  } else {
207  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer);
208  }
209 }
210 
211 ////////////////////////////////////////////////////////////////////////////////
212 /// Unbind the frame-buffer object.
213 
214 void TGLFBO::Unbind()
215 {
216  if (fMSSamples > 0)
217  {
218  glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fMSFrameBuffer);
219  glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fFrameBuffer);
220  glBlitFramebufferEXT(0, 0, fW, fH, 0, 0, fW, fH, GL_COLOR_BUFFER_BIT, GL_NEAREST);
221  }
222 
223  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Bind texture.
228 
229 void TGLFBO::BindTexture()
230 {
231  glPushAttrib(GL_TEXTURE_BIT);
232  glBindTexture(GL_TEXTURE_2D, fColorTexture);
233  glEnable(GL_TEXTURE_2D);
234 
235  if (fIsRescaled)
236  {
237  glMatrixMode(GL_TEXTURE);
238  glPushMatrix();
239  glScalef(fWScale, fHScale, 1);
240  glMatrixMode(GL_MODELVIEW);
241  }
242 }
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 /// Unbind texture.
246 
247 void TGLFBO::UnbindTexture()
248 {
249  if (fIsRescaled)
250  {
251  glMatrixMode(GL_TEXTURE);
252  glPopMatrix();
253  glMatrixMode(GL_MODELVIEW);
254  }
255 
256  glPopAttrib();
257 }
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 
261 void TGLFBO::SetAsReadBuffer()
262 {
263  glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fFrameBuffer);
264 }
265 
266 //==============================================================================
267 
268 ////////////////////////////////////////////////////////////////////////////////
269 
270 void TGLFBO::InitStandard()
271 {
272  glGenFramebuffersEXT(1, &fFrameBuffer);
273  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer);
274 
275  fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT);
276  fColorTexture = CreateAndAttachColorTexture();
277 }
278 
279 ////////////////////////////////////////////////////////////////////////////////
280 
281 void TGLFBO::InitMultiSample()
282 {
283  glGenFramebuffersEXT(1, &fMSFrameBuffer);
284  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fMSFrameBuffer);
285 
286  fMSColorBuffer = CreateAndAttachRenderBuffer(GL_RGBA8, GL_COLOR_ATTACHMENT0);
287  fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT);
288  // fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL_ATTACHMENT);
289 
290  glGenFramebuffersEXT(1, &fFrameBuffer);
291  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer);
292 
293  fColorTexture = CreateAndAttachColorTexture();
294 }
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 
298 UInt_t TGLFBO::CreateAndAttachRenderBuffer(Int_t format, Int_t type)
299 {
300  UInt_t id = 0;
301 
302  glGenRenderbuffersEXT(1, &id);
303  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
304 
305  if (fMSSamples > 0)
306  {
307  if (fMSCoverageSamples > 0)
308  glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, fMSCoverageSamples, fMSSamples, format, fW, fH);
309  else
310  glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, fMSSamples, format, fW, fH);
311  }
312  else
313  {
314  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fW, fH);
315  }
316 
317  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, type, GL_RENDERBUFFER_EXT, id);
318 
319  return id;
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Initialize color-texture and attach it to current FB.
324 
325 UInt_t TGLFBO::CreateAndAttachColorTexture()
326 {
327  UInt_t id = 0;
328 
329  glGenTextures(1, &id);
330 
331  glBindTexture(GL_TEXTURE_2D, id);
332  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
333  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
334  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
335  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
336  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, fW, fH, 0, GL_RGBA,
337  GL_UNSIGNED_BYTE, NULL);
338 
339  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
340  GL_TEXTURE_2D, id, 0);
341 
342  return id;
343 }
344 
345 ////////////////////////////////////////////////////////////////////////////////
346 /// Return state of fgRescaleToPow2 static member.
347 
348 Bool_t TGLFBO::GetRescaleToPow2()
349 {
350  return fgRescaleToPow2;
351 }
352 
353 ////////////////////////////////////////////////////////////////////////////////
354 /// Set state of fgRescaleToPow2 static member.
355 /// Default is kTRUE as this works better on older hardware, especially ATI.
356 
357 void TGLFBO::SetRescaleToPow2(Bool_t r)
358 {
359  fgRescaleToPow2 = r;
360 }