1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4     (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 ----------------------------------------------------------------------------
27 */
28 #include "OgreD3D9HardwareIndexBuffer.h"
29 #include "OgreD3D9Mappings.h"
30 #include "OgreException.h"
31 #include "OgreD3D9HardwareBufferManager.h"
32 #include "OgreD3D9RenderSystem.h"
33 #include "OgreRoot.h"
34 #include "OgreD3D9Device.h"
35 #include "OgreD3D9ResourceManager.h"
36 
37 namespace Ogre {
38 
39 	//---------------------------------------------------------------------
D3D9HardwareIndexBuffer(HardwareBufferManagerBase * mgr,HardwareIndexBuffer::IndexType idxType,size_t numIndexes,HardwareBuffer::Usage usage,bool useSystemMemory,bool useShadowBuffer)40     D3D9HardwareIndexBuffer::D3D9HardwareIndexBuffer(HardwareBufferManagerBase* mgr, HardwareIndexBuffer::IndexType idxType,
41         size_t numIndexes, HardwareBuffer::Usage usage,
42         bool useSystemMemory, bool useShadowBuffer)
43         : HardwareIndexBuffer(mgr, idxType, numIndexes, usage, useSystemMemory,
44 		useShadowBuffer ||
45 		// Allocate the system memory buffer for restoring after device lost.
46 		(((usage & HardwareBuffer::HBU_WRITE_ONLY) != 0) &&
47 			D3D9RenderSystem::getResourceManager()->getAutoHardwareBufferManagement()))
48    {
49 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
50 
51 		D3DPOOL eResourcePool;
52 
53 #if OGRE_D3D_MANAGE_BUFFERS
54 		eResourcePool = useSystemMemory? D3DPOOL_SYSTEMMEM :
55 			// If not system mem, use managed pool UNLESS buffer is discardable
56 			// if discardable, keeping the software backing is expensive
57 			((usage & HardwareBuffer::HBU_DISCARDABLE) || (D3D9RenderSystem::isDirectX9Ex())) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
58 #else
59 		eResourcePool = useSystemMemory? D3DPOOL_SYSTEMMEM : D3DPOOL_DEFAULT;
60 #endif
61 
62 		// Set the desired memory pool.
63 		mBufferDesc.Pool = eResourcePool;
64 
65 		// Set source buffer to NULL.
66 		mSourceBuffer = NULL;
67 		mSourceLockedBytes  = NULL;
68 
69 		// Create buffer resource(s).
70 		for (uint i = 0; i < D3D9RenderSystem::getResourceCreationDeviceCount(); ++i)
71 		{
72 			IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getResourceCreationDevice(i);
73 
74 			createBuffer(d3d9Device, mBufferDesc.Pool);
75 		}
76     }
77 	//---------------------------------------------------------------------
~D3D9HardwareIndexBuffer()78     D3D9HardwareIndexBuffer::~D3D9HardwareIndexBuffer()
79     {
80 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
81 
82 		DeviceToBufferResourcesIterator it = mMapDeviceToBufferResources.begin();
83 
84 		while (it != mMapDeviceToBufferResources.end())
85 		{
86 			SAFE_RELEASE(it->second->mBuffer);
87 			if (it->second != NULL)
88 			{
89 				OGRE_FREE (it->second, MEMCATEGORY_RENDERSYS);
90 				it->second = NULL;
91 			}
92 			++it;
93 		}
94 		mMapDeviceToBufferResources.clear();
95 	}
96 	//---------------------------------------------------------------------
lockImpl(size_t offset,size_t length,LockOptions options)97     void* D3D9HardwareIndexBuffer::lockImpl(size_t offset,
98         size_t length, LockOptions options)
99     {
100 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
101 
102 		DeviceToBufferResourcesIterator it = mMapDeviceToBufferResources.begin();
103 
104 		while (it != mMapDeviceToBufferResources.end())
105 		{
106 			BufferResources* bufferResources = it->second;
107 
108 			if (options != HBL_READ_ONLY)
109 				bufferResources->mOutOfDate = true;
110 
111 			// Case it is the first buffer lock in this frame.
112 			if (bufferResources->mLockLength == 0)
113 			{
114 				if (offset < bufferResources->mLockOffset)
115 					bufferResources->mLockOffset = offset;
116 				if (length > bufferResources->mLockLength)
117 					bufferResources->mLockLength = length;
118 			}
119 
120 			// Case buffer already locked in this frame.
121 			else
122 			{
123 				size_t highPoint = std::max( offset + length,
124 					bufferResources->mLockOffset + bufferResources->mLockLength );
125 				bufferResources->mLockOffset = std::min( bufferResources->mLockOffset, offset );
126 				bufferResources->mLockLength = highPoint - bufferResources->mLockOffset;
127 			}
128 
129 			bufferResources->mLockOptions = options;
130 
131 			++it;
132 		}
133 
134 		// Lock the source buffer.
135 		mSourceLockedBytes = _lockBuffer(mSourceBuffer, mSourceBuffer->mLockOffset, mSourceBuffer->mLockLength);
136 
137 		return mSourceLockedBytes;
138 	}
139 	//---------------------------------------------------------------------
unlockImpl(void)140 	void D3D9HardwareIndexBuffer::unlockImpl(void)
141     {
142 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
143 
144 		DeviceToBufferResourcesIterator it = mMapDeviceToBufferResources.begin();
145 		uint nextFrameNumber = Root::getSingleton().getNextFrameNumber();
146 
147 		while (it != mMapDeviceToBufferResources.end())
148 		{
149 			BufferResources* bufferResources = it->second;
150 
151 			if (bufferResources->mOutOfDate &&
152 				bufferResources->mBuffer != NULL &&
153 				nextFrameNumber - bufferResources->mLastUsedFrame <= 1)
154 			{
155 				if (mSourceBuffer != bufferResources)
156 				{
157 					updateBufferResources(mSourceLockedBytes, bufferResources);
158 				}
159 			}
160 
161 			++it;
162 		}
163 
164 		// Unlock the source buffer.
165 		_unlockBuffer(mSourceBuffer);
166 		mSourceLockedBytes = NULL;
167 	 }
168 	//---------------------------------------------------------------------
readData(size_t offset,size_t length,void * pDest)169     void D3D9HardwareIndexBuffer::readData(size_t offset, size_t length,
170         void* pDest)
171     {
172        // There is no functional interface in D3D, just do via manual
173         // lock, copy & unlock
174         void* pSrc = this->lock(offset, length, HardwareBuffer::HBL_READ_ONLY);
175         memcpy(pDest, pSrc, length);
176         this->unlock();
177 
178     }
179 	//---------------------------------------------------------------------
writeData(size_t offset,size_t length,const void * pSource,bool discardWholeBuffer)180     void D3D9HardwareIndexBuffer::writeData(size_t offset, size_t length,
181             const void* pSource,
182 			bool discardWholeBuffer)
183     {
184         // There is no functional interface in D3D, just do via manual
185         // lock, copy & unlock
186         void* pDst = this->lock(offset, length,
187             discardWholeBuffer ? HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NORMAL);
188         memcpy(pDst, pSource, length);
189         this->unlock();
190 	}
191 	//---------------------------------------------------------------------
notifyOnDeviceCreate(IDirect3DDevice9 * d3d9Device)192 	void D3D9HardwareIndexBuffer::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
193 	{
194 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
195 
196 		if (D3D9RenderSystem::getResourceManager()->getCreationPolicy() == RCP_CREATE_ON_ALL_DEVICES)
197 			createBuffer(d3d9Device, mBufferDesc.Pool);
198 
199 	}
200 	//---------------------------------------------------------------------
notifyOnDeviceDestroy(IDirect3DDevice9 * d3d9Device)201 	void D3D9HardwareIndexBuffer::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
202 	{
203 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
204 
205 		DeviceToBufferResourcesIterator it = mMapDeviceToBufferResources.find(d3d9Device);
206 
207 		if (it != mMapDeviceToBufferResources.end())
208 		{
209 			// Case this is the source buffer.
210 			if (it->second == mSourceBuffer)
211 			{
212 				mSourceBuffer = NULL;
213 			}
214 
215 			SAFE_RELEASE(it->second->mBuffer);
216 			if (it->second != NULL)
217 			{
218 				OGRE_FREE (it->second, MEMCATEGORY_RENDERSYS);
219 				it->second = NULL;
220 			}
221 			mMapDeviceToBufferResources.erase(it);
222 
223 			// Case source buffer just destroyed -> switch to another one if exits.
224 			if (mSourceBuffer == NULL && mMapDeviceToBufferResources.size() > 0)
225 			{
226 				mSourceBuffer = mMapDeviceToBufferResources.begin()->second;
227 			}
228 		}
229 	}
230 	//---------------------------------------------------------------------
notifyOnDeviceLost(IDirect3DDevice9 * d3d9Device)231 	void D3D9HardwareIndexBuffer::notifyOnDeviceLost(IDirect3DDevice9* d3d9Device)
232 	{
233 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
234 
235 		if (mBufferDesc.Pool == D3DPOOL_DEFAULT)
236 		{
237 			DeviceToBufferResourcesIterator it = mMapDeviceToBufferResources.find(d3d9Device);
238 
239 			if (it != mMapDeviceToBufferResources.end())
240 			{
241 				SAFE_RELEASE(it->second->mBuffer);
242 			}
243 		}
244 	}
245 	//---------------------------------------------------------------------
notifyOnDeviceReset(IDirect3DDevice9 * d3d9Device)246 	void D3D9HardwareIndexBuffer::notifyOnDeviceReset(IDirect3DDevice9* d3d9Device)
247 	{
248 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
249 
250 		if (mBufferDesc.Pool == D3DPOOL_DEFAULT)
251 		{
252 			createBuffer(d3d9Device, mBufferDesc.Pool);
253 		}
254 	}
255 	//---------------------------------------------------------------------
createBuffer(IDirect3DDevice9 * d3d9Device,D3DPOOL ePool)256 	void D3D9HardwareIndexBuffer::createBuffer(IDirect3DDevice9* d3d9Device, D3DPOOL ePool)
257 	{
258 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
259 
260 		BufferResources* bufferResources;
261 		HRESULT hr;
262 
263 		DeviceToBufferResourcesIterator it;
264 
265 		// Find the vertex buffer of this device.
266 		it = mMapDeviceToBufferResources.find(d3d9Device);
267 		if (it != mMapDeviceToBufferResources.end())
268 		{
269 			bufferResources = it->second;
270 			SAFE_RELEASE(bufferResources->mBuffer);
271 		}
272 		else
273 		{
274 			bufferResources = OGRE_ALLOC_T(BufferResources, 1, MEMCATEGORY_RENDERSYS);
275 			mMapDeviceToBufferResources[d3d9Device] = bufferResources;
276 		}
277 
278 		bufferResources->mBuffer = NULL;
279 		bufferResources->mOutOfDate = true;
280 		bufferResources->mLockOffset = 0;
281 		bufferResources->mLockLength = getSizeInBytes();
282 		bufferResources->mLockOptions = HBL_NORMAL;
283 		bufferResources->mLastUsedFrame = Root::getSingleton().getNextFrameNumber();
284 
285 		// Create the Index buffer
286 		hr = d3d9Device->CreateIndexBuffer(
287 			static_cast<UINT>(mSizeInBytes),
288 			D3D9Mappings::get(mUsage),
289 			D3D9Mappings::get(mIndexType),
290 			ePool,
291 			&bufferResources->mBuffer,
292 			NULL
293 			);
294 
295 		if (FAILED(hr))
296 		{
297 			String msg = DXGetErrorDescription(hr);
298 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
299 				"Cannot create D3D9 Index buffer: " + msg,
300 				"D3D9HardwareIndexBuffer::createBuffer");
301 		}
302 
303 		hr = bufferResources->mBuffer->GetDesc(&mBufferDesc);
304 		if (FAILED(hr))
305 		{
306 			String msg = DXGetErrorDescription(hr);
307 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
308 				"Cannot get D3D9 Index buffer desc: " + msg,
309 				"D3D9HardwareIndexBuffer::createBuffer");
310 		}
311 		// Update source buffer if need to.
312 		if (mSourceBuffer == NULL)
313 		{
314 			mSourceBuffer = bufferResources;
315 		}
316 
317 		// This is a new buffer and source buffer exists we must update the content now
318 		// to prevent situation where the source buffer will be destroyed and we won't be able to restore its content.
319 		else
320 		{
321 			updateBufferContent(bufferResources);
322 		}
323 	}
324 	//---------------------------------------------------------------------
getD3DIndexBuffer(void)325 	IDirect3DIndexBuffer9* D3D9HardwareIndexBuffer::getD3DIndexBuffer(void)
326 	{
327 		IDirect3DDevice9* d3d9Device = D3D9RenderSystem::getActiveD3D9Device();
328 		DeviceToBufferResourcesIterator it;
329 
330 		// Find the index buffer of this device.
331 		it = mMapDeviceToBufferResources.find(d3d9Device);
332 
333 		// Case index buffer was not found for the current device -> create it.
334 		if (it == mMapDeviceToBufferResources.end() || it->second->mBuffer == NULL)
335 		{
336 			createBuffer(d3d9Device, mBufferDesc.Pool);
337 			it = mMapDeviceToBufferResources.find(d3d9Device);
338 		}
339 
340 		// Make sure that the buffer content is updated.
341 		updateBufferContent(it->second);
342 
343 		it->second->mLastUsedFrame = Root::getSingleton().getNextFrameNumber();
344 
345 		return it->second->mBuffer;
346 	}
347 
348 	//---------------------------------------------------------------------
updateBufferContent(BufferResources * bufferResources)349 	void D3D9HardwareIndexBuffer::updateBufferContent(BufferResources* bufferResources)
350 	{
351 		if (bufferResources->mOutOfDate)
352 		{
353 			if (mShadowBuffer != NULL)
354 			{
355 				const char* shadowData = (const char*)mShadowBuffer->lock(HBL_NORMAL);
356 				updateBufferResources(shadowData, bufferResources);
357 				mShadowBuffer->unlock();
358 			}
359 			else if (mSourceBuffer != bufferResources && (mUsage & HardwareBuffer::HBU_WRITE_ONLY) == 0)
360 			{
361 				mSourceBuffer->mLockOptions = HBL_READ_ONLY;
362 				mSourceLockedBytes = _lockBuffer(mSourceBuffer, 0, mSizeInBytes);
363 				updateBufferResources(mSourceLockedBytes, bufferResources);
364 				_unlockBuffer(mSourceBuffer);
365 				mSourceLockedBytes = NULL;
366 			}
367 		}
368 	}
369 
370 	//---------------------------------------------------------------------
updateBufferResources(const char * systemMemoryBuffer,BufferResources * bufferResources)371 	bool D3D9HardwareIndexBuffer::updateBufferResources(const char* systemMemoryBuffer,
372 		BufferResources* bufferResources)
373 	{
374 		assert(bufferResources != NULL);
375 		assert(bufferResources->mBuffer != NULL);
376 		assert(bufferResources->mOutOfDate);
377 
378 
379 		char* dstBytes = _lockBuffer(bufferResources, bufferResources->mLockOffset, bufferResources->mLockLength);
380 		memcpy(dstBytes, systemMemoryBuffer, bufferResources->mLockLength);
381 		_unlockBuffer(bufferResources);
382 
383 		return true;
384 	}
385 
386 	//---------------------------------------------------------------------
_lockBuffer(BufferResources * bufferResources,size_t offset,size_t length)387 	char* D3D9HardwareIndexBuffer::_lockBuffer(BufferResources* bufferResources, size_t offset, size_t length)
388 	{
389 		HRESULT hr;
390 		char* pSourceBytes;
391 
392 
393 		// Lock the buffer.
394 		hr = bufferResources->mBuffer->Lock(
395 			static_cast<UINT>(offset),
396 			static_cast<UINT>(length),
397 			(void**)&pSourceBytes,
398 			D3D9Mappings::get(mSourceBuffer->mLockOptions, mUsage));
399 
400 		if (FAILED(hr))
401 		{
402 			String msg = DXGetErrorDescription(hr);
403 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
404 				"Cannot lock D3D9 vertex buffer: " + msg,
405 				"D3D9HardwareVertexBuffer::_lockBuffer");
406 		}
407 
408 		return pSourceBytes;
409 	}
410 
411 	//---------------------------------------------------------------------
_unlockBuffer(BufferResources * bufferResources)412 	void D3D9HardwareIndexBuffer::_unlockBuffer( BufferResources* bufferResources )
413 	{
414 		HRESULT hr;
415 
416 		// Unlock the buffer.
417 		hr = bufferResources->mBuffer->Unlock();
418 		if (FAILED(hr))
419 		{
420 			String msg = DXGetErrorDescription(hr);
421 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
422 				"Cannot unlock D3D9 vertex buffer: " + msg,
423 				"D3D9HardwareVertexBuffer::_unlockBuffer");
424 		}
425 
426 		// Reset attributes.
427 		bufferResources->mOutOfDate = false;
428 		bufferResources->mLockOffset = mSizeInBytes;
429 		bufferResources->mLockLength = 0;
430 		bufferResources->mLockOptions = HBL_NORMAL;
431 
432 	}
433 }
434