123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172 |
- /**
- * @file llvertexbuffer.cpp
- * @brief LLVertexBuffer implementation
- *
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include <algorithm> // For std::sort
- #include <utility> // For std::move
- #include "llvertexbuffer.h"
- #include "llapp.h" // For LLApp::isExiting()
- #include "llglslshader.h"
- #include "llmemory.h" // For ll_aligned_*()
- #include "llrender.h" // For LLRender::sCurrentFrame
- #include "llshadermgr.h"
- #include "llsys.h"
- #include "hbtracy.h"
- // Define to 1 to enable (but this is slow).
- #define TRACE_WITH_TRACY 0
- #if !TRACE_WITH_TRACY
- # undef LL_TRACY_TIMER
- # define LL_TRACY_TIMER(name)
- #endif
- // Helper functions
- // Next Highest Power Of Two: returns first number > v that is a power of 2, or
- // v if v is already a power of 2
- U32 nhpo2(U32 v)
- {
- U32 r = 2;
- while (r < v) r *= 2;
- return r;
- }
- // Which power of 2 is i ? Assumes i is a power of 2 > 0.
- U32 wpo2(U32 i)
- {
- llassert(i > 0 && nhpo2(i) == i);
- U32 r = 0;
- while (i >>= 1) ++r;
- return r;
- }
- static void flush_vbo(GLenum target, U32 start, U32 end, U8* data)
- {
- if (end)
- {
- constexpr U32 block_size = 8192;
- for (U32 i = start; i <= end; i += block_size)
- {
- U32 tend = llmin(i + block_size, end);
- glBufferSubData(target, i, tend - i + 1, data + (i - start));
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLVBOPool class
- // GL name pools for vertex buffers
- ///////////////////////////////////////////////////////////////////////////////
- constexpr U32 POOL_SIZE = 4096;
- class LLVBOPool
- {
- protected:
- LOG_CLASS(LLVBOPool);
- public:
- LL_INLINE LLVBOPool()
- : mAllocated(0),
- mReserved(0),
- mRequested(0),
- mBufferCount(0),
- mTotalHits(0),
- mAllocCount(0),
- mMissCount(0),
- mSkipped(0)
- {
- }
- LL_INLINE ~LLVBOPool()
- {
- logStats();
- clear();
- if (sNameIdx)
- {
- glDeleteBuffers(sNameIdx, sNamePool);
- sNameIdx = 0;
- }
- }
- LL_INLINE U32 adjustSize(U32 size)
- {
- U32 block_size = llmax(nhpo2(size) / 8, 16);
- return size + block_size - (size % block_size);
- }
- U8* allocate(S32 type, U32 size, U32& name);
- // Size MUST be the size provided to allocate that returned the given name
- void free(S32 type, U32 size, U32 name, U8* data);
- void clean(bool force = false);
- void clear();
- U64 getVRAMMegabytes() const
- {
- return BYTES2MEGABYTES(mAllocated + mReserved);
- }
- void logStats();
- private:
- U32 genBuffer();
- void deleteBuffer(U32 name);
- private:
- struct Entry
- {
- LL_INLINE Entry(U8* data, U32 name, U32 current_frame)
- : mData(data),
- mGLName(name),
- mFrameStamp(current_frame)
- {
- }
- U8* mData;
- U32 mGLName;
- U32 mFrameStamp;
- };
- typedef std::list<Entry> entry_list_t;
- typedef fast_hmap<U32, entry_list_t > pool_map_t;
- pool_map_t mVBOPool;
- pool_map_t mIBOPool;
- S64 mAllocated;
- S64 mReserved;
- S64 mRequested;
- U32 mBufferCount;
- U32 mTotalHits;
- U32 mAllocCount;
- U32 mMissCount;
- U32 mSkipped;
- // Used to avoid calling glGenBuffers() for every VBO creation
- static U32 sNamePool[POOL_SIZE];
- static U32 sNameIdx;
- };
- static LLVBOPool* sVBOPool = NULL;
- // Static members
- U32 LLVBOPool::sNamePool[POOL_SIZE];
- U32 LLVBOPool::sNameIdx = 0;
- U32 LLVBOPool::genBuffer()
- {
- if (!sNameIdx)
- {
- if (gGLManager.mIsAMD)
- {
- // Workaround for AMD bug.
- for (U32 i = 0; i < POOL_SIZE; ++i)
- {
- glGenBuffers(1, sNamePool + i);
- }
- }
- else
- {
- glGenBuffers(POOL_SIZE, sNamePool);
- }
- sNameIdx = POOL_SIZE;
- }
- return sNamePool[--sNameIdx];
- }
- U8* LLVBOPool::allocate(S32 type, U32 size, U32& name)
- {
- U8* ret = NULL;
- ++mAllocCount;
- mRequested += size;
- size = adjustSize(size);
- mAllocated += size;
- auto& pool = type == GL_ELEMENT_ARRAY_BUFFER ? mIBOPool : mVBOPool;
- pool_map_t::iterator iter = pool.find(size);
- if (iter != pool.end())
- {
- ++mTotalHits;
- mReserved -= size;
- if (mReserved < 0)
- {
- llwarns << "Reserved buffers accounting mismatch: "
- << mReserved << ". Zeroed." << llendl;
- mReserved = 0;
- }
- // Found a free buffer
- entry_list_t& entries = iter->second;
- Entry& entry = entries.back();
- name = entry.mGLName;
- ret = entry.mData;
- // Remove this entry from the list
- entries.pop_back();
- if (entries.empty())
- {
- // Remove this list of empty entries
- pool.erase(iter);
- }
- return ret;
- }
- // Cache miss, allocate a new buffer
- ++mMissCount;
- name = genBuffer();
- glBindBuffer(type, name);
- // Note: we now use the GL_DYNAMIC_DRAW hint everywhere: I did test (with
- // a key = usage << 32 + size for the cache) with usage hints preservation,
- // but it simply does not change anything at all to frame rates (my guess
- // is that modern GL drivers find the right usage and ignore the hint,
- // which most programmers get wrong anyway). HB
- glBufferData(type, size, NULL, GL_DYNAMIC_DRAW);
- ret = (U8*)ll_aligned_malloc(size, 64);
- if (ret)
- {
- ++mBufferCount;
- if (type == GL_ELEMENT_ARRAY_BUFFER)
- {
- LLVertexBuffer::sGLRenderIndices = name;
- }
- else
- {
- LLVertexBuffer::sGLRenderBuffer = name;
- }
- }
- else
- {
- LLMemory::allocationFailed();
- llwarns << "Memory allocation for Vertex Buffer. Do expect a crash soon..."
- << llendl;
- }
- return ret;
- }
- void LLVBOPool::free(S32 type, U32 size, U32 name, U8* data)
- {
- if (name == LLVertexBuffer::sGLRenderBuffer)
- {
- LLVertexBuffer::unbind();
- }
- mRequested -= size;
- if (mRequested < 0)
- {
- llwarns << "Requested buffers accounting mismatch: " << mRequested
- << ". Zeroed." << llendl;
- mRequested = 0;
- }
- size = adjustSize(size);
- mAllocated -= size;
- if (mAllocated < 0)
- {
- llwarns << "Allocated buffers accounting mismatch: " << mAllocated
- << ". Zeroed." << llendl;
- mAllocated = 0;
- }
- mReserved += size;
- auto& pool = type == GL_ELEMENT_ARRAY_BUFFER ? mIBOPool : mVBOPool;
- pool_map_t::iterator iter = pool.find(size);
- if (iter != pool.end())
- {
- // Re-add this freed pool to the existing list
- iter->second.emplace_front(data, name, LLRender::sCurrentFrame);
- }
- else
- {
- // Make a new list and add this entry to it.
- entry_list_t newlist;
- newlist.emplace_front(data, name, LLRender::sCurrentFrame);
- pool.emplace(size, std::move(newlist));
- }
- }
- void LLVBOPool::clean(bool force)
- {
- if (!force && mMissCount < 1024 &&
- // Do not let the VBO cache grow and stay too large either... HB
- (mBufferCount < 5 * POOL_SIZE || mSkipped < 600))
- {
- ++mSkipped;
- return;
- }
- mMissCount = mSkipped = 0;
- constexpr U32 MAX_FRAME_AGE = 120;
- U32 current_frame = LLRender::sCurrentFrame;
- std::vector<U32> pending_deletions;
- for (pool_map_t::iterator it = mIBOPool.begin(), end = mIBOPool.end();
- it != end; )
- {
- auto& entries = it->second;
- while (!entries.empty())
- {
- auto& entry = entries.back();
- if (current_frame - entry.mFrameStamp < MAX_FRAME_AGE)
- {
- break;
- }
- ll_aligned_free(entry.mData);
- mReserved -= it->first;
- --mBufferCount;
- pending_deletions.push_back(entry.mGLName);
- entries.pop_back();
- }
- if (entries.empty())
- {
- it = mIBOPool.erase(it);
- }
- else
- {
- ++it;
- }
- }
- for (pool_map_t::iterator it = mVBOPool.begin(), end = mVBOPool.end();
- it != end; )
- {
- auto& entries = it->second;
- while (!entries.empty())
- {
- auto& entry = entries.back();
- if (current_frame - entry.mFrameStamp < MAX_FRAME_AGE)
- {
- break;
- }
- ll_aligned_free(entry.mData);
- mReserved -= it->first;
- --mBufferCount;
- pending_deletions.push_back(entry.mGLName);
- entries.pop_back();
- }
- if (entries.empty())
- {
- it = mVBOPool.erase(it);
- }
- else
- {
- ++it;
- }
- }
- if (mReserved < 0)
- {
- llwarns << "Reserved buffers accounting mismatch: " << mReserved
- << ". Zeroed." << llendl;
- mReserved = 0;
- }
- size_t pending = pending_deletions.size();
- if (pending)
- {
- glDeleteBuffers(pending, pending_deletions.data());
- // Only log stats when the debug tag is enabled. HB
- bool log_stats = false;
- LL_DEBUGS("VertexBuffer") << "Erased " << pending;
- log_stats = true;
- LL_CONT << " expired buffers." << LL_ENDL;
- if (log_stats)
- {
- logStats();
- }
- }
- }
- void LLVBOPool::clear()
- {
- std::vector<U32> pending_deletions;
- pending_deletions.reserve(mIBOPool.size() + mVBOPool.size());
- for (auto& entries : mIBOPool)
- {
- for (auto& entry : entries.second)
- {
- ll_aligned_free(entry.mData);
- --mBufferCount;
- pending_deletions.push_back(entry.mGLName);
- }
- }
- for (auto& entries : mVBOPool)
- {
- for (auto& entry : entries.second)
- {
- ll_aligned_free(entry.mData);
- --mBufferCount;
- pending_deletions.push_back(entry.mGLName);
- }
- }
- size_t pending = pending_deletions.size();
- if (pending)
- {
- glDeleteBuffers(pending, pending_deletions.data());
- }
- mIBOPool.clear();
- mVBOPool.clear();
- mReserved = 0;
- }
- void LLVBOPool::logStats()
- {
- if (!mRequested || !mAllocCount)
- {
- return;
- }
- llinfos << "VBO pool stats: " << mBufferCount << " total buffers, "
- << BYTES2MEGABYTES(mRequested) << "MB in use, "
- << BYTES2MEGABYTES(mAllocated) << "MB allocated (overhead: "
- << 0.1f * ((mAllocated - mRequested) * 1000 / mRequested) << "%), "
- << BYTES2MEGABYTES(mReserved) << "MB available in cache, "
- << BYTES2MEGABYTES(mAllocated + mReserved)
- << "MB total in VRAM. Cache hit rate: "
- << 0.1f * (mTotalHits * 1000 / mAllocCount) << "%" << LL_ENDL;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLVertexBuffer class
- ///////////////////////////////////////////////////////////////////////////////
- #if LL_DEBUG_VB_ALLOC
- LLVertexBuffer::instances_set_t LLVertexBuffer::sInstances;
- #endif
- LLPointer<LLVertexBuffer> LLVertexBuffer::sUtilityBuffer = NULL;
- U32 LLVertexBuffer::sBindCount = 0;
- U32 LLVertexBuffer::sSetCount = 0;
- S32 LLVertexBuffer::sGLCount = 0;
- U32 LLVertexBuffer::sGLRenderBuffer = 0;
- U32 LLVertexBuffer::sGLRenderIndices = 0;
- U32 LLVertexBuffer::sLastMask = 0;
- U32 LLVertexBuffer::sVertexCount = 0;
- U32 LLVertexBuffer::sIndexCount = 0;
- bool LLVertexBuffer::sVBOActive = false;
- bool LLVertexBuffer::sIBOActive = false;
- const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
- {
- sizeof(LLVector4), // TYPE_VERTEX,
- sizeof(LLVector4), // TYPE_NORMAL,
- sizeof(LLVector2), // TYPE_TEXCOORD0,
- sizeof(LLVector2), // TYPE_TEXCOORD1,
- sizeof(LLVector2), // TYPE_TEXCOORD2,
- sizeof(LLVector2), // TYPE_TEXCOORD3,
- sizeof(LLColor4U), // TYPE_COLOR,
- sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
- sizeof(LLVector4), // TYPE_TANGENT,
- sizeof(F32), // TYPE_WEIGHT,
- sizeof(LLVector4), // TYPE_WEIGHT4,
- sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
- sizeof(U64), // TYPE_JOINT,
- // Actually exists as position.w, no extra data, but stride is 16 bytes
- sizeof(LLVector4), // TYPE_TEXTURE_INDEX
- };
- static const std::string vb_type_name[] =
- {
- "TYPE_VERTEX",
- "TYPE_NORMAL",
- "TYPE_TEXCOORD0",
- "TYPE_TEXCOORD1",
- "TYPE_TEXCOORD2",
- "TYPE_TEXCOORD3",
- "TYPE_COLOR",
- "TYPE_EMISSIVE",
- "TYPE_TANGENT",
- "TYPE_WEIGHT",
- "TYPE_WEIGHT4",
- "TYPE_CLOTHWEIGHT",
- "TYPE_JOINT",
- "TYPE_TEXTURE_INDEX",
- "TYPE_MAX",
- "TYPE_INDEX",
- };
- const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
- {
- GL_TRIANGLES,
- GL_TRIANGLE_STRIP,
- GL_TRIANGLE_FAN,
- GL_POINTS,
- GL_LINES,
- GL_LINE_STRIP,
- GL_LINE_LOOP,
- };
- //static
- void LLVertexBuffer::initClass()
- {
- if (!sVBOPool)
- {
- sVBOPool = new LLVBOPool();
- }
- if (gUsePBRShaders)
- {
- // Do not allocate the utility buffer for PBR rendering. This would
- // break draw calls using it. *TODO: repair it for PBR. HB
- sUtilityBuffer = NULL;
- return;
- }
- sUtilityBuffer = new LLVertexBuffer(MAP_VERTEX | MAP_NORMAL |
- MAP_TEXCOORD0);
- #if LL_DEBUG_VB_ALLOC
- sUtilityBuffer->setOwner("Utility buffer");
- #endif
- if (!sUtilityBuffer->allocateBuffer(65536, 65536))
- {
- sUtilityBuffer = NULL;
- llwarns << "Failed to allocate the utility buffer" << llendl;
- }
- }
- //static
- S32 LLVertexBuffer::getVRAMMegabytes()
- {
- return sVBOPool ? sVBOPool->getVRAMMegabytes() : 0;
- }
- //static
- void LLVertexBuffer::cleanupVBOPool()
- {
- if (sVBOPool)
- {
- sVBOPool->clean();
- }
- }
- //static
- void LLVertexBuffer::cleanupClass()
- {
- unbind();
- sLastMask = 0;
- sUtilityBuffer = NULL;
- if (sVBOPool)
- {
- // Note: do *not* destroy the existing VBO pool unless we are exiting;
- // this would cause VB memory accounting mismatches. HB
- if (LLApp::isExiting())
- {
- delete sVBOPool;
- sVBOPool = NULL;
- }
- else
- {
- sVBOPool->clear();
- }
- }
- }
- LLVertexBuffer::LLVertexBuffer(U32 typemask)
- : mNumVerts(0),
- mNumIndices(0),
- mIndicesType(GL_UNSIGNED_SHORT),
- mIndicesStride(sizeof(U16)),
- mSize(0),
- mIndicesSize(0),
- mTypeMask(typemask),
- mTypeMaskMask(0),
- mGLBuffer(0),
- mGLIndices(0),
- mMappedData(NULL),
- mMappedIndexData(NULL),
- mCachedBuffer(false)
- {
- // Zero out offsets
- for (U32 i = 0; i < TYPE_MAX; ++i)
- {
- mOffsets[i] = 0;
- }
- #if LL_DEBUG_VB_ALLOC
- sInstances.insert(this);
- #endif
- }
- // Protected, use unref()
- //virtual
- LLVertexBuffer::~LLVertexBuffer()
- {
- unmapBuffer();
- destroyGLBuffer();
- destroyGLIndices();
- sVertexCount -= mNumVerts;
- sIndexCount -= mNumIndices;
- #if LL_DEBUG_VB_ALLOC
- sInstances.erase(this);
- #endif
- if (gDebugGL)
- {
- if (mMappedData)
- {
- llerrs << "Failed to clear vertex buffer vertices" << llendl;
- }
- if (mMappedIndexData)
- {
- llerrs << "Failed to clear vertex buffer indices" << llendl;
- }
- }
- }
- #if LL_DEBUG_VB_ALLOC
- //static
- void LLVertexBuffer::dumpInstances()
- {
- if (sInstances.empty())
- {
- return;
- }
- llinfos << "Allocated buffers:";
- for (instances_set_t::const_iterator it = sInstances.begin(),
- end = sInstances.end();
- it != end; ++it)
- {
- const LLVertexBuffer* vb = *it;
- llcont << "\n - 0x" << std::hex << intptr_t(vb) << std::dec << ": "
- << vb->mOwner;
- }
- llcont << llendl;
- }
- #endif
- //static
- void LLVertexBuffer::setupClientArrays(U32 data_mask)
- {
- if (sLastMask != data_mask)
- {
- if (!gGLManager.mHasVertexAttribIPointer)
- {
- // Make sure texture index is disabled
- data_mask = data_mask & ~MAP_TEXTURE_INDEX;
- }
- for (U32 i = 0; i < TYPE_MAX; ++i)
- {
- U32 mask = 1 << i;
- if (sLastMask & mask)
- {
- // Was enabled
- if (!(data_mask & mask))
- {
- // Needs to be disabled
- glDisableVertexAttribArray((GLint)i);
- }
- }
- else if (data_mask & mask)
- {
- // Was disabled and needs to be enabled
- glEnableVertexAttribArray((GLint)i);
- }
- }
- sLastMask = data_mask;
- }
- }
- // LL's new (fixed) but slow code, and without normals support.
- //static
- void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
- {
- gGL.begin(mode);
- for (U32 i = 0, count = pos.size(); i < count; ++i)
- {
- gGL.vertex3fv(pos[i].mV);
- }
- gGL.end(true);
- }
- //static
- void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos,
- const std::vector<LLVector3>& norm)
- {
- U32 count = pos.size();
- if (count == 0)
- {
- return;
- }
- if (count <= 65536 && sUtilityBuffer.notNull())
- {
- gGL.syncMatrices();
- if (norm.size() < count)
- {
- llwarns_once << "Less normals (" << norm.size()
- << ") than vertices (" << count
- << "), aborting." << llendl;
- return;
- }
- // Vertex-buffer based, optimized code
- LLStrider<LLVector3> vertex_strider;
- LLStrider<LLVector3> normal_strider;
- if (!sUtilityBuffer->getVertexStrider(vertex_strider) ||
- !sUtilityBuffer->getNormalStrider(normal_strider))
- {
- llwarns_sparse << "Failed to get striders, aborting." << llendl;
- return;
- }
- for (U32 i = 0; i < count; ++i)
- {
- *(vertex_strider++) = pos[i];
- *(normal_strider++) = norm[i];
- }
- sUtilityBuffer->setBuffer(MAP_VERTEX | MAP_NORMAL);
- sUtilityBuffer->drawArrays(mode, 0, pos.size());
- }
- else
- {
- // Fallback to LL's new (fixed) but slow code, and without normals
- // support
- drawArrays(mode, pos);
- }
- }
- //static
- void LLVertexBuffer::drawElements(U32 num_vertices, const LLVector4a* posp,
- const LLVector2* tcp, U32 num_indices,
- const U16* indicesp)
- {
- if (!posp || !indicesp || num_vertices <= 0 || num_indices <= 0)
- {
- llwarns << (posp ? "" : "NULL positions pointer - ")
- << (indicesp ? "" : "NULL indices pointer - ")
- << num_vertices << " vertices - " << num_indices
- << " indices. Aborting." << llendl;
- return;
- }
- gGL.syncMatrices();
- if (num_vertices <= 65536 && num_indices <= 65536 &&
- sUtilityBuffer.notNull())
- {
- // Vertex-buffer based, optimized code
- LLStrider<LLVector4a> vertex_strider;
- LLStrider<U16> index_strider;
- if (!sUtilityBuffer->getVertexStrider(vertex_strider) ||
- !sUtilityBuffer->getIndexStrider(index_strider))
- {
- llwarns_sparse << "Failed to get striders, aborting." << llendl;
- return;
- }
- U32 index_size = ((num_indices * sizeof(U16)) + 0xF) & ~0xF;
- LLVector4a::memcpyNonAliased16((F32*)index_strider.get(),
- (F32*)indicesp, index_size);
- U32 vertex_size = ((num_vertices * 4 * sizeof(F32)) + 0xF) & ~0xF;
- LLVector4a::memcpyNonAliased16((F32*)vertex_strider.get(), (F32*)posp,
- vertex_size);
- U32 mask = LLVertexBuffer::MAP_VERTEX;
- if (tcp)
- {
- mask |= LLVertexBuffer::MAP_TEXCOORD0;
- LLStrider<LLVector2> tc_strider;
- if (!sUtilityBuffer->getTexCoord0Strider(tc_strider))
- {
- llwarns_sparse << "Failed to get coord strider, aborting."
- << llendl;
- return;
- }
- U32 tc_size = ((num_vertices * 2 * sizeof(F32)) + 0xF) & ~0xF;
- LLVector4a::memcpyNonAliased16((F32*)tc_strider.get(), (F32*)tcp,
- tc_size);
- }
- sUtilityBuffer->setBuffer(mask);
- sUtilityBuffer->draw(LLRender::TRIANGLES, num_indices, 0);
- }
- else // LL's new but slow code
- {
- unbind();
- gGL.begin(LLRender::TRIANGLES);
- if (tcp)
- {
- for (U32 i = 0; i < num_indices; ++i)
- {
- U16 idx = indicesp[i];
- gGL.texCoord2fv(tcp[idx].mV);
- gGL.vertex3fv(posp[idx].getF32ptr());
- }
- }
- else
- {
- for (U32 i = 0; i < num_indices; ++i)
- {
- U16 idx = indicesp[i];
- gGL.vertex3fv(posp[idx].getF32ptr());
- }
- }
- gGL.end(true);
- }
- }
- bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count,
- U32 indices_offset) const
- {
- if (start >= mNumVerts || end >= mNumVerts)
- {
- llwarns << "Bad vertex buffer draw range: [" << start << ", " << end
- << "] vs " << mNumVerts << llendl;
- return false;
- }
- if (indices_offset >= mNumIndices || indices_offset + count > mNumIndices)
- {
- llwarns << "Bad index buffer draw range: [" << indices_offset << ", "
- << indices_offset + count << "] vs " << mNumIndices << llendl;
- return false;
- }
- if (gUsePBRShaders && gDebugGL)
- {
- U16* idx = (U16*)mMappedIndexData + indices_offset;
- for (U32 i = 0; i < count; ++i)
- {
- if (idx[i] < start || idx[i] > end)
- {
- llwarns << "Index out of range:" << idx[i] << " not in ["
- << start << ", " << end << "]" << llendl;
- return false;
- }
- }
- LLVector4a* v = (LLVector4a*)mMappedData;
- for (U32 i = start; i <= end; ++i)
- {
- if (!v[i].isFinite3())
- {
- llwarns << "Non-finite vertex position data detected."
- << llendl;
- return false;
- }
- }
- LLGLSLShader* shaderp = LLGLSLShader::sCurBoundShaderPtr;
- if (shaderp && shaderp->mFeatures.mIndexedTextureChannels > 1)
- {
- LLVector4a* v = (LLVector4a*)mMappedData;
- for (U32 i = start; i < end; ++i)
- {
- U32 idx = U32(v[i][3] + 0.25f);
- if (idx >= (U32)shaderp->mFeatures.mIndexedTextureChannels)
- {
- llwarns << "Bad texture index (" << idx
- << ") found for shader: " << shaderp->mName
- << ". Max index should be "
- << shaderp->mFeatures.mIndexedTextureChannels - 1
- << "." << llendl;
- return false;
- }
- }
- }
- }
- return true;
- }
- void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count,
- U32 indices_offset) const
- {
- gGL.syncMatrices();
- if (gDebugGL && !gUsePBRShaders)
- {
- if (!LLGLSLShader::sCurBoundShaderPtr)
- {
- llwarns << "No bound shader." << llendl;
- llassert(false);
- }
- if (mGLIndices != sGLRenderIndices)
- {
- llwarns << "Wrong index buffer bound." << llendl;
- llassert(false);
- }
- if (mGLBuffer != sGLRenderBuffer)
- {
- llwarns << "Wrong vertex buffer bound." << llendl;
- llassert(false);
- }
- if (!validateRange(start, end, count, indices_offset))
- {
- llwarns << "Check failed." << llendl;
- llassert(false);
- }
- if (!gUsePBRShaders)
- {
- GLint elem = 0;
- glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &elem);
- if ((U32)elem != mGLIndices)
- {
- llwarns << "Wrong index buffer bound." << llendl;
- llassert(false);
- }
- }
- }
- LLGLSLShader::startProfile();
- glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType,
- (const void*)(indices_offset * mIndicesStride));
- LLGLSLShader::stopProfile();
- }
- void LLVertexBuffer::drawRangeFast(U32 start, U32 end, U32 count,
- U32 indices_offset) const
- {
- gGL.syncMatrices();
- glDrawRangeElements(sGLMode[LLRender::TRIANGLES], start, end, count,
- mIndicesType,
- (const void*)(indices_offset * mIndicesStride));
- }
- void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
- {
- drawRange(mode, 0, mNumVerts - 1, count, indices_offset);
- }
- void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
- {
- gGL.syncMatrices();
- if (gDebugGL && !gUsePBRShaders)
- {
- if (!LLGLSLShader::sCurBoundShaderPtr)
- {
- llwarns << "No bound shader" << llendl;
- llassert(false);
- }
- if (first >= mNumVerts || first + count > mNumVerts)
- {
- llwarns << "Bad vertex buffer draw range: [" << first << ", "
- << first + count << "] vs " << mNumVerts << ". Aborted."
- << llendl;
- llassert(false);
- }
- if (mGLBuffer != sGLRenderBuffer || !sVBOActive)
- {
- llwarns << "Wrong vertex buffer bound." << llendl;
- llassert(false);
- }
- }
- LLGLSLShader::startProfile();
- glDrawArrays(sGLMode[mode], first, count);
- LLGLSLShader::stopProfile();
- }
- //static
- void LLVertexBuffer::unbind()
- {
- if (sVBOActive)
- {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- sVBOActive = false;
- }
- if (sIBOActive)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- sIBOActive = false;
- }
- sGLRenderBuffer = sGLRenderIndices = 0;
- if (!gUsePBRShaders)
- {
- setupClientArrays(0);
- }
- }
- //static
- U32 LLVertexBuffer::calcOffsets(U32 typemask, U32* offsets, U32 num_vertices)
- {
- U32 offset = 0;
- for (U32 i = 0; i < TYPE_TEXTURE_INDEX; ++i)
- {
- U32 mask = 1 << i;
- if (typemask & mask)
- {
- if (offsets && sTypeSize[i])
- {
- offsets[i] = offset;
- offset += sTypeSize[i] * num_vertices;
- offset = (offset + 0xF) & ~0xF;
- }
- }
- }
- offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12;
- return offset;
- }
- //static
- U32 LLVertexBuffer::calcVertexSize(U32 typemask)
- {
- U32 size = 0;
- for (U32 i = 0; i < TYPE_TEXTURE_INDEX; ++i)
- {
- U32 mask = 1 << i;
- if (typemask & mask)
- {
- size += sTypeSize[i];
- }
- }
- return size;
- }
- void LLVertexBuffer::genBuffer(U32 size)
- {
- if (sVBOPool)
- {
- mSize = size;
- mMappedData = sVBOPool->allocate(GL_ARRAY_BUFFER, size, mGLBuffer);
- ++sGLCount;
- }
- }
- void LLVertexBuffer::genIndices(U32 size)
- {
- if (sVBOPool)
- {
- mIndicesSize = size;
- mMappedIndexData = sVBOPool->allocate(GL_ELEMENT_ARRAY_BUFFER, size,
- mGLIndices);
- ++sGLCount;
- }
- }
- bool LLVertexBuffer::createGLBuffer(U32 size)
- {
- if (mGLBuffer || mMappedData)
- {
- destroyGLBuffer();
- }
- if (size == 0)
- {
- return true;
- }
- genBuffer(size);
- return mMappedData != NULL;
- }
- bool LLVertexBuffer::createGLIndices(U32 size)
- {
- if (mGLIndices)
- {
- destroyGLIndices();
- }
- if (size == 0)
- {
- return true;
- }
- genIndices(size);
- return mMappedIndexData != NULL;
- }
- void LLVertexBuffer::destroyGLBuffer()
- {
- if (mGLBuffer || mMappedData)
- {
- if (sVBOPool)
- {
- sVBOPool->free(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData);
- }
- mSize = 0;
- mGLBuffer = 0;
- mMappedData = NULL;
- --sGLCount;
- }
- }
- void LLVertexBuffer::destroyGLIndices()
- {
- if (mGLIndices || mMappedIndexData)
- {
- if (sVBOPool)
- {
- sVBOPool->free(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices,
- mMappedIndexData);
- }
- mIndicesSize = 0;
- mGLIndices = 0;
- mMappedIndexData = NULL;
- --sGLCount;
- }
- }
- bool LLVertexBuffer::updateNumVerts(U32 nverts)
- {
- bool success = true;
- if (nverts > 65536)
- {
- llwarns << "Vertex buffer overflow !" << llendl;
- nverts = 65536;
- }
- U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
- if (needed_size != mSize)
- {
- success = createGLBuffer(needed_size);
- }
- sVertexCount -= mNumVerts;
- mNumVerts = nverts;
- sVertexCount += mNumVerts;
- return success;
- }
- bool LLVertexBuffer::updateNumIndices(U32 nindices)
- {
- bool success = true;
- U32 needed_size = sizeof(U16) * nindices;
- if (needed_size != mIndicesSize)
- {
- success = createGLIndices(needed_size);
- }
- sIndexCount -= mNumIndices;
- mNumIndices = nindices;
- sIndexCount += mNumIndices;
- return success;
- }
- bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices)
- {
- if (nverts > 65536)
- {
- llerrs << "To many vertices: " << nverts << llendl;
- }
- bool success = updateNumVerts(nverts);
- success &= updateNumIndices(nindices);
- if (success && !gUsePBRShaders && (nverts || nindices))
- {
- unmapBuffer();
- }
- return success;
- }
- static bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start,
- U32 end)
- {
- if (end < region.mStart || start > region.mEnd)
- {
- // There is a gap, do not merge
- return false;
- }
- region.mStart = llmin(region.mStart, start);
- region.mEnd = llmax(region.mEnd, end);
- return true;
- }
- // Map for data access
- U8* LLVertexBuffer::mapVertexBuffer(S32 type, U32 index, S32 count)
- {
- if (!mCachedBuffer && !gUsePBRShaders)
- {
- bindGLBuffer(true);
- }
- if (count == -1)
- {
- count = mNumVerts - index;
- }
- U32 start = mOffsets[type] + sTypeSize[type] * index;
- U32 end = start + sTypeSize[type] * count - 1;
- bool mapped = false;
- // Flag region as mapped
- for (U32 i = 0, count = mMappedVertexRegions.size(); i < count; ++i)
- {
- MappedRegion& region = mMappedVertexRegions[i];
- if (expand_region(region, start, end))
- {
- mapped = true;
- break;
- }
- }
- if (!mapped)
- {
- // Not already mapped, map new region
- mMappedVertexRegions.emplace_back(start, end);
- }
- return mMappedData + mOffsets[type] + sTypeSize[type] * index;
- }
- U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
- {
- bindGLIndices(!mCachedBuffer);
- if (count == -1)
- {
- count = mNumIndices - index;
- }
- U32 start = sizeof(U16) * index;
- U32 end = start + sizeof(U16) * count - 1;
- bool mapped = false;
- // See if range is already mapped
- for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
- {
- MappedRegion& region = mMappedIndexRegions[i];
- if (expand_region(region, start, end))
- {
- mapped = true;
- break;
- }
- }
- if (!mapped)
- {
- // Not already mapped, map new region
- mMappedIndexRegions.emplace_back(start, end);
- }
- return mMappedIndexData + sizeof(U16) * index;
- }
- struct SortMappedRegion
- {
- LL_INLINE bool operator()(const LLVertexBuffer::MappedRegion& lhs,
- const LLVertexBuffer::MappedRegion& rhs)
- {
- return lhs.mStart < rhs.mStart;
- }
- };
- void LLVertexBuffer::unmapBuffer()
- {
- if (mMappedData && !mMappedVertexRegions.empty())
- {
- LL_TRACY_TIMER(TRC_VBO_UNMAP);
- if (mGLBuffer != sGLRenderBuffer)
- {
- glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
- sGLRenderBuffer = mGLBuffer;
- }
- U32 start = 0;
- U32 end = 0;
- std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(),
- SortMappedRegion());
- for (U32 i = 0, count = mMappedVertexRegions.size(); i < count; ++i)
- {
- const MappedRegion& region = mMappedVertexRegions[i];
- if (region.mStart == end + 1)
- {
- end = region.mEnd;
- }
- else
- {
- flush_vbo(GL_ARRAY_BUFFER, start, end,
- (U8*)mMappedData + start);
- start = region.mStart;
- end = region.mEnd;
- }
- }
- flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
- stop_glerror();
- mMappedVertexRegions.clear();
- }
- if (mMappedIndexData && !mMappedIndexRegions.empty())
- {
- LL_TRACY_TIMER(TRC_IBO_UNMAP);
- if (mGLIndices != sGLRenderIndices)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
- sGLRenderIndices = mGLIndices;
- }
- U32 start = 0;
- U32 end = 0;
- std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(),
- SortMappedRegion());
- for (U32 i = 0, count = mMappedIndexRegions.size(); i < count; ++i)
- {
- const MappedRegion& region = mMappedIndexRegions[i];
- if (region.mStart == end + 1)
- {
- end = region.mEnd;
- }
- else
- {
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end,
- (U8*)mMappedIndexData + start);
- start = region.mStart;
- end = region.mEnd;
- }
- }
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end,
- (U8*)mMappedIndexData + start);
- stop_glerror();
- mMappedIndexRegions.clear();
- }
- }
- void LLVertexBuffer::resetVertexData()
- {
- if (mMappedData && mSize)
- {
- memset((void*)mMappedData, 0, mSize);
- }
- }
- void LLVertexBuffer::resetIndexData()
- {
- if (mMappedIndexData && mIndicesSize)
- {
- memset((void*)mMappedIndexData, 0, mIndicesSize);
- }
- }
- template <class T, S32 type>
- class VertexBufferStrider
- {
- protected:
- LOG_CLASS(VertexBufferStrider);
- public:
- typedef LLStrider<T> strider_t;
- static bool get(LLVertexBuffer& vbo, strider_t& strider, U32 index,
- S32 count)
- {
- if (type == LLVertexBuffer::TYPE_INDEX)
- {
- U8* ptr = vbo.mapIndexBuffer(index, count);
- strider = (T*)ptr;
- if (!ptr)
- {
- llwarns << "mapIndexBuffer() failed !" << llendl;
- return false;
- }
- strider.setStride(0);
- return true;
- }
- else if (vbo.hasDataType(type))
- {
- U8* ptr = vbo.mapVertexBuffer(type, index, count);
- strider = (T*)ptr;
- if (!ptr)
- {
- llwarns << "mapVertexBuffer() failed !" << llendl;
- return false;
- }
- strider.setStride(LLVertexBuffer::sTypeSize[type]);
- return true;
- }
- llwarns << "Could not find valid vertex data." << llendl;
- return false;
- }
- };
- bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector3, TYPE_VERTEX>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector4a, TYPE_VERTEX>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider,
- U32 index, S32 count)
- {
- if (mIndicesType != GL_UNSIGNED_SHORT)
- {
- llassert(false);
- return false; // Cannot access 32 bits indices with U16 strider...
- }
- return VertexBufferStrider<U16, TYPE_INDEX>::get(*this, strider, index,
- count);
- }
- bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector2, TYPE_TEXCOORD0>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector2, TYPE_TEXCOORD1>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector2, TYPE_TEXCOORD2>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector3, TYPE_NORMAL>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector4a>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector4a, TYPE_NORMAL>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector3, TYPE_TANGENT>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector4a, TYPE_TANGENT>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLColor4U, TYPE_COLOR>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLColor4U, TYPE_EMISSIVE>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<F32, TYPE_WEIGHT>::get(*this, strider, index,
- count);
- }
- bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4a>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector4a, TYPE_WEIGHT4>::get(*this, strider,
- index, count);
- }
- bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4a>& strider,
- U32 index, S32 count)
- {
- return VertexBufferStrider<LLVector4a, TYPE_CLOTHWEIGHT>::get(*this,
- strider,
- index,
- count);
- }
- bool LLVertexBuffer::bindGLBuffer(bool force_bind)
- {
- if (mGLBuffer &&
- (force_bind || (mGLBuffer != sGLRenderBuffer || !sVBOActive)))
- {
- LL_TRACY_TIMER(TRC_BIND_GL_BUFFER);
- glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
- sGLRenderBuffer = mGLBuffer;
- ++sBindCount;
- sVBOActive = true;
- return true;
- }
- return false;
- }
- bool LLVertexBuffer::bindGLBufferFast()
- {
- if (mGLBuffer != sGLRenderBuffer || !sVBOActive)
- {
- glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
- sGLRenderBuffer = mGLBuffer;
- ++sBindCount;
- sVBOActive = true;
- return true;
- }
- return false;
- }
- bool LLVertexBuffer::bindGLIndices(bool force_bind)
- {
- if (mGLIndices &&
- (force_bind || (mGLIndices != sGLRenderIndices || !sIBOActive)))
- {
- LL_TRACY_TIMER(TRC_BIND_GL_INDICES);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
- sGLRenderIndices = mGLIndices;
- stop_glerror();
- ++sBindCount;
- sIBOActive = true;
- return true;
- }
- return false;
- }
- bool LLVertexBuffer::bindGLIndicesFast()
- {
- if (mGLIndices != sGLRenderIndices || !sIBOActive)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
- sGLRenderIndices = mGLIndices;
- ++sBindCount;
- sIBOActive = true;
- return true;
- }
- return false;
- }
- //static
- std::string LLVertexBuffer::listMissingBits(U32 unsatisfied_mask)
- {
- std::string report;
- if (unsatisfied_mask & MAP_VERTEX)
- {
- report = "\n - Missing vert pos";
- }
- if (unsatisfied_mask & MAP_NORMAL)
- {
- report += "\n - Missing normals";
- }
- if (unsatisfied_mask & MAP_TEXCOORD0)
- {
- report += "\n - Missing tex coord 0";
- }
- if (unsatisfied_mask & MAP_TEXCOORD1)
- {
- report += "\n - Missing tex coord 1";
- }
- if (unsatisfied_mask & MAP_TEXCOORD2)
- {
- report += "\n - Missing tex coord 2";
- }
- if (unsatisfied_mask & MAP_TEXCOORD3)
- {
- report += "\n - Missing tex coord 3";
- }
- if (unsatisfied_mask & MAP_COLOR)
- {
- report += "\n - Missing vert color";
- }
- if (unsatisfied_mask & MAP_EMISSIVE)
- {
- report += "\n - Missing emissive";
- }
- if (unsatisfied_mask & MAP_TANGENT)
- {
- report += "\n - Missing tangent";
- }
- if (unsatisfied_mask & MAP_WEIGHT)
- {
- report += "\n - Missing weight";
- }
- if (unsatisfied_mask & MAP_WEIGHT4)
- {
- report += "\n - Missing weight4";
- }
- if (unsatisfied_mask & MAP_CLOTHWEIGHT)
- {
- report += "\n - Missing cloth weight";
- }
- if (unsatisfied_mask & MAP_TEXTURE_INDEX)
- {
- report += "\n - Missing tex index";
- }
- if (unsatisfied_mask & TYPE_INDEX)
- {
- report += "\n - Missing indices";
- }
- return report;
- }
- // Set for rendering. For the legacy EE renderer only.
- void LLVertexBuffer::setBuffer(U32 data_mask)
- {
- // *HACK: in order to simplify the dual-renderer code and reduce the number
- // of tests in it...
- if (gUsePBRShaders)
- {
- setBuffer();
- return;
- }
- unmapBuffer();
- // Set up pointers if the data mask is different ...
- bool setup = sLastMask != data_mask;
- if (data_mask && gDebugGL)
- {
- // Make sure data requirements are fulfilled
- LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
- if (shader)
- {
- U32 required_mask = 0;
- for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i)
- {
- if (shader->getAttribLocation(i) > -1)
- {
- U32 required = 1 << i;
- if ((data_mask & required) == 0)
- {
- llwarns << "Missing attribute: "
- << LLShaderMgr::sReservedAttribs[i] << llendl;
- }
- required_mask |= required;
- }
- }
- U32 unsatisfied_mask = required_mask & ~data_mask;
- if (unsatisfied_mask)
- {
- llwarns << "Shader consumption mismatches data provision:"
- << listMissingBits(unsatisfied_mask) << llendl;
- }
- }
- }
- bool bind_buffer = mGLBuffer && bindGLBufferFast();
- bool bind_indices = mGLIndices && bindGLIndicesFast();
- setup |= bind_buffer || bind_indices;
- if (gDebugGL)
- {
- GLint buff;
- glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buff);
- if ((U32)buff != mGLBuffer)
- {
- llwarns_once << "Invalid GL vertex buffer bound: " << buff
- << " - Expected: " << mGLBuffer << llendl;
- }
- if (mGLIndices)
- {
- glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buff);
- if ((U32)buff != mGLIndices)
- {
- llerrs << "Invalid GL index buffer bound: " << buff << llendl;
- }
- }
- }
- setupClientArrays(data_mask);
- if (setup && data_mask && mGLBuffer)
- {
- setupVertexBuffer(data_mask);
- }
- }
- // Set fast for rendering. For the legacy EE renderer only.
- void LLVertexBuffer::setBufferFast(U32 data_mask)
- {
- // *HACK: in order to simplify the dual-renderer code and reduce the number
- // of tests in it...
- if (gUsePBRShaders)
- {
- setBuffer();
- return;
- }
- // Set up pointers if the data mask is different ...
- bool setup = sLastMask != data_mask;
- bool bind_buffer = bindGLBufferFast();
- bool bind_indices = bindGLIndicesFast();
- setup = setup || bind_buffer || bind_indices;
- setupClientArrays(data_mask);
- if (data_mask && setup)
- {
- setupVertexBuffer(data_mask);
- }
- }
- // New method used by the PBR renderer
- void LLVertexBuffer::setBuffer()
- {
- LLGLSLShader* shaderp = LLGLSLShader::sCurBoundShaderPtr;
- if (!shaderp)
- {
- // Issuing a simple warning and returning at this point would cause a
- // crash later on; so just crash now, in a "clean" way and with a
- // prominent error message (most likely, a shader failed to load). HB
- llerrs << "No bound shader !" << llendl;
- }
- U32 data_mask = shaderp->mAttributeMask;
- if (gDebugGL)
- {
- if (!mMappedVertexRegions.empty() || !mMappedIndexRegions.empty())
- {
- llwarns << "Data was pending on this buffer" << llendl;
- }
- if ((data_mask & mTypeMask) != data_mask)
- {
- llwarns << "Masks mismatch: shader mask = " << std::hex
- << data_mask << " - VB mask = " << mTypeMask << std::dec
- << llendl;
- }
- }
- if (sGLRenderBuffer != mGLBuffer)
- {
- glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
- sGLRenderBuffer = mGLBuffer;
- setupVertexBuffer(data_mask);
- }
- else if (sLastMask != data_mask)
- {
- setupVertexBuffer(data_mask);
- sLastMask = data_mask;
- }
- if (mGLIndices != sGLRenderIndices)
- {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
- sGLRenderIndices = mGLIndices;
- }
- }
- // Only to be used for external (non rendering) purpose, such as with GLOD. HB
- void LLVertexBuffer::setBufferNoShader(U32 data_mask)
- {
- llassert_always(!LLGLSLShader::sCurBoundShaderPtr);
- unmapBuffer();
- bool setup = sLastMask != data_mask;
- bool bind_buffer = mGLBuffer && bindGLBufferFast();
- bool bind_indices = mGLIndices && bindGLIndicesFast();
- setup |= bind_buffer || bind_indices;
- setupClientArrays(data_mask);
- if (setup && data_mask && mGLBuffer)
- {
- setupVertexBuffer(data_mask);
- }
- }
- //virtual
- void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
- {
- if (!gUsePBRShaders)
- {
- data_mask &= ~mTypeMaskMask;
- }
- if (gDebugGL && !gUsePBRShaders && (data_mask & mTypeMask) != data_mask)
- {
- for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i)
- {
- U32 mask = 1 << i;
- if (mask & data_mask && !(mask & mTypeMask))
- {
- // Bit set in data_mask, but not set in mTypeMask
- llwarns << "Missing required component " << vb_type_name[i]
- << llendl;
- }
- }
- llassert(false);
- }
- void* ptr;
- // NOTE: the 'loc' variable is *required* to pass as reference (passing
- // TYPE_* directly to glVertexAttribPointer() causes a crash), unlike
- // the OpenGL documentation prototype for this function... Go figure ! HB
- GLint loc;
- if (data_mask & MAP_NORMAL)
- {
- loc = TYPE_NORMAL;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_NORMAL]);
- glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, sizeof(LLVector4),
- ptr);
- }
- if (data_mask & MAP_TEXCOORD3)
- {
- loc = TYPE_TEXCOORD3;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_TEXCOORD3]);
- glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, sizeof(LLVector2),
- ptr);
- }
- if (data_mask & MAP_TEXCOORD2)
- {
- loc = TYPE_TEXCOORD2;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_TEXCOORD2]);
- glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, sizeof(LLVector2),
- ptr);
- }
- if (data_mask & MAP_TEXCOORD1)
- {
- loc = TYPE_TEXCOORD1;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_TEXCOORD1]);
- glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, sizeof(LLVector2),
- ptr);
- }
- if (data_mask & MAP_TANGENT)
- {
- loc = TYPE_TANGENT;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_TANGENT]);
- glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, sizeof(LLVector4),
- ptr);
- }
- if (data_mask & MAP_TEXCOORD0)
- {
- loc = TYPE_TEXCOORD0;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_TEXCOORD0]);
- glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, sizeof(LLVector2),
- ptr);
- }
- if (data_mask & MAP_COLOR)
- {
- loc = TYPE_COLOR;
- // Bind emissive instead of color pointer if emissive is present
- if (data_mask & MAP_EMISSIVE)
- {
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_EMISSIVE]);
- }
- else
- {
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_COLOR]);
- }
- // Note: sTypeSize[TYPE_COLOR] == sTypeSize[TYPE_EMISSIVE]. HB
- glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE,
- sizeof(LLColor4U), ptr);
- }
- if (data_mask & MAP_EMISSIVE)
- {
- loc = TYPE_EMISSIVE;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_EMISSIVE]);
- glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE,
- sizeof(LLColor4U), ptr);
- if (!(data_mask & MAP_COLOR))
- {
- // Map emissive to color channel when color is not also being bound
- // to avoid unnecessary shader swaps
- loc = TYPE_COLOR;
- glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE,
- sizeof(LLColor4U), ptr);
- }
- }
- if (data_mask & MAP_WEIGHT)
- {
- loc = TYPE_WEIGHT;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_WEIGHT]);
- glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, sizeof(F32), ptr);
- }
- if (data_mask & MAP_WEIGHT4)
- {
- loc = TYPE_WEIGHT4;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_WEIGHT4]);
- glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, sizeof(LLVector4),
- ptr);
- }
- if (data_mask & MAP_JOINT)
- {
- loc = TYPE_JOINT;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_JOINT]);
- glVertexAttribIPointer(loc, 4, GL_UNSIGNED_SHORT, sizeof(U64), ptr);
- }
- if (data_mask & MAP_CLOTHWEIGHT)
- {
- loc = TYPE_CLOTHWEIGHT;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_CLOTHWEIGHT]);
- glVertexAttribPointer(loc, 4, GL_FLOAT, GL_TRUE, sizeof(LLVector4),
- ptr);
- }
- if (data_mask & MAP_TEXTURE_INDEX && gGLManager.mHasVertexAttribIPointer)
- {
- loc = TYPE_TEXTURE_INDEX;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_VERTEX] + 12);
- glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, sizeof(LLVector4),
- ptr);
- }
- if (data_mask & MAP_VERTEX)
- {
- loc = TYPE_VERTEX;
- ptr = reinterpret_cast<void*>(mOffsets[TYPE_VERTEX]);
- glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, sizeof(LLVector4),
- ptr);
- }
- stop_glerror();
- ++sSetCount;
- }
- void LLVertexBuffer::setPositionData(const LLVector4a* data)
- {
- mCachedBuffer = true;
- if (!gUsePBRShaders)
- {
- bindGLBuffer();
- }
- flush_vbo(GL_ARRAY_BUFFER, 0, mNumVerts * sizeof(LLVector4a) - 1, (U8*)data);
- }
- void LLVertexBuffer::setTexCoord0Data(const LLVector2* data)
- {
- if (!gUsePBRShaders)
- {
- bindGLBuffer();
- }
- U32 start = mOffsets[TYPE_TEXCOORD0];
- flush_vbo(GL_ARRAY_BUFFER, start,
- start + mNumVerts * sizeof(LLVector2) - 1, (U8*)data);
- }
- void LLVertexBuffer::setTexCoord1Data(const LLVector2* data)
- {
- if (!gUsePBRShaders)
- {
- bindGLBuffer();
- }
- U32 start = mOffsets[TYPE_TEXCOORD1];
- flush_vbo(GL_ARRAY_BUFFER, start,
- start + mNumVerts * sizeof(LLVector2) - 1, (U8*)data);
- }
- void LLVertexBuffer::setColorData(const LLColor4U* data)
- {
- if (!gUsePBRShaders)
- {
- bindGLBuffer();
- }
- U32 start = mOffsets[TYPE_COLOR];
- flush_vbo(GL_ARRAY_BUFFER, start,
- start + mNumVerts * sizeof(LLColor4U) - 1, (U8*)data);
- }
- // For use by the llgltf library
- void LLVertexBuffer::setIndexData(const U16* data)
- {
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * mNumIndices - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setIndexData(const U32* data)
- {
- if (mIndicesType != GL_UNSIGNED_INT)
- {
- // *HACK: vertex buffers are initialized as 16 bits indices, but can be
- // switched to 32 bits indices.
- mIndicesType = GL_UNSIGNED_INT;
- mIndicesStride = sizeof(U32);
- mNumIndices /= 2;
- }
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * mNumIndices - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setNormalData(const LLVector4a* data)
- {
- U32 start = mOffsets[TYPE_NORMAL];
- flush_vbo(GL_ARRAY_BUFFER, start,
- start + sizeof(LLVector4) * mNumVerts - 1, (U8*)data);
- }
- void LLVertexBuffer::setTangentData(const LLVector4a* data)
- {
- U32 start = mOffsets[TYPE_TANGENT];
- flush_vbo(GL_ARRAY_BUFFER, start,
- start + sizeof(LLVector4) * mNumVerts - 1, (U8*)data);
- }
- void LLVertexBuffer::setWeight4Data(const LLVector4a* data)
- {
- U32 start = mOffsets[TYPE_WEIGHT4];
- flush_vbo(GL_ARRAY_BUFFER, start,
- start + sizeof(LLVector4) * mNumVerts - 1, (U8*)data);
- }
- void LLVertexBuffer::setJointData(const U64* data)
- {
- U32 start = mOffsets[TYPE_JOINT];
- flush_vbo(GL_ARRAY_BUFFER, start, start + sizeof(U64) * mNumVerts - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setPositionData(const LLVector4a* data, U32 offset, U32 count)
- {
- constexpr U32 size = (U32)sizeof(LLVector4a);
- flush_vbo(GL_ARRAY_BUFFER, offset * size, (offset + count) * size - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setTexCoord0Data(const LLVector2* data, U32 offset,
- U32 count)
- {
- constexpr U32 size = (U32)sizeof(LLVector2);
- U32 start = mOffsets[TYPE_TEXCOORD0];
- flush_vbo(GL_ARRAY_BUFFER,
- start + offset * size, start + (offset + count) * size - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setTexCoord1Data(const LLVector2* data, U32 offset,
- U32 count)
- {
- constexpr U32 size = (U32)sizeof(LLVector2);
- U32 start = mOffsets[TYPE_TEXCOORD1];
- flush_vbo(GL_ARRAY_BUFFER,
- start + offset * size, start + (offset + count) * size - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setColorData(const LLColor4U* data, U32 offset, U32 count)
- {
- constexpr U32 size = (U32)sizeof(LLColor4U);
- U32 start = mOffsets[TYPE_COLOR];
- flush_vbo(GL_ARRAY_BUFFER,
- start + offset * size, start + (offset + count) * size - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setIndexData(const U16* data, U32 offset, U32 count)
- {
- constexpr U32 size = (U32)sizeof(U16);
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER,
- offset * size, (offset + count) * size - 1, (U8*)data);
- }
- void LLVertexBuffer::setIndexData(const U32* data, U32 offset, U32 count)
- {
- constexpr U32 size = (U32)sizeof(U32);
- if (mIndicesType != GL_UNSIGNED_INT)
- {
- // *HACK: vertex buffers are initialized as 16 bits indices, but can be
- // switched to 32 bits indices.
- mIndicesType = GL_UNSIGNED_INT;
- mIndicesStride = size;
- mNumIndices /= 2;
- }
- flush_vbo(GL_ELEMENT_ARRAY_BUFFER,
- offset * size, (offset + count) * size - 1, (U8*)data);
- }
- void LLVertexBuffer::setNormalData(const LLVector4a* data, U32 offset,
- U32 count)
- {
- constexpr U32 size = (U32)sizeof(LLVector4a);
- U32 start = mOffsets[TYPE_NORMAL];
- flush_vbo(GL_ARRAY_BUFFER,
- start + offset * size, start + (offset + count) * size - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setTangentData(const LLVector4a* data, U32 offset,
- U32 count)
- {
- constexpr U32 size = (U32)sizeof(LLVector4a);
- U32 start = mOffsets[TYPE_TANGENT];
- flush_vbo(GL_ARRAY_BUFFER,
- start + offset * size, start + (offset + count) * size - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setWeight4Data(const LLVector4a* data, U32 offset,
- U32 count)
- {
- constexpr U32 size = (U32)sizeof(LLVector4a);
- U32 start = mOffsets[TYPE_WEIGHT4];
- flush_vbo(GL_ARRAY_BUFFER,
- start + offset * size, start + (offset + count) * size - 1,
- (U8*)data);
- }
- void LLVertexBuffer::setJointData(const U64* data, U32 offset, U32 count)
- {
- constexpr U32 size = (U32)sizeof(U64);
- U32 start = mOffsets[TYPE_JOINT];
- flush_vbo(GL_ARRAY_BUFFER,
- start + offset * size, start + (offset + count) * size - 1,
- (U8*)data);
- }
|