PageRenderTime 199ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/game-ui-solution/OGRE-1.7.2/RenderSystems/GLES/src/OgreGLESFBORenderTexture.cpp

http://game-ui-solution.googlecode.com/
C++ | 454 lines | 295 code | 56 blank | 103 comment | 52 complexity | ad5e1d6db86467b1e7387a7fb6e30f8e MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.1, ISC, Unlicense, MPL-2.0-no-copyleft-exception, GPL-2.0, BSD-3-Clause, MIT, LGPL-3.0
  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-2009 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 "OgreGLESFBORenderTexture.h"
  25. #include "OgreGLESPixelFormat.h"
  26. #include "OgreLogManager.h"
  27. #include "OgreRoot.h"
  28. #include "OgreGLESHardwarePixelBuffer.h"
  29. #include "OgreGLESFBOMultiRenderTarget.h"
  30. namespace Ogre {
  31. //-----------------------------------------------------------------------------
  32. GLESFBORenderTexture::GLESFBORenderTexture(GLESFBOManager *manager, const String &name,
  33. const GLESSurfaceDesc &target, bool writeGamma, uint fsaa):
  34. GLESRenderTexture(name, target, writeGamma, fsaa),
  35. mFB(manager, fsaa)
  36. {
  37. // Bind target to surface 0 and initialise
  38. mFB.bindSurface(0, target);
  39. GL_CHECK_ERROR;
  40. // Get attributes
  41. mWidth = mFB.getWidth();
  42. mHeight = mFB.getHeight();
  43. }
  44. void GLESFBORenderTexture::getCustomAttribute(const String& name, void* pData)
  45. {
  46. if(name=="FBO")
  47. {
  48. *static_cast<GLESFrameBufferObject **>(pData) = &mFB;
  49. }
  50. }
  51. void GLESFBORenderTexture::swapBuffers(bool waitForVSync)
  52. {
  53. mFB.swapBuffers();
  54. }
  55. /// Size of probe texture
  56. #define PROBE_SIZE 16
  57. /// Stencil and depth formats to be tried
  58. static const GLenum stencilFormats[] =
  59. {
  60. GL_NONE, // No stencil
  61. GL_STENCIL_INDEX8_OES
  62. };
  63. static const size_t stencilBits[] =
  64. {
  65. 0, 8
  66. };
  67. #define STENCILFORMAT_COUNT (sizeof(stencilFormats)/sizeof(GLenum))
  68. static const GLenum depthFormats[] =
  69. {
  70. GL_NONE,
  71. GL_DEPTH_COMPONENT16_OES,
  72. GL_DEPTH_COMPONENT24_OES, // Prefer 24 bit depth
  73. GL_DEPTH24_STENCIL8_OES // packed depth / stencil
  74. };
  75. static const size_t depthBits[] =
  76. {
  77. 0,16,24,24
  78. };
  79. #define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum))
  80. GLESFBOManager::GLESFBOManager()
  81. : mTempFBO(0)
  82. {
  83. detectFBOFormats();
  84. glGenFramebuffersOES(1, &mTempFBO);
  85. GL_CHECK_ERROR;
  86. }
  87. GLESFBOManager::~GLESFBOManager()
  88. {
  89. if(!mRenderBufferMap.empty())
  90. {
  91. LogManager::getSingleton().logMessage("GL ES: Warning! GLESFBOManager destructor called, but not all renderbuffers were released.");
  92. }
  93. glDeleteFramebuffersOES(1, &mTempFBO);
  94. GL_CHECK_ERROR;
  95. }
  96. /** Try a certain FBO format, and return the status. Also sets mDepthRB and mStencilRB.
  97. @returns true if this combo is supported
  98. false if this combo is not supported
  99. */
  100. GLuint GLESFBOManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
  101. {
  102. GLuint status, depthRB = 0, stencilRB = 0;
  103. if(depthFormat != GL_NONE)
  104. {
  105. /// Generate depth renderbuffer
  106. glGenRenderbuffersOES(1, &depthRB);
  107. /// Bind it to FBO
  108. glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRB);
  109. /// Allocate storage for depth buffer
  110. glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthFormat,
  111. PROBE_SIZE, PROBE_SIZE);
  112. /// Attach depth
  113. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES,
  114. GL_RENDERBUFFER_OES, depthRB);
  115. }
  116. // Stencil buffers aren't available on iPhone
  117. if(stencilFormat != GL_NONE)
  118. {
  119. /// Generate stencil renderbuffer
  120. glGenRenderbuffersOES(1, &stencilRB);
  121. /// Bind it to FBO
  122. glBindRenderbufferOES(GL_RENDERBUFFER_OES, stencilRB);
  123. /// Allocate storage for stencil buffer
  124. glRenderbufferStorageOES(GL_RENDERBUFFER_OES, stencilFormat,
  125. PROBE_SIZE, PROBE_SIZE);
  126. /// Attach stencil
  127. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES,
  128. GL_RENDERBUFFER_OES, stencilRB);
  129. }
  130. status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
  131. /// If status is negative, clean up
  132. // Detach and destroy
  133. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, 0);
  134. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, 0);
  135. if (depthRB)
  136. glDeleteRenderbuffersOES(1, &depthRB);
  137. if (stencilRB)
  138. glDeleteRenderbuffersOES(1, &stencilRB);
  139. return status == GL_FRAMEBUFFER_COMPLETE_OES;
  140. }
  141. /** Try a certain packed depth/stencil format, and return the status.
  142. @returns true if this combo is supported
  143. false if this combo is not supported
  144. */
  145. bool GLESFBOManager::_tryPackedFormat(GLenum packedFormat)
  146. {
  147. GLuint packedRB;
  148. /// Generate renderbuffer
  149. glGenRenderbuffersOES(1, &packedRB);
  150. /// Bind it to FBO
  151. glBindRenderbufferOES(GL_RENDERBUFFER_OES, packedRB);
  152. /// Allocate storage for buffer
  153. glRenderbufferStorageOES(GL_RENDERBUFFER_OES, packedFormat, PROBE_SIZE, PROBE_SIZE);
  154. /// Attach depth
  155. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES,
  156. GL_RENDERBUFFER_OES, packedRB);
  157. /// Attach stencil
  158. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES,
  159. GL_RENDERBUFFER_OES, packedRB);
  160. GLuint status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
  161. /// Detach and destroy
  162. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, 0);
  163. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, 0);
  164. glDeleteRenderbuffersOES(1, &packedRB);
  165. return status == GL_FRAMEBUFFER_COMPLETE_OES;
  166. }
  167. /** Detect which internal formats are allowed as RTT
  168. Also detect what combinations of stencil and depth are allowed with this internal
  169. format.
  170. */
  171. void GLESFBOManager::detectFBOFormats()
  172. {
  173. // Try all formats, and report which ones work as target
  174. GLuint fb, tid;
  175. GLenum target = GL_TEXTURE_2D;
  176. for(size_t x=0; x<PF_COUNT; ++x)
  177. {
  178. mProps[x].valid = false;
  179. // Fetch GL format token
  180. GLenum fmt = GLESPixelUtil::getGLInternalFormat((PixelFormat)x);
  181. if(fmt == GL_NONE && x!=0)
  182. continue;
  183. // No test for compressed formats
  184. if(PixelUtil::isCompressed((PixelFormat)x))
  185. continue;
  186. // Create and attach framebuffer
  187. glGenFramebuffersOES(1, &fb);
  188. glBindFramebufferOES(GL_FRAMEBUFFER_OES, fb);
  189. if (fmt!=GL_NONE)
  190. {
  191. // Create and attach texture
  192. glGenTextures(1, &tid);
  193. glBindTexture(target, tid);
  194. // Set some default parameters
  195. glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
  196. glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  197. glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  198. glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  199. glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, fmt, GL_UNSIGNED_BYTE, 0);
  200. glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
  201. target, tid, 0);
  202. }
  203. // Check status
  204. GLuint status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
  205. // Ignore status in case of fmt==GL_NONE, because no implementation will accept
  206. // a buffer without *any* attachment. Buffers with only stencil and depth attachment
  207. // might still be supported, so we must continue probing.
  208. if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE_OES)
  209. {
  210. mProps[x].valid = true;
  211. StringUtil::StrStreamType str;
  212. str << "FBO " << PixelUtil::getFormatName((PixelFormat)x)
  213. << " depth/stencil support: ";
  214. // For each depth/stencil formats
  215. for (size_t depth = 0; depth < DEPTHFORMAT_COUNT; ++depth)
  216. {
  217. if (depthFormats[depth] != GL_DEPTH24_STENCIL8_OES)
  218. {
  219. // General depth/stencil combination
  220. for (size_t stencil = 0; stencil < STENCILFORMAT_COUNT; ++stencil)
  221. {
  222. //StringUtil::StrStreamType l;
  223. //l << "Trying " << PixelUtil::getFormatName((PixelFormat)x)
  224. // << " D" << depthBits[depth]
  225. // << "S" << stencilBits[stencil];
  226. //LogManager::getSingleton().logMessage(l.str());
  227. if (_tryFormat(depthFormats[depth], stencilFormats[stencil]))
  228. {
  229. /// Add mode to allowed modes
  230. str << "D" << depthBits[depth] << "S" << stencilBits[stencil] << " ";
  231. FormatProperties::Mode mode;
  232. mode.depth = depth;
  233. mode.stencil = stencil;
  234. mProps[x].modes.push_back(mode);
  235. }
  236. }
  237. }
  238. else
  239. {
  240. // Packed depth/stencil format
  241. if (_tryPackedFormat(depthFormats[depth]))
  242. {
  243. /// Add mode to allowed modes
  244. str << "Packed-D" << depthBits[depth] << "S" << 8 << " ";
  245. FormatProperties::Mode mode;
  246. mode.depth = depth;
  247. mode.stencil = 0; // unuse
  248. mProps[x].modes.push_back(mode);
  249. }
  250. }
  251. }
  252. LogManager::getSingleton().logMessage(str.str());
  253. }
  254. // Delete texture and framebuffer
  255. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
  256. glDeleteFramebuffersOES(1, &fb);
  257. if (fmt!=GL_NONE)
  258. glDeleteTextures(1, &tid);
  259. }
  260. String fmtstring;
  261. for(size_t x=0; x<PF_COUNT; ++x)
  262. {
  263. if(mProps[x].valid)
  264. fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" ";
  265. }
  266. LogManager::getSingleton().logMessage("[GLES] : Valid FBO targets " + fmtstring);
  267. }
  268. void GLESFBOManager::getBestDepthStencil(GLenum internalFormat, GLenum *depthFormat, GLenum *stencilFormat)
  269. {
  270. const FormatProperties &props = mProps[internalFormat];
  271. /// Decide what stencil and depth formats to use
  272. /// [best supported for internal format]
  273. size_t bestmode=0;
  274. int bestscore=-1;
  275. for(size_t mode=0; mode<props.modes.size(); mode++)
  276. {
  277. int desirability = 0;
  278. /// Find most desirable mode
  279. /// desirability == 0 if no depth, no stencil
  280. /// desirability == 1000...2000 if no depth, stencil
  281. /// desirability == 2000...3000 if depth, no stencil
  282. /// desirability == 3000+ if depth and stencil
  283. /// beyond this, the total numer of bits (stencil+depth) is maximised
  284. if(props.modes[mode].stencil)
  285. desirability += 1000;
  286. if(props.modes[mode].depth)
  287. desirability += 2000;
  288. if(depthBits[props.modes[mode].depth]==24) // Prefer 24 bit for now
  289. desirability += 500;
  290. if(depthFormats[props.modes[mode].depth]==GL_DEPTH24_STENCIL8_OES) // Prefer 24/8 packed
  291. desirability += 5000;
  292. desirability += stencilBits[props.modes[mode].stencil] + depthBits[props.modes[mode].depth];
  293. if(desirability>bestscore)
  294. {
  295. bestscore = desirability;
  296. bestmode = mode;
  297. }
  298. }
  299. *depthFormat = depthFormats[props.modes[bestmode].depth];
  300. *stencilFormat = stencilFormats[props.modes[bestmode].stencil];
  301. }
  302. GLESFBORenderTexture *GLESFBOManager::createRenderTexture(const String &name,
  303. const GLESSurfaceDesc &target, bool writeGamma, uint fsaa)
  304. {
  305. GLESFBORenderTexture *retval = OGRE_NEW GLESFBORenderTexture(this, name, target, writeGamma, fsaa);
  306. return retval;
  307. }
  308. MultiRenderTarget *GLESFBOManager::createMultiRenderTarget(const String & name)
  309. {
  310. return OGRE_NEW GLESFBOMultiRenderTarget(this, name);
  311. }
  312. void GLESFBOManager::bind(RenderTarget *target)
  313. {
  314. /// Check if the render target is in the rendertarget->FBO map
  315. GLESFrameBufferObject *fbo = 0;
  316. target->getCustomAttribute("FBO", &fbo);
  317. if(fbo)
  318. fbo->bind();
  319. else
  320. // Old style context (window/pbuffer) or copying render texture
  321. #if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
  322. // The screen buffer is 1 on iPhone
  323. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 1);
  324. #else
  325. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
  326. #endif
  327. GL_CHECK_ERROR;
  328. }
  329. GLESSurfaceDesc GLESFBOManager::requestRenderBuffer(GLenum format, size_t width, size_t height, uint fsaa)
  330. {
  331. GLESSurfaceDesc retval;
  332. retval.buffer = 0; // Return 0 buffer if GL_NONE is requested
  333. if(format != GL_NONE)
  334. {
  335. RBFormat key(format, width, height, fsaa);
  336. RenderBufferMap::iterator it = mRenderBufferMap.find(key);
  337. if(it != mRenderBufferMap.end())
  338. {
  339. retval.buffer = it->second.buffer;
  340. retval.zoffset = 0;
  341. retval.numSamples = fsaa;
  342. // Increase refcount
  343. ++it->second.refcount;
  344. }
  345. else
  346. {
  347. // New one
  348. GLESRenderBuffer *rb = OGRE_NEW GLESRenderBuffer(format, width, height, fsaa);
  349. mRenderBufferMap[key] = RBRef(rb);
  350. retval.buffer = rb;
  351. retval.zoffset = 0;
  352. retval.numSamples = fsaa;
  353. }
  354. }
  355. // std::cerr << "Requested renderbuffer with format " << std::hex << format << std::dec << " of " << width << "x" << height << " :" << retval.buffer << std::endl;
  356. return retval;
  357. }
  358. //-----------------------------------------------------------------------
  359. void GLESFBOManager::requestRenderBuffer(const GLESSurfaceDesc &surface)
  360. {
  361. if(surface.buffer == 0)
  362. return;
  363. RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight(), surface.numSamples);
  364. RenderBufferMap::iterator it = mRenderBufferMap.find(key);
  365. assert(it != mRenderBufferMap.end());
  366. if (it != mRenderBufferMap.end()) // Just in case
  367. {
  368. assert(it->second.buffer == surface.buffer);
  369. // Increase refcount
  370. ++it->second.refcount;
  371. }
  372. }
  373. //-----------------------------------------------------------------------
  374. void GLESFBOManager::releaseRenderBuffer(const GLESSurfaceDesc &surface)
  375. {
  376. if(surface.buffer == 0)
  377. return;
  378. RBFormat key(surface.buffer->getGLFormat(), surface.buffer->getWidth(), surface.buffer->getHeight(), surface.numSamples);
  379. RenderBufferMap::iterator it = mRenderBufferMap.find(key);
  380. if(it != mRenderBufferMap.end())
  381. {
  382. // Decrease refcount
  383. --it->second.refcount;
  384. if(it->second.refcount==0)
  385. {
  386. // If refcount reaches zero, delete buffer and remove from map
  387. OGRE_DELETE it->second.buffer;
  388. mRenderBufferMap.erase(it);
  389. //std::cerr << "Destroyed renderbuffer of format " << std::hex << key.format << std::dec
  390. // << " of " << key.width << "x" << key.height << std::endl;
  391. }
  392. }
  393. }
  394. }