aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llrender/llvertexbuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llrender/llvertexbuffer.cpp922
1 files changed, 922 insertions, 0 deletions
diff --git a/linden/indra/llrender/llvertexbuffer.cpp b/linden/indra/llrender/llvertexbuffer.cpp
new file mode 100644
index 0000000..b94f593
--- /dev/null
+++ b/linden/indra/llrender/llvertexbuffer.cpp
@@ -0,0 +1,922 @@
1#include "linden_common.h"
2
3#include "llvertexbuffer.h"
4// #include "llrender.h"
5#include "llglheaders.h"
6#include "llmemory.h"
7#include "llmemtype.h"
8
9//============================================================================
10
11//static
12S32 LLVertexBuffer::sCount = 0;
13S32 LLVertexBuffer::sGLCount = 0;
14BOOL LLVertexBuffer::sEnableVBOs = TRUE;
15U32 LLVertexBuffer::sGLRenderBuffer = 0;
16U32 LLVertexBuffer::sGLRenderIndices = 0;
17U32 LLVertexBuffer::sLastMask = 0;
18BOOL LLVertexBuffer::sVBOActive = FALSE;
19BOOL LLVertexBuffer::sIBOActive = FALSE;
20U32 LLVertexBuffer::sAllocatedBytes = 0;
21BOOL LLVertexBuffer::sRenderActive = FALSE;
22
23std::vector<U32> LLVertexBuffer::sDeleteList;
24LLVertexBuffer::buffer_list_t LLVertexBuffer::sLockedList;
25
26S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
27{
28 sizeof(LLVector3), // TYPE_VERTEX,
29 sizeof(LLVector3), // TYPE_NORMAL,
30 sizeof(LLVector2), // TYPE_TEXCOORD,
31 sizeof(LLVector2), // TYPE_TEXCOORD2,
32 sizeof(LLColor4U), // TYPE_COLOR,
33 sizeof(LLVector3), // TYPE_BINORMAL,
34 sizeof(F32), // TYPE_WEIGHT,
35 sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
36};
37
38//static
39void LLVertexBuffer::initClass(bool use_vbo)
40{
41 sEnableVBOs = use_vbo;
42}
43
44//static
45void LLVertexBuffer::unbind()
46{
47 if (sVBOActive)
48 {
49 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
50 sVBOActive = FALSE;
51 }
52 if (sIBOActive)
53 {
54 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
55 sIBOActive = FALSE;
56 }
57
58 sGLRenderBuffer = 0;
59 sGLRenderIndices = 0;
60}
61
62//static
63void LLVertexBuffer::cleanupClass()
64{
65 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
66 sLockedList.clear();
67 startRender();
68 stopRender();
69 clientCopy(); // deletes GL buffers
70}
71
72//static, call before rendering VBOs
73void LLVertexBuffer::startRender()
74{
75 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
76 if (sEnableVBOs)
77 {
78 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
79 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
80 sVBOActive = FALSE;
81 sIBOActive = FALSE;
82 }
83
84 sRenderActive = TRUE;
85 sGLRenderBuffer = 0;
86 sGLRenderIndices = 0;
87 sLastMask = 0;
88}
89
90void LLVertexBuffer::stopRender()
91{
92 sRenderActive = FALSE;
93}
94
95void LLVertexBuffer::clientCopy(F64 max_time)
96{
97 if (!sDeleteList.empty())
98 {
99 size_t num = sDeleteList.size();
100 glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
101 sDeleteList.clear();
102 sGLCount -= num;
103 }
104
105 if (sEnableVBOs)
106 {
107 LLTimer timer;
108 BOOL reset = TRUE;
109 buffer_list_t::iterator iter = sLockedList.begin();
110 while(iter != sLockedList.end())
111 {
112 LLVertexBuffer* buffer = *iter;
113 if (buffer->isLocked() && buffer->useVBOs())
114 {
115 buffer->setBuffer(0);
116 }
117 ++iter;
118 if (reset)
119 {
120 reset = FALSE;
121 timer.reset(); //skip first copy (don't count pipeline stall)
122 }
123 else
124 {
125 if (timer.getElapsedTimeF64() > max_time)
126 {
127 break;
128 }
129 }
130
131 }
132
133 sLockedList.erase(sLockedList.begin(), iter);
134 }
135}
136
137//----------------------------------------------------------------------------
138
139// For debugging
140struct VTNC /// Simple
141{
142 F32 v1,v2,v3;
143 F32 n1,n2,n3;
144 F32 t1,t2;
145 U32 c;
146};
147static VTNC dbg_vtnc;
148
149struct VTUNCB // Simple + Bump
150{
151 F32 v1,v2,v3;
152 F32 n1,n2,n3;
153 F32 t1,t2;
154 F32 u1,u2;
155 F32 b1,b2,b3;
156 U32 c;
157};
158static VTUNCB dbg_vtuncb;
159
160struct VTUNC // Surfacepatch
161{
162 F32 v1,v2,v3;
163 F32 n1,n2,n3;
164 F32 t1,t2;
165 F32 u1,u2;
166 U32 c;
167};
168static VTUNC dbg_vtunc;
169
170struct VTNW /// Avatar
171{
172 F32 v1,v2,v3;
173 F32 n1,n2,n3;
174 F32 t1,t2;
175 F32 w;
176};
177static VTNW dbg_vtnw;
178
179struct VTNPAD /// Avatar Output
180{
181 F32 v1,v2,v3,p1;
182 F32 n1,n2,n3,p2;
183 F32 t1,t2,p3,p4;
184};
185static VTNPAD dbg_vtnpad;
186
187//----------------------------------------------------------------------------
188
189LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
190 LLRefCount(),
191 mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0),
192 mMappedData(NULL),
193 mMappedIndexData(NULL), mLocked(FALSE),
194 mFinal(FALSE),
195 mFilthy(FALSE),
196 mEmpty(TRUE),
197 mResized(FALSE)
198{
199 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
200 if (!sEnableVBOs)
201 {
202 mUsage = GL_STREAM_DRAW_ARB;
203 }
204
205 S32 stride = 0;
206 for (S32 i=0; i<TYPE_MAX; i++)
207 {
208 U32 mask = 1<<i;
209 if (typemask & mask)
210 {
211 mOffsets[i] = stride;
212 stride += sTypeOffsets[i];
213 }
214 }
215 mTypeMask = typemask;
216 mStride = stride;
217 sCount++;
218}
219
220// protected, use unref()
221//virtual
222LLVertexBuffer::~LLVertexBuffer()
223{
224 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
225 destroyGLBuffer();
226 destroyGLIndices();
227 sCount--;
228
229 if (mLocked)
230 {
231 //pull off of locked list
232 for (buffer_list_t::iterator i = sLockedList.begin(); i != sLockedList.end(); ++i)
233 {
234 if (*i == this)
235 {
236 sLockedList.erase(i);
237 break;
238 }
239 }
240 }
241};
242
243//----------------------------------------------------------------------------
244
245void LLVertexBuffer::createGLBuffer()
246{
247 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
248
249 U32 size = getSize();
250 if (mGLBuffer)
251 {
252 destroyGLBuffer();
253 }
254
255 if (size == 0)
256 {
257 return;
258 }
259
260 mMappedData = new U8[size];
261 memset(mMappedData, 0, size);
262 mEmpty = TRUE;
263
264 if (useVBOs())
265 {
266 glGenBuffersARB(1, (GLuint*) &mGLBuffer);
267 mResized = TRUE;
268 sGLCount++;
269 }
270 else
271 {
272 static int gl_buffer_idx = 0;
273 mGLBuffer = ++gl_buffer_idx;
274 }
275}
276
277void LLVertexBuffer::createGLIndices()
278{
279 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
280 U32 size = getIndicesSize();
281
282 if (mGLIndices)
283 {
284 destroyGLIndices();
285 }
286
287 if (size == 0)
288 {
289 return;
290 }
291
292 mMappedIndexData = new U8[size];
293 memset(mMappedIndexData, 0, size);
294 mEmpty = TRUE;
295
296 if (useVBOs())
297 {
298 glGenBuffersARB(1, (GLuint*) &mGLIndices);
299 mResized = TRUE;
300 sGLCount++;
301 }
302 else
303 {
304 static int gl_buffer_idx = 0;
305 mGLIndices = ++gl_buffer_idx;
306 }
307}
308
309void LLVertexBuffer::destroyGLBuffer()
310{
311 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
312 if (mGLBuffer)
313 {
314 if (useVBOs())
315 {
316 sDeleteList.push_back(mGLBuffer);
317 }
318
319 delete [] mMappedData;
320 mMappedData = NULL;
321 mEmpty = TRUE;
322 sAllocatedBytes -= getSize();
323 }
324
325 mGLBuffer = 0;
326}
327
328void LLVertexBuffer::destroyGLIndices()
329{
330 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
331 if (mGLIndices)
332 {
333 if (useVBOs())
334 {
335 sDeleteList.push_back(mGLIndices);
336 }
337
338 delete [] mMappedIndexData;
339 mMappedIndexData = NULL;
340 mEmpty = TRUE;
341 sAllocatedBytes -= getIndicesSize();
342 }
343
344 mGLIndices = 0;
345}
346
347void LLVertexBuffer::updateNumVerts(S32 nverts)
348{
349 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
350 if (!mDynamicSize)
351 {
352 mNumVerts = nverts;
353 }
354 else if (mUsage == GL_STATIC_DRAW_ARB ||
355 nverts > mNumVerts ||
356 nverts < mNumVerts/2)
357 {
358 if (mUsage != GL_STATIC_DRAW_ARB)
359 {
360 nverts += nverts/4;
361 }
362
363 mNumVerts = nverts;
364 }
365}
366
367void LLVertexBuffer::updateNumIndices(S32 nindices)
368{
369 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
370 if (!mDynamicSize)
371 {
372 mNumIndices = nindices;
373 }
374 else if (mUsage == GL_STATIC_DRAW_ARB ||
375 nindices > mNumIndices ||
376 nindices < mNumIndices/2)
377 {
378 if (mUsage != GL_STATIC_DRAW_ARB)
379 {
380 nindices += nindices/4;
381 }
382
383 mNumIndices = nindices;
384 }
385}
386
387void LLVertexBuffer::makeStatic()
388{
389 if (!sEnableVBOs)
390 {
391 return;
392 }
393
394 if (sRenderActive)
395 {
396 llerrs << "Make static called during render." << llendl;
397 }
398
399 if (mUsage != GL_STATIC_DRAW_ARB)
400 {
401 if (useVBOs())
402 {
403 if (mGLBuffer)
404 {
405 sDeleteList.push_back(mGLBuffer);
406 }
407 if (mGLIndices)
408 {
409 sDeleteList.push_back(mGLIndices);
410 }
411 }
412
413 if (mGLBuffer)
414 {
415 sGLCount++;
416 glGenBuffersARB(1, (GLuint*) &mGLBuffer);
417 }
418 if (mGLIndices)
419 {
420 sGLCount++;
421 glGenBuffersARB(1, (GLuint*) &mGLIndices);
422 }
423
424 mUsage = GL_STATIC_DRAW_ARB;
425 mResized = TRUE;
426
427 if (!mLocked)
428 {
429 mLocked = TRUE;
430 sLockedList.push_back(this);
431 }
432 }
433}
434
435void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
436{
437 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
438
439 updateNumVerts(nverts);
440 updateNumIndices(nindices);
441
442 if (mMappedData)
443 {
444 llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl;
445 }
446 if (create && (nverts || nindices))
447 {
448 createGLBuffer();
449 createGLIndices();
450 }
451
452 sAllocatedBytes += getSize() + getIndicesSize();
453}
454
455void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
456{
457 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
458 mDynamicSize = TRUE;
459 if (mUsage == GL_STATIC_DRAW_ARB)
460 { //always delete/allocate static buffers on resize
461 destroyGLBuffer();
462 destroyGLIndices();
463 allocateBuffer(newnverts, newnindices, TRUE);
464 mFinal = FALSE;
465 }
466 else if (newnverts > mNumVerts || newnindices > mNumIndices ||
467 newnverts < mNumVerts/2 || newnindices < mNumIndices/2)
468 {
469 sAllocatedBytes -= getSize() + getIndicesSize();
470
471 S32 oldsize = getSize();
472 S32 old_index_size = getIndicesSize();
473
474 updateNumVerts(newnverts);
475 updateNumIndices(newnindices);
476
477 S32 newsize = getSize();
478 S32 new_index_size = getIndicesSize();
479
480 sAllocatedBytes += newsize + new_index_size;
481
482 if (newsize)
483 {
484 if (!mGLBuffer)
485 { //no buffer exists, create a new one
486 createGLBuffer();
487 }
488 else
489 {
490 //delete old buffer, keep GL buffer for now
491 U8* old = mMappedData;
492 mMappedData = new U8[newsize];
493 if (old)
494 {
495 memcpy(mMappedData, old, llmin(newsize, oldsize));
496 if (newsize > oldsize)
497 {
498 memset(mMappedData+oldsize, 0, newsize-oldsize);
499 }
500
501 delete [] old;
502 }
503 else
504 {
505 memset(mMappedData, 0, newsize);
506 mEmpty = TRUE;
507 }
508 mResized = TRUE;
509 }
510 }
511 else if (mGLBuffer)
512 {
513 destroyGLBuffer();
514 }
515
516 if (new_index_size)
517 {
518 if (!mGLIndices)
519 {
520 createGLIndices();
521 }
522 else
523 {
524 //delete old buffer, keep GL buffer for now
525 U8* old = mMappedIndexData;
526 mMappedIndexData = new U8[new_index_size];
527 if (old)
528 {
529 memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
530 if (new_index_size > old_index_size)
531 {
532 memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
533 }
534 delete [] old;
535 }
536 else
537 {
538 memset(mMappedIndexData, 0, new_index_size);
539 mEmpty = TRUE;
540 }
541 mResized = TRUE;
542 }
543 }
544 else if (mGLIndices)
545 {
546 destroyGLIndices();
547 }
548 }
549}
550
551BOOL LLVertexBuffer::useVBOs() const
552{
553 //it's generally ineffective to use VBO for things that are streaming
554 //when we already have a client buffer around
555 if (mUsage == GL_STREAM_DRAW_ARB)
556 {
557 return FALSE;
558 }
559
560 return sEnableVBOs && (!sRenderActive || !mLocked);
561}
562
563//----------------------------------------------------------------------------
564
565// Map for data access
566U8* LLVertexBuffer::mapBuffer(S32 access)
567{
568 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
569 if (sRenderActive)
570 {
571 llwarns << "Buffer mapped during render frame!" << llendl;
572 }
573 if (!mGLBuffer && !mGLIndices)
574 {
575 llerrs << "LLVertexBuffer::mapBuffer() called before createGLBuffer" << llendl;
576 }
577 if (mFinal)
578 {
579 llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl;
580 }
581 if (!mMappedData && !mMappedIndexData)
582 {
583 llerrs << "LLVertexBuffer::mapBuffer() called on unallocated buffer." << llendl;
584 }
585
586 if (!mLocked && useVBOs())
587 {
588 mLocked = TRUE;
589 sLockedList.push_back(this);
590 }
591
592 return mMappedData;
593}
594
595void LLVertexBuffer::unmapBuffer()
596{
597 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
598 if (mMappedData || mMappedIndexData)
599 {
600 if (useVBOs() && mLocked)
601 {
602 if (mGLBuffer)
603 {
604 if (mResized)
605 {
606 glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), mMappedData, mUsage);
607 }
608 else
609 {
610 if (mEmpty || mDirtyRegions.empty())
611 {
612 glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), mMappedData);
613 }
614 else
615 {
616 for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i)
617 {
618 DirtyRegion& region = *i;
619 glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, region.mIndex*mStride, region.mCount*mStride, mMappedData + region.mIndex*mStride);
620 }
621 }
622 }
623 }
624
625 if (mGLIndices)
626 {
627 if (mResized)
628 {
629 glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), mMappedIndexData, mUsage);
630 }
631 else
632 {
633 if (mEmpty || mDirtyRegions.empty())
634 {
635 glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), mMappedIndexData);
636 }
637 else
638 {
639 for (std::vector<DirtyRegion>::iterator i = mDirtyRegions.begin(); i != mDirtyRegions.end(); ++i)
640 {
641 DirtyRegion& region = *i;
642 glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, region.mIndicesIndex*sizeof(U32),
643 region.mIndicesCount*sizeof(U32), mMappedIndexData + region.mIndicesIndex*sizeof(U32));
644 }
645 }
646 }
647 }
648
649 mDirtyRegions.clear();
650 mFilthy = FALSE;
651 mResized = FALSE;
652
653 if (mUsage == GL_STATIC_DRAW_ARB)
654 { //static draw buffers can only be mapped a single time
655 //throw out client data (we won't be using it again)
656 delete [] mMappedData;
657 delete [] mMappedIndexData;
658 mMappedIndexData = NULL;
659 mMappedData = NULL;
660 mEmpty = TRUE;
661 mFinal = TRUE;
662 }
663 else
664 {
665 mEmpty = FALSE;
666 }
667
668 mLocked = FALSE;
669
670 glFlush();
671 }
672 }
673}
674
675//----------------------------------------------------------------------------
676
677template <class T,S32 type> struct VertexBufferStrider
678{
679 typedef LLStrider<T> strider_t;
680 static bool get(LLVertexBuffer& vbo,
681 strider_t& strider,
682 S32 index)
683 {
684 vbo.mapBuffer();
685 if (type == LLVertexBuffer::TYPE_INDEX)
686 {
687 S32 stride = sizeof(T);
688 strider = (T*)(vbo.getMappedIndices() + index*stride);
689 strider.setStride(0);
690 return TRUE;
691 }
692 else if (vbo.hasDataType(type))
693 {
694 S32 stride = vbo.getStride();
695 strider = (T*)(vbo.getMappedData() + vbo.getOffset(type) + index*stride);
696 strider.setStride(stride);
697 return TRUE;
698 }
699 else
700 {
701 llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
702 }
703 return FALSE;
704 }
705};
706
707
708bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index)
709{
710 return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index);
711}
712bool LLVertexBuffer::getIndexStrider(LLStrider<U32>& strider, S32 index)
713{
714 return VertexBufferStrider<U32,TYPE_INDEX>::get(*this, strider, index);
715}
716bool LLVertexBuffer::getTexCoordStrider(LLStrider<LLVector2>& strider, S32 index)
717{
718 return VertexBufferStrider<LLVector2,TYPE_TEXCOORD>::get(*this, strider, index);
719}
720bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index)
721{
722 return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index);
723}
724bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index)
725{
726 return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index);
727}
728bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index)
729{
730 return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index);
731}
732bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index)
733{
734 return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index);
735}
736bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index)
737{
738 return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index);
739}
740bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index)
741{
742 return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index);
743}
744
745void LLVertexBuffer::setStride(S32 type, S32 new_stride)
746{
747 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
748 if (mNumVerts)
749 {
750 llerrs << "LLVertexBuffer::setOffset called with mNumVerts = " << mNumVerts << llendl;
751 }
752 // This code assumes that setStride() will only be called once per VBO per type.
753 S32 delta = new_stride - sTypeOffsets[type];
754 for (S32 i=type+1; i<TYPE_MAX; i++)
755 {
756 if (mTypeMask & (1<<i))
757 {
758 mOffsets[i] += delta;
759 }
760 }
761 mStride += delta;
762}
763
764//----------------------------------------------------------------------------
765
766// Set for rendering
767void LLVertexBuffer::setBuffer(U32 data_mask)
768{
769 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
770 //set up pointers if the data mask is different ...
771 BOOL setup = (sLastMask != data_mask);
772
773 if (useVBOs())
774 {
775 if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
776 {
777 glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
778 sVBOActive = TRUE;
779 setup = TRUE; // ... or the bound buffer changed
780 }
781 if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))
782 {
783 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
784 sIBOActive = TRUE;
785 }
786
787 unmapBuffer();
788 }
789 else
790 {
791 if (mGLBuffer)
792 {
793 if (sEnableVBOs && sVBOActive)
794 {
795 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
796 sVBOActive = FALSE;
797 setup = TRUE; // ... or a VBO is deactivated
798 }
799 if (sGLRenderBuffer != mGLBuffer)
800 {
801 setup = TRUE; // ... or a client memory pointer changed
802 }
803 }
804 if (sEnableVBOs && mGLIndices && sIBOActive)
805 {
806 glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
807 sIBOActive = FALSE;
808 }
809 }
810
811 if (mGLIndices)
812 {
813 sGLRenderIndices = mGLIndices;
814 }
815 if (mGLBuffer)
816 {
817 sGLRenderBuffer = mGLBuffer;
818 if (data_mask && setup)
819 {
820 if (!sRenderActive)
821 {
822 llwarns << "Vertex buffer set for rendering outside of render frame." << llendl;
823 }
824 setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
825 sLastMask = data_mask;
826 }
827 }
828}
829
830// virtual (default)
831void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
832{
833 LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
834 stop_glerror();
835 U8* base = useVBOs() ? NULL : mMappedData;
836 S32 stride = mStride;
837
838 if ((data_mask & mTypeMask) != data_mask)
839 {
840 llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
841 }
842
843 if (data_mask & MAP_VERTEX)
844 {
845 glVertexPointer(3,GL_FLOAT, stride, (void*)(base + 0));
846 }
847 if (data_mask & MAP_NORMAL)
848 {
849 glNormalPointer(GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_NORMAL]));
850 }
851 if (data_mask & MAP_TEXCOORD2)
852 {
853 glClientActiveTextureARB(GL_TEXTURE1_ARB);
854 glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
855 }
856 if (data_mask & MAP_TEXCOORD)
857 {
858 glClientActiveTextureARB(GL_TEXTURE0_ARB);
859 glTexCoordPointer(2,GL_FLOAT, stride, (void*)(base + mOffsets[TYPE_TEXCOORD]));
860 }
861 if (data_mask & MAP_COLOR)
862 {
863 glColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)(base + mOffsets[TYPE_COLOR]));
864 }
865 if (data_mask & MAP_BINORMAL)
866 {
867 glVertexAttribPointerARB(6, 3, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_BINORMAL]));
868 }
869 if (data_mask & MAP_WEIGHT)
870 {
871 glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT]));
872 }
873 if (data_mask & MAP_CLOTHWEIGHT)
874 {
875 glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
876 }
877
878 llglassertok();
879}
880
881void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count)
882{
883 if (useVBOs() && !mFilthy)
884 {
885 if (!mDirtyRegions.empty())
886 {
887 DirtyRegion& region = *(mDirtyRegions.rbegin());
888
889 if (region.mIndex+region.mCount > vert_index)
890 {
891 //this buffer has received multiple updates since the last copy, mark it filthy
892 mFilthy = TRUE;
893 mDirtyRegions.clear();
894 return;
895 }
896
897 if (region.mIndex + region.mCount == vert_index &&
898 region.mIndicesIndex + region.mIndicesCount == indices_index)
899 {
900 region.mCount += vert_count;
901 region.mIndicesCount += indices_count;
902 return;
903 }
904 }
905
906 mDirtyRegions.push_back(DirtyRegion(vert_index,vert_count,indices_index,indices_count));
907 }
908}
909
910void LLVertexBuffer::markClean()
911{
912 if (!mResized && !mEmpty && !mFilthy)
913 {
914 buffer_list_t::reverse_iterator iter = sLockedList.rbegin();
915 if (*iter == this)
916 {
917 mLocked = FALSE;
918 sLockedList.pop_back();
919 }
920 }
921}
922