PageRenderTime 32ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llrender/llrendertarget.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 535 lines | 429 code | 77 blank | 29 comment | 59 complexity | 59ff2c73529a77b0fd337f428be808d4 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llrendertarget.cpp
  3. * @brief LLRenderTarget implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llrendertarget.h"
  28. #include "llrender.h"
  29. #include "llgl.h"
  30. LLRenderTarget* LLRenderTarget::sBoundTarget = NULL;
  31. U32 LLRenderTarget::sBytesAllocated = 0;
  32. void check_framebuffer_status()
  33. {
  34. if (gDebugGL)
  35. {
  36. GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
  37. switch (status)
  38. {
  39. case GL_FRAMEBUFFER_COMPLETE:
  40. break;
  41. default:
  42. llwarns << "check_framebuffer_status failed -- " << std::hex << status << llendl;
  43. ll_fail("check_framebuffer_status failed");
  44. break;
  45. }
  46. }
  47. }
  48. bool LLRenderTarget::sUseFBO = false;
  49. LLRenderTarget::LLRenderTarget() :
  50. mResX(0),
  51. mResY(0),
  52. mTex(0),
  53. mFBO(0),
  54. mDepth(0),
  55. mStencil(0),
  56. mUseDepth(false),
  57. mRenderDepth(false),
  58. mUsage(LLTexUnit::TT_TEXTURE)
  59. {
  60. }
  61. LLRenderTarget::~LLRenderTarget()
  62. {
  63. release();
  64. }
  65. bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples)
  66. {
  67. stop_glerror();
  68. release();
  69. stop_glerror();
  70. mResX = resx;
  71. mResY = resy;
  72. mStencil = stencil;
  73. mUsage = usage;
  74. mUseDepth = depth;
  75. if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
  76. {
  77. if (depth)
  78. {
  79. if (!allocateDepth())
  80. {
  81. llwarns << "Failed to allocate depth buffer for render target." << llendl;
  82. return false;
  83. }
  84. }
  85. glGenFramebuffers(1, (GLuint *) &mFBO);
  86. if (mDepth)
  87. {
  88. glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
  89. if (mStencil)
  90. {
  91. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
  92. stop_glerror();
  93. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
  94. stop_glerror();
  95. }
  96. else
  97. {
  98. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
  99. stop_glerror();
  100. }
  101. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  102. }
  103. stop_glerror();
  104. }
  105. return addColorAttachment(color_fmt);
  106. }
  107. bool LLRenderTarget::addColorAttachment(U32 color_fmt)
  108. {
  109. if (color_fmt == 0)
  110. {
  111. return true;
  112. }
  113. U32 offset = mTex.size();
  114. if (offset >= 4 ||
  115. (offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)))
  116. {
  117. llerrs << "Too many color attachments!" << llendl;
  118. }
  119. U32 tex;
  120. LLImageGL::generateTextures(1, &tex);
  121. gGL.getTexUnit(0)->bindManual(mUsage, tex);
  122. stop_glerror();
  123. {
  124. clear_glerror();
  125. LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  126. if (glGetError() != GL_NO_ERROR)
  127. {
  128. llwarns << "Could not allocate color buffer for render target." << llendl;
  129. return false;
  130. }
  131. }
  132. sBytesAllocated += mResX*mResY*4;
  133. stop_glerror();
  134. if (offset == 0)
  135. { //use bilinear filtering on single texture render targets that aren't multisampled
  136. gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
  137. stop_glerror();
  138. }
  139. else
  140. { //don't filter data attachments
  141. gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
  142. stop_glerror();
  143. }
  144. if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
  145. {
  146. gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
  147. stop_glerror();
  148. }
  149. else
  150. {
  151. // ATI doesn't support mirrored repeat for rectangular textures.
  152. gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
  153. stop_glerror();
  154. }
  155. if (mFBO)
  156. {
  157. stop_glerror();
  158. glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
  159. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
  160. LLTexUnit::getInternalType(mUsage), tex, 0);
  161. stop_glerror();
  162. check_framebuffer_status();
  163. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  164. }
  165. mTex.push_back(tex);
  166. if (gDebugGL)
  167. { //bind and unbind to validate target
  168. bindTarget();
  169. flush();
  170. }
  171. return true;
  172. }
  173. bool LLRenderTarget::allocateDepth()
  174. {
  175. if (mStencil)
  176. {
  177. //use render buffers where stencil buffers are in play
  178. glGenRenderbuffers(1, (GLuint *) &mDepth);
  179. glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
  180. stop_glerror();
  181. clear_glerror();
  182. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
  183. glBindRenderbuffer(GL_RENDERBUFFER, 0);
  184. }
  185. else
  186. {
  187. LLImageGL::generateTextures(1, &mDepth);
  188. gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
  189. U32 internal_type = LLTexUnit::getInternalType(mUsage);
  190. stop_glerror();
  191. clear_glerror();
  192. LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
  193. gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
  194. }
  195. sBytesAllocated += mResX*mResY*4;
  196. if (glGetError() != GL_NO_ERROR)
  197. {
  198. llwarns << "Unable to allocate depth buffer for render target." << llendl;
  199. return false;
  200. }
  201. return true;
  202. }
  203. void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
  204. {
  205. if (!mFBO || !target.mFBO)
  206. {
  207. llerrs << "Cannot share depth buffer between non FBO render targets." << llendl;
  208. }
  209. if (target.mDepth)
  210. {
  211. llerrs << "Attempting to override existing depth buffer. Detach existing buffer first." << llendl;
  212. }
  213. if (target.mUseDepth)
  214. {
  215. llerrs << "Attempting to override existing shared depth buffer. Detach existing buffer first." << llendl;
  216. }
  217. if (mDepth)
  218. {
  219. stop_glerror();
  220. glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
  221. stop_glerror();
  222. if (mStencil)
  223. {
  224. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
  225. stop_glerror();
  226. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
  227. stop_glerror();
  228. target.mStencil = true;
  229. }
  230. else
  231. {
  232. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
  233. stop_glerror();
  234. }
  235. check_framebuffer_status();
  236. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  237. target.mUseDepth = true;
  238. }
  239. }
  240. void LLRenderTarget::release()
  241. {
  242. if (mDepth)
  243. {
  244. if (mStencil)
  245. {
  246. glDeleteRenderbuffers(1, (GLuint*) &mDepth);
  247. stop_glerror();
  248. }
  249. else
  250. {
  251. LLImageGL::deleteTextures(1, &mDepth, true);
  252. stop_glerror();
  253. }
  254. mDepth = 0;
  255. sBytesAllocated -= mResX*mResY*4;
  256. }
  257. else if (mUseDepth && mFBO)
  258. { //detach shared depth buffer
  259. glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
  260. if (mStencil)
  261. { //attached as a renderbuffer
  262. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
  263. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
  264. mStencil = false;
  265. }
  266. else
  267. { //attached as a texture
  268. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
  269. }
  270. mUseDepth = false;
  271. }
  272. if (mFBO)
  273. {
  274. glDeleteFramebuffers(1, (GLuint *) &mFBO);
  275. mFBO = 0;
  276. }
  277. if (mTex.size() > 0)
  278. {
  279. sBytesAllocated -= mResX*mResY*4*mTex.size();
  280. LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
  281. mTex.clear();
  282. }
  283. mResX = mResY = 0;
  284. sBoundTarget = NULL;
  285. }
  286. void LLRenderTarget::bindTarget()
  287. {
  288. if (mFBO)
  289. {
  290. stop_glerror();
  291. glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
  292. stop_glerror();
  293. if (gGLManager.mHasDrawBuffers)
  294. { //setup multiple render targets
  295. GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
  296. GL_COLOR_ATTACHMENT1,
  297. GL_COLOR_ATTACHMENT2,
  298. GL_COLOR_ATTACHMENT3};
  299. glDrawBuffersARB(mTex.size(), drawbuffers);
  300. }
  301. if (mTex.empty())
  302. { //no color buffer to draw to
  303. glDrawBuffer(GL_NONE);
  304. glReadBuffer(GL_NONE);
  305. }
  306. check_framebuffer_status();
  307. stop_glerror();
  308. }
  309. glViewport(0, 0, mResX, mResY);
  310. sBoundTarget = this;
  311. }
  312. // static
  313. void LLRenderTarget::unbindTarget()
  314. {
  315. if (gGLManager.mHasFramebufferObject)
  316. {
  317. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  318. }
  319. sBoundTarget = NULL;
  320. }
  321. void LLRenderTarget::clear(U32 mask_in)
  322. {
  323. U32 mask = GL_COLOR_BUFFER_BIT;
  324. if (mUseDepth)
  325. {
  326. mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
  327. }
  328. if (mFBO)
  329. {
  330. check_framebuffer_status();
  331. stop_glerror();
  332. glClear(mask & mask_in);
  333. stop_glerror();
  334. }
  335. else
  336. {
  337. LLGLEnable scissor(GL_SCISSOR_TEST);
  338. glScissor(0, 0, mResX, mResY);
  339. stop_glerror();
  340. glClear(mask & mask_in);
  341. }
  342. }
  343. U32 LLRenderTarget::getTexture(U32 attachment) const
  344. {
  345. if (attachment > mTex.size()-1)
  346. {
  347. llerrs << "Invalid attachment index." << llendl;
  348. }
  349. if (mTex.empty())
  350. {
  351. return 0;
  352. }
  353. return mTex[attachment];
  354. }
  355. void LLRenderTarget::bindTexture(U32 index, S32 channel)
  356. {
  357. gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index));
  358. }
  359. void LLRenderTarget::flush(bool fetch_depth)
  360. {
  361. gGL.flush();
  362. if (!mFBO)
  363. {
  364. gGL.getTexUnit(0)->bind(this);
  365. glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY);
  366. if (fetch_depth)
  367. {
  368. if (!mDepth)
  369. {
  370. allocateDepth();
  371. }
  372. gGL.getTexUnit(0)->bind(this);
  373. glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0);
  374. }
  375. gGL.getTexUnit(0)->disable();
  376. }
  377. else
  378. {
  379. stop_glerror();
  380. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  381. stop_glerror();
  382. }
  383. }
  384. void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
  385. S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
  386. {
  387. GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
  388. LLGLDepthTest depth(write_depth, write_depth);
  389. gGL.flush();
  390. if (!source.mFBO || !mFBO)
  391. {
  392. llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
  393. return;
  394. }
  395. if (mask == GL_DEPTH_BUFFER_BIT && source.mStencil != mStencil)
  396. {
  397. stop_glerror();
  398. glBindFramebuffer(GL_FRAMEBUFFER, source.mFBO);
  399. check_framebuffer_status();
  400. gGL.getTexUnit(0)->bind(this, true);
  401. stop_glerror();
  402. glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1);
  403. stop_glerror();
  404. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  405. stop_glerror();
  406. }
  407. else
  408. {
  409. glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
  410. stop_glerror();
  411. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);
  412. stop_glerror();
  413. check_framebuffer_status();
  414. stop_glerror();
  415. glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
  416. stop_glerror();
  417. glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
  418. stop_glerror();
  419. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  420. stop_glerror();
  421. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  422. stop_glerror();
  423. }
  424. }
  425. //static
  426. void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
  427. S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
  428. {
  429. if (!source.mFBO)
  430. {
  431. llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
  432. }
  433. {
  434. GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
  435. LLGLDepthTest depth(write_depth, write_depth);
  436. glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
  437. stop_glerror();
  438. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  439. stop_glerror();
  440. check_framebuffer_status();
  441. stop_glerror();
  442. glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
  443. stop_glerror();
  444. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  445. stop_glerror();
  446. }
  447. }
  448. bool LLRenderTarget::isComplete() const
  449. {
  450. return (!mTex.empty() || mDepth) ? true : false;
  451. }
  452. void LLRenderTarget::getViewport(S32* viewport)
  453. {
  454. viewport[0] = 0;
  455. viewport[1] = 0;
  456. viewport[2] = mResX;
  457. viewport[3] = mResY;
  458. }