332 lines
11 KiB
C++
332 lines
11 KiB
C++
/**
|
|
* @file llvertexbuffer.h
|
|
* @brief LLVertexBuffer wrapper for OpengGL vertex buffer objects
|
|
*
|
|
* $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$
|
|
*/
|
|
|
|
#ifndef LL_LLVERTEXBUFFER_H
|
|
#define LL_LLVERTEXBUFFER_H
|
|
|
|
#include "llgl.h"
|
|
#include "v2math.h"
|
|
#include "v3math.h"
|
|
#include "v4math.h"
|
|
#include "v4coloru.h"
|
|
#include "llstrider.h"
|
|
#include "llmemory.h"
|
|
#include "llrender.h"
|
|
#include <set>
|
|
#include <vector>
|
|
#include <list>
|
|
|
|
#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
|
|
|
|
//============================================================================
|
|
// NOTES
|
|
// Threading:
|
|
// All constructors should take an 'create' paramater which should only be
|
|
// 'true' when called from the main thread. Otherwise createGLBuffer() will
|
|
// be called as soon as getVertexPointer(), etc is called (which MUST ONLY be
|
|
// called from the main (i.e OpenGL) thread)
|
|
|
|
|
|
//============================================================================
|
|
// gl name pools for dynamic and streaming buffers
|
|
class LLVBOPool
|
|
{
|
|
public:
|
|
static U32 sBytesPooled;
|
|
|
|
U32 mUsage;
|
|
U32 mType;
|
|
|
|
//size MUST be a power of 2
|
|
U8* allocate(U32& name, U32 size);
|
|
|
|
//size MUST be the size provided to allocate that returned the given name
|
|
void release(U32 name, U8* buffer, U32 size);
|
|
|
|
//destroy all records in mFreeList
|
|
void cleanup();
|
|
|
|
class Record
|
|
{
|
|
public:
|
|
U32 mGLName;
|
|
U8* mClientData;
|
|
};
|
|
|
|
typedef std::list<Record> record_list_t;
|
|
std::vector<record_list_t> mFreeList;
|
|
};
|
|
|
|
class LLGLFence
|
|
{
|
|
public:
|
|
virtual void placeFence() = 0;
|
|
virtual void wait() = 0;
|
|
};
|
|
|
|
//============================================================================
|
|
// base class
|
|
class LLPrivateMemoryPool ;
|
|
class LLVertexBuffer : public LLRefCount
|
|
{
|
|
public:
|
|
class MappedRegion
|
|
{
|
|
public:
|
|
S32 mType;
|
|
S32 mIndex;
|
|
S32 mCount;
|
|
|
|
MappedRegion(S32 type, S32 index, S32 count);
|
|
};
|
|
|
|
LLVertexBuffer(const LLVertexBuffer& rhs)
|
|
{
|
|
*this = rhs;
|
|
}
|
|
|
|
const LLVertexBuffer& operator=(const LLVertexBuffer& rhs)
|
|
{
|
|
llerrs << "Illegal operation!" << llendl;
|
|
return *this;
|
|
}
|
|
|
|
static LLVBOPool sStreamVBOPool;
|
|
static LLVBOPool sDynamicVBOPool;
|
|
static LLVBOPool sStreamIBOPool;
|
|
static LLVBOPool sDynamicIBOPool;
|
|
|
|
static BOOL sUseStreamDraw;
|
|
static BOOL sUseVAO;
|
|
static BOOL sPreferStreamDraw;
|
|
|
|
static void initClass(bool use_vbo, bool no_vbo_mapping);
|
|
static void cleanupClass();
|
|
static void setupClientArrays(U32 data_mask);
|
|
static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
|
|
static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
|
|
|
|
static void unbind(); //unbind any bound vertex buffer
|
|
|
|
//get the size of a vertex with the given typemask
|
|
static S32 calcVertexSize(const U32& typemask);
|
|
|
|
//get the size of a buffer with the given typemask and vertex count
|
|
//fill offsets with the offset of each vertex component array into the buffer
|
|
// indexed by the following enum
|
|
static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
|
|
|
|
|
|
//WARNING -- when updating these enums you MUST
|
|
// 1 - update LLVertexBuffer::sTypeSize
|
|
// 2 - add a strider accessor
|
|
// 3 - modify LLVertexBuffer::setupVertexBuffer
|
|
// 4 - modify LLVertexBuffer::setupClientArray
|
|
// 5 - modify LLViewerShaderMgr::mReservedAttribs
|
|
// 6 - update LLVertexBuffer::setupVertexArray
|
|
enum {
|
|
TYPE_VERTEX = 0,
|
|
TYPE_NORMAL,
|
|
TYPE_TEXCOORD0,
|
|
TYPE_TEXCOORD1,
|
|
TYPE_TEXCOORD2,
|
|
TYPE_TEXCOORD3,
|
|
TYPE_COLOR,
|
|
TYPE_EMISSIVE,
|
|
TYPE_BINORMAL,
|
|
TYPE_WEIGHT,
|
|
TYPE_WEIGHT4,
|
|
TYPE_CLOTHWEIGHT,
|
|
TYPE_TEXTURE_INDEX,
|
|
TYPE_MAX,
|
|
TYPE_INDEX,
|
|
};
|
|
enum {
|
|
MAP_VERTEX = (1<<TYPE_VERTEX),
|
|
MAP_NORMAL = (1<<TYPE_NORMAL),
|
|
MAP_TEXCOORD0 = (1<<TYPE_TEXCOORD0),
|
|
MAP_TEXCOORD1 = (1<<TYPE_TEXCOORD1),
|
|
MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2),
|
|
MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3),
|
|
MAP_COLOR = (1<<TYPE_COLOR),
|
|
MAP_EMISSIVE = (1<<TYPE_EMISSIVE),
|
|
// These use VertexAttribPointer and should possibly be made generic
|
|
MAP_BINORMAL = (1<<TYPE_BINORMAL),
|
|
MAP_WEIGHT = (1<<TYPE_WEIGHT),
|
|
MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
|
|
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
|
|
MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX),
|
|
};
|
|
|
|
protected:
|
|
friend class LLRender;
|
|
|
|
virtual ~LLVertexBuffer(); // use unref()
|
|
|
|
virtual void setupVertexBuffer(U32 data_mask); // pure virtual, called from mapBuffer()
|
|
void setupVertexArray();
|
|
|
|
void genBuffer(U32 size);
|
|
void genIndices(U32 size);
|
|
bool bindGLBuffer(bool force_bind = false);
|
|
bool bindGLIndices(bool force_bind = false);
|
|
bool bindGLArray();
|
|
void releaseBuffer();
|
|
void releaseIndices();
|
|
void createGLBuffer(U32 size);
|
|
void createGLIndices(U32 size);
|
|
void destroyGLBuffer();
|
|
void destroyGLIndices();
|
|
void updateNumVerts(S32 nverts);
|
|
void updateNumIndices(S32 nindices);
|
|
virtual BOOL useVBOs() const;
|
|
void unmapBuffer();
|
|
|
|
public:
|
|
LLVertexBuffer(U32 typemask, S32 usage);
|
|
|
|
// map for data access
|
|
/*volatile */U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
|
|
/*volatile */U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
|
|
|
|
// set for rendering
|
|
virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
|
|
void flush(); //flush pending data to GL memory
|
|
// allocate buffer
|
|
void allocateBuffer(S32 nverts, S32 nindices, bool create);
|
|
virtual void resizeBuffer(S32 newnverts, S32 newnindices);
|
|
|
|
// Only call each getVertexPointer, etc, once before calling unmapBuffer()
|
|
// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
|
|
// example:
|
|
// vb->getVertexBuffer(verts);
|
|
// vb->getNormalStrider(norms);
|
|
// setVertsNorms(verts, norms);
|
|
// vb->unmapBuffer();
|
|
bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getVertexStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getIndexStrider(LLStrider<U16>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
|
|
|
|
|
|
BOOL isEmpty() const { return mEmpty; }
|
|
BOOL isLocked() const { return mVertexLocked || mIndexLocked; }
|
|
S32 getNumVerts() const { return mNumVerts; }
|
|
S32 getNumIndices() const { return mNumIndices; }
|
|
|
|
/*volatile */U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
|
|
/*volatile */U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
|
|
U32 getTypeMask() const { return mTypeMask; }
|
|
bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); }
|
|
S32 getSize() const;
|
|
S32 getIndicesSize() const { return mIndicesSize; }
|
|
/*volatile */U8* getMappedData() const { return mMappedData; }
|
|
/*volatile */U8* getMappedIndices() const { return mMappedIndexData; }
|
|
S32 getOffset(S32 type) const { return mOffsets[type]; }
|
|
S32 getUsage() const { return mUsage; }
|
|
|
|
void draw(U32 mode, U32 count, U32 indices_offset) const;
|
|
void drawArrays(U32 mode, U32 offset, U32 count) const;
|
|
void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
|
|
|
|
//for debugging, validate data in given range is valid
|
|
void validateRange(U32 start, U32 end, U32 count, U32 offset) const;
|
|
|
|
|
|
|
|
protected:
|
|
S32 mNumVerts; // Number of vertices allocated
|
|
S32 mNumIndices; // Number of indices allocated
|
|
|
|
ptrdiff_t mAlignedOffset;
|
|
ptrdiff_t mAlignedIndexOffset;
|
|
S32 mSize;
|
|
S32 mIndicesSize;
|
|
U32 mTypeMask;
|
|
S32 mUsage; // GL usage
|
|
U32 mGLBuffer; // GL VBO handle
|
|
U32 mGLIndices; // GL IBO handle
|
|
U32 mGLArray; // GL VAO handle
|
|
|
|
/*volatile */U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
|
|
/*volatile */U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped)
|
|
BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory
|
|
BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory
|
|
BOOL mFinal; // if TRUE, buffer can not be mapped again
|
|
BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded.
|
|
S32 mOffsets[TYPE_MAX];
|
|
|
|
std::vector<MappedRegion> mMappedVertexRegions;
|
|
std::vector<MappedRegion> mMappedIndexRegions;
|
|
|
|
mutable LLGLFence* mFence;
|
|
|
|
void placeFence() const;
|
|
void waitFence() const;
|
|
|
|
|
|
private:
|
|
static LLPrivateMemoryPool* sPrivatePoolp ;
|
|
|
|
public:
|
|
static S32 sCount;
|
|
static S32 sGLCount;
|
|
static S32 sMappedCount;
|
|
static BOOL sMapped;
|
|
typedef std::list<LLVertexBuffer*> buffer_list_t;
|
|
|
|
static BOOL sDisableVBOMapping; //disable glMapBufferARB
|
|
static BOOL sEnableVBOs;
|
|
static S32 sTypeSize[TYPE_MAX];
|
|
static U32 sGLMode[LLRender::NUM_MODES];
|
|
static U32 sGLRenderBuffer;
|
|
static U32 sGLRenderArray;
|
|
static U32 sGLRenderIndices;
|
|
static BOOL sVBOActive;
|
|
static BOOL sIBOActive;
|
|
static U32 sLastMask;
|
|
static U32 sAllocatedBytes;
|
|
static U32 sBindCount;
|
|
static U32 sSetCount;
|
|
};
|
|
|
|
|
|
#endif // LL_LLVERTEXBUFFER_H
|