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