BsD3D11Texture.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsD3D11Texture.h"
  4. #include "BsD3D11Mappings.h"
  5. #include "BsD3D11Device.h"
  6. #include "BsD3D11RenderAPI.h"
  7. #include "BsD3D11TextureView.h"
  8. #include "CoreThread/BsCoreThread.h"
  9. #include "Error/BsException.h"
  10. #include "Threading/BsAsyncOp.h"
  11. #include "Profiling/BsRenderStats.h"
  12. #include "Math/BsMath.h"
  13. #include "BsD3D11CommandBuffer.h"
  14. namespace bs { namespace ct
  15. {
  16. D3D11Texture::D3D11Texture(const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData,
  17. GpuDeviceFlags deviceMask)
  18. : Texture(desc, initialData, deviceMask),
  19. m1DTex(nullptr), m2DTex(nullptr), m3DTex(nullptr), mDXGIFormat(DXGI_FORMAT_UNKNOWN), mDXGIColorFormat(DXGI_FORMAT_UNKNOWN),
  20. mTex(nullptr), mInternalFormat(PF_UNKNOWN), mStagingBuffer(nullptr), mDXGIDepthStencilFormat(DXGI_FORMAT_UNKNOWN),
  21. mLockedSubresourceIdx(-1), mLockedForReading(false), mStaticBuffer(nullptr)
  22. {
  23. assert((deviceMask == GDF_DEFAULT || deviceMask == GDF_PRIMARY) && "Multiple GPUs not supported natively on DirectX 11.");
  24. }
  25. D3D11Texture::~D3D11Texture()
  26. {
  27. clearBufferViews();
  28. SAFE_RELEASE(mTex);
  29. SAFE_RELEASE(m1DTex);
  30. SAFE_RELEASE(m2DTex);
  31. SAFE_RELEASE(m3DTex);
  32. SAFE_RELEASE(mStagingBuffer);
  33. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
  34. }
  35. void D3D11Texture::initialize()
  36. {
  37. THROW_IF_NOT_CORE_THREAD;
  38. switch (mProperties.getTextureType())
  39. {
  40. case TEX_TYPE_1D:
  41. create1DTex();
  42. break;
  43. case TEX_TYPE_2D:
  44. case TEX_TYPE_CUBE_MAP:
  45. create2DTex();
  46. break;
  47. case TEX_TYPE_3D:
  48. create3DTex();
  49. break;
  50. default:
  51. BS_EXCEPT(RenderingAPIException, "Unknown texture type");
  52. }
  53. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
  54. Texture::initialize();
  55. }
  56. void D3D11Texture::copyImpl(const SPtr<Texture>& target, const TEXTURE_COPY_DESC& desc,
  57. const SPtr<CommandBuffer>& commandBuffer)
  58. {
  59. auto executeRef = [this](const SPtr<Texture>& target, const TEXTURE_COPY_DESC& desc)
  60. {
  61. D3D11Texture* other = static_cast<D3D11Texture*>(target.get());
  62. UINT32 srcResIdx = D3D11CalcSubresource(desc.srcMip, desc.srcFace, mProperties.getNumMipmaps() + 1);
  63. UINT32 destResIdx = D3D11CalcSubresource(desc.dstMip, desc.dstFace, target->getProperties().getNumMipmaps() + 1);
  64. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  65. D3D11Device& device = rs->getPrimaryDevice();
  66. bool srcHasMultisample = mProperties.getNumSamples() > 1;
  67. bool destHasMultisample = target->getProperties().getNumSamples() > 1;
  68. bool copyEntireSurface = desc.srcVolume.getWidth() == 0 ||
  69. desc.srcVolume.getHeight() == 0 ||
  70. desc.srcVolume.getDepth() == 0;
  71. if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
  72. {
  73. if(copyEntireSurface)
  74. device.getImmediateContext()->ResolveSubresource(other->getDX11Resource(), destResIdx, mTex, srcResIdx, mDXGIFormat);
  75. else
  76. {
  77. // Need to first resolve to a temporary texture, then copy
  78. TEXTURE_DESC tempDesc;
  79. tempDesc.width = mProperties.getWidth();
  80. tempDesc.height = mProperties.getHeight();
  81. tempDesc.format = mProperties.getFormat();
  82. tempDesc.hwGamma = mProperties.isHardwareGammaEnabled();
  83. SPtr<D3D11Texture> temporary = std::static_pointer_cast<D3D11Texture>(Texture::create(tempDesc));
  84. device.getImmediateContext()->ResolveSubresource(temporary->getDX11Resource(), 0, mTex, srcResIdx, mDXGIFormat);
  85. TEXTURE_COPY_DESC tempCopyDesc;
  86. tempCopyDesc.dstMip = desc.dstMip;
  87. tempCopyDesc.dstFace = desc.dstFace;
  88. tempCopyDesc.dstPosition = desc.dstPosition;
  89. temporary->copy(target, tempCopyDesc);
  90. }
  91. }
  92. else
  93. {
  94. D3D11_BOX srcRegion;
  95. srcRegion.left = desc.srcVolume.left;
  96. srcRegion.right = desc.srcVolume.right;
  97. srcRegion.top = desc.srcVolume.top;
  98. srcRegion.bottom = desc.srcVolume.bottom;
  99. srcRegion.front = desc.srcVolume.front;
  100. srcRegion.back = desc.srcVolume.back;
  101. D3D11_BOX* srcRegionPtr = nullptr;
  102. if(!copyEntireSurface)
  103. srcRegionPtr = &srcRegion;
  104. device.getImmediateContext()->CopySubresourceRegion(
  105. other->getDX11Resource(),
  106. destResIdx,
  107. (UINT32)desc.dstPosition.x,
  108. (UINT32)desc.dstPosition.y,
  109. (UINT32)desc.dstPosition.z,
  110. mTex,
  111. srcResIdx,
  112. srcRegionPtr);
  113. if (device.hasError())
  114. {
  115. String errorDescription = device.getErrorDescription();
  116. BS_EXCEPT(RenderingAPIException, "D3D11 device cannot copy subresource\nError Description:" + errorDescription);
  117. }
  118. }
  119. };
  120. if (commandBuffer == nullptr)
  121. executeRef(target, desc);
  122. else
  123. {
  124. auto execute = [=]() { executeRef(target, desc); };
  125. SPtr<D3D11CommandBuffer> cb = std::static_pointer_cast<D3D11CommandBuffer>(commandBuffer);
  126. cb->queueCommand(execute);
  127. }
  128. }
  129. PixelData D3D11Texture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
  130. UINT32 queueIdx)
  131. {
  132. if (mProperties.getNumSamples() > 1)
  133. BS_EXCEPT(InvalidStateException, "Multisampled textures cannot be accessed from the CPU directly.");
  134. #if BS_PROFILING_ENABLED
  135. if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
  136. {
  137. BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
  138. }
  139. if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
  140. {
  141. BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
  142. }
  143. #endif
  144. UINT32 mipWidth = std::max(1u, mProperties.getWidth() >> mipLevel);
  145. UINT32 mipHeight = std::max(1u, mProperties.getHeight() >> mipLevel);
  146. UINT32 mipDepth = std::max(1u, mProperties.getDepth() >> mipLevel);
  147. PixelData lockedArea(mipWidth, mipHeight, mipDepth, mInternalFormat);
  148. D3D11_MAP flags = D3D11Mappings::getLockOptions(options);
  149. UINT32 rowPitch, slicePitch;
  150. if(flags == D3D11_MAP_READ || flags == D3D11_MAP_READ_WRITE)
  151. {
  152. UINT8* data = (UINT8*)mapstagingbuffer(flags, face, mipLevel, rowPitch, slicePitch);
  153. lockedArea.setExternalBuffer(data);
  154. lockedArea.setRowPitch(rowPitch);
  155. lockedArea.setSlicePitch(slicePitch);
  156. mLockedForReading = true;
  157. }
  158. else
  159. {
  160. if ((mProperties.getUsage() & TU_DYNAMIC) != 0)
  161. {
  162. UINT8* data = (UINT8*)map(mTex, flags, face, mipLevel, rowPitch, slicePitch);
  163. lockedArea.setExternalBuffer(data);
  164. lockedArea.setRowPitch(rowPitch);
  165. lockedArea.setSlicePitch(slicePitch);
  166. }
  167. else
  168. lockedArea.setExternalBuffer((UINT8*)mapstaticbuffer(lockedArea, mipLevel, face));
  169. mLockedForReading = false;
  170. }
  171. return lockedArea;
  172. }
  173. void D3D11Texture::unlockImpl()
  174. {
  175. if(mLockedForReading)
  176. unmapstagingbuffer();
  177. else
  178. {
  179. if ((mProperties.getUsage() & TU_DYNAMIC) != 0)
  180. unmap(mTex);
  181. else
  182. unmapstaticbuffer();
  183. }
  184. }
  185. void D3D11Texture::readDataImpl(PixelData& dest, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
  186. {
  187. if (mProperties.getNumSamples() > 1)
  188. {
  189. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  190. return;
  191. }
  192. PixelData myData = lock(GBL_READ_ONLY, mipLevel, face, deviceIdx, queueIdx);
  193. PixelUtil::bulkPixelConversion(myData, dest);
  194. unlock();
  195. }
  196. void D3D11Texture::writeDataImpl(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer,
  197. UINT32 queueIdx)
  198. {
  199. PixelFormat format = mProperties.getFormat();
  200. if (mProperties.getNumSamples() > 1)
  201. {
  202. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  203. return;
  204. }
  205. mipLevel = Math::clamp(mipLevel, (UINT32)mipLevel, mProperties.getNumMipmaps());
  206. face = Math::clamp(face, (UINT32)0, mProperties.getNumFaces() - 1);
  207. if (face > 0 && mProperties.getTextureType() == TEX_TYPE_3D)
  208. {
  209. LOGERR("3D texture arrays are not supported.");
  210. return;
  211. }
  212. if ((mProperties.getUsage() & TU_DYNAMIC) != 0)
  213. {
  214. PixelData myData = lock(discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY, mipLevel, face, 0, queueIdx);
  215. PixelUtil::bulkPixelConversion(src, myData);
  216. unlock();
  217. }
  218. else if ((mProperties.getUsage() & TU_DEPTHSTENCIL) == 0)
  219. {
  220. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  221. D3D11Device& device = rs->getPrimaryDevice();
  222. UINT subresourceIdx = D3D11CalcSubresource(mipLevel, face, mProperties.getNumMipmaps() + 1);
  223. UINT32 rowWidth = D3D11Mappings::getSizeInBytes(format, src.getWidth());
  224. UINT32 sliceWidth = D3D11Mappings::getSizeInBytes(format, src.getWidth(), src.getHeight());
  225. device.getImmediateContext()->UpdateSubresource(mTex, subresourceIdx, nullptr, src.getData(), rowWidth, sliceWidth);
  226. if (device.hasError())
  227. {
  228. String errorDescription = device.getErrorDescription();
  229. BS_EXCEPT(RenderingAPIException, "D3D11 device cannot map texture\nError Description:" + errorDescription);
  230. }
  231. BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
  232. }
  233. else
  234. {
  235. BS_EXCEPT(RenderingAPIException, "Trying to write into a buffer with unsupported usage: " + toString(mProperties.getUsage()));
  236. }
  237. }
  238. void D3D11Texture::create1DTex()
  239. {
  240. UINT32 width = mProperties.getWidth();
  241. int usage = mProperties.getUsage();
  242. UINT32 numMips = mProperties.getNumMipmaps();
  243. PixelFormat format = mProperties.getFormat();
  244. bool hwGamma = mProperties.isHardwareGammaEnabled();
  245. PixelFormat closestFormat = D3D11Mappings::getClosestSupportedPF(format, TEX_TYPE_1D, usage);
  246. UINT32 numFaces = mProperties.getNumFaces();
  247. // We must have those defined here
  248. assert(width > 0);
  249. // Determine which D3D11 pixel format we'll use
  250. HRESULT hr;
  251. DXGI_FORMAT d3dPF = D3D11Mappings::getPF(closestFormat, hwGamma);
  252. if (format != closestFormat)
  253. {
  254. LOGWRN(StringUtil::format("Provided pixel format is not supported by the driver: {0}. Falling back on: {1}.",
  255. format, closestFormat));
  256. }
  257. mInternalFormat = closestFormat;
  258. mDXGIColorFormat = d3dPF;
  259. mDXGIDepthStencilFormat = d3dPF;
  260. // TODO - Consider making this a parameter eventually
  261. bool readableDepth = true;
  262. D3D11_TEXTURE1D_DESC desc;
  263. desc.Width = static_cast<UINT32>(width);
  264. desc.ArraySize = numFaces == 0 ? 1 : numFaces;
  265. desc.Format = d3dPF;
  266. desc.MiscFlags = 0;
  267. if((usage & TU_RENDERTARGET) != 0)
  268. {
  269. desc.Usage = D3D11_USAGE_DEFAULT;
  270. desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
  271. desc.CPUAccessFlags = 0;
  272. desc.MipLevels = 1;
  273. }
  274. else if ((usage & TU_DEPTHSTENCIL) != 0)
  275. {
  276. desc.Usage = D3D11_USAGE_DEFAULT;
  277. if(readableDepth)
  278. desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
  279. else
  280. desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
  281. desc.CPUAccessFlags = 0;
  282. desc.MipLevels = 1;
  283. desc.Format = D3D11Mappings::getTypelessDepthStencilPF(closestFormat);
  284. mDXGIColorFormat = D3D11Mappings::getShaderResourceDepthStencilPF(closestFormat);
  285. mDXGIDepthStencilFormat = d3dPF;
  286. }
  287. else
  288. {
  289. desc.Usage = D3D11Mappings::getUsage((GpuBufferUsage)usage);
  290. desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
  291. desc.CPUAccessFlags = D3D11Mappings::getAccessFlags((GpuBufferUsage)usage);
  292. // Determine total number of mipmaps including main one (d3d11 convention)
  293. desc.MipLevels = (numMips == MIP_UNLIMITED || (1U << numMips) > width) ? 0 : numMips + 1;
  294. }
  295. if ((usage & TU_LOADSTORE) != 0)
  296. desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
  297. // Create the texture
  298. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  299. D3D11Device& device = rs->getPrimaryDevice();
  300. hr = device.getD3D11Device()->CreateTexture1D(&desc, nullptr, &m1DTex);
  301. // Check result and except if failed
  302. if (FAILED(hr) || device.hasError())
  303. {
  304. String errorDescription = device.getErrorDescription();
  305. BS_EXCEPT(RenderingAPIException, "Error creating texture\nError Description:" + errorDescription);
  306. }
  307. hr = m1DTex->QueryInterface(__uuidof(ID3D11Resource), (void **)&mTex);
  308. if(FAILED(hr) || device.hasError())
  309. {
  310. String errorDescription = device.getErrorDescription();
  311. BS_EXCEPT(RenderingAPIException, "Can't get base texture\nError Description:" + errorDescription);
  312. }
  313. m1DTex->GetDesc(&desc);
  314. if(numMips != (desc.MipLevels - 1))
  315. {
  316. BS_EXCEPT(RenderingAPIException, "Driver returned different number of mip maps than requested. " \
  317. "Requested: " + toString(numMips) + ". Got: " + toString(desc.MipLevels - 1) + ".");
  318. }
  319. mDXGIFormat = desc.Format;
  320. // Create texture view
  321. if ((usage & TU_DEPTHSTENCIL) == 0 || readableDepth)
  322. {
  323. TEXTURE_VIEW_DESC viewDesc;
  324. viewDesc.mostDetailMip = 0;
  325. viewDesc.numMips = desc.MipLevels;
  326. viewDesc.firstArraySlice = 0;
  327. viewDesc.numArraySlices = desc.ArraySize;
  328. viewDesc.usage = GVU_DEFAULT;
  329. mShaderResourceView = bs_shared_ptr<D3D11TextureView>(new (bs_alloc<D3D11TextureView>()) D3D11TextureView(this, viewDesc));
  330. }
  331. }
  332. void D3D11Texture::create2DTex()
  333. {
  334. UINT32 width = mProperties.getWidth();
  335. UINT32 height = mProperties.getHeight();
  336. int usage = mProperties.getUsage();
  337. UINT32 numMips = mProperties.getNumMipmaps();
  338. PixelFormat format = mProperties.getFormat();
  339. bool hwGamma = mProperties.isHardwareGammaEnabled();
  340. UINT32 sampleCount = mProperties.getNumSamples();
  341. TextureType texType = mProperties.getTextureType();
  342. PixelFormat closestFormat = D3D11Mappings::getClosestSupportedPF(format, texType, usage);
  343. UINT32 numFaces = mProperties.getNumFaces();
  344. // TODO - Consider making this a parameter eventually
  345. bool readableDepth = true;
  346. // We must have those defined here
  347. assert(width > 0 || height > 0);
  348. // Determine which D3D11 pixel format we'll use
  349. HRESULT hr;
  350. DXGI_FORMAT d3dPF = D3D11Mappings::getPF(closestFormat, hwGamma);
  351. if (format != closestFormat)
  352. {
  353. LOGWRN(StringUtil::format("Provided pixel format is not supported by the driver: {0}. Falling back on: {1}.",
  354. format, closestFormat));
  355. }
  356. mInternalFormat = closestFormat;
  357. mDXGIColorFormat = d3dPF;
  358. mDXGIDepthStencilFormat = d3dPF;
  359. D3D11_TEXTURE2D_DESC desc;
  360. desc.Width = static_cast<UINT32>(width);
  361. desc.Height = static_cast<UINT32>(height);
  362. desc.ArraySize = numFaces == 0 ? 1 : numFaces;;
  363. desc.Format = d3dPF;
  364. desc.MiscFlags = 0;
  365. if((usage & TU_RENDERTARGET) != 0)
  366. {
  367. desc.Usage = D3D11_USAGE_DEFAULT;
  368. desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; // TODO - Add flags to allow RT be created without shader resource flags (might be more optimal)
  369. desc.CPUAccessFlags = 0;
  370. DXGI_SAMPLE_DESC sampleDesc;
  371. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  372. rs->determineMultisampleSettings(sampleCount, d3dPF, &sampleDesc);
  373. desc.SampleDesc = sampleDesc;
  374. }
  375. else if((usage & TU_DEPTHSTENCIL) != 0)
  376. {
  377. desc.Usage = D3D11_USAGE_DEFAULT;
  378. desc.CPUAccessFlags = 0;
  379. desc.Format = D3D11Mappings::getTypelessDepthStencilPF(closestFormat);
  380. if(readableDepth)
  381. desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
  382. else
  383. desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
  384. DXGI_SAMPLE_DESC sampleDesc;
  385. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  386. rs->determineMultisampleSettings(sampleCount, d3dPF, &sampleDesc);
  387. desc.SampleDesc = sampleDesc;
  388. mDXGIColorFormat = D3D11Mappings::getShaderResourceDepthStencilPF(closestFormat);
  389. mDXGIDepthStencilFormat = d3dPF;
  390. }
  391. else
  392. {
  393. desc.Usage = D3D11Mappings::getUsage((GpuBufferUsage)usage);
  394. desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
  395. desc.CPUAccessFlags = D3D11Mappings::getAccessFlags((GpuBufferUsage)usage);
  396. DXGI_SAMPLE_DESC sampleDesc;
  397. sampleDesc.Count = 1;
  398. sampleDesc.Quality = 0;
  399. desc.SampleDesc = sampleDesc;
  400. }
  401. // Determine total number of mipmaps including main one (d3d11 convention)
  402. desc.MipLevels = (numMips == MIP_UNLIMITED || (1U << numMips) > width) ? 0 : numMips + 1;
  403. if (texType == TEX_TYPE_CUBE_MAP)
  404. desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
  405. if ((usage & TU_LOADSTORE) != 0)
  406. {
  407. if(desc.SampleDesc.Count <= 1)
  408. desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
  409. else
  410. {
  411. LOGWRN("Unable to create a load-store texture with multiple samples. This is not supported on DirectX 11. "
  412. "Ignoring load-store usage flag.");
  413. }
  414. }
  415. // Create the texture
  416. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  417. D3D11Device& device = rs->getPrimaryDevice();
  418. hr = device.getD3D11Device()->CreateTexture2D(&desc, nullptr, &m2DTex);
  419. // Check result and except if failed
  420. if (FAILED(hr) || device.hasError())
  421. {
  422. String errorDescription = device.getErrorDescription();
  423. BS_EXCEPT(RenderingAPIException, "Error creating texture\nError Description:" + errorDescription);
  424. }
  425. hr = m2DTex->QueryInterface(__uuidof(ID3D11Resource), (void **)&mTex);
  426. if(FAILED(hr) || device.hasError())
  427. {
  428. String errorDescription = device.getErrorDescription();
  429. BS_EXCEPT(RenderingAPIException, "Can't get base texture\nError Description:" + errorDescription);
  430. }
  431. m2DTex->GetDesc(&desc);
  432. if(numMips != (desc.MipLevels - 1))
  433. {
  434. BS_EXCEPT(RenderingAPIException, "Driver returned different number of mip maps than requested. " \
  435. "Requested: " + toString(numMips) + ". Got: " + toString(desc.MipLevels - 1) + ".");
  436. }
  437. mDXGIFormat = desc.Format;
  438. // Create shader texture view
  439. if((usage & TU_DEPTHSTENCIL) == 0 || readableDepth)
  440. {
  441. TEXTURE_VIEW_DESC viewDesc;
  442. viewDesc.mostDetailMip = 0;
  443. viewDesc.numMips = desc.MipLevels;
  444. viewDesc.firstArraySlice = 0;
  445. viewDesc.numArraySlices = desc.ArraySize;
  446. viewDesc.usage = GVU_DEFAULT;
  447. mShaderResourceView = bs_shared_ptr<D3D11TextureView>(new (bs_alloc<D3D11TextureView>()) D3D11TextureView(this, viewDesc));
  448. }
  449. }
  450. void D3D11Texture::create3DTex()
  451. {
  452. UINT32 width = mProperties.getWidth();
  453. UINT32 height = mProperties.getHeight();
  454. UINT32 depth = mProperties.getDepth();
  455. int usage = mProperties.getUsage();
  456. UINT32 numMips = mProperties.getNumMipmaps();
  457. PixelFormat format = mProperties.getFormat();
  458. bool hwGamma = mProperties.isHardwareGammaEnabled();
  459. PixelFormat closestFormat = D3D11Mappings::getClosestSupportedPF(format, TEX_TYPE_3D, usage);
  460. // TODO - Consider making this a parameter eventually
  461. bool readableDepth = true;
  462. // We must have those defined here
  463. assert(width > 0 && height > 0 && depth > 0);
  464. // Determine which D3D11 pixel format we'll use
  465. HRESULT hr;
  466. DXGI_FORMAT d3dPF = D3D11Mappings::getPF(closestFormat, hwGamma);
  467. if (format != closestFormat)
  468. {
  469. LOGWRN(StringUtil::format("Provided pixel format is not supported by the driver: {0}. Falling back on: {1}.",
  470. format, closestFormat));
  471. }
  472. mInternalFormat = closestFormat;
  473. mDXGIColorFormat = d3dPF;
  474. mDXGIDepthStencilFormat = d3dPF;
  475. D3D11_TEXTURE3D_DESC desc;
  476. desc.Width = static_cast<UINT32>(width);
  477. desc.Height = static_cast<UINT32>(height);
  478. desc.Depth = static_cast<UINT32>(depth);
  479. desc.Format = d3dPF;
  480. desc.MiscFlags = 0;
  481. if ((mProperties.getUsage() & TU_RENDERTARGET) != 0)
  482. {
  483. desc.Usage = D3D11_USAGE_DEFAULT;
  484. desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
  485. desc.CPUAccessFlags = 0;
  486. desc.MipLevels = 1;
  487. }
  488. else if ((mProperties.getUsage() & TU_DEPTHSTENCIL) != 0)
  489. {
  490. desc.Usage = D3D11_USAGE_DEFAULT;
  491. desc.CPUAccessFlags = 0;
  492. desc.MipLevels = 1;
  493. if (readableDepth)
  494. desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
  495. else
  496. desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
  497. mDXGIColorFormat = D3D11Mappings::getShaderResourceDepthStencilPF(closestFormat);
  498. mDXGIDepthStencilFormat = d3dPF;
  499. }
  500. else
  501. {
  502. desc.Usage = D3D11Mappings::getUsage((GpuBufferUsage)usage);
  503. desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
  504. desc.CPUAccessFlags = D3D11Mappings::getAccessFlags((GpuBufferUsage)usage);
  505. // Determine total number of mipmaps including main one (d3d11 convention)
  506. desc.MipLevels = (numMips == MIP_UNLIMITED || (1U << numMips)
  507. > std::max(std::max(width, height), depth)) ? 0 : numMips + 1;
  508. }
  509. if ((usage & TU_LOADSTORE) != 0)
  510. desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
  511. // Create the texture
  512. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  513. D3D11Device& device = rs->getPrimaryDevice();
  514. hr = device.getD3D11Device()->CreateTexture3D(&desc, nullptr, &m3DTex);
  515. // Check result and except if failed
  516. if (FAILED(hr) || device.hasError())
  517. {
  518. String errorDescription = device.getErrorDescription();
  519. BS_EXCEPT(RenderingAPIException, "Error creating texture\nError Description:" + errorDescription);
  520. }
  521. hr = m3DTex->QueryInterface(__uuidof(ID3D11Resource), (void **)&mTex);
  522. if(FAILED(hr) || device.hasError())
  523. {
  524. String errorDescription = device.getErrorDescription();
  525. BS_EXCEPT(RenderingAPIException, "Can't get base texture\nError Description:" + errorDescription);
  526. }
  527. // Create texture view
  528. m3DTex->GetDesc(&desc);
  529. if (mProperties.getNumMipmaps() != (desc.MipLevels - 1))
  530. {
  531. BS_EXCEPT(RenderingAPIException, "Driver returned different number of mip maps than requested. " \
  532. "Requested: " + toString(mProperties.getNumMipmaps()) + ". Got: " + toString(desc.MipLevels - 1) + ".");
  533. }
  534. mDXGIFormat = desc.Format;
  535. if ((usage & TU_DEPTHSTENCIL) == 0 || readableDepth)
  536. {
  537. TEXTURE_VIEW_DESC viewDesc;
  538. viewDesc.mostDetailMip = 0;
  539. viewDesc.numMips = desc.MipLevels;
  540. viewDesc.firstArraySlice = 0;
  541. viewDesc.numArraySlices = 1;
  542. viewDesc.usage = GVU_DEFAULT;
  543. mShaderResourceView = bs_shared_ptr<D3D11TextureView>(new (bs_alloc<D3D11TextureView>()) D3D11TextureView(this, viewDesc));
  544. }
  545. }
  546. void* D3D11Texture::map(ID3D11Resource* res, D3D11_MAP flags, UINT32 mipLevel, UINT32 face, UINT32& rowPitch, UINT32& slicePitch)
  547. {
  548. D3D11_MAPPED_SUBRESOURCE pMappedResource;
  549. pMappedResource.pData = nullptr;
  550. mipLevel = Math::clamp(mipLevel, (UINT32)mipLevel, mProperties.getNumMipmaps());
  551. face = Math::clamp(face, (UINT32)0, mProperties.getNumFaces() - 1);
  552. if (mProperties.getTextureType() == TEX_TYPE_3D)
  553. face = 0;
  554. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  555. D3D11Device& device = rs->getPrimaryDevice();
  556. mLockedSubresourceIdx = D3D11CalcSubresource(mipLevel, face, mProperties.getNumMipmaps() + 1);
  557. device.getImmediateContext()->Map(res, mLockedSubresourceIdx, flags, 0, &pMappedResource);
  558. if (device.hasError())
  559. {
  560. String errorDescription = device.getErrorDescription();
  561. BS_EXCEPT(RenderingAPIException, "D3D11 device cannot map texture\nError Description:" + errorDescription);
  562. }
  563. UINT32 bytesPerPixel = PixelUtil::getNumElemBytes(mProperties.getFormat());
  564. rowPitch = pMappedResource.RowPitch / bytesPerPixel;
  565. slicePitch = pMappedResource.DepthPitch / bytesPerPixel;
  566. return pMappedResource.pData;
  567. }
  568. void D3D11Texture::unmap(ID3D11Resource* res)
  569. {
  570. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  571. D3D11Device& device = rs->getPrimaryDevice();
  572. device.getImmediateContext()->Unmap(res, mLockedSubresourceIdx);
  573. if (device.hasError())
  574. {
  575. String errorDescription = device.getErrorDescription();
  576. BS_EXCEPT(RenderingAPIException, "D3D11 device unmap resource\nError Description:" + errorDescription);
  577. }
  578. }
  579. void* D3D11Texture::mapstagingbuffer(D3D11_MAP flags, UINT32 mipLevel, UINT32 face, UINT32& rowPitch, UINT32& slicePitch)
  580. {
  581. // Note: I am creating and destroying a staging resource every time a texture is read.
  582. // Consider offering a flag on init that will keep this active all the time (at the cost of double memory).
  583. // Reading is slow operation anyway so I don't believe doing it as we are now will influence it much.
  584. if(!mStagingBuffer)
  585. createStagingBuffer();
  586. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  587. D3D11Device& device = rs->getPrimaryDevice();
  588. device.getImmediateContext()->CopyResource(mStagingBuffer, mTex);
  589. return map(mStagingBuffer, flags, face, mipLevel, rowPitch, slicePitch);
  590. }
  591. void D3D11Texture::unmapstagingbuffer()
  592. {
  593. unmap(mStagingBuffer);
  594. SAFE_RELEASE(mStagingBuffer);
  595. }
  596. void* D3D11Texture::mapstaticbuffer(PixelData lock, UINT32 mipLevel, UINT32 face)
  597. {
  598. UINT32 sizeOfImage = lock.getConsecutiveSize();
  599. mLockedSubresourceIdx = D3D11CalcSubresource(mipLevel, face, mProperties.getNumMipmaps()+1);
  600. mStaticBuffer = bs_new<PixelData>(lock.getWidth(), lock.getHeight(), lock.getDepth(), lock.getFormat());
  601. mStaticBuffer->allocateInternalBuffer();
  602. return mStaticBuffer->getData();
  603. }
  604. void D3D11Texture::unmapstaticbuffer()
  605. {
  606. UINT32 rowWidth = D3D11Mappings::getSizeInBytes(mStaticBuffer->getFormat(), mStaticBuffer->getWidth());
  607. UINT32 sliceWidth = D3D11Mappings::getSizeInBytes(mStaticBuffer->getFormat(), mStaticBuffer->getWidth(), mStaticBuffer->getHeight());
  608. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  609. D3D11Device& device = rs->getPrimaryDevice();
  610. device.getImmediateContext()->UpdateSubresource(mTex, mLockedSubresourceIdx, nullptr, mStaticBuffer->getData(), rowWidth, sliceWidth);
  611. if (device.hasError())
  612. {
  613. String errorDescription = device.getErrorDescription();
  614. BS_EXCEPT(RenderingAPIException, "D3D11 device cannot map texture\nError Description:" + errorDescription);
  615. }
  616. if(mStaticBuffer != nullptr)
  617. bs_delete(mStaticBuffer);
  618. }
  619. ID3D11ShaderResourceView* D3D11Texture::getSRV() const
  620. {
  621. return mShaderResourceView->getSRV();
  622. }
  623. void D3D11Texture::createStagingBuffer()
  624. {
  625. D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
  626. D3D11Device& device = rs->getPrimaryDevice();
  627. switch (mProperties.getTextureType())
  628. {
  629. case TEX_TYPE_1D:
  630. {
  631. D3D11_TEXTURE1D_DESC desc;
  632. m1DTex->GetDesc(&desc);
  633. desc.BindFlags = 0;
  634. desc.MiscFlags = 0;
  635. desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
  636. desc.Usage = D3D11_USAGE_STAGING;
  637. device.getD3D11Device()->CreateTexture1D(&desc, nullptr, (ID3D11Texture1D**)(&mStagingBuffer));
  638. }
  639. break;
  640. case TEX_TYPE_2D:
  641. case TEX_TYPE_CUBE_MAP:
  642. {
  643. D3D11_TEXTURE2D_DESC desc;
  644. m2DTex->GetDesc(&desc);
  645. desc.BindFlags = 0;
  646. desc.MiscFlags = 0;
  647. desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
  648. desc.Usage = D3D11_USAGE_STAGING;
  649. device.getD3D11Device()->CreateTexture2D(&desc, nullptr, (ID3D11Texture2D**)(&mStagingBuffer));
  650. }
  651. break;
  652. case TEX_TYPE_3D:
  653. {
  654. D3D11_TEXTURE3D_DESC desc;
  655. m3DTex->GetDesc(&desc);
  656. desc.BindFlags = 0;
  657. desc.MiscFlags = 0;
  658. desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
  659. desc.Usage = D3D11_USAGE_STAGING;
  660. device.getD3D11Device()->CreateTexture3D(&desc, nullptr, (ID3D11Texture3D**)(&mStagingBuffer));
  661. }
  662. break;
  663. }
  664. }
  665. SPtr<TextureView> D3D11Texture::createView(const TEXTURE_VIEW_DESC& desc)
  666. {
  667. return bs_shared_ptr<D3D11TextureView>(new (bs_alloc<D3D11TextureView>()) D3D11TextureView(this, desc));
  668. }
  669. }}