PageRenderTime 71ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/RenderSystems/GL3Plus/src/OgreGL3PlusHardwarePixelBuffer.cpp

https://bitbucket.org/masterfalcon/ogre-gl3plus/
C++ | 1060 lines | 797 code | 89 blank | 174 comment | 135 complexity | 83741adfd249c51100f4306dff72347c MD5 | raw file
Possible License(s): MIT, LGPL-2.1
  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 "OgreRenderSystem.h"
  25. #include "OgreGL3PlusHardwarePixelBuffer.h"
  26. #include "OgreGL3PlusPixelFormat.h"
  27. #include "OgreGL3PlusFBORenderTexture.h"
  28. #include "OgreGL3PlusGpuProgram.h"
  29. #include "OgreRoot.h"
  30. #include "OgreGLSLLinkProgramManager.h"
  31. #include "OgreGLSLLinkProgram.h"
  32. static int computeLog(GLuint value)
  33. {
  34. int i;
  35. i = 0;
  36. /* Error! */
  37. if (value == 0) return -1;
  38. for (;;)
  39. {
  40. if (value & 1)
  41. {
  42. /* Error! */
  43. if (value != 1) return -1;
  44. return i;
  45. }
  46. value = value >> 1;
  47. i++;
  48. }
  49. }
  50. namespace Ogre {
  51. GL3PlusHardwarePixelBuffer::GL3PlusHardwarePixelBuffer(size_t mWidth, size_t mHeight,
  52. size_t mDepth, PixelFormat mFormat,
  53. HardwareBuffer::Usage usage)
  54. : HardwarePixelBuffer(mWidth, mHeight, mDepth, mFormat, usage, false, false),
  55. mBuffer(mWidth, mHeight, mDepth, mFormat),
  56. mGLInternalFormat(GL_NONE)
  57. {
  58. mCurrentLockOptions = (LockOptions)0;
  59. }
  60. GL3PlusHardwarePixelBuffer::~GL3PlusHardwarePixelBuffer()
  61. {
  62. // Force free buffer
  63. delete [] (uint8*)mBuffer.data;
  64. }
  65. void GL3PlusHardwarePixelBuffer::allocateBuffer()
  66. {
  67. if (mBuffer.data)
  68. // Already allocated
  69. return;
  70. mBuffer.data = new uint8[mSizeInBytes];
  71. // TODO use PBO if we're HBU_DYNAMIC
  72. }
  73. void GL3PlusHardwarePixelBuffer::freeBuffer()
  74. {
  75. // Free buffer if we're STATIC to save memory
  76. if (mUsage & HBU_STATIC)
  77. {
  78. delete [] (uint8*)mBuffer.data;
  79. mBuffer.data = 0;
  80. }
  81. }
  82. PixelBox GL3PlusHardwarePixelBuffer::lockImpl(const Image::Box lockBox, LockOptions options)
  83. {
  84. allocateBuffer();
  85. if(options != HardwareBuffer::HBL_DISCARD)
  86. {
  87. // Download the old contents of the texture
  88. download(mBuffer);
  89. }
  90. mCurrentLockOptions = options;
  91. mLockedBox = lockBox;
  92. return mBuffer.getSubVolume(lockBox);
  93. }
  94. void GL3PlusHardwarePixelBuffer::unlockImpl(void)
  95. {
  96. if (mCurrentLockOptions != HardwareBuffer::HBL_READ_ONLY)
  97. {
  98. // From buffer to card, only upload if was locked for writing
  99. upload(mCurrentLock, mLockedBox);
  100. }
  101. freeBuffer();
  102. }
  103. void GL3PlusHardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox)
  104. {
  105. if (!mBuffer.contains(dstBox))
  106. {
  107. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
  108. "Destination box out of range",
  109. "GL3PlusHardwarePixelBuffer::blitFromMemory");
  110. }
  111. PixelBox scaled;
  112. if (src.getWidth() != dstBox.getWidth() ||
  113. src.getHeight() != dstBox.getHeight() ||
  114. src.getDepth() != dstBox.getDepth())
  115. {
  116. // Scale to destination size. Use DevIL and not iluScale because ILU screws up for
  117. // floating point textures and cannot cope with 3D images.
  118. // This also does pixel format conversion if needed
  119. allocateBuffer();
  120. scaled = mBuffer.getSubVolume(dstBox);
  121. Image::scale(src, scaled, Image::FILTER_BILINEAR);
  122. }
  123. else if(GL3PlusPixelUtil::getGLOriginFormat(src.format) == 0)
  124. {
  125. // Extents match, but format is not accepted as valid source format for GL
  126. // do conversion in temporary buffer
  127. allocateBuffer();
  128. scaled = mBuffer.getSubVolume(dstBox);
  129. PixelUtil::bulkPixelConversion(src, scaled);
  130. }
  131. else
  132. {
  133. allocateBuffer();
  134. // No scaling or conversion needed
  135. scaled = src;
  136. }
  137. upload(scaled, dstBox);
  138. freeBuffer();
  139. }
  140. void GL3PlusHardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst)
  141. {
  142. if (!mBuffer.contains(srcBox))
  143. {
  144. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
  145. "source box out of range",
  146. "GL3PlusHardwarePixelBuffer::blitToMemory");
  147. }
  148. if (srcBox.left == 0 && srcBox.right == getWidth() &&
  149. srcBox.top == 0 && srcBox.bottom == getHeight() &&
  150. srcBox.front == 0 && srcBox.back == getDepth() &&
  151. dst.getWidth() == getWidth() &&
  152. dst.getHeight() == getHeight() &&
  153. dst.getDepth() == getDepth() &&
  154. GL3PlusPixelUtil::getGLOriginFormat(dst.format) != 0)
  155. {
  156. // The direct case: the user wants the entire texture in a format supported by GL
  157. // so we don't need an intermediate buffer
  158. download(dst);
  159. }
  160. else
  161. {
  162. // Use buffer for intermediate copy
  163. allocateBuffer();
  164. // Download entire buffer
  165. download(mBuffer);
  166. if(srcBox.getWidth() != dst.getWidth() ||
  167. srcBox.getHeight() != dst.getHeight() ||
  168. srcBox.getDepth() != dst.getDepth())
  169. {
  170. // We need scaling
  171. Image::scale(mBuffer.getSubVolume(srcBox), dst, Image::FILTER_BILINEAR);
  172. }
  173. else
  174. {
  175. // Just copy the bit that we need
  176. PixelUtil::bulkPixelConversion(mBuffer.getSubVolume(srcBox), dst);
  177. }
  178. freeBuffer();
  179. }
  180. }
  181. void GL3PlusHardwarePixelBuffer::upload(const PixelBox &data, const Image::Box &dest)
  182. {
  183. OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
  184. "Upload not possible for this pixelbuffer type",
  185. "GL3PlusHardwarePixelBuffer::upload");
  186. }
  187. void GL3PlusHardwarePixelBuffer::download(const PixelBox &data)
  188. {
  189. OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
  190. "Download not possible for this pixelbuffer type",
  191. "GL3PlusHardwarePixelBuffer::download");
  192. }
  193. void GL3PlusHardwarePixelBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset)
  194. {
  195. OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
  196. "Framebuffer bind not possible for this pixelbuffer type",
  197. "GL3PlusHardwarePixelBuffer::bindToFramebuffer");
  198. }
  199. // TextureBuffer
  200. GL3PlusTextureBuffer::GL3PlusTextureBuffer(const String &baseName, GLenum target, GLuint id,
  201. GLint face, GLint level, Usage usage, bool crappyCard,
  202. bool writeGamma, uint fsaa)
  203. : GL3PlusHardwarePixelBuffer(0, 0, 0, PF_UNKNOWN, usage),
  204. mTarget(target), mTextureID(id), mFace(face), mLevel(level), mSoftwareMipmap(crappyCard), mSliceTRT(0)
  205. {
  206. // devise mWidth, mHeight and mDepth and mFormat
  207. GLint value = 0;
  208. glBindTexture(mTarget, mTextureID);
  209. GL_CHECK_ERROR
  210. // Get face identifier
  211. mFaceTarget = mTarget;
  212. if(mTarget == GL_TEXTURE_CUBE_MAP)
  213. mFaceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
  214. // Get width
  215. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_WIDTH, &value);
  216. GL_CHECK_ERROR
  217. mWidth = value;
  218. // Get height
  219. if(target == GL_TEXTURE_1D)
  220. value = 1; // Height always 1 for 1D textures
  221. else
  222. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_HEIGHT, &value);
  223. mHeight = value;
  224. GL_CHECK_ERROR
  225. // Get depth
  226. if(target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY)
  227. value = 1; // Depth always 1 for non-3D textures
  228. else
  229. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_DEPTH, &value);
  230. mDepth = value;
  231. GL_CHECK_ERROR
  232. // Get format
  233. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_INTERNAL_FORMAT, &value);
  234. GL_CHECK_ERROR
  235. mGLInternalFormat = value;
  236. mFormat = GL3PlusPixelUtil::getClosestOGREFormat(value);
  237. // Default
  238. mRowPitch = mWidth;
  239. mSlicePitch = mHeight*mWidth;
  240. mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
  241. // Log a message
  242. std::stringstream str;
  243. str << "GL3PlusHardwarePixelBuffer constructed for texture " << mTextureID
  244. << " face " << mFace << " level " << mLevel << ": "
  245. << "width=" << mWidth << " height="<< mHeight << " depth=" << mDepth
  246. << " format=" << PixelUtil::getFormatName(mFormat);
  247. LogManager::getSingleton().logMessage(LML_NORMAL, str.str());
  248. // Set up a pixel box
  249. mBuffer = PixelBox(mWidth, mHeight, mDepth, mFormat);
  250. if (mWidth==0 || mHeight==0 || mDepth==0)
  251. // We are invalid, do not allocate a buffer
  252. return;
  253. // Is this a render target?
  254. if (mUsage & TU_RENDERTARGET)
  255. {
  256. // Create render target for each slice
  257. mSliceTRT.reserve(mDepth);
  258. for(size_t zoffset=0; zoffset<mDepth; ++zoffset)
  259. {
  260. String name;
  261. name = "rtt/" + StringConverter::toString((size_t)this) + "/" + baseName;
  262. GL3PlusSurfaceDesc surface;
  263. surface.buffer = this;
  264. surface.zoffset = zoffset;
  265. RenderTexture *trt = GL3PlusRTTManager::getSingleton().createRenderTexture(name, surface, writeGamma, fsaa);
  266. mSliceTRT.push_back(trt);
  267. Root::getSingleton().getRenderSystem()->attachRenderTarget(*mSliceTRT[zoffset]);
  268. }
  269. }
  270. }
  271. GL3PlusTextureBuffer::~GL3PlusTextureBuffer()
  272. {
  273. if (mUsage & TU_RENDERTARGET)
  274. {
  275. // Delete all render targets that are not yet deleted via _clearSliceRTT because the rendertarget
  276. // was deleted by the user.
  277. for (SliceTRT::const_iterator it = mSliceTRT.begin(); it != mSliceTRT.end(); ++it)
  278. {
  279. Root::getSingleton().getRenderSystem()->destroyRenderTarget((*it)->getName());
  280. }
  281. }
  282. }
  283. void GL3PlusTextureBuffer::upload(const PixelBox &data, const Image::Box &dest)
  284. {
  285. glBindTexture(mTarget, mTextureID);
  286. GL_CHECK_ERROR
  287. if (PixelUtil::isCompressed(data.format))
  288. {
  289. if(data.format != mFormat || !data.isConsecutive())
  290. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
  291. "Compressed images must be consecutive, in the source format",
  292. "GL3PlusTextureBuffer::upload");
  293. GLenum format = GL3PlusPixelUtil::getClosestGLInternalFormat(mFormat);
  294. // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
  295. // for compressed formats
  296. switch(mTarget) {
  297. case GL_TEXTURE_1D:
  298. // some systems (e.g. old Apple) don't like compressed subimage calls
  299. // so prefer non-sub versions
  300. if (dest.left == 0)
  301. {
  302. glCompressedTexImage1D(GL_TEXTURE_1D, mLevel,
  303. format,
  304. dest.getWidth(),
  305. 0,
  306. data.getConsecutiveSize(),
  307. data.data);
  308. }
  309. else
  310. {
  311. glCompressedTexSubImage1D(GL_TEXTURE_1D, mLevel,
  312. dest.left,
  313. dest.getWidth(),
  314. format, data.getConsecutiveSize(),
  315. data.data);
  316. }
  317. break;
  318. case GL_TEXTURE_2D:
  319. case GL_TEXTURE_CUBE_MAP:
  320. case GL_TEXTURE_RECTANGLE:
  321. // some systems (e.g. old Apple) don't like compressed subimage calls
  322. // so prefer non-sub versions
  323. if (dest.left == 0 && dest.top == 0)
  324. {
  325. glCompressedTexImage2D(mFaceTarget, mLevel,
  326. format,
  327. dest.getWidth(),
  328. dest.getHeight(),
  329. 0,
  330. data.getConsecutiveSize(),
  331. data.data);
  332. }
  333. else
  334. {
  335. glCompressedTexSubImage2D(mFaceTarget, mLevel,
  336. dest.left, dest.top,
  337. dest.getWidth(), dest.getHeight(),
  338. format, data.getConsecutiveSize(),
  339. data.data);
  340. }
  341. break;
  342. case GL_TEXTURE_3D:
  343. case GL_TEXTURE_2D_ARRAY:
  344. // some systems (e.g. old Apple) don't like compressed subimage calls
  345. // so prefer non-sub versions
  346. // if (dest.left == 0 && dest.top == 0 && dest.front == 0)
  347. // {
  348. // glCompressedTexImage3D(mTarget, mLevel,
  349. // format,
  350. // dest.getWidth(),
  351. // dest.getHeight(),
  352. // dest.getDepth(),
  353. // 0,
  354. // data.getConsecutiveSize(),
  355. // data.data);
  356. // }
  357. // else
  358. // {
  359. glCompressedTexSubImage3D(mTarget, mLevel,
  360. dest.left, dest.top, dest.front,
  361. dest.getWidth(), dest.getHeight(), dest.getDepth(),
  362. format, data.getConsecutiveSize(),
  363. data.data);
  364. // }
  365. break;
  366. }
  367. GL_CHECK_ERROR
  368. }
  369. else if(mSoftwareMipmap)
  370. {
  371. if(data.getWidth() != data.rowPitch)
  372. glPixelStorei(GL_UNPACK_ROW_LENGTH, data.rowPitch);
  373. if(data.getHeight()*data.getWidth() != data.slicePitch)
  374. glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()));
  375. if(data.left > 0 || data.top > 0 || data.front > 0)
  376. glPixelStorei(GL_UNPACK_SKIP_PIXELS, data.left + data.rowPitch * data.top + data.slicePitch * data.front);
  377. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  378. GL_CHECK_ERROR
  379. buildMipmaps(data);
  380. }
  381. else
  382. {
  383. if(data.getWidth() != data.rowPitch)
  384. glPixelStorei(GL_UNPACK_ROW_LENGTH, data.rowPitch);
  385. if(data.getHeight()*data.getWidth() != data.slicePitch)
  386. glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()));
  387. if(data.left > 0 || data.top > 0 || data.front > 0)
  388. glPixelStorei(GL_UNPACK_SKIP_PIXELS, data.left + data.rowPitch * data.top + data.slicePitch * data.front);
  389. if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) {
  390. // Standard alignment of 4 is not right
  391. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  392. }
  393. GL_CHECK_ERROR
  394. switch(mTarget) {
  395. case GL_TEXTURE_1D:
  396. glTexSubImage1D(GL_TEXTURE_1D, mLevel,
  397. dest.left,
  398. dest.getWidth(),
  399. GL3PlusPixelUtil::getGLOriginFormat(data.format), GL3PlusPixelUtil::getGLOriginDataType(data.format),
  400. data.data);
  401. break;
  402. case GL_TEXTURE_2D:
  403. case GL_TEXTURE_CUBE_MAP:
  404. case GL_TEXTURE_RECTANGLE:
  405. glTexSubImage2D(mFaceTarget, mLevel,
  406. dest.left, dest.top,
  407. dest.getWidth(), dest.getHeight(),
  408. GL3PlusPixelUtil::getGLOriginFormat(data.format), GL3PlusPixelUtil::getGLOriginDataType(data.format),
  409. data.data);
  410. break;
  411. case GL_TEXTURE_3D:
  412. case GL_TEXTURE_2D_ARRAY:
  413. glTexSubImage3D(
  414. mTarget, mLevel,
  415. dest.left, dest.top, dest.front,
  416. dest.getWidth(), dest.getHeight(), dest.getDepth(),
  417. GL3PlusPixelUtil::getGLOriginFormat(data.format), GL3PlusPixelUtil::getGLOriginDataType(data.format),
  418. data.data);
  419. break;
  420. }
  421. GL_CHECK_ERROR
  422. if (mUsage & TU_AUTOMIPMAP)
  423. {
  424. glGenerateMipmap(mTarget);
  425. GL_CHECK_ERROR
  426. }
  427. }
  428. // Restore defaults
  429. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  430. glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
  431. glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
  432. glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  433. }
  434. //-----------------------------------------------------------------------------
  435. void GL3PlusTextureBuffer::download(const PixelBox &data)
  436. {
  437. if(data.getWidth() != getWidth() ||
  438. data.getHeight() != getHeight() ||
  439. data.getDepth() != getDepth())
  440. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL",
  441. "GL3PlusTextureBuffer::download");
  442. glBindTexture( mTarget, mTextureID );
  443. GL_CHECK_ERROR
  444. if(PixelUtil::isCompressed(data.format))
  445. {
  446. if(data.format != mFormat || !data.isConsecutive())
  447. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
  448. "Compressed images must be consecutive, in the source format",
  449. "GL3PlusTextureBuffer::download");
  450. // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
  451. // for compressed formate
  452. glGetCompressedTexImage(mFaceTarget, mLevel, data.data);
  453. GL_CHECK_ERROR
  454. }
  455. else
  456. {
  457. if(data.getWidth() != data.rowPitch)
  458. glPixelStorei(GL_PACK_ROW_LENGTH, data.rowPitch);
  459. if(data.getHeight()*data.getWidth() != data.slicePitch)
  460. glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()));
  461. if(data.left > 0 || data.top > 0 || data.front > 0)
  462. glPixelStorei(GL_PACK_SKIP_PIXELS, data.left + data.rowPitch * data.top + data.slicePitch * data.front);
  463. if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) {
  464. // Standard alignment of 4 is not right
  465. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  466. }
  467. GL_CHECK_ERROR
  468. // We can only get the entire texture
  469. glGetTexImage(mFaceTarget, mLevel,
  470. GL3PlusPixelUtil::getGLOriginFormat(data.format), GL3PlusPixelUtil::getGLOriginDataType(data.format),
  471. data.data);
  472. GL_CHECK_ERROR
  473. // Restore defaults
  474. glPixelStorei(GL_PACK_ROW_LENGTH, 0);
  475. glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
  476. glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
  477. glPixelStorei(GL_PACK_ALIGNMENT, 4);
  478. }
  479. }
  480. //-----------------------------------------------------------------------------
  481. void GL3PlusTextureBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset)
  482. {
  483. assert(zoffset < mDepth);
  484. switch(mTarget)
  485. {
  486. case GL_TEXTURE_1D:
  487. glFramebufferTexture1D(GL_FRAMEBUFFER, attachment,
  488. mFaceTarget, mTextureID, mLevel);
  489. break;
  490. case GL_TEXTURE_2D:
  491. case GL_TEXTURE_CUBE_MAP:
  492. case GL_TEXTURE_RECTANGLE:
  493. glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
  494. mFaceTarget, mTextureID, mLevel);
  495. break;
  496. case GL_TEXTURE_3D:
  497. case GL_TEXTURE_2D_ARRAY:
  498. glFramebufferTexture3D(GL_FRAMEBUFFER, attachment,
  499. mFaceTarget, mTextureID, mLevel, zoffset);
  500. break;
  501. }
  502. GL_CHECK_ERROR
  503. }
  504. //-----------------------------------------------------------------------------
  505. void GL3PlusTextureBuffer::copyFromFramebuffer(size_t zoffset)
  506. {
  507. glBindTexture(mTarget, mTextureID);
  508. GL_CHECK_ERROR
  509. switch(mTarget)
  510. {
  511. case GL_TEXTURE_1D:
  512. glCopyTexSubImage1D(mFaceTarget, mLevel, 0, 0, 0, mWidth);
  513. break;
  514. case GL_TEXTURE_2D:
  515. case GL_TEXTURE_CUBE_MAP:
  516. case GL_TEXTURE_RECTANGLE:
  517. glCopyTexSubImage2D(mFaceTarget, mLevel, 0, 0, 0, 0, mWidth, mHeight);
  518. break;
  519. case GL_TEXTURE_3D:
  520. case GL_TEXTURE_2D_ARRAY:
  521. glCopyTexSubImage3D(mFaceTarget, mLevel, 0, 0, zoffset, 0, 0, mWidth, mHeight);
  522. break;
  523. }
  524. GL_CHECK_ERROR
  525. }
  526. //-----------------------------------------------------------------------------
  527. void GL3PlusTextureBuffer::blit(const HardwarePixelBufferSharedPtr &src, const Image::Box &srcBox, const Image::Box &dstBox)
  528. {
  529. GL3PlusTextureBuffer *srct = static_cast<GL3PlusTextureBuffer *>(src.getPointer());
  530. /// Check for FBO support first
  531. /// Destination texture must be 1D, 2D, 3D, or Cube
  532. /// Source texture must be 1D, 2D or 3D
  533. // This does not sem to work for RTTs after the first update
  534. // I have no idea why! For the moment, disable
  535. if((src->getUsage() & TU_RENDERTARGET) == 0 &&
  536. (srct->mTarget == GL_TEXTURE_1D || srct->mTarget == GL_TEXTURE_2D
  537. || srct->mTarget == GL_TEXTURE_RECTANGLE || srct->mTarget == GL_TEXTURE_3D)
  538. && mTarget != GL_TEXTURE_2D_ARRAY)
  539. {
  540. blitFromTexture(srct, srcBox, dstBox);
  541. }
  542. else
  543. {
  544. GL3PlusHardwarePixelBuffer::blit(src, srcBox, dstBox);
  545. }
  546. }
  547. //-----------------------------------------------------------------------------
  548. // Very fast texture-to-texture blitter and hardware bi/trilinear scaling implementation using FBO
  549. // Destination texture must be 1D, 2D, 3D, or Cube
  550. // Source texture must be 1D, 2D or 3D
  551. // Supports compressed formats as both source and destination format, it will use the hardware DXT compressor
  552. // if available.
  553. // @author W.J. van der Laan
  554. void GL3PlusTextureBuffer::blitFromTexture(GL3PlusTextureBuffer *src, const Image::Box &srcBox, const Image::Box &dstBox)
  555. {
  556. //std::cerr << "GL3PlusTextureBuffer::blitFromTexture " <<
  557. //src->mTextureID << ":" << srcBox.left << "," << srcBox.top << "," << srcBox.right << "," << srcBox.bottom << " " <<
  558. //mTextureID << ":" << dstBox.left << "," << dstBox.top << "," << dstBox.right << "," << dstBox.bottom << std::endl;
  559. /// Store reference to FBO manager
  560. GL3PlusFBOManager *fboMan = static_cast<GL3PlusFBOManager *>(GL3PlusRTTManager::getSingletonPtr());
  561. RenderSystem* rsys = Root::getSingleton().getRenderSystem();
  562. rsys->_disableTextureUnitsFrom(0);
  563. glActiveTexture(GL_TEXTURE0);
  564. GL_CHECK_ERROR
  565. /// Disable alpha, depth and scissor testing, disable blending,
  566. /// disable culling, disble lighting, disable fog and reset foreground
  567. /// colour.
  568. glDisable(GL_DEPTH_TEST);
  569. glDisable(GL_SCISSOR_TEST);
  570. glDisable(GL_BLEND);
  571. glDisable(GL_CULL_FACE);
  572. GL_CHECK_ERROR
  573. // Set up source texture
  574. glBindTexture(src->mTarget, src->mTextureID);
  575. GL_CHECK_ERROR
  576. // Set filtering modes depending on the dimensions and source
  577. if(srcBox.getWidth()==dstBox.getWidth() &&
  578. srcBox.getHeight()==dstBox.getHeight() &&
  579. srcBox.getDepth()==dstBox.getDepth())
  580. {
  581. // Dimensions match -- use nearest filtering (fastest and pixel correct)
  582. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  583. GL_CHECK_ERROR
  584. glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  585. GL_CHECK_ERROR
  586. }
  587. else
  588. {
  589. // Dimensions don't match -- use bi or trilinear filtering depending on the
  590. // source texture.
  591. if(src->mUsage & TU_AUTOMIPMAP)
  592. {
  593. // Automatic mipmaps, we can safely use trilinear filter which
  594. // brings greatly improved quality for minimisation.
  595. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  596. GL_CHECK_ERROR
  597. glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  598. GL_CHECK_ERROR
  599. }
  600. else
  601. {
  602. // Manual mipmaps, stay safe with bilinear filtering so that no
  603. // intermipmap leakage occurs.
  604. glTexParameteri(src->mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  605. GL_CHECK_ERROR
  606. glTexParameteri(src->mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  607. GL_CHECK_ERROR
  608. }
  609. }
  610. // Clamp to edge (fastest)
  611. glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  612. GL_CHECK_ERROR
  613. glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  614. GL_CHECK_ERROR
  615. glTexParameteri(src->mTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  616. GL_CHECK_ERROR
  617. // Set origin base level mipmap to make sure we source from the right mip
  618. // level.
  619. glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, src->mLevel);
  620. GL_CHECK_ERROR
  621. // Store old binding so it can be restored later
  622. GLint oldfb;
  623. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfb);
  624. GL_CHECK_ERROR
  625. // Set up temporary FBO
  626. glBindFramebuffer(GL_FRAMEBUFFER, fboMan->getTemporaryFBO());
  627. GL_CHECK_ERROR
  628. GLuint tempTex = 0;
  629. if(!fboMan->checkFormat(mFormat))
  630. {
  631. // If target format not directly supported, create intermediate texture
  632. GLenum tempFormat = GL3PlusPixelUtil::getClosestGLInternalFormat(fboMan->getSupportedAlternative(mFormat));
  633. glGenTextures(1, &tempTex);
  634. GL_CHECK_ERROR
  635. glBindTexture(GL_TEXTURE_2D, tempTex);
  636. GL_CHECK_ERROR
  637. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  638. GL_CHECK_ERROR
  639. // Allocate temporary texture of the size of the destination area
  640. glTexImage2D(GL_TEXTURE_2D, 0, tempFormat,
  641. GL3PlusPixelUtil::optionalPO2(dstBox.getWidth()), GL3PlusPixelUtil::optionalPO2(dstBox.getHeight()),
  642. 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  643. GL_CHECK_ERROR
  644. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
  645. GL_TEXTURE_2D, tempTex, 0);
  646. GL_CHECK_ERROR
  647. // Set viewport to size of destination slice
  648. glViewport(0, 0, dstBox.getWidth(), dstBox.getHeight());
  649. GL_CHECK_ERROR
  650. }
  651. else
  652. {
  653. // We are going to bind directly, so set viewport to size and position of destination slice
  654. glViewport(dstBox.left, dstBox.top, dstBox.getWidth(), dstBox.getHeight());
  655. GL_CHECK_ERROR
  656. }
  657. // Process each destination slice
  658. for(size_t slice=dstBox.front; slice<dstBox.back; ++slice)
  659. {
  660. if(!tempTex)
  661. {
  662. // Bind directly
  663. bindToFramebuffer(GL_COLOR_ATTACHMENT0, slice);
  664. }
  665. /// Calculate source texture coordinates
  666. float u1 = (float)srcBox.left / (float)src->mWidth;
  667. float v1 = (float)srcBox.top / (float)src->mHeight;
  668. float u2 = (float)srcBox.right / (float)src->mWidth;
  669. float v2 = (float)srcBox.bottom / (float)src->mHeight;
  670. /// Calculate source slice for this destination slice
  671. float w = (float)(slice - dstBox.front) / (float)dstBox.getDepth();
  672. /// Get slice # in source
  673. w = w * (float)srcBox.getDepth() + srcBox.front;
  674. /// Normalise to texture coordinate in 0.0 .. 1.0
  675. w = (w+0.5f) / (float)src->mDepth;
  676. /// Finally we're ready to rumble
  677. glBindTexture(src->mTarget, src->mTextureID);
  678. GL_CHECK_ERROR
  679. glEnable(src->mTarget);
  680. GL_CHECK_ERROR
  681. GLfloat squareVertices[] = {
  682. -1.0f, -1.0f,
  683. 1.0f, -1.0f,
  684. -1.0f, 1.0f,
  685. 1.0f, 1.0f,
  686. };
  687. GLfloat texCoords[] = {
  688. u1, v1, w,
  689. u2, v1, w,
  690. u2, v2, w,
  691. u1, v2, w
  692. };
  693. GLSLLinkProgram* linkProgram = GLSLLinkProgramManager::getSingleton().getActiveLinkProgram();
  694. // Draw the textured quad
  695. glVertexAttribPointer(linkProgram->getAttributeIndex(VES_POSITION, 0),
  696. 2,
  697. GL_FLOAT,
  698. 0,
  699. 0,
  700. squareVertices);
  701. GL_CHECK_ERROR
  702. glEnableVertexAttribArray(linkProgram->getAttributeIndex(VES_POSITION, 0));
  703. GL_CHECK_ERROR
  704. glVertexAttribPointer(linkProgram->getAttributeIndex(VES_TEXTURE_COORDINATES, 0),
  705. 3,
  706. GL_FLOAT,
  707. 0,
  708. 0,
  709. texCoords);
  710. GL_CHECK_ERROR
  711. glEnableVertexAttribArray(linkProgram->getAttributeIndex(VES_TEXTURE_COORDINATES, 0));
  712. GL_CHECK_ERROR
  713. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  714. GL_CHECK_ERROR
  715. glDisable(src->mTarget);
  716. GL_CHECK_ERROR
  717. if(tempTex)
  718. {
  719. // Copy temporary texture
  720. glBindTexture(mTarget, mTextureID);
  721. GL_CHECK_ERROR
  722. switch(mTarget)
  723. {
  724. case GL_TEXTURE_1D:
  725. glCopyTexSubImage1D(mFaceTarget, mLevel,
  726. dstBox.left,
  727. 0, 0, dstBox.getWidth());
  728. break;
  729. case GL_TEXTURE_2D:
  730. case GL_TEXTURE_CUBE_MAP:
  731. case GL_TEXTURE_RECTANGLE:
  732. glCopyTexSubImage2D(mFaceTarget, mLevel,
  733. dstBox.left, dstBox.top,
  734. 0, 0, dstBox.getWidth(), dstBox.getHeight());
  735. break;
  736. case GL_TEXTURE_3D:
  737. case GL_TEXTURE_2D_ARRAY:
  738. glCopyTexSubImage3D(mFaceTarget, mLevel,
  739. dstBox.left, dstBox.top, slice,
  740. 0, 0, dstBox.getWidth(), dstBox.getHeight());
  741. break;
  742. }
  743. GL_CHECK_ERROR
  744. }
  745. }
  746. // Finish up
  747. if(!tempTex)
  748. {
  749. // Generate mipmaps
  750. if(mUsage & TU_AUTOMIPMAP)
  751. {
  752. glBindTexture(mTarget, mTextureID);
  753. GL_CHECK_ERROR
  754. glGenerateMipmap(mTarget);
  755. GL_CHECK_ERROR
  756. }
  757. }
  758. // Reset source texture to sane state
  759. glBindTexture(src->mTarget, src->mTextureID);
  760. GL_CHECK_ERROR
  761. glTexParameteri(src->mTarget, GL_TEXTURE_BASE_LEVEL, 0);
  762. GL_CHECK_ERROR
  763. // Detach texture from temporary framebuffer
  764. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
  765. GL_RENDERBUFFER, 0);
  766. GL_CHECK_ERROR
  767. // Restore old framebuffer
  768. glBindFramebuffer(GL_FRAMEBUFFER, oldfb);
  769. GL_CHECK_ERROR
  770. glDeleteTextures(1, &tempTex);
  771. GL_CHECK_ERROR
  772. }
  773. //-----------------------------------------------------------------------------
  774. // blitFromMemory doing hardware trilinear scaling
  775. void GL3PlusTextureBuffer::blitFromMemory(const PixelBox &src_orig, const Image::Box &dstBox)
  776. {
  777. // Fall back to normal GLHardwarePixelBuffer::blitFromMemory in case
  778. // - FBO is not supported
  779. // - Either source or target is luminance due doesn't looks like supported by hardware
  780. // - the source dimensions match the destination ones, in which case no scaling is needed
  781. // TODO: Check that extension is NOT available
  782. if(PixelUtil::isLuminance(src_orig.format) ||
  783. PixelUtil::isLuminance(mFormat) ||
  784. (src_orig.getWidth() == dstBox.getWidth() &&
  785. src_orig.getHeight() == dstBox.getHeight() &&
  786. src_orig.getDepth() == dstBox.getDepth()))
  787. {
  788. GL3PlusHardwarePixelBuffer::blitFromMemory(src_orig, dstBox);
  789. return;
  790. }
  791. if(!mBuffer.contains(dstBox))
  792. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range",
  793. "GL3PlusTextureBuffer::blitFromMemory");
  794. // For scoped deletion of conversion buffer
  795. MemoryDataStreamPtr buf;
  796. PixelBox src;
  797. // First, convert the srcbox to a OpenGL compatible pixel format
  798. if(GL3PlusPixelUtil::getGLOriginFormat(src_orig.format) == 0)
  799. {
  800. // Convert to buffer internal format
  801. buf.bind(OGRE_NEW MemoryDataStream(PixelUtil::getMemorySize(src_orig.getWidth(), src_orig.getHeight(),
  802. src_orig.getDepth(), mFormat)));
  803. src = PixelBox(src_orig.getWidth(), src_orig.getHeight(), src_orig.getDepth(), mFormat, buf->getPtr());
  804. PixelUtil::bulkPixelConversion(src_orig, src);
  805. }
  806. else
  807. {
  808. // No conversion needed
  809. src = src_orig;
  810. }
  811. // Create temporary texture to store source data
  812. GLuint id;
  813. GLenum target = (src.getDepth()!=1)?GL_TEXTURE_3D:GL_TEXTURE_2D;
  814. GLsizei width = GL3PlusPixelUtil::optionalPO2(src.getWidth());
  815. GLsizei height = GL3PlusPixelUtil::optionalPO2(src.getHeight());
  816. GLsizei depth = GL3PlusPixelUtil::optionalPO2(src.getDepth());
  817. GLenum format = GL3PlusPixelUtil::getClosestGLInternalFormat(src.format);
  818. // Generate texture name
  819. glGenTextures(1, &id);
  820. // Set texture type
  821. glBindTexture(target, id);
  822. glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 1000 );
  823. // glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE );
  824. /// Allocate texture memory
  825. if(target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY)
  826. glTexImage3D(target, 0, format, width, height, depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  827. else
  828. glTexImage2D(target, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  829. /// GL texture buffer
  830. GL3PlusTextureBuffer tex(StringUtil::BLANK, target, id, 0, 0, (Usage)(TU_AUTOMIPMAP|HBU_STATIC_WRITE_ONLY), false, false, 0);
  831. /// Upload data to 0,0,0 in temporary texture
  832. Image::Box tempTarget(0, 0, 0, src.getWidth(), src.getHeight(), src.getDepth());
  833. tex.upload(src, tempTarget);
  834. // Blit
  835. blitFromTexture(&tex, tempTarget, dstBox);
  836. // Delete temp texture
  837. glDeleteTextures(1, &id);
  838. }
  839. RenderTexture *GL3PlusTextureBuffer::getRenderTarget(size_t zoffset)
  840. {
  841. assert(mUsage & TU_RENDERTARGET);
  842. assert(zoffset < mDepth);
  843. return mSliceTRT[zoffset];
  844. }
  845. void GL3PlusTextureBuffer::buildMipmaps(const PixelBox &data)
  846. {
  847. PixelBox scaled = data;
  848. scaled.data = data.data;
  849. scaled.left = data.left;
  850. scaled.right = data.right;
  851. scaled.top = data.top;
  852. scaled.bottom = data.bottom;
  853. scaled.front = data.front;
  854. scaled.back = data.back;
  855. GLenum glFormat = GL3PlusPixelUtil::getGLOriginFormat(data.format);
  856. GLenum dataType = GL3PlusPixelUtil::getGLOriginDataType(data.format);
  857. int width = data.getWidth();
  858. int height = data.getHeight();
  859. int depth = data.getDepth();
  860. int logW = computeLog(width);
  861. int logH = computeLog(height);
  862. int level = (logW > logH ? logW : logH);
  863. for (int mip = 0; mip <= level; mip++)
  864. {
  865. glFormat = GL3PlusPixelUtil::getGLOriginFormat(scaled.format);
  866. dataType = GL3PlusPixelUtil::getGLOriginDataType(scaled.format);
  867. switch(mTarget)
  868. {
  869. case GL_TEXTURE_1D:
  870. glTexImage1D(mFaceTarget,
  871. mip,
  872. glFormat,
  873. width,
  874. 0,
  875. GL_RGBA,
  876. dataType,
  877. scaled.data);
  878. GL_CHECK_ERROR
  879. break;
  880. case GL_TEXTURE_2D:
  881. case GL_TEXTURE_CUBE_MAP:
  882. case GL_TEXTURE_RECTANGLE:
  883. glTexImage2D(mFaceTarget,
  884. mip,
  885. glFormat,
  886. width, height,
  887. 0,
  888. GL_RGBA,
  889. dataType,
  890. scaled.data);
  891. GL_CHECK_ERROR
  892. break;
  893. case GL_TEXTURE_3D:
  894. case GL_TEXTURE_2D_ARRAY:
  895. glTexImage3D(mFaceTarget,
  896. mip,
  897. glFormat,
  898. width, height, depth,
  899. 0,
  900. GL_RGBA,
  901. dataType,
  902. scaled.data);
  903. GL_CHECK_ERROR
  904. break;
  905. }
  906. if (mip != 0)
  907. {
  908. delete[] (uint8*) scaled.data;
  909. scaled.data = 0;
  910. }
  911. if (width > 1)
  912. {
  913. width = width / 2;
  914. }
  915. if (height > 1)
  916. {
  917. height = height / 2;
  918. }
  919. int sizeInBytes = PixelUtil::getMemorySize(width, height, 1,
  920. data.format);
  921. scaled = PixelBox(width, height, 1, data.format);
  922. scaled.data = new uint8[sizeInBytes];
  923. Image::scale(data, scaled, Image::FILTER_LINEAR);
  924. }
  925. }
  926. //********* GL3PlusRenderBuffer
  927. //-----------------------------------------------------------------------------
  928. GL3PlusRenderBuffer::GL3PlusRenderBuffer(GLenum format, size_t width, size_t height, GLsizei numSamples):
  929. GL3PlusHardwarePixelBuffer(width, height, 1, GL3PlusPixelUtil::getClosestOGREFormat(format), HBU_WRITE_ONLY),
  930. mRenderbufferID(0)
  931. {
  932. mGLInternalFormat = format;
  933. // Generate renderbuffer
  934. glGenRenderbuffers(1, &mRenderbufferID);
  935. GL_CHECK_ERROR
  936. // Bind it to FBO
  937. glBindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
  938. GL_CHECK_ERROR
  939. // Allocate storage for depth buffer
  940. if (numSamples > 0)
  941. {
  942. glRenderbufferStorageMultisample(GL_RENDERBUFFER,
  943. numSamples, format, width, height);
  944. }
  945. else
  946. {
  947. glRenderbufferStorage(GL_RENDERBUFFER, format,
  948. width, height);
  949. }
  950. GL_CHECK_ERROR
  951. }
  952. //-----------------------------------------------------------------------------
  953. GL3PlusRenderBuffer::~GL3PlusRenderBuffer()
  954. {
  955. // Generate renderbuffer
  956. glDeleteRenderbuffers(1, &mRenderbufferID);
  957. GL_CHECK_ERROR
  958. }
  959. //-----------------------------------------------------------------------------
  960. void GL3PlusRenderBuffer::bindToFramebuffer(GLenum attachment, size_t zoffset)
  961. {
  962. assert(zoffset < mDepth);
  963. glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
  964. GL_RENDERBUFFER, mRenderbufferID);
  965. GL_CHECK_ERROR
  966. }
  967. };