CmGLHardwarePixelBuffer.cpp 33 KB

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