1 //
2 // Copyright (c) 2008-2017 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
23 #include "../../Precompiled.h"
24
25 #include "../../Core/Context.h"
26 #include "../../Graphics/Graphics.h"
27 #include "../../Graphics/GraphicsImpl.h"
28 #include "../../Graphics/IndexBuffer.h"
29 #include "../../IO/Log.h"
30
31 #include "../../DebugNew.h"
32
33 namespace Urho3D
34 {
35
OnDeviceLost()36 void IndexBuffer::OnDeviceLost()
37 {
38 // Dynamic buffers are in the default pool and need to be released on device loss
39 if (dynamic_)
40 Release();
41 }
42
OnDeviceReset()43 void IndexBuffer::OnDeviceReset()
44 {
45 // Dynamic buffers are in the default pool and need to be recreated after device reset
46 if (dynamic_ || !object_.ptr_)
47 {
48 Create();
49 dataLost_ = !UpdateToGPU();
50 }
51 else if (dataPending_)
52 dataLost_ = !UpdateToGPU();
53
54 dataPending_ = false;
55 }
56
Release()57 void IndexBuffer::Release()
58 {
59 Unlock();
60
61 if (graphics_ && graphics_->GetIndexBuffer() == this)
62 graphics_->SetIndexBuffer(0);
63
64 URHO3D_SAFE_RELEASE(object_.ptr_);
65 }
66
SetData(const void * data)67 bool IndexBuffer::SetData(const void* data)
68 {
69 if (!data)
70 {
71 URHO3D_LOGERROR("Null pointer for index buffer data");
72 return false;
73 }
74
75 if (!indexSize_)
76 {
77 URHO3D_LOGERROR("Index size not defined, can not set index buffer data");
78 return false;
79 }
80
81 if (shadowData_ && data != shadowData_.Get())
82 memcpy(shadowData_.Get(), data, indexCount_ * indexSize_);
83
84 if (object_.ptr_)
85 {
86 if (graphics_->IsDeviceLost())
87 {
88 URHO3D_LOGWARNING("Index buffer data assignment while device is lost");
89 dataPending_ = true;
90 return true;
91 }
92
93 void* hwData = MapBuffer(0, indexCount_, true);
94 if (hwData)
95 {
96 memcpy(hwData, data, indexCount_ * indexSize_);
97 UnmapBuffer();
98 }
99 else
100 return false;
101 }
102
103 dataLost_ = false;
104 return true;
105 }
106
SetDataRange(const void * data,unsigned start,unsigned count,bool discard)107 bool IndexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard)
108 {
109 if (start == 0 && count == indexCount_)
110 return SetData(data);
111
112 if (!data)
113 {
114 URHO3D_LOGERROR("Null pointer for index buffer data");
115 return false;
116 }
117
118 if (!indexSize_)
119 {
120 URHO3D_LOGERROR("Index size not defined, can not set index buffer data");
121 return false;
122 }
123
124 if (start + count > indexCount_)
125 {
126 URHO3D_LOGERROR("Illegal range for setting new index buffer data");
127 return false;
128 }
129
130 if (!count)
131 return true;
132
133 if (shadowData_ && shadowData_.Get() + start * indexSize_ != data)
134 memcpy(shadowData_.Get() + start * indexSize_, data, count * indexSize_);
135
136 if (object_.ptr_)
137 {
138 if (graphics_->IsDeviceLost())
139 {
140 URHO3D_LOGWARNING("Index buffer data assignment while device is lost");
141 dataPending_ = true;
142 return true;
143 }
144
145 void* hwData = MapBuffer(start, count, discard);
146 if (hwData)
147 {
148 memcpy(hwData, data, count * indexSize_);
149 UnmapBuffer();
150 }
151 else
152 return false;
153 }
154
155 return true;
156 }
157
Lock(unsigned start,unsigned count,bool discard)158 void* IndexBuffer::Lock(unsigned start, unsigned count, bool discard)
159 {
160 if (lockState_ != LOCK_NONE)
161 {
162 URHO3D_LOGERROR("Index buffer already locked");
163 return 0;
164 }
165
166 if (!indexSize_)
167 {
168 URHO3D_LOGERROR("Index size not defined, can not lock index buffer");
169 return 0;
170 }
171
172 if (start + count > indexCount_)
173 {
174 URHO3D_LOGERROR("Illegal range for locking index buffer");
175 return 0;
176 }
177
178 if (!count)
179 return 0;
180
181 lockStart_ = start;
182 lockCount_ = count;
183
184 // Because shadow data must be kept in sync, can only lock hardware buffer if not shadowed
185 if (object_.ptr_ && !shadowData_ && !graphics_->IsDeviceLost())
186 return MapBuffer(start, count, discard);
187 else if (shadowData_)
188 {
189 lockState_ = LOCK_SHADOW;
190 return shadowData_.Get() + start * indexSize_;
191 }
192 else if (graphics_)
193 {
194 lockState_ = LOCK_SCRATCH;
195 lockScratchData_ = graphics_->ReserveScratchBuffer(count * indexSize_);
196 return lockScratchData_;
197 }
198 else
199 return 0;
200 }
201
Unlock()202 void IndexBuffer::Unlock()
203 {
204 switch (lockState_)
205 {
206 case LOCK_HARDWARE:
207 UnmapBuffer();
208 break;
209
210 case LOCK_SHADOW:
211 SetDataRange(shadowData_.Get() + lockStart_ * indexSize_, lockStart_, lockCount_);
212 lockState_ = LOCK_NONE;
213 break;
214
215 case LOCK_SCRATCH:
216 SetDataRange(lockScratchData_, lockStart_, lockCount_);
217 if (graphics_)
218 graphics_->FreeScratchBuffer(lockScratchData_);
219 lockScratchData_ = 0;
220 lockState_ = LOCK_NONE;
221 break;
222
223 default: break;
224 }
225 }
226
Create()227 bool IndexBuffer::Create()
228 {
229 Release();
230
231 if (!indexCount_)
232 return true;
233
234 if (graphics_)
235 {
236 if (graphics_->IsDeviceLost())
237 {
238 URHO3D_LOGWARNING("Index buffer creation while device is lost");
239 return true;
240 }
241
242 unsigned pool = dynamic_ ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
243 unsigned d3dUsage = dynamic_ ? D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY : 0;
244
245 IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
246 HRESULT hr = device->CreateIndexBuffer(
247 indexCount_ * indexSize_,
248 d3dUsage,
249 indexSize_ == sizeof(unsigned) ? D3DFMT_INDEX32 : D3DFMT_INDEX16,
250 (D3DPOOL)pool,
251 (IDirect3DIndexBuffer9**)&object_,
252 0);
253 if (FAILED(hr))
254 {
255 URHO3D_SAFE_RELEASE(object_.ptr_)
256 URHO3D_LOGD3DERROR("Could not create index buffer", hr);
257 return false;
258 }
259 }
260
261 return true;
262 }
263
UpdateToGPU()264 bool IndexBuffer::UpdateToGPU()
265 {
266 if (object_.ptr_ && shadowData_)
267 return SetData(shadowData_.Get());
268 else
269 return false;
270 }
271
MapBuffer(unsigned start,unsigned count,bool discard)272 void* IndexBuffer::MapBuffer(unsigned start, unsigned count, bool discard)
273 {
274 void* hwData = 0;
275
276 if (object_.ptr_)
277 {
278 DWORD flags = 0;
279
280 if (discard && dynamic_)
281 flags = D3DLOCK_DISCARD;
282
283 HRESULT hr = ((IDirect3DIndexBuffer9*)object_.ptr_)->Lock(start * indexSize_, count * indexSize_, &hwData, flags);
284 if (FAILED(hr))
285 URHO3D_LOGD3DERROR("Could not lock index buffer", hr);
286 else
287 lockState_ = LOCK_HARDWARE;
288 }
289
290 return hwData;
291 }
292
UnmapBuffer()293 void IndexBuffer::UnmapBuffer()
294 {
295 if (object_.ptr_ && lockState_ == LOCK_HARDWARE)
296 {
297 ((IDirect3DIndexBuffer9*)object_.ptr_)->Unlock();
298 lockState_ = LOCK_NONE;
299 }
300 }
301
302 }
303