CmGLRenderTexture.cpp 19 KB

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