summaryrefslogtreecommitdiff
path: root/Runner/Graphics/VertexBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runner/Graphics/VertexBuffer.cpp')
-rw-r--r--Runner/Graphics/VertexBuffer.cpp322
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