BsGLPixelBuffer.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsGLPixelBuffer.h"
  4. #include "BsGLTexture.h"
  5. #include "BsGLSupport.h"
  6. #include "BsGLPixelFormat.h"
  7. #include "BsException.h"
  8. #include "BsBitwise.h"
  9. #include "BsGLRenderTexture.h"
  10. #include "BsRenderStats.h"
  11. namespace BansheeEngine
  12. {
  13. GLPixelBuffer::GLPixelBuffer(UINT32 inWidth, UINT32 inHeight, UINT32 inDepth,
  14. PixelFormat inFormat, GpuBufferUsage usage)
  15. : PixelBuffer(inWidth, inHeight, inDepth, inFormat, usage, false),
  16. mBuffer(inWidth, inHeight, inDepth, inFormat),
  17. mGLInternalFormat(GL_NONE)
  18. {
  19. mCurrentLockOptions = (GpuLockOptions)0;
  20. }
  21. GLPixelBuffer::~GLPixelBuffer()
  22. {
  23. mBuffer.freeInternalBuffer();
  24. }
  25. void GLPixelBuffer::allocateBuffer()
  26. {
  27. if(mBuffer.getData())
  28. return;
  29. mBuffer.allocateInternalBuffer();
  30. // TODO: use PBO if we're HBU_DYNAMIC
  31. }
  32. void GLPixelBuffer::freeBuffer()
  33. {
  34. if(mUsage & GBU_STATIC)
  35. {
  36. mBuffer.freeInternalBuffer();
  37. }
  38. }
  39. PixelData GLPixelBuffer::lockImpl(PixelVolume lockBox, GpuLockOptions options)
  40. {
  41. allocateBuffer();
  42. if(options != GBL_WRITE_ONLY_DISCARD)
  43. {
  44. // Download the old contents of the texture
  45. download(mBuffer);
  46. }
  47. mCurrentLockOptions = options;
  48. mLockedBox = lockBox;
  49. return mBuffer.getSubVolume(lockBox);
  50. }
  51. void GLPixelBuffer::unlockImpl(void)
  52. {
  53. if (mCurrentLockOptions != GBL_READ_ONLY)
  54. {
  55. // From buffer to card, only upload if was locked for writing
  56. upload(mCurrentLock, mLockedBox);
  57. }
  58. freeBuffer();
  59. }
  60. void GLPixelBuffer::upload(const PixelData& data, const PixelVolume& dest)
  61. {
  62. BS_EXCEPT(RenderingAPIException, "Upload not possible for this pixel buffer type");
  63. }
  64. void GLPixelBuffer::download(const PixelData& data)
  65. {
  66. BS_EXCEPT(RenderingAPIException, "Download not possible for this pixel buffer type");
  67. }
  68. void GLPixelBuffer::blitFromTexture(GLTextureBuffer* src)
  69. {
  70. blitFromTexture(src,
  71. PixelVolume(0, 0, 0, src->getWidth(), src->getHeight(), src->getDepth()),
  72. PixelVolume(0, 0, 0, mWidth, mHeight, mDepth)
  73. );
  74. }
  75. void GLPixelBuffer::blitFromTexture(GLTextureBuffer* src, const PixelVolume& srcBox, const PixelVolume& dstBox)
  76. {
  77. BS_EXCEPT(RenderingAPIException, "BlitFromTexture not possible for this pixel buffer type");
  78. }
  79. void GLPixelBuffer::bindToFramebuffer(GLenum attachment, UINT32 zoffset)
  80. {
  81. BS_EXCEPT(RenderingAPIException, "Framebuffer bind not possible for this pixel buffer type");
  82. }
  83. GLTextureBuffer::GLTextureBuffer(GLenum target, GLuint id,
  84. GLint face, GLint level, GpuBufferUsage usage,
  85. bool writeGamma, UINT32 multisampleCount):
  86. GLPixelBuffer(0, 0, 0, PF_UNKNOWN, usage),
  87. mTarget(target), mFaceTarget(0), mTextureID(id), mFace(face), mLevel(level), mMultisampleCount(multisampleCount)
  88. {
  89. GLint value = 0;
  90. glBindTexture(mTarget, mTextureID);
  91. // Get face identifier
  92. mFaceTarget = mTarget;
  93. if(mTarget == GL_TEXTURE_CUBE_MAP)
  94. mFaceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
  95. // Get width
  96. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_WIDTH, &value);
  97. mWidth = value;
  98. // Get height
  99. if(target == GL_TEXTURE_1D)
  100. value = 1; // Height always 1 for 1D textures
  101. else
  102. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_HEIGHT, &value);
  103. mHeight = value;
  104. // Get depth
  105. if(target != GL_TEXTURE_3D)
  106. value = 1; // Depth always 1 for non-3D textures
  107. else
  108. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_DEPTH, &value);
  109. mDepth = value;
  110. // Get format
  111. glGetTexLevelParameteriv(mFaceTarget, level, GL_TEXTURE_INTERNAL_FORMAT, &value);
  112. mGLInternalFormat = value;
  113. mFormat = GLPixelUtil::getClosestEngineFormat(value);
  114. // Default
  115. mRowPitch = mWidth;
  116. mSlicePitch = mHeight*mWidth;
  117. mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
  118. // Set up pixel box
  119. mBuffer = PixelData(mWidth, mHeight, mDepth, mFormat);
  120. }
  121. GLTextureBuffer::~GLTextureBuffer()
  122. { }
  123. void GLTextureBuffer::upload(const PixelData &data, const PixelVolume &dest)
  124. {
  125. if((mUsage & TU_RENDERTARGET) != 0)
  126. BS_EXCEPT(NotImplementedException, "Writing to render texture from CPU not supported.");
  127. if ((mUsage & TU_DEPTHSTENCIL) != 0)
  128. BS_EXCEPT(NotImplementedException, "Writing to depth stencil texture from CPU not supported.");
  129. glBindTexture( mTarget, mTextureID );
  130. if(PixelUtil::isCompressed(data.getFormat()))
  131. {
  132. if(data.getFormat() != mFormat || !data.isConsecutive())
  133. BS_EXCEPT(InvalidParametersException,
  134. "Compressed images must be consecutive, in the source format");
  135. GLenum format = GLPixelUtil::getClosestGLInternalFormat(mFormat);
  136. switch(mTarget) {
  137. case GL_TEXTURE_1D:
  138. if (dest.left == 0)
  139. {
  140. glCompressedTexImage1D(GL_TEXTURE_1D, mLevel,
  141. format,
  142. dest.getWidth(),
  143. 0,
  144. data.getConsecutiveSize(),
  145. data.getData());
  146. }
  147. else
  148. {
  149. glCompressedTexSubImage1D(GL_TEXTURE_1D, mLevel,
  150. dest.left,
  151. dest.getWidth(),
  152. format, data.getConsecutiveSize(),
  153. data.getData());
  154. }
  155. break;
  156. case GL_TEXTURE_2D:
  157. case GL_TEXTURE_CUBE_MAP:
  158. if (dest.left == 0 && dest.top == 0)
  159. {
  160. glCompressedTexImage2D(mFaceTarget, mLevel,
  161. format,
  162. dest.getWidth(),
  163. dest.getHeight(),
  164. 0,
  165. data.getConsecutiveSize(),
  166. data.getData());
  167. }
  168. else
  169. {
  170. glCompressedTexSubImage2D(mFaceTarget, mLevel,
  171. dest.left, dest.top,
  172. dest.getWidth(), dest.getHeight(),
  173. format, data.getConsecutiveSize(),
  174. data.getData());
  175. }
  176. break;
  177. case GL_TEXTURE_3D:
  178. if (dest.left == 0 && dest.top == 0 && dest.front == 0)
  179. {
  180. glCompressedTexImage3D(GL_TEXTURE_3D, mLevel,
  181. format,
  182. dest.getWidth(),
  183. dest.getHeight(),
  184. dest.getDepth(),
  185. 0,
  186. data.getConsecutiveSize(),
  187. data.getData());
  188. }
  189. else
  190. {
  191. glCompressedTexSubImage3D(GL_TEXTURE_3D, mLevel,
  192. dest.left, dest.top, dest.front,
  193. dest.getWidth(), dest.getHeight(), dest.getDepth(),
  194. format, data.getConsecutiveSize(),
  195. data.getData());
  196. }
  197. break;
  198. }
  199. }
  200. else
  201. {
  202. if(data.getWidth() != data.getRowPitch())
  203. glPixelStorei(GL_UNPACK_ROW_LENGTH, data.getRowPitch());
  204. if(data.getHeight()*data.getWidth() != data.getSlicePitch())
  205. glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (data.getSlicePitch()/data.getWidth()));
  206. if(data.getLeft() > 0 || data.getTop() > 0 || data.getFront() > 0)
  207. glPixelStorei(GL_UNPACK_SKIP_PIXELS, data.getLeft() + data.getRowPitch() * data.getTop() + data.getSlicePitch() * data.getFront());
  208. if((data.getWidth()*PixelUtil::getNumElemBytes(data.getFormat())) & 3)
  209. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  210. switch(mTarget) {
  211. case GL_TEXTURE_1D:
  212. glTexSubImage1D(GL_TEXTURE_1D, mLevel,
  213. dest.left,
  214. dest.getWidth(),
  215. GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()),
  216. data.getData());
  217. break;
  218. case GL_TEXTURE_2D:
  219. case GL_TEXTURE_CUBE_MAP:
  220. glTexSubImage2D(mFaceTarget, mLevel,
  221. dest.left, dest.top,
  222. dest.getWidth(), dest.getHeight(),
  223. GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()),
  224. data.getData());
  225. break;
  226. case GL_TEXTURE_3D:
  227. glTexSubImage3D(
  228. GL_TEXTURE_3D, mLevel,
  229. dest.left, dest.top, dest.front,
  230. dest.getWidth(), dest.getHeight(), dest.getDepth(),
  231. GLPixelUtil::getGLOriginFormat(data.getFormat()), GLPixelUtil::getGLOriginDataType(data.getFormat()),
  232. data.getData());
  233. break;
  234. }
  235. }
  236. // Restore defaults
  237. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  238. glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
  239. glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
  240. glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  241. BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
  242. }
  243. void GLTextureBuffer::download(const PixelData &data)
  244. {
  245. if(data.getWidth() != getWidth() || data.getHeight() != getHeight() || data.getDepth() != getDepth())
  246. BS_EXCEPT(InvalidParametersException, "only download of entire buffer is supported by GL");
  247. glBindTexture( mTarget, mTextureID );
  248. if(PixelUtil::isCompressed(data.getFormat()))
  249. {
  250. if(data.getFormat() != mFormat || !data.isConsecutive())
  251. BS_EXCEPT(InvalidParametersException,
  252. "Compressed images must be consecutive, in the source format");
  253. // Data must be consecutive and at beginning of buffer as PixelStorei not allowed
  254. // for compressed formate
  255. glGetCompressedTexImage(mFaceTarget, mLevel, data.getData());
  256. }
  257. else
  258. {
  259. if(data.getWidth() != data.getRowPitch())
  260. glPixelStorei(GL_PACK_ROW_LENGTH, data.getRowPitch());
  261. if(data.getHeight()*data.getWidth() != data.getSlicePitch())
  262. glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.getSlicePitch()/data.getWidth()));
  263. if(data.getLeft() > 0 || data.getTop() > 0 || data.getFront() > 0)
  264. glPixelStorei(GL_PACK_SKIP_PIXELS, data.getLeft() + data.getRowPitch() * data.getTop() + data.getSlicePitch() * data.getFront());
  265. if((data.getWidth()*PixelUtil::getNumElemBytes(data.getFormat())) & 3)
  266. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  267. // We can only get the entire texture
  268. glGetTexImage(mFaceTarget, mLevel, GLPixelUtil::getGLOriginFormat(data.getFormat()),
  269. GLPixelUtil::getGLOriginDataType(data.getFormat()), data.getData());
  270. // Restore defaults
  271. glPixelStorei(GL_PACK_ROW_LENGTH, 0);
  272. glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
  273. glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
  274. glPixelStorei(GL_PACK_ALIGNMENT, 4);
  275. }
  276. BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
  277. }
  278. void GLTextureBuffer::bindToFramebuffer(GLenum attachment, UINT32 zoffset)
  279. {
  280. assert(zoffset < mDepth);
  281. switch(mTarget)
  282. {
  283. case GL_TEXTURE_1D:
  284. glFramebufferTexture1D(GL_FRAMEBUFFER, attachment,
  285. mFaceTarget, mTextureID, mLevel);
  286. break;
  287. case GL_TEXTURE_2D:
  288. case GL_TEXTURE_CUBE_MAP:
  289. glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
  290. mFaceTarget, mTextureID, mLevel);
  291. break;
  292. case GL_TEXTURE_2D_MULTISAMPLE:
  293. glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
  294. mFaceTarget, mTextureID, 0);
  295. break;
  296. case GL_TEXTURE_3D:
  297. glFramebufferTexture3D(GL_FRAMEBUFFER, attachment,
  298. mFaceTarget, mTextureID, mLevel, zoffset);
  299. break;
  300. }
  301. }
  302. void GLTextureBuffer::copyFromFramebuffer(UINT32 zoffset)
  303. {
  304. glBindTexture(mTarget, mTextureID);
  305. switch(mTarget)
  306. {
  307. case GL_TEXTURE_1D:
  308. glCopyTexSubImage1D(mFaceTarget, mLevel, 0, 0, 0, mWidth);
  309. break;
  310. case GL_TEXTURE_2D:
  311. case GL_TEXTURE_CUBE_MAP:
  312. glCopyTexSubImage2D(mFaceTarget, mLevel, 0, 0, 0, 0, mWidth, mHeight);
  313. break;
  314. case GL_TEXTURE_3D:
  315. glCopyTexSubImage3D(mFaceTarget, mLevel, 0, 0, zoffset, 0, 0, mWidth, mHeight);
  316. break;
  317. }
  318. }
  319. void GLTextureBuffer::blitFromTexture(GLTextureBuffer* src, const PixelVolume& srcBox, const PixelVolume& dstBox)
  320. {
  321. if (src->mMultisampleCount > 0 && mMultisampleCount == 0) // Resolving MS texture
  322. {
  323. if (mTarget != GL_TEXTURE_2D || mTarget != GL_TEXTURE_2D_MULTISAMPLE)
  324. BS_EXCEPT(InvalidParametersException, "Non-2D multisampled texture not supported.");
  325. GLint currentFBO = 0;
  326. glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFBO);
  327. GLuint readFBO = GLRTTManager::instance().getBlitReadFBO();
  328. GLuint drawFBO = GLRTTManager::instance().getBlitDrawFBO();
  329. // Attach source texture
  330. glBindFramebuffer(GL_FRAMEBUFFER, readFBO);
  331. src->bindToFramebuffer(0, 0);
  332. // Attach destination texture
  333. glBindFramebuffer(GL_FRAMEBUFFER, drawFBO);
  334. bindToFramebuffer(0, 0);
  335. // Perform blit
  336. glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
  337. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
  338. glReadBuffer(GL_COLOR_ATTACHMENT0);
  339. glDrawBuffer(GL_COLOR_ATTACHMENT0);
  340. glBlitFramebuffer(srcBox.left, srcBox.top, srcBox.right, srcBox.bottom,
  341. dstBox.left, dstBox.top, dstBox.right, dstBox.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  342. // Restore the previously bound FBO
  343. glBindFramebuffer(GL_FRAMEBUFFER, currentFBO);
  344. }
  345. else // Just plain copy
  346. {
  347. if (mMultisampleCount != src->mMultisampleCount)
  348. BS_EXCEPT(InvalidParametersException, "When copying textures their multisample counts must match.");
  349. if (mTarget == GL_TEXTURE_3D) // 3D textures can't have arrays so their Z coordinate is handled differently
  350. {
  351. glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, srcBox.front,
  352. mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, dstBox.front, srcBox.getWidth(), srcBox.getHeight(), srcBox.getDepth());
  353. }
  354. else
  355. {
  356. glCopyImageSubData(src->mTextureID, src->mTarget, src->mLevel, srcBox.left, srcBox.top, src->mFace,
  357. mTextureID, mTarget, mLevel, dstBox.left, dstBox.top, mFace, srcBox.getWidth(), srcBox.getHeight(), 1);
  358. }
  359. }
  360. }
  361. GLRenderBuffer::GLRenderBuffer(GLenum format, UINT32 width, UINT32 height, GLsizei numSamples):
  362. GLPixelBuffer(width, height, 1, GLPixelUtil::getClosestEngineFormat(format), GBU_DYNAMIC),
  363. mRenderbufferID(0)
  364. {
  365. mGLInternalFormat = format;
  366. glGenRenderbuffers(1, &mRenderbufferID);
  367. glBindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
  368. /// Allocate storage for depth buffer
  369. if (numSamples > 0)
  370. {
  371. glRenderbufferStorageMultisample(GL_RENDERBUFFER,
  372. numSamples, format, width, height);
  373. }
  374. else
  375. {
  376. glRenderbufferStorage(GL_RENDERBUFFER, format,
  377. width, height);
  378. }
  379. }
  380. GLRenderBuffer::~GLRenderBuffer()
  381. {
  382. glDeleteRenderbuffers(1, &mRenderbufferID);
  383. }
  384. void GLRenderBuffer::bindToFramebuffer(GLenum attachment, UINT32 zoffset)
  385. {
  386. assert(zoffset < mDepth);
  387. glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
  388. GL_RENDERBUFFER, mRenderbufferID);
  389. }
  390. };