BsGLRenderTexture.cpp 12 KB

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