D3D9IndexBuffer.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. //
  2. // Copyright (c) 2008-2014 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 "Precompiled.h"
  23. #include "Context.h"
  24. #include "Graphics.h"
  25. #include "GraphicsImpl.h"
  26. #include "IndexBuffer.h"
  27. #include "Log.h"
  28. #include "DebugNew.h"
  29. namespace Urho3D
  30. {
  31. IndexBuffer::IndexBuffer(Context* context) :
  32. Object(context),
  33. GPUObject(GetSubsystem<Graphics>()),
  34. indexCount_(0),
  35. indexSize_(0),
  36. pool_(D3DPOOL_MANAGED),
  37. usage_(0),
  38. lockState_(LOCK_NONE),
  39. lockStart_(0),
  40. lockCount_(0),
  41. lockScratchData_(0),
  42. shadowed_(false)
  43. {
  44. // Force shadowing mode if graphics subsystem does not exist
  45. if (!graphics_)
  46. shadowed_ = true;
  47. }
  48. IndexBuffer::~IndexBuffer()
  49. {
  50. Release();
  51. }
  52. void IndexBuffer::OnDeviceLost()
  53. {
  54. if (pool_ == D3DPOOL_DEFAULT)
  55. Release();
  56. }
  57. void IndexBuffer::OnDeviceReset()
  58. {
  59. if (pool_ == D3DPOOL_DEFAULT || !object_)
  60. {
  61. Create();
  62. dataLost_ = !UpdateToGPU();
  63. }
  64. else if (dataPending_)
  65. dataLost_ = !UpdateToGPU();
  66. dataPending_ = false;
  67. }
  68. void IndexBuffer::Release()
  69. {
  70. Unlock();
  71. if (object_)
  72. {
  73. if (!graphics_)
  74. return;
  75. if (graphics_->GetIndexBuffer() == this)
  76. graphics_->SetIndexBuffer(0);
  77. ((IDirect3DIndexBuffer9*)object_)->Release();
  78. object_ = 0;
  79. }
  80. }
  81. void IndexBuffer::SetShadowed(bool enable)
  82. {
  83. // If no graphics subsystem, can not disable shadowing
  84. if (!graphics_)
  85. enable = true;
  86. if (enable != shadowed_)
  87. {
  88. if (enable && indexCount_ && indexSize_)
  89. shadowData_ = new unsigned char[indexCount_ * indexSize_];
  90. else
  91. shadowData_.Reset();
  92. shadowed_ = enable;
  93. }
  94. }
  95. bool IndexBuffer::SetSize(unsigned indexCount, bool largeIndices, bool dynamic)
  96. {
  97. Unlock();
  98. if (dynamic)
  99. {
  100. pool_ = D3DPOOL_DEFAULT;
  101. usage_ = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
  102. }
  103. else
  104. {
  105. pool_ = D3DPOOL_MANAGED;
  106. usage_ = 0;
  107. }
  108. indexCount_ = indexCount;
  109. indexSize_ = largeIndices ? sizeof(unsigned) : sizeof(unsigned short);
  110. if (shadowed_ && indexCount_ && indexSize_)
  111. shadowData_ = new unsigned char[indexCount_ * indexSize_];
  112. else
  113. shadowData_.Reset();
  114. return Create();
  115. }
  116. bool IndexBuffer::SetData(const void* data)
  117. {
  118. if (!data)
  119. {
  120. LOGERROR("Null pointer for index buffer data");
  121. return false;
  122. }
  123. if (!indexSize_)
  124. {
  125. LOGERROR("Index size not defined, can not set index buffer data");
  126. return false;
  127. }
  128. if (shadowData_ && data != shadowData_.Get())
  129. memcpy(shadowData_.Get(), data, indexCount_ * indexSize_);
  130. if (object_)
  131. {
  132. if (graphics_->IsDeviceLost())
  133. {
  134. LOGWARNING("Index buffer data assignment while device is lost");
  135. dataPending_ = true;
  136. return true;
  137. }
  138. void* hwData = MapBuffer(0, indexCount_, true);
  139. if (hwData)
  140. {
  141. memcpy(hwData, data, indexCount_ * indexSize_);
  142. UnmapBuffer();
  143. }
  144. else
  145. return false;
  146. }
  147. dataLost_ = false;
  148. return true;
  149. }
  150. bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard)
  151. {
  152. if (start == 0 && count == indexCount_)
  153. return SetData(data);
  154. if (!data)
  155. {
  156. LOGERROR("Null pointer for index buffer data");
  157. return false;
  158. }
  159. if (!indexSize_)
  160. {
  161. LOGERROR("Index size not defined, can not set index buffer data");
  162. return false;
  163. }
  164. if (start + count > indexCount_)
  165. {
  166. LOGERROR("Illegal range for setting new index buffer data");
  167. return false;
  168. }
  169. if (!count)
  170. return true;
  171. if (shadowData_ && shadowData_.Get() + start * indexSize_ != data)
  172. memcpy(shadowData_.Get() + start * indexSize_, data, count * indexSize_);
  173. if (object_)
  174. {
  175. if (graphics_->IsDeviceLost())
  176. {
  177. LOGWARNING("Index buffer data assignment while device is lost");
  178. dataPending_ = true;
  179. return true;
  180. }
  181. void* hwData = MapBuffer(start, count, discard);
  182. if (hwData)
  183. {
  184. memcpy(hwData, data, count * indexSize_);
  185. UnmapBuffer();
  186. }
  187. else
  188. return false;
  189. }
  190. return true;
  191. }
  192. void* IndexBuffer::Lock(unsigned start, unsigned count, bool discard)
  193. {
  194. if (lockState_ != LOCK_NONE)
  195. {
  196. LOGERROR("Index buffer already locked");
  197. return 0;
  198. }
  199. if (!indexSize_)
  200. {
  201. LOGERROR("Index size not defined, can not lock index buffer");
  202. return 0;
  203. }
  204. if (start + count > indexCount_)
  205. {
  206. LOGERROR("Illegal range for locking index buffer");
  207. return 0;
  208. }
  209. if (!count)
  210. return 0;
  211. lockStart_ = start;
  212. lockCount_ = count;
  213. // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed
  214. if (object_ && !shadowData_ && !graphics_->IsDeviceLost())
  215. return MapBuffer(start, count, discard);
  216. else if (shadowData_)
  217. {
  218. lockState_ = LOCK_SHADOW;
  219. return shadowData_.Get() + start * indexSize_;
  220. }
  221. else if (graphics_)
  222. {
  223. lockState_ = LOCK_SCRATCH;
  224. lockScratchData_ = graphics_->ReserveScratchBuffer(count * indexSize_);
  225. return lockScratchData_;
  226. }
  227. else
  228. return 0;
  229. }
  230. void IndexBuffer::Unlock()
  231. {
  232. switch (lockState_)
  233. {
  234. case LOCK_HARDWARE:
  235. UnmapBuffer();
  236. break;
  237. case LOCK_SHADOW:
  238. SetDataRange(shadowData_.Get() + lockStart_ * indexSize_, lockStart_, lockCount_);
  239. lockState_ = LOCK_NONE;
  240. break;
  241. case LOCK_SCRATCH:
  242. SetDataRange(lockScratchData_, lockStart_, lockCount_);
  243. if (graphics_)
  244. graphics_->FreeScratchBuffer(lockScratchData_);
  245. lockScratchData_ = 0;
  246. lockState_ = LOCK_NONE;
  247. break;
  248. }
  249. }
  250. bool IndexBuffer::IsDynamic() const
  251. {
  252. return pool_ == D3DPOOL_DEFAULT;
  253. }
  254. bool IndexBuffer::GetUsedVertexRange(unsigned start, unsigned count, unsigned& minVertex, unsigned& vertexCount)
  255. {
  256. if (!shadowData_)
  257. {
  258. LOGERROR("Used vertex range can only be queried from an index buffer with shadow data");
  259. return false;
  260. }
  261. if (start + count > indexCount_)
  262. {
  263. LOGERROR("Illegal index range for querying used vertices");
  264. return false;
  265. }
  266. minVertex = M_MAX_UNSIGNED;
  267. unsigned maxVertex = 0;
  268. if (indexSize_ == sizeof(unsigned))
  269. {
  270. unsigned* indices = ((unsigned*)shadowData_.Get()) + start;
  271. for (unsigned i = 0; i < count; ++i)
  272. {
  273. if (indices[i] < minVertex)
  274. minVertex = indices[i];
  275. if (indices[i] > maxVertex)
  276. maxVertex = indices[i];
  277. }
  278. }
  279. else
  280. {
  281. unsigned short* indices = ((unsigned short*)shadowData_.Get()) + start;
  282. for (unsigned i = 0; i < count; ++i)
  283. {
  284. if (indices[i] < minVertex)
  285. minVertex = indices[i];
  286. if (indices[i] > maxVertex)
  287. maxVertex = indices[i];
  288. }
  289. }
  290. vertexCount = maxVertex - minVertex + 1;
  291. return true;
  292. }
  293. bool IndexBuffer::Create()
  294. {
  295. Release();
  296. if (!indexCount_)
  297. return true;
  298. if (graphics_)
  299. {
  300. if (graphics_->IsDeviceLost())
  301. {
  302. LOGWARNING("Index buffer creation while device is lost");
  303. return true;
  304. }
  305. IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
  306. if (!device || FAILED(device->CreateIndexBuffer(
  307. indexCount_ * indexSize_,
  308. usage_,
  309. indexSize_ == sizeof(unsigned) ? D3DFMT_INDEX32 : D3DFMT_INDEX16,
  310. (D3DPOOL)pool_,
  311. (IDirect3DIndexBuffer9**)&object_,
  312. 0)))
  313. {
  314. LOGERROR("Could not create index buffer");
  315. return false;
  316. }
  317. }
  318. return true;
  319. }
  320. bool IndexBuffer::UpdateToGPU()
  321. {
  322. if (object_ && shadowData_)
  323. return SetData(shadowData_.Get());
  324. else
  325. return false;
  326. }
  327. void* IndexBuffer::MapBuffer(unsigned start, unsigned count, bool discard)
  328. {
  329. void* hwData = 0;
  330. if (object_)
  331. {
  332. DWORD flags = 0;
  333. if (discard && usage_ & D3DUSAGE_DYNAMIC)
  334. flags = D3DLOCK_DISCARD;
  335. if (FAILED(((IDirect3DIndexBuffer9*)object_)->Lock(start * indexSize_, count * indexSize_, &hwData, flags)))
  336. LOGERROR("Could not lock index buffer");
  337. else
  338. lockState_ = LOCK_HARDWARE;
  339. }
  340. return hwData;
  341. }
  342. void IndexBuffer::UnmapBuffer()
  343. {
  344. if (object_ && lockState_ == LOCK_HARDWARE)
  345. {
  346. ((IDirect3DIndexBuffer9*)object_)->Unlock();
  347. lockState_ = LOCK_NONE;
  348. }
  349. }
  350. }