CmGLRenderTexture.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 "CmGLDepthStencilBuffer.h"
  27. #include "CmGLHardwarePixelBuffer.h"
  28. namespace CamelotEngine
  29. {
  30. GLRenderTexture::GLRenderTexture()
  31. :mFB(nullptr)
  32. {
  33. }
  34. GLRenderTexture::~GLRenderTexture()
  35. {
  36. if(mFB != nullptr)
  37. delete mFB;
  38. }
  39. void GLRenderTexture::createInternalResourcesImpl()
  40. {
  41. if(mFB != nullptr)
  42. delete mFB;
  43. mFB = new GLFrameBufferObject(mFSAA);
  44. GLSurfaceDesc surfaceDesc;
  45. surfaceDesc.numSamples = mFSAA;
  46. surfaceDesc.zoffset = 0;
  47. GLTexture* glTexture = static_cast<GLTexture*>(mTexture.get());
  48. surfaceDesc.buffer = std::static_pointer_cast<GLHardwarePixelBuffer>(glTexture->getBuffer(mFace, mMipLevel));
  49. mFB->bindSurface(0, surfaceDesc);
  50. GLDepthStencilBuffer* glDepthStencilBuffer = static_cast<GLDepthStencilBuffer*>(mDepthStencilBuffer.get());
  51. mFB->bindDepthStencil(glDepthStencilBuffer->getGLRenderBuffer());
  52. }
  53. void GLRenderTexture::getCustomAttribute(const String& name, void* pData)
  54. {
  55. if(name=="FBO")
  56. {
  57. *static_cast<GLFrameBufferObject **>(pData) = mFB;
  58. }
  59. else if (name == "GL_FBOID" || name == "GL_MULTISAMPLEFBOID")
  60. {
  61. *static_cast<GLuint*>(pData) = mFB->getGLFBOID();
  62. }
  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()
  94. {
  95. detectFBOFormats();
  96. glGenFramebuffersEXT(1, &mTempFBO);
  97. }
  98. GLRTTManager::~GLRTTManager()
  99. {
  100. glDeleteFramebuffersEXT(1, &mTempFBO);
  101. }
  102. /** Try a certain FBO format, and return the status. Also sets mDepthRB and mStencilRB.
  103. @returns true if this combo is supported
  104. false if this combo is not supported
  105. */
  106. GLuint GLRTTManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
  107. {
  108. GLuint status, depthRB = 0, stencilRB = 0;
  109. bool failed = false; // flag on GL errors
  110. if(depthFormat != GL_NONE)
  111. {
  112. /// Generate depth renderbuffer
  113. glGenRenderbuffersEXT(1, &depthRB);
  114. /// Bind it to FBO
  115. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRB);
  116. /// Allocate storage for depth buffer
  117. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat,
  118. PROBE_SIZE, PROBE_SIZE);
  119. /// Attach depth
  120. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
  121. GL_RENDERBUFFER_EXT, depthRB);
  122. }
  123. if(stencilFormat != GL_NONE)
  124. {
  125. /// Generate stencil renderbuffer
  126. glGenRenderbuffersEXT(1, &stencilRB);
  127. /// Bind it to FBO
  128. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencilRB);
  129. glGetError(); // NV hack
  130. /// Allocate storage for stencil buffer
  131. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, stencilFormat,
  132. PROBE_SIZE, PROBE_SIZE);
  133. if(glGetError() != GL_NO_ERROR) // NV hack
  134. failed = true;
  135. /// Attach stencil
  136. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
  137. GL_RENDERBUFFER_EXT, stencilRB);
  138. if(glGetError() != GL_NO_ERROR) // NV hack
  139. failed = true;
  140. }
  141. status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  142. /// If status is negative, clean up
  143. // Detach and destroy
  144. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  145. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  146. if (depthRB)
  147. glDeleteRenderbuffersEXT(1, &depthRB);
  148. if (stencilRB)
  149. glDeleteRenderbuffersEXT(1, &stencilRB);
  150. return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed;
  151. }
  152. /** Try a certain packed depth/stencil format, and return the status.
  153. @returns true if this combo is supported
  154. false if this combo is not supported
  155. */
  156. bool GLRTTManager::_tryPackedFormat(GLenum packedFormat)
  157. {
  158. GLuint packedRB = 0;
  159. bool failed = false; // flag on GL errors
  160. /// Generate renderbuffer
  161. glGenRenderbuffersEXT(1, &packedRB);
  162. /// Bind it to FBO
  163. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, packedRB);
  164. /// Allocate storage for buffer
  165. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, packedFormat, PROBE_SIZE, PROBE_SIZE);
  166. glGetError(); // NV hack
  167. /// Attach depth
  168. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
  169. GL_RENDERBUFFER_EXT, packedRB);
  170. if(glGetError() != GL_NO_ERROR) // NV hack
  171. failed = true;
  172. /// Attach stencil
  173. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
  174. GL_RENDERBUFFER_EXT, packedRB);
  175. if(glGetError() != GL_NO_ERROR) // NV hack
  176. failed = true;
  177. GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  178. /// Detach and destroy
  179. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  180. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  181. glDeleteRenderbuffersEXT(1, &packedRB);
  182. return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed;
  183. }
  184. /** Detect which internal formats are allowed as RTT
  185. Also detect what combinations of stencil and depth are allowed with this internal
  186. format.
  187. */
  188. void GLRTTManager::detectFBOFormats()
  189. {
  190. // Try all formats, and report which ones work as target
  191. GLuint fb = 0, tid = 0;
  192. GLint old_drawbuffer = 0, old_readbuffer = 0;
  193. GLenum target = GL_TEXTURE_2D;
  194. glGetIntegerv (GL_DRAW_BUFFER, &old_drawbuffer);
  195. glGetIntegerv (GL_READ_BUFFER, &old_readbuffer);
  196. for(size_t x=0; x<PF_COUNT; ++x)
  197. {
  198. mProps[x].valid = false;
  199. // Fetch GL format token
  200. GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x);
  201. if(fmt == GL_NONE && x!=0)
  202. continue;
  203. // No test for compressed formats
  204. if(PixelUtil::isCompressed((PixelFormat)x))
  205. continue;
  206. // Create and attach framebuffer
  207. glGenFramebuffersEXT(1, &fb);
  208. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
  209. if (fmt!=GL_NONE)
  210. {
  211. // Create and attach texture
  212. glGenTextures(1, &tid);
  213. glBindTexture(target, tid);
  214. // Set some default parameters so it won't fail on NVidia cards
  215. if (GLEW_VERSION_1_2)
  216. glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
  217. glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  218. glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  219. glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  220. glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  221. glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  222. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
  223. target, tid, 0);
  224. }
  225. else
  226. {
  227. // Draw to nowhere -- stencil/depth only
  228. glDrawBuffer(GL_NONE);
  229. glReadBuffer(GL_NONE);
  230. }
  231. // Check status
  232. GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  233. // Ignore status in case of fmt==GL_NONE, because no implementation will accept
  234. // a buffer without *any* attachment. Buffers with only stencil and depth attachment
  235. // might still be supported, so we must continue probing.
  236. if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE_EXT)
  237. {
  238. mProps[x].valid = true;
  239. // For each depth/stencil formats
  240. for (UINT32 depth = 0; depth < DEPTHFORMAT_COUNT; ++depth)
  241. {
  242. if (depthFormats[depth] != GL_DEPTH24_STENCIL8_EXT)
  243. {
  244. // General depth/stencil combination
  245. for (UINT32 stencil = 0; stencil < STENCILFORMAT_COUNT; ++stencil)
  246. {
  247. if (_tryFormat(depthFormats[depth], stencilFormats[stencil]))
  248. {
  249. /// Add mode to allowed modes
  250. FormatProperties::Mode mode;
  251. mode.depth = depth;
  252. mode.stencil = stencil;
  253. mProps[x].modes.push_back(mode);
  254. }
  255. }
  256. }
  257. else
  258. {
  259. // Packed depth/stencil format
  260. if (_tryPackedFormat(depthFormats[depth]))
  261. {
  262. /// Add mode to allowed modes
  263. FormatProperties::Mode mode;
  264. mode.depth = depth;
  265. mode.stencil = 0; // unuse
  266. mProps[x].modes.push_back(mode);
  267. }
  268. }
  269. }
  270. }
  271. // Delete texture and framebuffer
  272. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  273. glDeleteFramebuffersEXT(1, &fb);
  274. glFinish();
  275. if (fmt!=GL_NONE)
  276. glDeleteTextures(1, &tid);
  277. }
  278. // It seems a bug in nVidia driver: glBindFramebufferEXT should restore
  279. // draw and read buffers, but in some unclear circumstances it won't.
  280. glDrawBuffer(old_drawbuffer);
  281. glReadBuffer(old_readbuffer);
  282. String fmtstring = "";
  283. for(size_t x=0; x<PF_COUNT; ++x)
  284. {
  285. if(mProps[x].valid)
  286. fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" ";
  287. }
  288. }
  289. PixelFormat GLRTTManager::getSupportedAlternative(PixelFormat format)
  290. {
  291. if(checkFormat(format))
  292. return format;
  293. /// Find first alternative
  294. PixelComponentType pct = PixelUtil::getComponentType(format);
  295. switch(pct)
  296. {
  297. case PCT_BYTE: format = PF_A8R8G8B8; break;
  298. case PCT_SHORT: format = PF_SHORT_RGBA; break;
  299. case PCT_FLOAT16: format = PF_FLOAT16_RGBA; break;
  300. case PCT_FLOAT32: format = PF_FLOAT32_RGBA; break;
  301. case PCT_COUNT: break;
  302. }
  303. if(checkFormat(format))
  304. return format;
  305. /// If none at all, return to default
  306. return PF_A8R8G8B8;
  307. }
  308. }