D3D9VertexBuffer.cpp 12 KB

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