CmGLFBORenderTexture.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. -----------------------------------------------------------------------------
  3. This source file is part of OGRE
  4. (Object-oriented Graphics Rendering Engine)
  5. For the latest info, see http://www.ogre3d.org/
  6. Copyright (c) 2000-2011 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. */
  24. #include "CmGLFBORenderTexture.h"
  25. #include "CmGLPixelFormat.h"
  26. #include "CmGLHardwarePixelBuffer.h"
  27. #include "CmGLFBOMultiRenderTarget.h"
  28. namespace CamelotEngine {
  29. //-----------------------------------------------------------------------------
  30. GLFBORenderTexture::GLFBORenderTexture(GLFBOManager *manager, const String &name,
  31. const GLSurfaceDesc &target, bool writeGamma, UINT32 fsaa):
  32. GLRenderTexture(name, target, writeGamma, fsaa),
  33. mFB(manager, fsaa)
  34. {
  35. // Bind target to surface 0 and initialise
  36. mFB.bindSurface(0, target);
  37. // Get attributes
  38. mWidth = mFB.getWidth();
  39. mHeight = mFB.getHeight();
  40. }
  41. void GLFBORenderTexture::getCustomAttribute_internal(const String& name, void* pData)
  42. {
  43. if(name=="FBO")
  44. {
  45. *static_cast<GLFrameBufferObject **>(pData) = &mFB;
  46. }
  47. else if (name == "GL_FBOID")
  48. {
  49. *static_cast<GLuint*>(pData) = mFB.getGLFBOID();
  50. }
  51. else if (name == "GL_MULTISAMPLEFBOID")
  52. {
  53. *static_cast<GLuint*>(pData) = mFB.getGLMultisampleFBOID();
  54. }
  55. }
  56. void GLFBORenderTexture::swapBuffers(bool waitForVSync)
  57. {
  58. mFB.swapBuffers();
  59. }
  60. /// Size of probe texture
  61. #define PROBE_SIZE 16
  62. /// Stencil and depth formats to be tried
  63. static const GLenum stencilFormats[] =
  64. {
  65. GL_NONE, // No stencil
  66. GL_STENCIL_INDEX1_EXT,
  67. GL_STENCIL_INDEX4_EXT,
  68. GL_STENCIL_INDEX8_EXT,
  69. GL_STENCIL_INDEX16_EXT
  70. };
  71. static const UINT32 stencilBits[] =
  72. {
  73. 0, 1, 4, 8, 16
  74. };
  75. #define STENCILFORMAT_COUNT (sizeof(stencilFormats)/sizeof(GLenum))
  76. static const GLenum depthFormats[] =
  77. {
  78. GL_NONE,
  79. GL_DEPTH_COMPONENT16,
  80. GL_DEPTH_COMPONENT24, // Prefer 24 bit depth
  81. GL_DEPTH_COMPONENT32,
  82. GL_DEPTH24_STENCIL8_EXT // packed depth / stencil
  83. };
  84. static const UINT32 depthBits[] =
  85. {
  86. 0,16,24,32,24
  87. };
  88. #define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum))
  89. GLFBOManager::GLFBOManager(bool atimode):
  90. mATIMode(atimode)
  91. {
  92. detectFBOFormats();
  93. glGenFramebuffersEXT(1, &mTempFBO);
  94. }
  95. GLFBOManager::~GLFBOManager()
  96. {
  97. if(!mRenderBufferMap.empty())
  98. {
  99. // TODO LOG PORT - Log this somewhere
  100. //LogManager::getSingleton().logMessage("GL: Warning! GLFBOManager destructor called, but not all renderbuffers were released.");
  101. }
  102. glDeleteFramebuffersEXT(1, &mTempFBO);
  103. }
  104. /** Try a certain FBO format, and return the status. Also sets mDepthRB and mStencilRB.
  105. @returns true if this combo is supported
  106. false if this combo is not supported
  107. */
  108. GLuint GLFBOManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
  109. {
  110. GLuint status, depthRB = 0, stencilRB = 0;
  111. bool failed = false; // flag on GL errors
  112. if(depthFormat != GL_NONE)
  113. {
  114. /// Generate depth renderbuffer
  115. glGenRenderbuffersEXT(1, &depthRB);
  116. /// Bind it to FBO
  117. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRB);
  118. /// Allocate storage for depth buffer
  119. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat,
  120. PROBE_SIZE, PROBE_SIZE);
  121. /// Attach depth
  122. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
  123. GL_RENDERBUFFER_EXT, depthRB);
  124. }
  125. if(stencilFormat != GL_NONE)
  126. {
  127. /// Generate stencil renderbuffer
  128. glGenRenderbuffersEXT(1, &stencilRB);
  129. /// Bind it to FBO
  130. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencilRB);
  131. glGetError(); // NV hack
  132. /// Allocate storage for stencil buffer
  133. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, stencilFormat,
  134. PROBE_SIZE, PROBE_SIZE);
  135. if(glGetError() != GL_NO_ERROR) // NV hack
  136. failed = true;
  137. /// Attach stencil
  138. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
  139. GL_RENDERBUFFER_EXT, stencilRB);
  140. if(glGetError() != GL_NO_ERROR) // NV hack
  141. failed = true;
  142. }
  143. status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  144. /// If status is negative, clean up
  145. // Detach and destroy
  146. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  147. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  148. if (depthRB)
  149. glDeleteRenderbuffersEXT(1, &depthRB);
  150. if (stencilRB)
  151. glDeleteRenderbuffersEXT(1, &stencilRB);
  152. return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed;
  153. }
  154. /** Try a certain packed depth/stencil format, and return the status.
  155. @returns true if this combo is supported
  156. false if this combo is not supported
  157. */
  158. bool GLFBOManager::_tryPackedFormat(GLenum packedFormat)
  159. {
  160. GLuint packedRB = 0;
  161. bool failed = false; // flag on GL errors
  162. /// Generate renderbuffer
  163. glGenRenderbuffersEXT(1, &packedRB);
  164. /// Bind it to FBO
  165. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, packedRB);
  166. /// Allocate storage for buffer
  167. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, packedFormat, PROBE_SIZE, PROBE_SIZE);
  168. glGetError(); // NV hack
  169. /// Attach depth
  170. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
  171. GL_RENDERBUFFER_EXT, packedRB);
  172. if(glGetError() != GL_NO_ERROR) // NV hack
  173. failed = true;
  174. /// Attach stencil
  175. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
  176. GL_RENDERBUFFER_EXT, packedRB);
  177. if(glGetError() != GL_NO_ERROR) // NV hack
  178. failed = true;
  179. GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  180. /// Detach and destroy
  181. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  182. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  183. glDeleteRenderbuffersEXT(1, &packedRB);
  184. return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed;
  185. }
  186. /** Detect which internal formats are allowed as RTT
  187. Also detect what combinations of stencil and depth are allowed with this internal
  188. format.
  189. */
  190. void GLFBOManager::detectFBOFormats()
  191. {
  192. // Try all formats, and report which ones work as target
  193. GLuint fb = 0, tid = 0;
  194. GLint old_drawbuffer = 0, old_readbuffer = 0;
  195. GLenum target = GL_TEXTURE_2D;
  196. glGetIntegerv (GL_DRAW_BUFFER, &old_drawbuffer);
  197. glGetIntegerv (GL_READ_BUFFER, &old_readbuffer);
  198. for(size_t x=0; x<PF_COUNT; ++x)
  199. {
  200. mProps[x].valid = false;
  201. // Fetch GL format token
  202. GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x);
  203. if(fmt == GL_NONE && x!=0)
  204. continue;
  205. // No test for compressed formats
  206. if(PixelUtil::isCompressed((PixelFormat)x))
  207. continue;
  208. // Buggy ATI cards *crash* on non-RGB(A) formats
  209. int depths[4];
  210. PixelUtil::getBitDepths((PixelFormat)x, depths);
  211. if(fmt!=GL_NONE && mATIMode && (!depths[0] || !depths[1] || !depths[2]))
  212. continue;
  213. // Create and attach framebuffer
  214. glGenFramebuffersEXT(1, &fb);
  215. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
  216. if (fmt!=GL_NONE)
  217. {
  218. // Create and attach texture
  219. glGenTextures(1, &tid);
  220. glBindTexture(target, tid);
  221. // Set some default parameters so it won't fail on NVidia cards
  222. if (GLEW_VERSION_1_2)
  223. glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
  224. glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  225. glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  226. glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  227. glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  228. glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  229. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
  230. target, tid, 0);
  231. }
  232. else
  233. {
  234. // Draw to nowhere -- stencil/depth only
  235. glDrawBuffer(GL_NONE);
  236. glReadBuffer(GL_NONE);
  237. }
  238. // Check status
  239. GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  240. // Ignore status in case of fmt==GL_NONE, because no implementation will accept
  241. // a buffer without *any* attachment. Buffers with only stencil and depth attachment
  242. // might still be supported, so we must continue probing.
  243. if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE_EXT)
  244. {
  245. mProps[x].valid = true;
  246. StringUtil::StrStreamType str;
  247. str << "FBO " << PixelUtil::getFormatName((PixelFormat)x)
  248. << " depth/stencil support: ";
  249. // For each depth/stencil formats
  250. for (UINT32 depth = 0; depth < DEPTHFORMAT_COUNT; ++depth)
  251. {
  252. if (depthFormats[depth] != GL_DEPTH24_STENCIL8_EXT)
  253. {
  254. // General depth/stencil combination
  255. for (UINT32 stencil = 0; stencil < STENCILFORMAT_COUNT; ++stencil)
  256. {
  257. //StringUtil::StrStreamType l;
  258. //l << "Trying " << PixelUtil::getFormatName((PixelFormat)x)
  259. // << " D" << depthBits[depth]
  260. // << "S" << stencilBits[stencil];
  261. //LogManager::getSingleton().logMessage(l.str());
  262. if (_tryFormat(depthFormats[depth], stencilFormats[stencil]))
  263. {
  264. /// Add mode to allowed modes
  265. str << "D" << depthBits[depth] << "S" << stencilBits[stencil] << " ";
  266. FormatProperties::Mode mode;
  267. mode.depth = depth;
  268. mode.stencil = stencil;
  269. mProps[x].modes.push_back(mode);
  270. }
  271. }
  272. }
  273. else
  274. {
  275. // Packed depth/stencil format
  276. // #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
  277. // It now seems as if this workaround now *breaks* nvidia cards on Linux with the 169.12 drivers on Linux
  278. #if 0
  279. // Only query packed depth/stencil formats for 32-bit
  280. // non-floating point formats (ie not R32!)
  281. // Linux nVidia driver segfaults if you query others
  282. if (PixelUtil::getNumElemBits((PixelFormat)x) != 32 ||
  283. PixelUtil::isFloatingPoint((PixelFormat)x))
  284. {
  285. continue;
  286. }
  287. #endif
  288. if (_tryPackedFormat(depthFormats[depth]))
  289. {
  290. /// Add mode to allowed modes
  291. str << "Packed-D" << depthBits[depth] << "S" << 8 << " ";
  292. FormatProperties::Mode mode;
  293. mode.depth = depth;
  294. mode.stencil = 0; // unuse
  295. mProps[x].modes.push_back(mode);
  296. }
  297. }
  298. }
  299. }
  300. // Delete texture and framebuffer
  301. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  302. glDeleteFramebuffersEXT(1, &fb);
  303. // Workaround for NVIDIA / Linux 169.21 driver problem
  304. // see http://www.ogre3d.org/phpBB2/viewtopic.php?t=38037&start=25
  305. glFinish();
  306. if (fmt!=GL_NONE)
  307. glDeleteTextures(1, &tid);
  308. }
  309. // It seems a bug in nVidia driver: glBindFramebufferEXT should restore
  310. // draw and read buffers, but in some unclear circumstances it won't.
  311. glDrawBuffer(old_drawbuffer);
  312. glReadBuffer(old_readbuffer);
  313. String fmtstring = "";
  314. for(size_t x=0; x<PF_COUNT; ++x)
  315. {
  316. if(mProps[x].valid)
  317. fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" ";
  318. }
  319. }
  320. void GLFBOManager::getBestDepthStencil(GLenum internalFormat, GLenum *depthFormat, GLenum *stencilFormat)
  321. {
  322. const FormatProperties &props = mProps[internalFormat];
  323. /// Decide what stencil and depth formats to use
  324. /// [best supported for internal format]
  325. size_t bestmode=0;
  326. UINT32 bestscore=0;
  327. for(size_t mode=0; mode<props.modes.size(); mode++)
  328. {
  329. #if 0
  330. /// Always prefer D24S8
  331. if(stencilBits[props.modes[mode].stencil]==8 &&
  332. depthBits[props.modes[mode].depth]==24)
  333. {
  334. bestmode = mode;
  335. break;
  336. }
  337. #endif
  338. UINT32 desirability = 0;
  339. /// Find most desirable mode
  340. /// desirability == 0 if no depth, no stencil
  341. /// desirability == 1000...2000 if no depth, stencil
  342. /// desirability == 2000...3000 if depth, no stencil
  343. /// desirability == 3000+ if depth and stencil
  344. /// beyond this, the total numer of bits (stencil+depth) is maximised
  345. if(props.modes[mode].stencil)
  346. desirability += 1000;
  347. if(props.modes[mode].depth)
  348. desirability += 2000;
  349. if(depthBits[props.modes[mode].depth]==24) // Prefer 24 bit for now
  350. desirability += 500;
  351. if(depthFormats[props.modes[mode].depth]==GL_DEPTH24_STENCIL8_EXT) // Prefer 24/8 packed
  352. desirability += 5000;
  353. desirability += stencilBits[props.modes[mode].stencil] + depthBits[props.modes[mode].depth];
  354. if(desirability>bestscore)
  355. {
  356. bestscore = desirability;
  357. bestmode = mode;
  358. }
  359. }
  360. *depthFormat = depthFormats[props.modes[bestmode].depth];
  361. *stencilFormat = stencilFormats[props.modes[bestmode].stencil];
  362. }
  363. GLFBORenderTexture *GLFBOManager::createRenderTexture(const String &name,
  364. const GLSurfaceDesc &target, bool writeGamma, UINT32 fsaa)
  365. {
  366. GLFBORenderTexture *retval = new GLFBORenderTexture(this, name, target, writeGamma, fsaa);
  367. return retval;
  368. }
  369. MultiRenderTarget *GLFBOManager::createMultiRenderTarget(const String & name)
  370. {
  371. return new GLFBOMultiRenderTarget(this, name);
  372. }
  373. void GLFBOManager::bind(RenderTarget *target)
  374. {
  375. /// Check if the render target is in the rendertarget->FBO map
  376. GLFrameBufferObject *fbo = 0;
  377. target->getCustomAttribute_internal("FBO", &fbo);
  378. if(fbo)
  379. fbo->bind();
  380. else
  381. // Old style context (window/pbuffer) or copying render texture
  382. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  383. }
  384. GLSurfaceDesc GLFBOManager::requestRenderBuffer(GLenum format, UINT32 width, UINT32 height, UINT32 fsaa)
  385. {
  386. GLSurfaceDesc retval;
  387. retval.buffer = 0; // Return 0 buffer if GL_NONE is requested
  388. if(format != GL_NONE)
  389. {
  390. RBFormat key(format, width, height, fsaa);
  391. RenderBufferMap::iterator it = mRenderBufferMap.find(key);
  392. if(it != mRenderBufferMap.end())
  393. {
  394. retval.buffer = it->second.buffer;
  395. retval.zoffset = 0;
  396. retval.numSamples = fsaa;
  397. // Increase refcount
  398. ++it->second.refcount;
  399. }
  400. else
  401. {
  402. // New one
  403. GLRenderBuffer *rb = new GLRenderBuffer(format, width, height, fsaa);
  404. mRenderBufferMap[key] = RBRef(rb);
  405. retval.buffer = rb;
  406. retval.zoffset = 0;
  407. retval.numSamples = fsaa;
  408. }
  409. }
  410. //std::cerr << "Requested renderbuffer with format " << std::hex << format << std::dec << " of " << width << "x" << height << " :" << retval.buffer << std::endl;
  411. return retval;
  412. }
  413. //-----------------------------------------------------------------------
  414. void GLFBOManager::requestRenderBuffer(const GLSurfaceDesc &surface)
  415. {
  416. if(surface.buffer == 0)
  417. return;
  418. RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight(), surface.numSamples);
  419. RenderBufferMap::iterator it = mRenderBufferMap.find(key);
  420. assert(it != mRenderBufferMap.end());
  421. if (it != mRenderBufferMap.end()) // Just in case
  422. {
  423. assert(it->second.buffer == surface.buffer);
  424. // Increase refcount
  425. ++it->second.refcount;
  426. }
  427. }
  428. //-----------------------------------------------------------------------
  429. void GLFBOManager::releaseRenderBuffer(const GLSurfaceDesc &surface)
  430. {
  431. if(surface.buffer == 0)
  432. return;
  433. RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight(), surface.numSamples);
  434. RenderBufferMap::iterator it = mRenderBufferMap.find(key);
  435. if(it != mRenderBufferMap.end())
  436. {
  437. // Decrease refcount
  438. --it->second.refcount;
  439. if(it->second.refcount==0)
  440. {
  441. // If refcount reaches zero, delete buffer and remove from map
  442. delete it->second.buffer;
  443. mRenderBufferMap.erase(it);
  444. //std::cerr << "Destroyed renderbuffer of format " << std::hex << key.format << std::dec
  445. // << " of " << key.width << "x" << key.height << std::endl;
  446. }
  447. }
  448. }
  449. }