Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / driver / direct3d / driver_direct3d_vertex.cpp
blob985f29b93a05138f39f2206588bf9ae1aa9af867
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stddirect3d.h"
22 #include "nel/3d/vertex_buffer.h"
23 #include "nel/3d/light.h"
24 #include "nel/3d/index_buffer.h"
25 #include "nel/misc/rect.h"
26 #include "nel/3d/viewport.h"
27 #include "nel/3d/scissor.h"
28 #include "nel/3d/u_driver.h"
30 #include "driver_direct3d.h"
32 #ifdef DEBUG_NEW
33 #define new DEBUG_NEW
34 #endif
36 using namespace std;
37 using namespace NLMISC;
39 // 500K min.
40 #define NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE (20*1024)
44 namespace NL3D
47 // ***************************************************************************
49 CVBDrvInfosD3D::CVBDrvInfosD3D(CDriverD3D *drv, ItVBDrvInfoPtrList it, CVertexBuffer *vb) : IVBDrvInfos(drv, it, vb)
51 H_AUTO_D3D(CVBDrvInfosD3D_CVBDrvInfosD3D)
52 VertexDecl = NULL;
53 VertexDeclAliasDiffuseToSpecular = NULL;
54 ColorOffset = 0;
55 VertexBuffer = NULL;
56 Usage = 0;
57 VolatileVertexBuffer = NULL;
58 VertexDeclNoDiffuse = NULL;
59 #ifdef NL_DEBUG
60 Locked = false;
61 #endif
62 Driver = drv;
65 // ***************************************************************************
67 uint vertexCount=0;
69 CVBDrvInfosD3D::~CVBDrvInfosD3D()
71 H_AUTO_D3D(CVBDrvInfosD3D_CVBDrvInfosD3D)
72 CDriverD3D *driver = static_cast<CDriverD3D*>(_Driver);
73 // Restore non resident memory
74 if (VertexBufferPtr)
76 VertexBufferPtr->setLocation(CVertexBuffer::NotResident);
77 VertexBufferPtr = NULL;
80 // Don't release VertexDecl, it is release by the driver
81 if (VertexBuffer && !Volatile)
83 if (Driver)
85 if (Driver->_VertexBufferCache.VertexBuffer == VertexBuffer)
87 Driver->_VertexBufferCache.VertexBuffer = NULL;
88 Driver->touchRenderVariable(&Driver->_VertexBufferCache);
91 vertexCount--;
92 VertexBuffer->Release();
95 // Stats
96 if (Hardware)
97 driver->_VertexBufferHardSet.erase(this);
99 #ifdef NL_DEBUG
100 if (Locked)
102 nlinfo("VBuffer %s is still locked at destruction", VertexBufferPtr->getName().c_str()) ;
103 CDriverD3D *drv = NLMISC::safe_cast<CDriverD3D *>(_Driver);
104 drv->_LockedBuffers.erase(this);
106 #endif
111 // ***************************************************************************
113 uint8 *CVBDrvInfosD3D::lock (uint begin, uint end, bool readOnly)
115 H_AUTO_D3D(CVBDrvInfosD3D_lock)
116 nlassert (begin != end);
117 CDriverD3D *driver = static_cast<CDriverD3D*>(_Driver);
118 //nlinfo("lock from %s", VertexBufferPtr->getName().c_str());
119 #ifdef NL_DEBUG
120 nlassert(!Locked);
121 driver->_LockedBuffers.insert(this);
122 Locked = true;
123 static volatile bool dumpLockedBuffers = false;
124 if (dumpLockedBuffers)
126 nlinfo("Num locked buffers = %d", (int) driver->_LockedBuffers.size());
127 for(std::set<CVBDrvInfosD3D *>::iterator it = driver->_LockedBuffers.begin(); it != driver->_LockedBuffers.end(); ++it)
129 if (!(*it)->VertexBufferPtr)
131 nlinfo("Empty buffer");
133 else
135 nlinfo("Buffer %s at %p is Locked", (*it)->VertexBufferPtr->getName().c_str(), *it);
139 #endif
140 if (Volatile)
142 // Lock the good buffer
143 CVolatileVertexBuffer *&buffer = VolatileRAM ? (driver->_VolatileVertexBufferRAM[driver->_CurrentRenderPass&1]):
144 (driver->_VolatileVertexBufferAGP[driver->_CurrentRenderPass&1]);
145 uint8 *ptr = (uint8*)buffer->lock (end-begin, Stride, Offset);
146 if (!ptr)
148 // buffer full, swap them
149 CVolatileVertexBuffer *&bufferOther = VolatileRAM ? (driver->_VolatileVertexBufferRAM[(driver->_CurrentRenderPass + 1) &1]):
150 (driver->_VolatileVertexBufferAGP[(driver->_CurrentRenderPass + 1) &1]);
151 std::swap(buffer, bufferOther);
152 buffer->reset();
153 ptr = (uint8*)buffer->lock (end-begin, Stride, Offset);
154 nlassert(ptr);
156 nlassert(!VolatileVertexBuffer);
157 VolatileVertexBuffer = buffer;
158 VertexBuffer = buffer->VertexBuffer;
159 ptr -= begin;
161 // Current lock time
162 VolatileLockTime = driver->_CurrentRenderPass;
164 // Touch the vertex buffer
165 driver->touchRenderVariable (&driver->_VertexBufferCache);
167 return ptr;
169 else
171 nlassert (VertexBuffer);
172 // Lock Profile?
173 TTicks beforeLock = 0;
174 if(driver->_VBHardProfiling /*&& Hardware*/)
176 beforeLock= CTime::getPerformanceTime();
179 void *pbData;
180 if (VertexBuffer->Lock ( begin, end-begin, &pbData, readOnly?D3DLOCK_READONLY:0) != D3D_OK)
181 return NULL;
183 // Lock Profile?
184 if(driver->_VBHardProfiling /*&& Hardware*/)
186 TTicks afterLock;
187 afterLock= CTime::getPerformanceTime();
188 driver->appendVBHardLockProfile(afterLock-beforeLock, VertexBufferPtr);
190 return (uint8*)pbData;
194 // ***************************************************************************
196 void CVBDrvInfosD3D::unlock (uint /* begin */, uint /* end */)
198 H_AUTO_D3D(CVBDrvInfosD3D_unlock )
199 CDriverD3D *drv = NLMISC::safe_cast<CDriverD3D *>(_Driver);
200 #ifdef NL_DEBUG
201 nlassert(Locked);
202 drv->_LockedBuffers.erase(this);
203 Locked = false;
204 #endif
205 //nlinfo("unlock from %s", VertexBufferPtr->getName().c_str());
206 if (Volatile)
208 nlassert(VolatileVertexBuffer);
209 VolatileVertexBuffer->unlock ();
210 VolatileVertexBuffer = NULL;
212 else
213 VertexBuffer->Unlock ();
216 // ***************************************************************************
218 const D3DDECLTYPE RemapVertexBufferTypeNeL2D3D[CVertexBuffer::NumType]=
220 D3DDECLTYPE_UNUSED, // Double1,
221 D3DDECLTYPE_FLOAT1, // Float1,
222 D3DDECLTYPE_UNUSED, // Short1,
223 D3DDECLTYPE_UNUSED, // Double2,
224 D3DDECLTYPE_FLOAT2, // Float2,
225 D3DDECLTYPE_SHORT2, // Short2,
226 D3DDECLTYPE_UNUSED, // Double3,
227 D3DDECLTYPE_FLOAT3, // Float3,
228 D3DDECLTYPE_UNUSED, // Short3,
229 D3DDECLTYPE_UNUSED, // Double4,
230 D3DDECLTYPE_FLOAT4, // Float4,
231 D3DDECLTYPE_SHORT4, // Short4,
232 D3DDECLTYPE_D3DCOLOR, // UChar4,
235 // ***************************************************************************
237 const D3DDECLUSAGE RemapVertexBufferUsageNeL2D3D[CVertexBuffer::NumValue]=
239 D3DDECLUSAGE_POSITION, // Position
240 D3DDECLUSAGE_NORMAL, // Normal
241 D3DDECLUSAGE_TEXCOORD, // TexCoord0
242 D3DDECLUSAGE_TEXCOORD, // TexCoord1
243 D3DDECLUSAGE_TEXCOORD, // TexCoord2
244 D3DDECLUSAGE_TEXCOORD, // TexCoord3
245 D3DDECLUSAGE_TEXCOORD, // TexCoord4
246 D3DDECLUSAGE_TEXCOORD, // TexCoord5
247 D3DDECLUSAGE_TEXCOORD, // TexCoord6
248 D3DDECLUSAGE_TEXCOORD, // TexCoord7
249 D3DDECLUSAGE_COLOR, // PrimaryColor
250 D3DDECLUSAGE_COLOR, // SecondaryColor
251 D3DDECLUSAGE_BLENDWEIGHT, // Weight
252 D3DDECLUSAGE_BLENDINDICES, // PaletteSkin
253 D3DDECLUSAGE_FOG, // Fog
256 // ***************************************************************************
258 const uint RemapVertexBufferIndexNeL2D3D[CVertexBuffer::NumValue]=
260 0, // Position
261 0, // Normal
262 0, // TexCoord0
263 1, // TexCoord1
264 2, // TexCoord2
265 3, // TexCoord3
266 4, // TexCoord4
267 5, // TexCoord5
268 6, // TexCoord6
269 7, // TexCoord7
270 0, // PrimaryColor
271 1, // SecondaryColor
272 0, // Weight
273 0, // PaletteSkin
274 0, // Fog
277 // ***************************************************************************
279 DWORD RemapVertexBufferUsage[CVertexBuffer::LocationCount]=
281 D3DUSAGE_DYNAMIC, // RAMResident
282 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, // AGPResident
283 D3DUSAGE_WRITEONLY, // VRAMResident
284 0, // Not used
287 // ***************************************************************************
289 D3DPOOL RemapVertexBufferPool[CVertexBuffer::LocationCount]=
291 D3DPOOL_SYSTEMMEM, // RAMResident
292 D3DPOOL_DEFAULT, // AGPResident
293 D3DPOOL_DEFAULT, // VRAMResident
294 D3DPOOL_DEFAULT, // Not used
298 // ***************************************************************************
300 bool CDriverD3D::activeVertexBuffer(CVertexBuffer& VB)
302 H_AUTO_D3D(CDriverD3D_activeVertexBuffer)
303 // Must not be locked
304 nlassert (!VB.isLocked());
306 // Must not be empty
307 if (VB.capacity() == 0)
308 return false;
311 const bool touched = (VB.getTouchFlags() & (CVertexBuffer::TouchedReserve|CVertexBuffer::TouchedVertexFormat)) != 0;
313 CVBDrvInfosD3D *info = static_cast<CVBDrvInfosD3D*>(static_cast<IVBDrvInfos*>(VB.DrvInfos));
315 // Volatile buffers must be filled at each pass
316 nlassertex (!info || !info->Volatile || VB.getKeepLocalMemory() || (info->VolatileLockTime == _CurrentRenderPass), ("Volatile buffers must be filled at each pass"));
318 // Build the driver info
319 if (touched)
321 // Delete previous vertex buffer info
322 if (VB.DrvInfos)
324 delete VB.DrvInfos;
325 nlassert (VB.DrvInfos == NULL);
328 // Force the vertex color format to BGRA
329 VB.setVertexColorFormat (CVertexBuffer::TBGRA);
331 // Rebuild it
332 _VBDrvInfos.push_front (NULL);
333 ItVBDrvInfoPtrList ite = _VBDrvInfos.begin();
334 info = new CVBDrvInfosD3D(this, ite, &VB);
335 *ite = info;
337 // Use vertex color ?
338 info->UseVertexColor = (VB.getVertexFormat()&CVertexBuffer::PrimaryColorFlag) != 0;
339 info->Stride = (uint8)VB.getVertexSize();
341 // Create the vertex declaration
342 if (!createVertexDeclaration (VB.getVertexFormat(), VB.getValueTypePointer(), &(info->VertexDecl), info->ColorOffset, false, false))
343 return false;
344 info->VertexDeclAliasDiffuseToSpecular = NULL;
345 info->VertexDeclNoDiffuse = NULL;
346 if (VB.hasValueEx(CVertexBuffer::PrimaryColor) && !VB.hasValueEx(CVertexBuffer::SecondaryColor))
348 uint colorOffset2;
349 if (!createVertexDeclaration (VB.getVertexFormat(), VB.getValueTypePointer(), &(info->VertexDeclAliasDiffuseToSpecular), colorOffset2, true, false))
350 return false;
351 nlassert(colorOffset2 == info->ColorOffset); // should be the same value
353 if (_NbNeLTextureStages == 3 && info->UseVertexColor)
355 // Fix for radeon 7xxx -> if vertex color is not used it should not be declared (example : lighted material + vertex color but, no vertexColorLighted)
356 uint colorOffset2;
357 if (!createVertexDeclaration (VB.getVertexFormat(), VB.getValueTypePointer(), &(info->VertexDeclNoDiffuse), colorOffset2, false, true))
358 return false;
361 // Create the vertex buffer
362 const uint size = VB.capacity()*VB.getVertexSize();
363 uint preferredMemory = 0;
364 if (_DisableHardwareVertexArrayAGP)
366 preferredMemory = CVertexBuffer::RAMResident;
367 info->Volatile = false;
369 else
371 switch (VB.getPreferredMemory ())
373 case CVertexBuffer::RAMPreferred:
374 preferredMemory = CVertexBuffer::RAMResident;
375 info->Volatile = false;
376 break;
377 case CVertexBuffer::AGPPreferred:
378 preferredMemory = CVertexBuffer::AGPResident;
379 info->Volatile = false;
380 break;
381 case CVertexBuffer::StaticPreferred:
382 if (getStaticMemoryToVRAM())
383 preferredMemory = CVertexBuffer::VRAMResident;
384 else
385 preferredMemory = CVertexBuffer::AGPResident;
386 info->Volatile = false;
387 break;
388 case CVertexBuffer::RAMVolatile:
389 preferredMemory = CVertexBuffer::RAMResident;
390 info->Volatile = true;
391 break;
392 case CVertexBuffer::AGPVolatile:
393 preferredMemory = CVertexBuffer::AGPResident;
394 info->Volatile = true;
395 break;
399 // Volatile vertex buffer
400 if (info->Volatile)
402 nlassert (info->VertexBuffer == NULL);
403 info->Hardware = false;
404 info->VolatileRAM = preferredMemory == CVertexBuffer::RAMResident;
406 else
408 // Offset will be 0
409 info->Offset = 0;
411 bool success;
414 success = _DeviceInterface->CreateVertexBuffer(size, RemapVertexBufferUsage[preferredMemory],
415 0, RemapVertexBufferPool[preferredMemory], &(info->VertexBuffer), NULL) == D3D_OK;
416 if (success)
417 break;
419 while (preferredMemory--);
420 if (!success)
421 return false;
423 ++vertexCount;
425 // Hardware ?
426 info->Hardware = preferredMemory != CVertexBuffer::RAMResident;
428 // Stats
429 if (info->Hardware)
430 _VertexBufferHardSet.insert(info);
433 // Release the local vertex buffer
434 VB.DrvInfos = info;
435 VB.setLocation ((CVertexBuffer::TLocation)preferredMemory);
437 // Force the vertex buffer update
438 touchRenderVariable (&_VertexDeclCache);
439 touchRenderVariable (&_VertexBufferCache);
442 // Set the current vertex buffer
443 nlassert (info);
445 // Fill the buffer if in local memory
446 VB.fillBuffer ();
448 setVertexDecl (info->VertexDecl, info->VertexDeclAliasDiffuseToSpecular, info->VertexDeclNoDiffuse, info->Stride);
449 //setVertexBuffer (info->VertexBuffer, info->Offset, info->Stride, info->UseVertexColor, VB.getNumVertices(), VB.getPreferredMemory(), info->Usage, info->ColorOffset);
450 setVertexBuffer (info->VertexBuffer, info->Offset, info->Stride, info->UseVertexColor, VB.getNumVertices(), VB.getPreferredMemory(), info->Usage, info->ColorOffset);
453 // Set UVRouting
454 const uint8 *uvRouting = VB.getUVRouting();
455 uint i;
456 for (i=0; i<MaxTexture; i++)
457 setTextureIndexUV (i, uvRouting[i]);
460 // backup uv-routing, because some shader may change the routing
461 // For example, if the same vb is used for lightmap, then for standard shader, then uv routing will be wrong
462 std::copy(uvRouting, uvRouting + MaxTexture, _CurrentUVRouting);
464 /* Hulud test : read in a "write only" vertex buffer. Seams to work well. */
466 // Read the vertex buffer
467 CVBDrvInfosD3D *info = static_cast<CVBDrvInfosD3D*>(static_cast<IVBDrvInfos*>(VB.DrvInfos));
468 static vector<uint8> temp;
469 uint size = VB.capacity()*VB.getVertexSize();
471 // No special flag for the lock, the driver should return a valid vertex buffer pointer with previous values.
472 uint8 *out = info->lock (0, 0, false);
473 nlassert (out);
475 temp.resize (size);
476 memcpy (&(temp[0]), out, size);
478 info->unlock (0, 0);
479 out = info->lock (0, 0, false);
480 nlassert (out);
482 memcpy (out, &(temp[0]), size);
484 info->unlock (0, 0);
487 return true;
491 // ***************************************************************************
492 bool CDriverD3D::createVertexDeclaration (uint16 vertexFormat, const uint8 *typeArray,
493 IDirect3DVertexDeclaration9 **vertexDecl,
494 uint &colorOffset,
495 bool aliasDiffuseToSpecular,
496 bool bypassDiffuse,
497 uint *stride)
499 H_AUTO_D3D(CDriverD3D_createVertexDeclaration)
500 CVertexDeclaration declaration;
502 if (aliasDiffuseToSpecular)
504 // there should be a single color stream : diffuse
505 nlassert(vertexFormat & CVertexBuffer::PrimaryColorFlag); // diffuse required
506 nlassert(!(vertexFormat & CVertexBuffer::SecondaryColorFlag)); // specular should not be used
509 // Set the vertex format
510 uint i;
511 uint j = 0;
512 uint offset = 0;
513 colorOffset = 0;
514 for (i=0; i<CVertexBuffer::NumValue; i++)
516 // Slot used ?
517 if (vertexFormat & (1<<i))
519 if ((i != CVertexBuffer::Weight && i != CVertexBuffer::PaletteSkin) || _PixelShaderVersion != D3DPS_VERSION(1, 4)) // fix for radeon 8500/9000/9200 : hand when this is declared and not used
520 // don't let gap for other cards else render bug on some ...
522 D3DVERTEXELEMENT9 &vertexElement = declaration.VertexElements[j];
523 vertexElement.Stream = 0;
524 vertexElement.Type = BYTE(RemapVertexBufferTypeNeL2D3D[(uint)typeArray[i]]);
525 vertexElement.Offset = WORD(offset);
526 vertexElement.Method = D3DDECLMETHOD_DEFAULT;
527 vertexElement.Usage = BYTE(RemapVertexBufferUsageNeL2D3D[(uint)i]);
528 if (aliasDiffuseToSpecular && i == CVertexBuffer::PrimaryColor)
530 vertexElement.UsageIndex = 1; // Map to specular stream -> this free PrimaryColor to build a constant
531 // Ueful to emulate per stage constant (which we can do on 2 stages only)
533 else
535 vertexElement.UsageIndex = BYTE(RemapVertexBufferIndexNeL2D3D[(uint)i]);
538 // nico : Fix for Radeon 7xxx series
539 // Vertex declaration doesn't work when the vertex layout has vertex color defined after tex coord.
540 // For example, the following layout (Position/TexCoord0/Diffuse) will silently be converted into (Position/Diffuse/TexCoord0)
541 // It seems that the driver tries to map the vertex declaration to the matching FVF. FVF has a prefined order and requires Diffuse to appear
542 // before texture coordinates in the vertex. Don't know if it is a limitation of D3D related to the 7xxx sries of if it is a driver bug.
543 // The D3D debug dll doesn't issue a warning about it.
544 // To solve this 2 vertex streams are declared :
545 // - First streams contains Position/Normal/Texcoord
546 // - When vertex color are used, second stream contains Diffuse/Specular vertex component(s)
547 // In fact the 2 streams map to the same vertex buffer, but the 2nd stream has an added offset to point on the color component
548 // I tried to add this offset directly into the vertex declaration, but D3D complains about it...
549 // If the following field contains a non 0 value, then a second stream must be used for diffuse/specular with the given offset
550 if (_NbNeLTextureStages == 3)
552 if (vertexElement.Usage == D3DDECLUSAGE_COLOR)
554 if (bypassDiffuse)
556 continue;
558 vertexElement.Stream = 1;
559 if (colorOffset == 0)
561 vertexElement.Offset = 0;
562 colorOffset = offset;
564 else
566 vertexElement.Offset = 4;
570 j++;
572 offset += CVertexBuffer::SizeType[typeArray[i]];
576 // Set the stride ?
577 if (stride)
578 *stride = offset;
580 // End
581 D3DVERTEXELEMENT9 end = D3DDECL_END();
582 declaration.VertexElements[j] = end;
584 // Look for the same vertex declaration
585 std::list<CVertexDeclaration>::iterator ite = _VertexDeclarationList.begin();
586 while (ite != _VertexDeclarationList.end())
588 for (i=0; i<=j; i++)
590 const D3DVERTEXELEMENT9 &vertexElementNew = declaration.VertexElements[i];
591 const D3DVERTEXELEMENT9 &vertexElementOld = ite->VertexElements[i];
592 if ( (vertexElementNew.Stream != vertexElementOld.Stream) ||
593 (vertexElementNew.Type != vertexElementOld.Type) ||
594 (vertexElementNew.Offset != vertexElementOld.Offset) ||
595 (vertexElementNew.Method != vertexElementOld.Method) ||
596 (vertexElementNew.Usage != vertexElementOld.Usage) ||
597 (vertexElementNew.UsageIndex != vertexElementOld.UsageIndex))
600 break;
604 // All is good ?
605 if (i == (j+1))
607 // It is the same vertex declaration
608 *vertexDecl = ite->VertexDecl;
609 return true;
612 ite++;
615 // Not found, create the vertex declaration
616 if (_DeviceInterface->CreateVertexDeclaration (declaration.VertexElements, &(declaration.VertexDecl)) != D3D_OK)
618 return false;
621 // Add the vertex declaration
622 _VertexDeclarationList.push_back (declaration);
624 // Set the final declaration pointer
625 *vertexDecl = declaration.VertexDecl;
627 return true;
632 // ***************************************************************************
634 bool CDriverD3D::supportVertexBufferHard() const
636 H_AUTO_D3D(CDriverD3D_supportVertexBufferHard)
637 return !_DisableHardwareVertexArrayAGP;
640 // ***************************************************************************
642 bool CDriverD3D::supportVolatileVertexBuffer() const
644 H_AUTO_D3D(CDriverD3D_supportVolatileVertexBuffer)
645 return true;
649 // ***************************************************************************
651 void CDriverD3D::disableHardwareVertexArrayAGP()
653 H_AUTO_D3D(CDriverD3D_disableHardwareVertexArrayAGP)
654 _DisableHardwareVertexArrayAGP = true;
657 // ***************************************************************************
659 uint CDriverD3D::getMaxVerticesByVertexBufferHard() const
661 H_AUTO_D3D(CDriverD3D_getMaxVerticesByVertexBufferHard)
662 return _MaxVerticesByVertexBufferHard;
665 // ***************************************************************************
667 uint32 CDriverD3D::getAvailableVertexAGPMemory ()
669 H_AUTO_D3D(CDriverD3D_getAvailableVertexAGPMemory )
670 return _AGPMemoryAllocated;
673 // ***************************************************************************
675 uint32 CDriverD3D::getAvailableVertexVRAMMemory ()
677 H_AUTO_D3D(CDriverD3D_getAvailableVertexVRAMMemory )
678 return _VRAMMemoryAllocated;
681 // ***************************************************************************
683 bool CDriverD3D::initVertexBufferHard(uint agpMem, uint vramMem)
685 H_AUTO_D3D(CDriverD3D_initVertexBufferHard)
686 if(!supportVertexBufferHard())
687 return false;
689 // First, reset any VBHard created.
690 bool ok= true;
692 // Try to allocate AGPMemory.
693 _AGPMemoryAllocated = agpMem;
694 if(_AGPMemoryAllocated>0)
696 _AGPMemoryAllocated&= ~15; // ensure 16-bytes aligned mem count (maybe useful :) ).
697 _AGPMemoryAllocated= max(_AGPMemoryAllocated, (uint32)NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE);
698 while(_AGPMemoryAllocated >= NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
700 IDirect3DVertexBuffer9 *vb;
701 if (_DeviceInterface->CreateVertexBuffer (_AGPMemoryAllocated, D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC, 0,
702 D3DPOOL_DEFAULT, &vb, NULL) == D3D_OK)
704 D3DVERTEXBUFFER_DESC desc;
705 nlverify (vb->GetDesc (&desc) == D3D_OK);
706 if (((desc.Usage&(D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC)) == (D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC)) &&
707 (desc.Pool == D3DPOOL_DEFAULT))
709 nlinfo("%.d vertices supported", _MaxVerticesByVertexBufferHard);
710 nlinfo("Success to allocate %.1f Mo of AGP VAR Ram", _AGPMemoryAllocated / 1000000.f);
711 vb->Release();
712 break;
714 else
715 vb->Release();
717 else
719 _AGPMemoryAllocated/=2;
720 _AGPMemoryAllocated &=~15;
724 if(_AGPMemoryAllocated< NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
726 nlwarning("%.d vertices supported", _MaxVerticesByVertexBufferHard);
727 nlwarning("Failed to allocate %.1f Mo of AGP VAR Ram", NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE / 1000000.f);
728 ok= false;
733 // Try to allocate VRAMMemory.
734 _VRAMMemoryAllocated = vramMem;
735 if(_VRAMMemoryAllocated>0)
737 _VRAMMemoryAllocated&= ~15; // ensure 16-bytes aligned mem count (maybe useful :) ).
738 _VRAMMemoryAllocated= max(_VRAMMemoryAllocated, (uint32)NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE);
739 while(_VRAMMemoryAllocated>= NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
741 IDirect3DVertexBuffer9 *vb;
742 if (_DeviceInterface->CreateVertexBuffer (_VRAMMemoryAllocated, D3DUSAGE_WRITEONLY, 0,
743 D3DPOOL_DEFAULT, &vb, NULL) == D3D_OK)
745 vb->Release();
746 break;
748 else
750 _VRAMMemoryAllocated/=2;
751 _VRAMMemoryAllocated &=~15;
755 if(_VRAMMemoryAllocated< NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
757 ok= false;
761 return ok;
764 // ***************************************************************************
766 void CDriverD3D::mapTextureStageToUV(uint stage, uint uv)
768 H_AUTO_D3D(CDriverD3D_mapTextureStageToUV)
769 setTextureIndexUV (stage, uv);
772 // ***************************************************************************
773 // CVolatileVertexBuffer
774 // ***************************************************************************
776 CVolatileVertexBuffer::CVolatileVertexBuffer()
778 H_AUTO_D3D(CVolatileVertexBuffer_CVolatileVertexBuffer)
779 VertexBuffer = NULL;
780 Locked = false;
783 // ***************************************************************************
785 CVolatileVertexBuffer::~CVolatileVertexBuffer()
787 H_AUTO_D3D(CVolatileVertexBuffer_CVolatileVertexBufferDtor)
788 release ();
791 // ***************************************************************************
793 void CVolatileVertexBuffer::release ()
795 H_AUTO_D3D(CVolatileVertexBuffer_release )
796 if (VertexBuffer)
797 VertexBuffer->Release();
798 VertexBuffer = NULL;
801 // ***************************************************************************
803 void CVolatileVertexBuffer::init (CVertexBuffer::TLocation location, uint size, uint maxSize, CDriverD3D *driver)
805 H_AUTO_D3D(CVolatileVertexBuffer_init )
806 release();
807 if (maxSize < size) maxSize = size;
808 MaxSize = maxSize;
809 // Init the buffer
810 Location = location;
811 Size = size;
812 Driver = driver;
814 // Allocate the vertex buffer
815 if (Driver->_DeviceInterface->CreateVertexBuffer(size, RemapVertexBufferUsage[location],
816 0, RemapVertexBufferPool[location], &VertexBuffer, NULL) != D3D_OK)
818 // Location in RAM must not failed
819 nlassert (location != CVertexBuffer::RAMResident);
821 // Allocate in RAM
822 nlverify (Driver->_DeviceInterface->CreateVertexBuffer(size, RemapVertexBufferUsage[CVertexBuffer::RAMResident],
823 0, RemapVertexBufferPool[CVertexBuffer::RAMResident], &VertexBuffer, NULL) != D3D_OK);
825 Location = CVertexBuffer::RAMResident;
829 // ***************************************************************************
831 //volatile int callCount = 0;
832 //volatile int callStop = 17700;
836 void *CVolatileVertexBuffer::lock (uint size, uint stride, uint &offset)
838 nlassertex(!Locked, ("Volatile buffer usage should follow an atomic lock/unlock/render sequence"));
839 H_AUTO_D3D(CVolatileVertexBuffer_lock)
840 /* If not enough room to allocate this buffer, resise the buffer to Size+Size/2 but do not reset CurrentIndex
841 * to be sure the buffer will be large enough next pass. */
843 //if (callCount == callStop)
844 // nlstop;
845 //callCount++;
847 // Align the index
848 uint mod = CurrentIndex / stride;
849 if (CurrentIndex != (mod*stride))
850 CurrentIndex = (mod+1)*stride;
853 // Enough room for this vertex ?
854 if (CurrentIndex+size+stride > Size)
856 if (CurrentIndex+size > MaxSize && CurrentIndex != 0)
858 reset();
859 if (size > MaxSize)
861 init (Location, std::max (std::min(Size+Size/2, MaxSize), size), MaxSize, Driver);
864 else
866 // Max size not reached, so reallocate
867 init (Location, std::max (std::min(Size+Size/2, MaxSize), CurrentIndex+size), MaxSize, Driver);
868 reset(); // reallocate will cause a cpu stall anyway ...
872 // Lock Profile?
873 TTicks beforeLock = 0;
874 if(Driver->_VBHardProfiling)
876 beforeLock= CTime::getPerformanceTime();
878 // Lock the buffer, noblocking lock here if not the first allocation since a reset
880 VOID *pbData;
881 if (CurrentIndex==0)
883 nlverify (VertexBuffer->Lock (0, Size, &pbData, D3DLOCK_DISCARD) == D3D_OK);
885 else
887 nlverify (VertexBuffer->Lock (CurrentIndex, size, &pbData, D3DLOCK_NOOVERWRITE) == D3D_OK);
889 if(Driver->_VBHardProfiling)
891 TTicks afterLock;
892 afterLock= CTime::getPerformanceTime();
893 Driver->_VolatileVBLockTime += afterLock - beforeLock;
896 // Old buffer position
897 offset = CurrentIndex/stride;
899 // New buffer position
900 CurrentIndex += size;
901 Locked = true;
902 return pbData;
905 // ***************************************************************************
907 void CVolatileVertexBuffer::unlock ()
909 H_AUTO_D3D(CVolatileVertexBuffer_unlock )
910 nlassertex(Locked, ("Volatile buffer usage should follow an atomic lock/unlock/render sequence"));
911 nlverify (VertexBuffer->Unlock () == D3D_OK);
912 Locked = false;
915 // ***************************************************************************
916 void CVolatileVertexBuffer::reset ()
918 H_AUTO_D3D(CVolatileVertexBuffer_reset )
919 CurrentIndex = 0;
920 // callCount = 0;
923 // ***************************************************************************
925 } // NL3D