diff options
Diffstat (limited to 'Runner/Graphics/VertexBuffer.cpp')
-rw-r--r-- | Runner/Graphics/VertexBuffer.cpp | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/Runner/Graphics/VertexBuffer.cpp b/Runner/Graphics/VertexBuffer.cpp new file mode 100644 index 0000000..c9f5164 --- /dev/null +++ b/Runner/Graphics/VertexBuffer.cpp @@ -0,0 +1,322 @@ +#include "VertexBuffer.h" +#include "../Profiler/FrameStats.h" + +void SetupDefaultVertexArray(const VertexArrayInfo& info); +void InvalidateVertexInputCache(); + +// LUTs of vertex attributes +static const int kVertexAttrSize[VertexAttr_Count] = { + 3 * sizeof(float), // position + 3 * sizeof(float), // normal + 4 * sizeof(float), // tangent + 1 * sizeof(uint32), // color + 2 * sizeof(float), // uv0 + 2 * sizeof(float), // uv1 +}; + +static const int kVertexAttrDimension[VertexAttr_Count] = { + 3, // position + 3, // normal + 4, // tangent + 1, // color + 2, // uv0 + 2 // uv1 +}; + +enum VertexAttrFormat +{ + VertexAttrFormat_Float = 0, // position \ normal \ tangent \ uv0 \ uv1 + VertexAttrFormat_Float16 = 1, + VertexAttrFormat_Color = 2, // color + VertexAttrFormat_Byte = 3, + + VertexAttrFormat_Count = 4 +}; + +// map VertexAttrFormat to OpenGL type +static GLenum kGLVertexAttrFormat [VertexAttr_Count] = { + GL_FLOAT, // VertexAttrFormat_Float + GL_HALF_FLOAT, // VertexAttrFormat_Float16 + GL_UNSIGNED_BYTE, // VertexAttrFormat_Color + GL_BYTE // VertexAttrFormat_Byte +}; + +static bool IsGLVertexAttrNeedNormalized(uint attr, uint format) +{ + if(attr == VertexAttr_Position) + return false; + else // color and byte need to be normalized + return format != VertexAttrFormat_Float && format != VertexAttrFormat_Float16; +} + +static uint GetDefaultShaderChannelFormat(uint attr) +{ +// besides color, other attributes are all composite of float values + return attr == VertexAttr_Color ? VertexAttrFormat_Color : VertexAttrFormat_Float; +} + +static uint32 GetDefaultVertexAttrSize(/*VertexAttr*/ int attr) +{ + return kVertexAttrSize[attr]; +} + +static uint GetDefaultVertexAttrDimension(uint attr) +{ + return kVertexAttrDimension[attr]; +} + +static uint GetDefaultShaderChannelDimension(uint attr) +{ + return attr == VertexAttr_Color ? 4 : GetDefaultVertexAttrDimension(attr); +} + +// index is stored in unsgined short (GL_UNSIGNED_SHORT) +static const int kIndexSize = sizeof(uint16); +static GLenum kGLIndexFormat = GL_UNSIGNED_SHORT; + +// Get size used for vertexAttrMask +static uint32 GetDynamicChunkStride(uint32 vertexAttrMask) +{ + uint32 stride = 0; + for (int i = 0; i < vertexAttrMask; ++i) + { + if (vertexAttrMask & Mask(i)) + stride += GetDefaultVertexAttrSize(i); + } + return stride; +} + +VertexBuffer::VertexBuffer(VertexBufferType type) +{ +} + +VertexBuffer::~VertexBuffer() +{ +} + +SharedVertexBuffer::SharedVertexBuffer() +{ +} + +SharedVertexBuffer::~SharedVertexBuffer() +{ +} + +//GetChunk +//-> ReleaseChunk +//-> DrawChunk + +void SharedVertexBuffer::GetChunk(uint attrsMask, int maxVerts, int maxIndices, RenderMode mode, void **out_vb, void **out_ib) +{ + Assert(out_vb && out_ib); + + uint stride = GetDynamicChunkStride(attrsMask); // data size of single vertex + GLenum usage = GL_STREAM_DRAW; + uint vbufferSize = stride * maxVerts; + uint ibufferSize = kIndexSize * maxIndices; + + const bool mapVertexBuffer = vbufferSize >= DataBufferThreshold; + const bool mapIndexBuffer = ibufferSize >= DataBufferThreshold; + + GPU::DataBuffer* vertexBuffer = mapVertexBuffer ? GPU::ClaimBuffer(vbufferSize, usage) : 0; + GPU::DataBuffer* indexBuffer = mapIndexBuffer ? GPU::ClaimBuffer(ibufferSize, usage) : 0; + + if(vertexBuffer && vertexBuffer->GetSize() < vbufferSize) + vertexBuffer->Restore(vbufferSize, usage); + + if(indexBuffer && indexBuffer->GetSize() < ibufferSize) + indexBuffer->Restore(ibufferSize, usage); + + if(!mapVertexBuffer && m_CurVBData.size() < vbufferSize) + m_CurVBData.resize(vbufferSize); + + if(!mapIndexBuffer && m_CurIBData.size() < ibufferSize) + m_CurIBData.resize(ibufferSize); + + const GLenum access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT; + + if (vertexBuffer) + *out_vb = vertexBuffer->MapRange(0, vbufferSize, access); + else + *out_vb = &m_CurVBData[0]; + + if(indexBuffer) + *out_ib = indexBuffer->MapRange(0, ibufferSize, access); + else + *out_ib = &m_CurIBData[0]; + + m_CurVB = vertexBuffer; + m_CurIB = indexBuffer; + m_CurRenderMode = mode; + m_CurAttrMask = attrsMask; + m_CurStride = stride; +} + +void SharedVertexBuffer::ReleaseChunk(int actualVerts, int actualIndices) +{ + int actualVBufferSize = m_CurStride * actualVerts; + int actualIBufferSize = kIndexSize * actualIndices; + + const GLenum usage = GL_STREAM_DRAW; + + if (m_CurVB) + { + m_CurVB->FlushMapedRange(0, actualVBufferSize); + m_CurVB->UnMap(); + } + else if(actualVBufferSize >= DataBufferThreshold) + { + m_CurVB = GPU::ClaimBuffer(actualVBufferSize, usage); + m_CurVB->RestoreWithData(actualVBufferSize, usage, &m_CurVBData[0]); + } + + if (m_CurIB) + { + m_CurIB->FlushMapedRange(0, actualIBufferSize); + m_CurIB->UnMap(); + } + else if (actualIBufferSize >= DataBufferThreshold) + { + m_CurIB = GPU::ClaimBuffer(0, usage); + m_CurIB->RestoreWithData(0, usage, &m_CurIBData[0]); + } + + m_CurVertexCount = actualVerts; + m_CurIndexCount = actualIndices; +} + +void SharedVertexBuffer::DrawChunk() +{ + VertexArrayInfo vertexArray; + FillVertexArrayInfo(vertexArray); + + // bind vertex attributes data + SetupDefaultVertexArray(vertexArray); + + const void* indexPtr = m_CurIB ? 0 : (m_CurIBData.empty() ? 0 : &m_CurIBData[0]); + + if (m_CurIB) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_CurIB->GetHandle()); + + switch (m_CurRenderMode) + { + case RenderMode_Triangle: + glDrawElements(GL_TRIANGLES, m_CurIndexCount, kGLIndexFormat, indexPtr); + g_FrameStats.AddDrawCall(); + g_FrameStats.AddTrianglesCount(m_CurIndexCount / 3); + break; + case RenderMode_Line: + glDrawElements(GL_LINE, m_CurIndexCount, kGLIndexFormat, indexPtr); + g_FrameStats.AddDrawCall(); + break; + case RenderMode_Point: + glDrawElements(GL_POINT, m_CurIndexCount, kGLIndexFormat, indexPtr); + g_FrameStats.AddDrawCall(); + break; + } + + if(m_CurIB) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // End draw + Clean(); +} + +void SharedVertexBuffer::FillVertexArrayInfo(VertexArrayInfo& dst) +{ + const byte* basepointer = m_CurVB ? 0 : &m_CurVBData[0]; + const GLuint buffer = m_CurVB ? m_CurVB->GetHandle() : 0; + + int attrOffsets[VertexAttr_Count] = {0}; + + { + uint32 curOffset = 0; + for (uint idx = 0; idx < VertexAttr_Count; ++idx) + { + if (m_CurAttrMask & Mask(idx)) + { + attrOffsets[idx] = curOffset; + curOffset += GetDefaultVertexAttrSize(idx); + } + } + } + + for (uint32 attrIdx = 0; attrIdx < VertexAttr_Count; ++attrIdx) + { + if (m_CurAttrMask & Mask(attrIdx)) + { + dst.buffers[attrIdx] = buffer; + + dst.attributes[attrIdx].pointer = basepointer + attrOffsets[attrIdx]; + dst.attributes[attrIdx].componentType = GetDefaultShaderChannelFormat(attrIdx); + dst.attributes[attrIdx].componentNum = GetDefaultShaderChannelDimension(attrIdx); + dst.attributes[attrIdx].stride = m_CurStride; + + dst.enableMask |= Mask(attrIdx); + } + } +} + +void SharedVertexBuffer::Clean() +{ + if (m_CurVB) + { + GPU::ReleaseBuffer(m_CurVB); + m_CurVB = 0; + } + + if (m_CurIB) + { + GPU::ReleaseBuffer(m_CurIB); + m_CurIB = 0; + } + + m_CurRenderMode = (RenderMode)0; + m_CurAttrMask = 0; + m_CurStride = 0; + m_CurVertexCount = 0; + m_CurIndexCount = 0; + + m_CurVBData.clear(); + m_CurIBData.clear(); +} + +static uint32 sEnabledArrays = 0; + +void SetupDefaultVertexArray(const VertexArrayInfo& info) +{ + GLuint curBoundBuffer = 0; + + for (int attrIdx = 0; attrIdx < VertexAttr_Count; ++attrIdx) + { + if (info.enableMask & Mask(attrIdx)) + { + if (!sEnabledArrays & Mask(attrIdx)) + glEnableVertexAttribArray(attrIdx); + const GLuint buffer = info.buffers[attrIdx]; + const int numCompo = info.attributes[attrIdx].componentNum; + const GLenum compoType = kGLVertexAttrFormat[info.attributes[attrIdx].componentType]; + const bool normalized = IsGLVertexAttrNeedNormalized(attrIdx, compoType); + const uint stride = info.attributes[attrIdx].stride; + const void* pointer = info.attributes[attrIdx].pointer; + + if (curBoundBuffer != buffer) + { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + curBoundBuffer = buffer; + } + + glVertexAttribPointer(attrIdx, numCompo, compoType, normalized ? GL_TRUE : GL_FALSE, stride, pointer); + } + else if(sEnabledArrays & Mask(attrIdx)) + glDisableVertexAttribArray(attrIdx); + } + sEnabledArrays = info.enableMask; +} + +void InvalidateVertexInputCache() +{ + sEnabledArrays = 0; + for(int attrIdx = 0; attrIdx < VertexAttr_Count; ++attrIdx) + glDisableVertexAttribArray(attrIdx); +}
\ No newline at end of file |