BsGLRenderTexture.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsGLRenderTexture.h"
  4. #include "BsGLPixelFormat.h"
  5. #include "BsGLPixelBuffer.h"
  6. #include "BsTextureView.h"
  7. namespace BansheeEngine
  8. {
  9. #define PROBE_SIZE 16
  10. static const GLenum depthFormats[] =
  11. {
  12. GL_NONE,
  13. GL_DEPTH_COMPONENT16,
  14. GL_DEPTH_COMPONENT32,
  15. GL_DEPTH24_STENCIL8,
  16. GL_DEPTH32F_STENCIL8
  17. };
  18. #define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum))
  19. GLRenderTextureCore::GLRenderTextureCore(const RENDER_TEXTURE_CORE_DESC& desc)
  20. :RenderTextureCore(desc), mProperties(desc, true), mFB(nullptr)
  21. { }
  22. GLRenderTextureCore::~GLRenderTextureCore()
  23. {
  24. if (mFB != nullptr)
  25. bs_delete(mFB);
  26. }
  27. void GLRenderTextureCore::initialize()
  28. {
  29. RenderTextureCore::initialize();
  30. if (mFB != nullptr)
  31. bs_delete(mFB);
  32. mFB = bs_new<GLFrameBufferObject>();
  33. GLTextureCore* glTexture = static_cast<GLTextureCore*>(mColorSurface->getTexture().get());
  34. GLSurfaceDesc surfaceDesc;
  35. surfaceDesc.numSamples = getProperties().getMultisampleCount();
  36. if(mColorSurface->getNumArraySlices() == 1) // Binding a single texture layer
  37. {
  38. surfaceDesc.allLayers = false;
  39. if (glTexture->getProperties().getTextureType() != TEX_TYPE_3D)
  40. {
  41. surfaceDesc.zoffset = 0;
  42. surfaceDesc.buffer = glTexture->getBuffer(mColorSurface->getFirstArraySlice(), mColorSurface->getMostDetailedMip());
  43. }
  44. else
  45. {
  46. surfaceDesc.zoffset = mColorSurface->getFirstArraySlice();
  47. surfaceDesc.buffer = glTexture->getBuffer(0, mColorSurface->getMostDetailedMip());
  48. }
  49. }
  50. else // Binding an array of textures or a range of 3D texture slices
  51. {
  52. surfaceDesc.allLayers = true;
  53. if (glTexture->getProperties().getTextureType() != TEX_TYPE_3D)
  54. {
  55. if (mColorSurface->getNumArraySlices() != glTexture->getProperties().getNumFaces())
  56. LOGWRN("OpenGL doesn't support binding of arbitrary ranges for array textures. The entire range will be bound instead.");
  57. surfaceDesc.zoffset = 0;
  58. surfaceDesc.buffer = glTexture->getBuffer(0, mColorSurface->getMostDetailedMip());
  59. }
  60. else
  61. {
  62. if (mColorSurface->getNumArraySlices() != glTexture->getProperties().getDepth())
  63. LOGWRN("OpenGL doesn't support binding of arbitrary ranges for array textures. The entire range will be bound instead.");
  64. surfaceDesc.zoffset = 0;
  65. surfaceDesc.buffer = glTexture->getBuffer(0, mColorSurface->getMostDetailedMip());
  66. }
  67. }
  68. mFB->bindSurface(0, surfaceDesc);
  69. GLTextureCore* glDepthStencilTexture = static_cast<GLTextureCore*>(mDepthStencilSurface->getTexture().get());
  70. SPtr<GLPixelBuffer> depthStencilBuffer = nullptr;
  71. if (glDepthStencilTexture->getProperties().getTextureType() != TEX_TYPE_3D)
  72. {
  73. depthStencilBuffer = glDepthStencilTexture->getBuffer(mDepthStencilSurface->getFirstArraySlice(),
  74. mDepthStencilSurface->getMostDetailedMip());
  75. }
  76. mFB->bindDepthStencil(depthStencilBuffer);
  77. }
  78. void GLRenderTextureCore::getCustomAttribute(const String& name, void* data) const
  79. {
  80. if(name=="FBO")
  81. {
  82. *static_cast<GLFrameBufferObject**>(data) = mFB;
  83. }
  84. else if (name == "GL_FBOID" || name == "GL_MULTISAMPLEFBOID")
  85. {
  86. *static_cast<GLuint*>(data) = mFB->getGLFBOID();
  87. }
  88. }
  89. GLRTTManager::GLRTTManager()
  90. :mBlitReadFBO(0), mBlitWriteFBO(0)
  91. {
  92. detectFBOFormats();
  93. glGenFramebuffers(1, &mBlitReadFBO);
  94. glGenFramebuffers(1, &mBlitWriteFBO);
  95. }
  96. GLRTTManager::~GLRTTManager()
  97. {
  98. glDeleteFramebuffers(1, &mBlitReadFBO);
  99. glDeleteFramebuffers(1, &mBlitWriteFBO);
  100. }
  101. bool GLRTTManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
  102. {
  103. GLuint status, depthRB = 0, stencilRB = 0;
  104. bool failed = false;
  105. if(depthFormat != GL_NONE)
  106. {
  107. // Generate depth renderbuffer
  108. glGenRenderbuffers(1, &depthRB);
  109. // Bind it to FBO
  110. glBindRenderbuffer(GL_RENDERBUFFER, depthRB);
  111. // Allocate storage for depth buffer
  112. glRenderbufferStorage(GL_RENDERBUFFER, depthFormat,
  113. PROBE_SIZE, PROBE_SIZE);
  114. // Attach depth
  115. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
  116. GL_RENDERBUFFER, depthRB);
  117. }
  118. if(stencilFormat != GL_NONE)
  119. {
  120. // Generate stencil renderbuffer
  121. glGenRenderbuffers(1, &stencilRB);
  122. // Bind it to FBO
  123. glBindRenderbuffer(GL_RENDERBUFFER, stencilRB);
  124. glGetError();
  125. // Allocate storage for stencil buffer
  126. glRenderbufferStorage(GL_RENDERBUFFER, stencilFormat,
  127. PROBE_SIZE, PROBE_SIZE);
  128. if(glGetError() != GL_NO_ERROR)
  129. failed = true;
  130. // Attach stencil
  131. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
  132. GL_RENDERBUFFER, stencilRB);
  133. if(glGetError() != GL_NO_ERROR)
  134. failed = true;
  135. }
  136. status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  137. // Detach and destroy
  138. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
  139. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
  140. if (depthRB)
  141. glDeleteRenderbuffers(1, &depthRB);
  142. if (stencilRB)
  143. glDeleteRenderbuffers(1, &stencilRB);
  144. return status == GL_FRAMEBUFFER_COMPLETE && !failed;
  145. }
  146. bool GLRTTManager::_tryPackedFormat(GLenum packedFormat)
  147. {
  148. GLuint packedRB = 0;
  149. bool failed = false; // flag on GL errors
  150. // Generate renderbuffer
  151. glGenRenderbuffers(1, &packedRB);
  152. // Bind it to FBO
  153. glBindRenderbuffer(GL_RENDERBUFFER, packedRB);
  154. // Allocate storage for buffer
  155. glRenderbufferStorage(GL_RENDERBUFFER, packedFormat, PROBE_SIZE, PROBE_SIZE);
  156. glGetError();
  157. // Attach depth
  158. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
  159. GL_RENDERBUFFER, packedRB);
  160. if(glGetError() != GL_NO_ERROR)
  161. failed = true;
  162. // Attach stencil
  163. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
  164. GL_RENDERBUFFER, packedRB);
  165. if(glGetError() != GL_NO_ERROR)
  166. failed = true;
  167. GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  168. // Detach and destroy
  169. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
  170. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
  171. glDeleteRenderbuffers(1, &packedRB);
  172. return status == GL_FRAMEBUFFER_COMPLETE && !failed;
  173. }
  174. void GLRTTManager::detectFBOFormats()
  175. {
  176. // Try all formats, and report which ones work as target
  177. GLuint fb = 0, tid = 0;
  178. GLint old_drawbuffer = 0, old_readbuffer = 0;
  179. GLenum target = GL_TEXTURE_2D;
  180. glGetIntegerv (GL_DRAW_BUFFER, &old_drawbuffer);
  181. glGetIntegerv (GL_READ_BUFFER, &old_readbuffer);
  182. for(size_t x=0; x<PF_COUNT; ++x)
  183. {
  184. mProps[x].valid = false;
  185. // Fetch GL format token
  186. GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x);
  187. if(fmt == GL_NONE && x!=0)
  188. continue;
  189. // No test for compressed formats
  190. if(PixelUtil::isCompressed((PixelFormat)x))
  191. continue;
  192. // Create and attach framebuffer
  193. glGenFramebuffers(1, &fb);
  194. glBindFramebuffer(GL_FRAMEBUFFER, fb);
  195. if (fmt!=GL_NONE && !PixelUtil::isDepth((PixelFormat)x))
  196. {
  197. // Create and attach texture
  198. glGenTextures(1, &tid);
  199. glBindTexture(target, tid);
  200. // Set some default parameters so it won't fail on NVidia cards
  201. if (GLEW_VERSION_1_2)
  202. glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
  203. glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  204. glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  205. glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  206. glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  207. glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  208. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tid, 0);
  209. }
  210. else
  211. {
  212. // Draw to nowhere -- stencil/depth only
  213. glDrawBuffer(GL_NONE);
  214. glReadBuffer(GL_NONE);
  215. }
  216. // Check status
  217. GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  218. // Ignore status in case of fmt==GL_NONE, because no implementation will accept
  219. // a buffer without *any* attachment. Buffers with only stencil and depth attachment
  220. // might still be supported, so we must continue probing.
  221. if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE)
  222. {
  223. mProps[x].valid = true;
  224. // For each depth/stencil formats
  225. for (UINT32 depth = 0; depth < DEPTHFORMAT_COUNT; ++depth)
  226. {
  227. if (depthFormats[depth] != GL_DEPTH24_STENCIL8 && depthFormats[depth] != GL_DEPTH32F_STENCIL8)
  228. {
  229. if (_tryFormat(depthFormats[depth], GL_NONE))
  230. {
  231. /// Add mode to allowed modes
  232. FormatProperties::Mode mode;
  233. mode.depth = depth;
  234. mode.stencil = 0;
  235. mProps[x].modes.push_back(mode);
  236. }
  237. }
  238. else
  239. {
  240. // Packed depth/stencil format
  241. if (_tryPackedFormat(depthFormats[depth]))
  242. {
  243. /// Add mode to allowed modes
  244. FormatProperties::Mode mode;
  245. mode.depth = depth;
  246. mode.stencil = 0; // unuse
  247. mProps[x].modes.push_back(mode);
  248. }
  249. }
  250. }
  251. }
  252. // Delete texture and framebuffer
  253. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  254. glDeleteFramebuffers(1, &fb);
  255. glFinish();
  256. if (fmt != GL_NONE)
  257. glDeleteTextures(1, &tid);
  258. }
  259. // It seems a bug in nVidia driver: glBindFramebuffer should restore
  260. // draw and read buffers, but in some unclear circumstances it won't.
  261. glDrawBuffer(old_drawbuffer);
  262. glReadBuffer(old_readbuffer);
  263. String fmtstring = "";
  264. for(size_t x = 0; x < PF_COUNT; ++x)
  265. {
  266. if(mProps[x].valid)
  267. fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" ";
  268. }
  269. }
  270. PixelFormat GLRTTManager::getSupportedAlternative(PixelFormat format)
  271. {
  272. if(checkFormat(format))
  273. return format;
  274. // Find first alternative
  275. PixelComponentType pct = PixelUtil::getElementType(format);
  276. switch(pct)
  277. {
  278. case PCT_BYTE: format = PF_A8R8G8B8; break;
  279. case PCT_FLOAT16: format = PF_FLOAT16_RGBA; break;
  280. case PCT_FLOAT32: format = PF_FLOAT32_RGBA; break;
  281. default: break;
  282. }
  283. if(checkFormat(format))
  284. return format;
  285. // If none at all, return to default
  286. return PF_A8R8G8B8;
  287. }
  288. GLRenderTexture::GLRenderTexture(const RENDER_TEXTURE_DESC& desc)
  289. :RenderTexture(desc), mProperties(desc, true)
  290. {
  291. }
  292. }