BsGLPixelBuffer.cpp 13 KB

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