summaryrefslogtreecommitdiff
path: root/Client/Source/Graphics/GPUDataBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Client/Source/Graphics/GPUDataBuffer.cpp')
-rw-r--r--Client/Source/Graphics/GPUDataBuffer.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/Client/Source/Graphics/GPUDataBuffer.cpp b/Client/Source/Graphics/GPUDataBuffer.cpp
new file mode 100644
index 0000000..f5149d9
--- /dev/null
+++ b/Client/Source/Graphics/GPUDataBuffer.cpp
@@ -0,0 +1,207 @@
+#include <math.h>
+
+#include "GPUDataBuffer.h"
+
+namespace GPU
+{
+
+ // 修改buffer数据要绑定到这个目标上,其他情况下用GetHandle()绑定到其他目标
+ // GL_COPY_READ_BUFFER
+ static const GLenum kBufferTarget = GL_COPY_WRITE_BUFFER;
+
+ DataBuffer::DataBuffer()
+ {
+ glGenBuffers(1, &m_Handle);
+ m_Size = 0;
+ }
+
+ DataBuffer::~DataBuffer()
+ {
+ glDeleteBuffers(1, &m_Handle);
+ }
+
+ void DataBuffer::Restore(int size, GLenum usage)
+ {
+ RestoreWithData(size, usage, 0);
+ }
+
+ void DataBuffer::RestoreWithData(int size, GLenum usage, const void* data)
+ {
+ glBindBuffer(kBufferTarget, m_Handle);
+ glBufferData(kBufferTarget, size, data, usage);
+ glBindBuffer(kBufferTarget, 0);
+ m_Size = size;
+ m_Usage = usage;
+ }
+
+ // glBufferSubData
+ // glMapBuffer
+ // glMapBufferRange (best one)
+
+ void DataBuffer::Upload(int offset, int size, const void* data)
+ {
+ glBindBuffer(kBufferTarget, m_Handle);
+ glBufferSubData(kBufferTarget, offset, size, data);
+ glBindBuffer(kBufferTarget, 0);
+ }
+
+ void* DataBuffer::Map(uint32 access)
+ {
+ glBindBuffer(kBufferTarget, m_Handle);
+ void* ptr = glMapBuffer(kBufferTarget, access);
+ glBindBuffer(kBufferTarget, 0);
+ return ptr;
+ }
+
+ void* DataBuffer::MapRange(int offset, int size, uint32 access)
+ {
+ glBindBuffer(kBufferTarget, m_Handle);
+ void* ptr = glMapBufferRange(kBufferTarget, offset, size, access);
+ glBindBuffer(kBufferTarget, 0);
+ return ptr;
+ }
+
+ void DataBuffer::FlushMapedRange(int offset, int size)
+ {
+ glBindBuffer(kBufferTarget, m_Handle);
+ glFlushMappedBufferRange(kBufferTarget, offset, size);
+ glBindBuffer(kBufferTarget, 0);
+ }
+
+ void DataBuffer::UnMap()
+ {
+ glBindBuffer(kBufferTarget, m_Handle);
+ glUnmapBuffer(kBufferTarget);
+ glBindBuffer(kBufferTarget, 0);
+ }
+
+ void DataBuffer::Orphan()
+ {
+ glBindBuffer(kBufferTarget, m_Handle);
+ glBufferData(kBufferTarget, 0, 0, GL_STREAM_DRAW);
+ glBindBuffer(kBufferTarget, 0);
+ }
+
+//---------------------------------------------------------------------------------------
+
+ static bool IsBufferPoolCreated = false;
+
+ BufferPool::BufferPool()
+ :m_LiveBuffers()
+ {
+ Assert(!IsBufferPoolCreated);
+ IsBufferPoolCreated = true;
+ }
+
+ BufferPool::~BufferPool()
+ {
+ }
+
+ static const float kBufferAllocateWeight = 10.0f; //! Default weight for buffer allocation from scratch.
+ static const float kBufferSizeWeightFactor = 1.f / 8096.f; //!< Weight factor for size difference.
+ static const float kBufferUsageDiffWeight = 8.f; //!< Weight factor for usage difference.
+
+ static int ComputeBufferWeight(DataBuffer* buffer, int desiredSize, GLenum desiredUsage)
+ {
+ const int bufferSize = buffer->GetSize();
+ const GLenum bufferUsage = buffer->GetUsage();
+
+ if (bufferSize == 0)
+ return kBufferAllocateWeight;
+
+ const int sizeDiff = std::abs(bufferSize - desiredSize);
+
+ return float(sizeDiff)*kBufferSizeWeightFactor + ((bufferUsage != desiredUsage) ? kBufferUsageDiffWeight : 0.f);
+ }
+
+ DataBuffer* BufferPool::ClaimBuffer(int size, GLenum usage)
+ {
+ const float maxWeight = kBufferAllocateWeight;
+ const int maxCandidates = 5; // Number of potential candidates to consider actually.
+
+ const int sizeClass = GetSizeClass(size);
+ int numCandidates = 0; // Number of potential candidates considered
+ int bestBufferNdx = -1;
+ float bestWeight = std::numeric_limits<float>::infinity();
+
+ for (int idx = 0; idx < m_LiveBuffers[sizeClass].size(); ++idx)
+ {
+ DataBuffer* buffer = m_LiveBuffers[sizeClass][idx];
+ const float weight = ComputeBufferWeight(buffer, size, usage);
+
+ if (weight < maxWeight && weight < bestWeight)
+ {
+ bestWeight = weight;
+ bestBufferNdx = idx;
+ ++numCandidates;
+ }
+
+ if (numCandidates >= maxCandidates)
+ break; // Do not try other buffers, sorry.
+ }
+
+ if (bestBufferNdx >= 0)
+ {
+ DataBuffer* selectedBuffer = m_LiveBuffers[sizeClass][bestBufferNdx];
+
+ if (bestBufferNdx + 1 != m_LiveBuffers[sizeClass].size())
+ std::swap(m_LiveBuffers[sizeClass][bestBufferNdx], m_LiveBuffers[sizeClass].back());
+ m_LiveBuffers[sizeClass].pop_back();
+
+ return selectedBuffer;
+ }
+ else
+ return new DataBuffer();
+
+ }
+
+ void BufferPool::ReleaseBuffer(DataBuffer* buffer)
+ {
+ InsertToLive(buffer);
+ }
+
+ void BufferPool::OnEndFrame()
+ {
+ UpdatePendingBuffersArray();
+ }
+
+ void BufferPool::UpdatePendingBuffersArray()
+ {
+ }
+
+ void BufferPool::InsertToLive(DataBuffer* buffer)
+ {
+ const int bufferSize = buffer->GetSize();
+ const int sizeClass = GetSizeClass(bufferSize);
+
+ m_LiveBuffers[sizeClass].push_back(buffer);
+ }
+
+ uint BufferPool::GetSizeClass(uint bufferSize)
+ {
+ for (int idx = 0; idx < kSizeClassCount; ++idx)
+ {
+ if (bufferSize < GetSizeClassLimit(idx))
+ return idx;
+ }
+ Assert(false);
+ return 0;
+ }
+
+ DataBuffer* ClaimBuffer(int size, GLenum usage)
+ {
+ return BufferPool::Instance()->ClaimBuffer(size, usage);
+ }
+
+ void ReleaseBuffer(DataBuffer* buffer)
+ {
+ BufferPool::Instance()->ReleaseBuffer(buffer);
+ }
+
+ int BufferPool::GetSizeClassLimit(int classNdx)
+ {
+ // (0, 2^10] 2^11 2^12 2^13 2^14 2^15 INT_MAX
+ return classNdx + 1 < kSizeClassCount ? (1 << (classNdx*kSizeClassStepLog2 + kSizeClassBaseLog2)) : INT_MAX;
+ }
+
+}