BsGLTexture.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsGLTexture.h"
  4. #include "BsGLSupport.h"
  5. #include "BsGLPixelFormat.h"
  6. #include "BsGLPixelBuffer.h"
  7. #include "Error/BsException.h"
  8. #include "Utility/BsBitwise.h"
  9. #include "CoreThread/BsCoreThread.h"
  10. #include "Managers/BsTextureManager.h"
  11. #include "BsGLRenderTexture.h"
  12. #include "BsGLTextureView.h"
  13. #include "Profiling/BsRenderStats.h"
  14. #include "BsGLCommandBuffer.h"
  15. namespace bs { namespace ct
  16. {
  17. GLTexture::GLTexture(GLSupport& support, const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData,
  18. GpuDeviceFlags deviceMask)
  19. : Texture(desc, initialData, deviceMask),
  20. mTextureID(0), mGLFormat(0), mInternalFormat(PF_UNKNOWN), mGLSupport(support)
  21. {
  22. assert((deviceMask == GDF_DEFAULT || deviceMask == GDF_PRIMARY) && "Multiple GPUs not supported natively on OpenGL.");
  23. }
  24. GLTexture::~GLTexture()
  25. {
  26. mSurfaceList.clear();
  27. glDeleteTextures(1, &mTextureID);
  28. BS_CHECK_GL_ERROR();
  29. clearBufferViews();
  30. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
  31. }
  32. void GLTexture::initialize()
  33. {
  34. UINT32 width = mProperties.getWidth();
  35. UINT32 height = mProperties.getHeight();
  36. UINT32 depth = mProperties.getDepth();
  37. TextureType texType = mProperties.getTextureType();
  38. int usage = mProperties.getUsage();
  39. UINT32 numMips = mProperties.getNumMipmaps();
  40. UINT32 numFaces = mProperties.getNumFaces();
  41. PixelFormat pixFormat = mProperties.getFormat();
  42. mInternalFormat = GLPixelUtil::getClosestSupportedPF(pixFormat, texType, usage);
  43. if (pixFormat != mInternalFormat)
  44. {
  45. LOGWRN(StringUtil::format("Provided pixel format is not supported by the driver: {0}. Falling back on: {1}.",
  46. pixFormat, mInternalFormat));
  47. }
  48. // Check requested number of mipmaps
  49. UINT32 maxMips = PixelUtil::getMaxMipmaps(width, height, depth, mProperties.getFormat());
  50. if (numMips > maxMips)
  51. {
  52. LOGERR("Invalid number of mipmaps. Maximum allowed is: " + toString(maxMips));
  53. numMips = maxMips;
  54. }
  55. if ((usage & TU_DEPTHSTENCIL) != 0)
  56. {
  57. if (texType != TEX_TYPE_2D && texType != TEX_TYPE_CUBE_MAP)
  58. {
  59. LOGERR("Only 2D and cubemap depth stencil textures are supported. Ignoring depth-stencil flag.");
  60. usage &= ~TU_DEPTHSTENCIL;
  61. }
  62. }
  63. // Include the base mip level
  64. numMips += 1;
  65. // Generate texture handle
  66. glGenTextures(1, &mTextureID);
  67. BS_CHECK_GL_ERROR();
  68. // Set texture type
  69. glBindTexture(getGLTextureTarget(), mTextureID);
  70. BS_CHECK_GL_ERROR();
  71. // This needs to be set otherwise the texture doesn't get rendered
  72. glTexParameteri(getGLTextureTarget(), GL_TEXTURE_MAX_LEVEL, numMips - 1);
  73. BS_CHECK_GL_ERROR();
  74. // Allocate internal buffer so that glTexSubImageXD can be used
  75. mGLFormat = GLPixelUtil::getGLInternalFormat(mInternalFormat, mProperties.isHardwareGammaEnabled());
  76. UINT32 sampleCount = mProperties.getNumSamples();
  77. if((usage & (TU_RENDERTARGET | TU_DEPTHSTENCIL)) != 0 && mProperties.getTextureType() == TEX_TYPE_2D && sampleCount > 1)
  78. {
  79. if (numFaces <= 1)
  80. {
  81. // Create immutable storage if available, fallback to mutable
  82. #if BS_OPENGL_4_3 || BS_OPENGLES_3_1
  83. glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, mGLFormat, width, height, GL_TRUE);
  84. BS_CHECK_GL_ERROR();
  85. #else
  86. glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCount, mGLFormat, width, height, GL_TRUE);
  87. BS_CHECK_GL_ERROR();
  88. #endif
  89. }
  90. else
  91. {
  92. // Create immutable storage if available, fallback to mutable
  93. #if BS_OPENGL_4_3 || BS_OPENGLES_3_2
  94. glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, sampleCount, mGLFormat, width, height, numFaces, GL_TRUE);
  95. BS_CHECK_GL_ERROR();
  96. #else
  97. glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, sampleCount, mGLFormat, width, height, numFaces, GL_TRUE);
  98. BS_CHECK_GL_ERROR();
  99. #endif
  100. }
  101. }
  102. else
  103. {
  104. // Create immutable storage if available, fallback to mutable
  105. #if BS_OPENGL_4_2 || BS_OPENGLES_3_1
  106. switch (texType)
  107. {
  108. case TEX_TYPE_1D:
  109. {
  110. if (numFaces <= 1)
  111. {
  112. glTexStorage1D(GL_TEXTURE_1D, numMips, mGLFormat, width);
  113. BS_CHECK_GL_ERROR();
  114. }
  115. else
  116. {
  117. glTexStorage2D(GL_TEXTURE_1D_ARRAY, numMips, mGLFormat, width, numFaces);
  118. BS_CHECK_GL_ERROR();
  119. }
  120. }
  121. break;
  122. case TEX_TYPE_2D:
  123. {
  124. if (numFaces <= 1)
  125. {
  126. glTexStorage2D(GL_TEXTURE_2D, numMips, mGLFormat, width, height);
  127. BS_CHECK_GL_ERROR();
  128. }
  129. else
  130. {
  131. glTexStorage3D(GL_TEXTURE_2D_ARRAY, numMips, mGLFormat, width, height, numFaces);
  132. BS_CHECK_GL_ERROR();
  133. }
  134. }
  135. break;
  136. case TEX_TYPE_3D:
  137. glTexStorage3D(GL_TEXTURE_3D, numMips, mGLFormat, width, height, depth);
  138. BS_CHECK_GL_ERROR();
  139. break;
  140. case TEX_TYPE_CUBE_MAP:
  141. {
  142. if (numFaces <= 6)
  143. {
  144. glTexStorage2D(GL_TEXTURE_CUBE_MAP, numMips, mGLFormat, width, height);
  145. BS_CHECK_GL_ERROR();
  146. }
  147. else
  148. {
  149. glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, numMips, mGLFormat, width, height, numFaces);
  150. BS_CHECK_GL_ERROR();
  151. }
  152. }
  153. break;
  154. }
  155. #else
  156. if((usage & TU_DEPTHSTENCIL) != 0 && mProperties.getTextureType() == TEX_TYPE_2D)
  157. {
  158. GLenum depthStencilType = GLPixelUtil::getDepthStencilTypeFromPF(mInternalFormat);
  159. GLenum depthStencilFormat = GLPixelUtil::getDepthStencilFormatFromPF(mInternalFormat);
  160. if (numFaces <= 1)
  161. {
  162. glTexImage2D(GL_TEXTURE_2D, 0, mGLFormat, width, height, 0,
  163. depthStencilFormat, depthStencilType, nullptr);
  164. }
  165. else
  166. {
  167. glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, mGLFormat, width, height, numFaces, 0,
  168. depthStencilFormat, depthStencilType, nullptr);
  169. }
  170. }
  171. else
  172. {
  173. GLenum baseFormat = GLPixelUtil::getGLOriginFormat(mInternalFormat);
  174. GLenum baseDataType = GLPixelUtil::getGLOriginDataType(mInternalFormat);
  175. for (UINT32 mip = 0; mip <= numMips; mip++)
  176. {
  177. switch (texType)
  178. {
  179. case TEX_TYPE_1D:
  180. {
  181. if (numFaces <= 1)
  182. glTexImage1D(GL_TEXTURE_1D, mip, mGLFormat, width, 0, baseFormat, baseDataType, nullptr);
  183. else
  184. glTexImage2D(GL_TEXTURE_1D_ARRAY, mip, mGLFormat, width, numFaces, 0, baseFormat, baseDataType, nullptr);
  185. }
  186. break;
  187. case TEX_TYPE_2D:
  188. {
  189. if (numFaces <= 1)
  190. glTexImage2D(GL_TEXTURE_2D, mip, mGLFormat, width, height, 0, baseFormat, baseDataType, nullptr);
  191. else
  192. glTexImage3D(GL_TEXTURE_2D_ARRAY, mip, mGLFormat, width, height, numFaces, 0, baseFormat, baseDataType, nullptr);
  193. }
  194. break;
  195. case TEX_TYPE_3D:
  196. glTexImage3D(GL_TEXTURE_3D, mip, mGLFormat, width, height,
  197. depth, 0, baseFormat, baseDataType, nullptr);
  198. break;
  199. case TEX_TYPE_CUBE_MAP:
  200. {
  201. if (numFaces <= 6)
  202. {
  203. for (UINT32 face = 0; face < 6; face++)
  204. {
  205. glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, mGLFormat,
  206. width, height, 0, baseFormat, baseDataType, nullptr);
  207. }
  208. }
  209. else
  210. {
  211. glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, mGLFormat,
  212. width, height, numFaces, 0, baseFormat, baseDataType, nullptr);
  213. }
  214. }
  215. break;
  216. }
  217. if(width > 1)
  218. width = width/2;
  219. if(height > 1)
  220. height = height/2;
  221. if(depth > 1)
  222. depth = depth/2;
  223. }
  224. }
  225. #endif
  226. }
  227. createSurfaceList();
  228. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
  229. Texture::initialize();
  230. }
  231. GLenum GLTexture::getGLTextureTarget() const
  232. {
  233. return getGLTextureTarget(mProperties.getTextureType(), mProperties.getNumSamples(), mProperties.getNumFaces());
  234. }
  235. GLuint GLTexture::getGLID() const
  236. {
  237. THROW_IF_NOT_CORE_THREAD;
  238. return mTextureID;
  239. }
  240. GLenum GLTexture::getGLTextureTarget(TextureType type, UINT32 numSamples, UINT32 numFaces)
  241. {
  242. switch (type)
  243. {
  244. case TEX_TYPE_1D:
  245. if (numFaces <= 1)
  246. return GL_TEXTURE_1D;
  247. else
  248. return GL_TEXTURE_1D_ARRAY;
  249. case TEX_TYPE_2D:
  250. if (numSamples > 1)
  251. {
  252. if (numFaces <= 1)
  253. return GL_TEXTURE_2D_MULTISAMPLE;
  254. else
  255. return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
  256. }
  257. else
  258. {
  259. if (numFaces <= 1)
  260. return GL_TEXTURE_2D;
  261. else
  262. return GL_TEXTURE_2D_ARRAY;
  263. }
  264. case TEX_TYPE_3D:
  265. return GL_TEXTURE_3D;
  266. case TEX_TYPE_CUBE_MAP:
  267. if (numFaces <= 6)
  268. return GL_TEXTURE_CUBE_MAP;
  269. else
  270. return GL_TEXTURE_CUBE_MAP_ARRAY;
  271. default:
  272. return 0;
  273. };
  274. }
  275. PixelData GLTexture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
  276. UINT32 queueIdx)
  277. {
  278. if (mProperties.getNumSamples() > 1)
  279. BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
  280. if(mLockedBuffer != nullptr)
  281. BS_EXCEPT(InternalErrorException, "Trying to lock a buffer that's already locked.");
  282. UINT32 mipWidth = std::max(1u, mProperties.getWidth() >> mipLevel);
  283. UINT32 mipHeight = std::max(1u, mProperties.getHeight() >> mipLevel);
  284. UINT32 mipDepth = std::max(1u, mProperties.getDepth() >> mipLevel);
  285. PixelData lockedArea(mipWidth, mipHeight, mipDepth, mProperties.getFormat());
  286. mLockedBuffer = getBuffer(face, mipLevel);
  287. lockedArea.setExternalBuffer((UINT8*)mLockedBuffer->lock(options));
  288. return lockedArea;
  289. }
  290. void GLTexture::unlockImpl()
  291. {
  292. if (mLockedBuffer == nullptr)
  293. {
  294. LOGERR("Trying to unlock a buffer that's not locked.");
  295. return;
  296. }
  297. mLockedBuffer->unlock();
  298. mLockedBuffer = nullptr;
  299. }
  300. void GLTexture::readDataImpl(PixelData& dest, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
  301. {
  302. if (mProperties.getNumSamples() > 1)
  303. {
  304. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  305. return;
  306. }
  307. if(dest.getFormat() != mInternalFormat)
  308. {
  309. PixelData temp(dest.getExtents(), mInternalFormat);
  310. temp.allocateInternalBuffer();
  311. getBuffer(face, mipLevel)->download(temp);
  312. PixelUtil::bulkPixelConversion(temp, dest);
  313. }
  314. else
  315. getBuffer(face, mipLevel)->download(dest);
  316. }
  317. void GLTexture::writeDataImpl(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer,
  318. UINT32 queueIdx)
  319. {
  320. if (mProperties.getNumSamples() > 1)
  321. {
  322. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  323. return;
  324. }
  325. if (src.getFormat() != mInternalFormat)
  326. {
  327. PixelData temp(src.getExtents(), mInternalFormat);
  328. temp.allocateInternalBuffer();
  329. PixelUtil::bulkPixelConversion(src, temp);
  330. getBuffer(face, mipLevel)->upload(temp, temp.getExtents());
  331. }
  332. else
  333. getBuffer(face, mipLevel)->upload(src, src.getExtents());
  334. }
  335. void GLTexture::copyImpl(const SPtr<Texture>& target, const TEXTURE_COPY_DESC& desc,
  336. const SPtr<CommandBuffer>& commandBuffer)
  337. {
  338. auto executeRef = [this](const SPtr<Texture>& target, const TEXTURE_COPY_DESC& desc)
  339. {
  340. GLTexture* destTex = static_cast<GLTexture*>(target.get());
  341. GLTextureBuffer* dest = static_cast<GLTextureBuffer*>(destTex->getBuffer(desc.dstFace, desc.dstMip).get());
  342. GLTextureBuffer* src = static_cast<GLTextureBuffer*>(getBuffer(desc.srcFace, desc.srcMip).get());
  343. bool copyEntireSurface = desc.srcVolume.getWidth() == 0 ||
  344. desc.srcVolume.getHeight() == 0 ||
  345. desc.srcVolume.getDepth() == 0;
  346. if(copyEntireSurface)
  347. dest->blitFromTexture(src);
  348. else
  349. {
  350. PixelVolume dstVolume;
  351. dstVolume.left = (UINT32)desc.dstPosition.x;
  352. dstVolume.top = (UINT32)desc.dstPosition.y;
  353. dstVolume.front = (UINT32)desc.dstPosition.z;
  354. dstVolume.right = dstVolume.left + desc.srcVolume.getWidth();
  355. dstVolume.bottom = dstVolume.top + desc.srcVolume.getHeight();
  356. dstVolume.back = dstVolume.front + desc.srcVolume.getDepth();
  357. dest->blitFromTexture(src, desc.srcVolume, dstVolume);
  358. }
  359. };
  360. if (commandBuffer == nullptr)
  361. executeRef(target, desc);
  362. else
  363. {
  364. auto execute = [=]() { executeRef(target, desc); };
  365. SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
  366. cb->queueCommand(execute);
  367. }
  368. }
  369. void GLTexture::createSurfaceList()
  370. {
  371. mSurfaceList.clear();
  372. for (UINT32 face = 0; face < mProperties.getNumFaces(); face++)
  373. {
  374. for (UINT32 mip = 0; mip <= mProperties.getNumMipmaps(); mip++)
  375. {
  376. GLPixelBuffer *buf = bs_new<GLTextureBuffer>(getGLTextureTarget(), mTextureID, face, mip,
  377. static_cast<GpuBufferUsage>(mProperties.getUsage()), mInternalFormat, mProperties.getNumSamples());
  378. mSurfaceList.push_back(bs_shared_ptr<GLPixelBuffer>(buf));
  379. if(buf->getWidth() == 0 || buf->getHeight() == 0 || buf->getDepth() == 0)
  380. {
  381. BS_EXCEPT(RenderingAPIException,
  382. "Zero sized texture surface on texture face "
  383. + toString(face)
  384. + " mipmap "+toString(mip)
  385. + ". Probably, the GL driver refused to create the texture.");
  386. }
  387. }
  388. }
  389. }
  390. SPtr<GLPixelBuffer> GLTexture::getBuffer(UINT32 face, UINT32 mipmap)
  391. {
  392. THROW_IF_NOT_CORE_THREAD;
  393. if(face >= mProperties.getNumFaces())
  394. BS_EXCEPT(InvalidParametersException, "Face index out of range");
  395. if (mipmap > mProperties.getNumMipmaps())
  396. BS_EXCEPT(InvalidParametersException, "Mipmap index out of range");
  397. unsigned int idx = face * (mProperties.getNumMipmaps() + 1) + mipmap;
  398. assert(idx < mSurfaceList.size());
  399. return mSurfaceList[idx];
  400. }
  401. SPtr<TextureView> GLTexture::createView(const TEXTURE_VIEW_DESC& desc)
  402. {
  403. return bs_shared_ptr<GLTextureView>(new (bs_alloc<GLTextureView>()) GLTextureView(this, desc));
  404. }
  405. }}