D3D11VertexBuffer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../../Graphics/Graphics.h"
  23. #include "../../Graphics/GraphicsImpl.h"
  24. #include "../../IO/Log.h"
  25. #include "../../Graphics/VertexBuffer.h"
  26. #include "../../DebugNew.h"
  27. namespace Urho3D
  28. {
  29. const unsigned VertexBuffer::elementSize[] =
  30. {
  31. 3 * sizeof(float), // Position
  32. 3 * sizeof(float), // Normal
  33. 4 * sizeof(unsigned char), // Color
  34. 2 * sizeof(float), // Texcoord1
  35. 2 * sizeof(float), // Texcoord2
  36. 3 * sizeof(float), // Cubetexcoord1
  37. 3 * sizeof(float), // Cubetexcoord2
  38. 4 * sizeof(float), // Tangent
  39. 4 * sizeof(float), // Blendweights
  40. 4 * sizeof(unsigned char), // Blendindices
  41. 4 * sizeof(float), // Instancematrix1
  42. 4 * sizeof(float), // Instancematrix2
  43. 4 * sizeof(float) // Instancematrix3
  44. };
  45. const char* VertexBuffer::elementSemantics[] =
  46. {
  47. "POSITION",
  48. "NORMAL",
  49. "COLOR",
  50. "TEXCOORD",
  51. "TEXCOORD",
  52. "TEXCOORD",
  53. "TEXCOORD",
  54. "TANGENT",
  55. "BLENDWEIGHT",
  56. "BLENDINDICES",
  57. "TEXCOORD",
  58. "TEXCOORD",
  59. "TEXCOORD"
  60. };
  61. const unsigned VertexBuffer::elementSemanticIndices[] =
  62. {
  63. 0,
  64. 0,
  65. 0,
  66. 0,
  67. 1,
  68. 0,
  69. 1,
  70. 0,
  71. 0,
  72. 0,
  73. 2,
  74. 3,
  75. 4
  76. };
  77. const unsigned VertexBuffer::elementFormats[] =
  78. {
  79. DXGI_FORMAT_R32G32B32_FLOAT,
  80. DXGI_FORMAT_R32G32B32_FLOAT,
  81. DXGI_FORMAT_R8G8B8A8_UNORM,
  82. DXGI_FORMAT_R32G32_FLOAT,
  83. DXGI_FORMAT_R32G32_FLOAT,
  84. DXGI_FORMAT_R32G32B32_FLOAT,
  85. DXGI_FORMAT_R32G32B32_FLOAT,
  86. DXGI_FORMAT_R32G32B32A32_FLOAT,
  87. DXGI_FORMAT_R32G32B32A32_FLOAT,
  88. DXGI_FORMAT_R8G8B8A8_UINT,
  89. DXGI_FORMAT_R32G32B32A32_FLOAT,
  90. DXGI_FORMAT_R32G32B32A32_FLOAT,
  91. DXGI_FORMAT_R32G32B32A32_FLOAT
  92. };
  93. VertexBuffer::VertexBuffer(Context* context) :
  94. Object(context),
  95. GPUObject(GetSubsystem<Graphics>()),
  96. vertexCount_(0),
  97. elementMask_(0),
  98. lockState_(LOCK_NONE),
  99. lockStart_(0),
  100. lockCount_(0),
  101. lockScratchData_(0),
  102. dynamic_(false),
  103. shadowed_(false)
  104. {
  105. UpdateOffsets();
  106. // Force shadowing mode if graphics subsystem does not exist
  107. if (!graphics_)
  108. shadowed_ = true;
  109. }
  110. VertexBuffer::~VertexBuffer()
  111. {
  112. Release();
  113. }
  114. void VertexBuffer::Release()
  115. {
  116. Unlock();
  117. if (object_)
  118. {
  119. if (!graphics_)
  120. return;
  121. for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
  122. {
  123. if (graphics_->GetVertexBuffer(i) == this)
  124. graphics_->SetVertexBuffer(0);
  125. }
  126. ((ID3D11Buffer*)object_)->Release();
  127. object_ = 0;
  128. }
  129. }
  130. void VertexBuffer::SetShadowed(bool enable)
  131. {
  132. // If no graphics subsystem, can not disable shadowing
  133. if (!graphics_)
  134. enable = true;
  135. if (enable != shadowed_)
  136. {
  137. if (enable && vertexSize_ && vertexCount_)
  138. shadowData_ = new unsigned char[vertexCount_ * vertexSize_];
  139. else
  140. shadowData_.Reset();
  141. shadowed_ = enable;
  142. }
  143. }
  144. bool VertexBuffer::SetSize(unsigned vertexCount, unsigned elementMask, bool dynamic)
  145. {
  146. Unlock();
  147. dynamic_ = dynamic;
  148. vertexCount_ = vertexCount;
  149. elementMask_ = elementMask;
  150. UpdateOffsets();
  151. if (shadowed_ && vertexCount_ && vertexSize_)
  152. shadowData_ = new unsigned char[vertexCount_ * vertexSize_];
  153. else
  154. shadowData_.Reset();
  155. return Create();
  156. }
  157. bool VertexBuffer::SetData(const void* data)
  158. {
  159. if (!data)
  160. {
  161. LOGERROR("Null pointer for vertex buffer data");
  162. return false;
  163. }
  164. if (!vertexSize_)
  165. {
  166. LOGERROR("Vertex elements not defined, can not set vertex buffer data");
  167. return false;
  168. }
  169. if (shadowData_ && data != shadowData_.Get())
  170. memcpy(shadowData_.Get(), data, vertexCount_ * vertexSize_);
  171. if (object_)
  172. {
  173. if (dynamic_)
  174. {
  175. void* hwData = MapBuffer(0, vertexCount_, true);
  176. if (hwData)
  177. {
  178. memcpy(hwData, data, vertexCount_ * vertexSize_);
  179. UnmapBuffer();
  180. }
  181. else
  182. return false;
  183. }
  184. else
  185. {
  186. D3D11_BOX destBox;
  187. destBox.left = 0;
  188. destBox.right = vertexCount_ * vertexSize_;
  189. destBox.top = 0;
  190. destBox.bottom = 1;
  191. destBox.front = 0;
  192. destBox.back = 1;
  193. graphics_->GetImpl()->GetDeviceContext()->UpdateSubresource((ID3D11Buffer*)object_, 0, &destBox, data, 0, 0);
  194. }
  195. }
  196. return true;
  197. }
  198. bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard)
  199. {
  200. if (start == 0 && count == vertexCount_)
  201. return SetData(data);
  202. if (!data)
  203. {
  204. LOGERROR("Null pointer for vertex buffer data");
  205. return false;
  206. }
  207. if (!vertexSize_)
  208. {
  209. LOGERROR("Vertex elements not defined, can not set vertex buffer data");
  210. return false;
  211. }
  212. if (start + count > vertexCount_)
  213. {
  214. LOGERROR("Illegal range for setting new vertex buffer data");
  215. return false;
  216. }
  217. if (!count)
  218. return true;
  219. if (shadowData_ && shadowData_.Get() + start * vertexSize_ != data)
  220. memcpy(shadowData_.Get() + start * vertexSize_, data, count * vertexSize_);
  221. if (object_)
  222. {
  223. if (dynamic_)
  224. {
  225. void* hwData = MapBuffer(start, count, discard);
  226. if (hwData)
  227. {
  228. memcpy(hwData, data, count * vertexSize_);
  229. UnmapBuffer();
  230. }
  231. else
  232. return false;
  233. }
  234. else
  235. {
  236. D3D11_BOX destBox;
  237. destBox.left = start * vertexSize_;
  238. destBox.right = destBox.left + count * vertexSize_;
  239. destBox.top = 0;
  240. destBox.bottom = 1;
  241. destBox.front = 0;
  242. destBox.back = 1;
  243. graphics_->GetImpl()->GetDeviceContext()->UpdateSubresource((ID3D11Buffer*)object_, 0, &destBox, data, 0, 0);
  244. }
  245. }
  246. return true;
  247. }
  248. void* VertexBuffer::Lock(unsigned start, unsigned count, bool discard)
  249. {
  250. if (lockState_ != LOCK_NONE)
  251. {
  252. LOGERROR("Vertex buffer already locked");
  253. return 0;
  254. }
  255. if (!vertexSize_)
  256. {
  257. LOGERROR("Vertex elements not defined, can not lock vertex buffer");
  258. return 0;
  259. }
  260. if (start + count > vertexCount_)
  261. {
  262. LOGERROR("Illegal range for locking vertex buffer");
  263. return 0;
  264. }
  265. if (!count)
  266. return 0;
  267. lockStart_ = start;
  268. lockCount_ = count;
  269. // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed
  270. if (object_ && !shadowData_ && dynamic_)
  271. return MapBuffer(start, count, discard);
  272. else if (shadowData_)
  273. {
  274. lockState_ = LOCK_SHADOW;
  275. return shadowData_.Get() + start * vertexSize_;
  276. }
  277. else if (graphics_)
  278. {
  279. lockState_ = LOCK_SCRATCH;
  280. lockScratchData_ = graphics_->ReserveScratchBuffer(count * vertexSize_);
  281. return lockScratchData_;
  282. }
  283. else
  284. return 0;
  285. }
  286. void VertexBuffer::Unlock()
  287. {
  288. switch (lockState_)
  289. {
  290. case LOCK_HARDWARE:
  291. UnmapBuffer();
  292. break;
  293. case LOCK_SHADOW:
  294. SetDataRange(shadowData_.Get() + lockStart_ * vertexSize_, lockStart_, lockCount_);
  295. lockState_ = LOCK_NONE;
  296. break;
  297. case LOCK_SCRATCH:
  298. SetDataRange(lockScratchData_, lockStart_, lockCount_);
  299. if (graphics_)
  300. graphics_->FreeScratchBuffer(lockScratchData_);
  301. lockScratchData_ = 0;
  302. lockState_ = LOCK_NONE;
  303. break;
  304. }
  305. }
  306. void VertexBuffer::UpdateOffsets()
  307. {
  308. unsigned elementOffset = 0;
  309. for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
  310. {
  311. if (elementMask_ & (1 << i))
  312. {
  313. elementOffset_[i] = elementOffset;
  314. elementOffset += elementSize[i];
  315. }
  316. else
  317. elementOffset_[i] = NO_ELEMENT;
  318. }
  319. vertexSize_ = elementOffset;
  320. }
  321. unsigned long long VertexBuffer::GetBufferHash(unsigned streamIndex, unsigned useMask)
  322. {
  323. unsigned long long bufferHash = elementMask_;
  324. unsigned long long maskHash;
  325. if (useMask == MASK_DEFAULT)
  326. maskHash = ((unsigned long long)elementMask_) * 0x100000000ULL;
  327. else
  328. maskHash = ((unsigned long long)useMask) * 0x100000000ULL;
  329. bufferHash |= maskHash;
  330. bufferHash <<= streamIndex * MAX_VERTEX_ELEMENTS;
  331. return bufferHash;
  332. }
  333. unsigned VertexBuffer::GetVertexSize(unsigned elementMask)
  334. {
  335. unsigned vertexSize = 0;
  336. for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
  337. {
  338. if (elementMask & (1 << i))
  339. vertexSize += elementSize[i];
  340. }
  341. return vertexSize;
  342. }
  343. unsigned VertexBuffer::GetElementOffset(unsigned elementMask, VertexElement element)
  344. {
  345. unsigned offset = 0;
  346. for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
  347. {
  348. if (i == element)
  349. break;
  350. if (elementMask & (1 << i))
  351. offset += elementSize[i];
  352. }
  353. return offset;
  354. }
  355. bool VertexBuffer::Create()
  356. {
  357. Release();
  358. if (!vertexCount_ || !elementMask_)
  359. return true;
  360. if (graphics_)
  361. {
  362. D3D11_BUFFER_DESC bufferDesc;
  363. memset(&bufferDesc, 0, sizeof bufferDesc);
  364. bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
  365. bufferDesc.CPUAccessFlags = dynamic_ ? D3D11_CPU_ACCESS_WRITE : 0;
  366. bufferDesc.Usage = dynamic_ ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
  367. bufferDesc.ByteWidth = (unsigned)(vertexCount_ * vertexSize_);
  368. graphics_->GetImpl()->GetDevice()->CreateBuffer(&bufferDesc, 0, (ID3D11Buffer**)&object_);
  369. if (!object_)
  370. {
  371. LOGERROR("Failed to create vertex buffer");
  372. return false;
  373. }
  374. }
  375. return true;
  376. }
  377. bool VertexBuffer::UpdateToGPU()
  378. {
  379. if (object_ && shadowData_)
  380. return SetData(shadowData_.Get());
  381. else
  382. return false;
  383. }
  384. void* VertexBuffer::MapBuffer(unsigned start, unsigned count, bool discard)
  385. {
  386. void* hwData = 0;
  387. if (object_)
  388. {
  389. D3D11_MAPPED_SUBRESOURCE mappedData;
  390. mappedData.pData = 0;
  391. graphics_->GetImpl()->GetDeviceContext()->Map((ID3D11Buffer*)object_, 0, discard ? D3D11_MAP_WRITE_DISCARD :
  392. D3D11_MAP_WRITE, 0, &mappedData);
  393. hwData = mappedData.pData;
  394. if (!hwData)
  395. LOGERROR("Failed to map vertex buffer");
  396. else
  397. lockState_ = LOCK_HARDWARE;
  398. }
  399. return hwData;
  400. }
  401. void VertexBuffer::UnmapBuffer()
  402. {
  403. if (object_ && lockState_ == LOCK_HARDWARE)
  404. {
  405. graphics_->GetImpl()->GetDeviceContext()->Unmap((ID3D11Buffer*)object_, 0);
  406. lockState_ = LOCK_NONE;
  407. }
  408. }
  409. }