1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00
Beef/BeefySysLib/gfx/DrawLayer.cpp
2020-01-31 17:16:44 -08:00

394 lines
9.4 KiB
C++

#include "BFApp.h"
#include "gfx/DrawLayer.h"
#include "gfx/Texture.h"
#include "gfx/RenderDevice.h"
#include "gfx/Shader.h"
#include "util/PerfTimer.h"
#include "util/BeefPerf.h"
USING_NS_BF;
static int sCurBatchId = 0;
DrawBatch::DrawBatch()
{
mId = ++sCurBatchId;
mVtxIdx = 0;
mIdxIdx = 0;
mAllocatedVertices = 0;
mAllocatedIndices = 0;
mIsIndexBufferHead = false;
mIsVertexBufferHead = false;
mVertices = NULL;
mIndices = NULL;
mRenderState = NULL;
mDrawLayer = NULL;
mNext = NULL;
Clear();
}
DrawBatch::~DrawBatch()
{
}
void DrawBatch::Clear()
{
mVtxIdx = 0;
mIdxIdx = 0;
for (int texIdx = 0; texIdx < MAX_TEXTURES; texIdx++)
mCurTextures[texIdx] = (Texture*)(intptr)-1;
}
void DrawBatch::Free()
{
RenderDevice* renderDevice = mDrawLayer->mRenderDevice;
if (mIsVertexBufferHead)
renderDevice->mPooledVertexBuffers.FreeMemoryBlock(mVertices);
if (mIsIndexBufferHead)
renderDevice->mPooledIndexBuffers.FreeMemoryBlock(mIndices);
mIsVertexBufferHead = false;
mIsIndexBufferHead = false;
Clear();
auto& pool = renderDevice->mDrawBatchPool;
pool.push_back(this);
}
DrawBatch* DrawBatch::AllocateChainedBatch(int minVtxCount, int minIdxCount)
{
mDrawLayer->CloseDrawBatch();
return mDrawLayer->AllocateBatch(minVtxCount, minIdxCount);
}
void* DrawBatch::AllocTris(int vtxCount)
{
int idxCount = vtxCount;
if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (idxCount + mIdxIdx >= mAllocatedIndices))
{
if (mVtxIdx > 0)
{
DrawBatch* nextBatch = AllocateChainedBatch(0, 0);
return nextBatch->AllocTris(vtxCount);
}
mRenderState = gBFApp->mRenderDevice->mCurRenderState;
}
uint16* idxPtr = mIndices + mIdxIdx;
void* vtxPtr = (uint8*)mVertices + (mVtxIdx * mVtxSize);
for (int idxNum = 0; idxNum < idxCount; idxNum++)
{
*idxPtr++ = mVtxIdx++;
mIdxIdx++;
}
return vtxPtr;
}
void* DrawBatch::AllocStrip(int vtxCount)
{
int idxCount = (vtxCount - 2) * 3;
if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (idxCount + mIdxIdx >= mAllocatedIndices))
{
if (mVtxIdx > 0)
{
DrawBatch* nextBatch = AllocateChainedBatch(0, 0);
return nextBatch->AllocStrip(vtxCount);
}
mRenderState = gBFApp->mRenderDevice->mCurRenderState;
}
uint16* idxPtr = mIndices + mIdxIdx;
void* vtxPtr = (uint8*)mVertices + (mVtxIdx * mVtxSize);
mVtxIdx += 2;
for (int idxNum = 0; idxNum < idxCount; idxNum += 3)
{
*idxPtr++ = mVtxIdx - 2;
*idxPtr++ = mVtxIdx - 1;
*idxPtr++ = mVtxIdx;
mVtxIdx++;
mIdxIdx += 3;
}
return vtxPtr;
}
void DrawBatch::AllocIndexed(int vtxCount, int idxCount, void** verticesOut, uint16** indicesOut, uint16* idxOfsOut)
{
if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (idxCount + mIdxIdx > mAllocatedIndices))
{
if (mVtxIdx > 0)
{
DrawBatch* nextBatch = AllocateChainedBatch(vtxCount, idxCount);
return nextBatch->AllocIndexed(vtxCount, idxCount, verticesOut, indicesOut, idxOfsOut);
}
mRenderState = gBFApp->mRenderDevice->mCurRenderState;
}
*verticesOut = (uint8*)mVertices + (mVtxIdx * mVtxSize);
*indicesOut = mIndices + mIdxIdx;
*idxOfsOut = mVtxIdx;
mVtxIdx += vtxCount;
mIdxIdx += idxCount;
}
//
DrawLayer::DrawLayer()
{
mRenderWindow = NULL;
mRenderDevice = NULL;
mIdxBuffer = NULL;
mVtxBuffer = NULL;
mRenderCmdBuffer = NULL;
mIdxByteIdx = 0;
mVtxByteIdx = 0;
mRenderCmdByteIdx = 0;
mCurDrawBatch = NULL;
for (int textureIdx = 0; textureIdx < MAX_TEXTURES; textureIdx++)
mCurTextures[textureIdx] = NULL;
}
DrawLayer::~DrawLayer()
{
NOP;
}
void DrawLayer::CloseDrawBatch()
{
if (mCurDrawBatch == NULL)
return;
mIdxByteIdx += mCurDrawBatch->mIdxIdx * sizeof(uint16);
mVtxByteIdx += mCurDrawBatch->mVtxIdx * mCurDrawBatch->mVtxSize;
BF_ASSERT(mVtxByteIdx <= DRAWBUFFER_VTXBUFFER_SIZE);
mCurDrawBatch = NULL;
}
void DrawLayer::QueueRenderCmd(RenderCmd* renderCmd)
{
CloseDrawBatch();
mRenderCmdList.PushBack(renderCmd);
renderCmd->CommandQueued(this);
}
DrawBatch* DrawLayer::AllocateBatch(int minVtxCount, int minIdxCount)
{
BP_ZONE("DrawLayer::AllocateBatch");
BF_ASSERT(mRenderDevice->mCurRenderState->mShader != NULL);
int vtxSize = mRenderDevice->mCurRenderState->mShader->mVertexSize;
if (minIdxCount == 0)
{
minIdxCount = 512;
minVtxCount = minIdxCount;
}
BF_ASSERT(minIdxCount * sizeof(uint16) <= DRAWBUFFER_IDXBUFFER_SIZE);
BF_ASSERT(minVtxCount * vtxSize <= DRAWBUFFER_VTXBUFFER_SIZE);
DrawBatch* drawBatch = NULL;
auto& pool = mRenderDevice->mDrawBatchPool;
if (pool.size() == 0)
{
drawBatch = CreateDrawBatch();
}
else
{
drawBatch = pool.back();
pool.pop_back();
}
drawBatch->mDrawLayer = this;
int needIdxBytes = minIdxCount * sizeof(uint16);
int needVtxBytes = minVtxCount * vtxSize;
if (needVtxBytes < DRAWBUFFER_VTXBUFFER_SIZE - mVtxByteIdx)
{
//mVtxByteIdx = ((mVtxByteIdx + vtxSize - 1) / vtxSize) * vtxSize;
drawBatch->mVertices = (Vertex3D*)((uint8*) mVtxBuffer + mVtxByteIdx);
drawBatch->mAllocatedVertices = (int)((DRAWBUFFER_VTXBUFFER_SIZE - mVtxByteIdx) / vtxSize);
drawBatch->mIsVertexBufferHead = false;
}
else
{
mVtxBuffer = mRenderDevice->mPooledVertexBuffers.AllocMemoryBlock();
mVtxByteIdx = 0;
drawBatch->mVertices = (Vertex3D*)mVtxBuffer;
drawBatch->mAllocatedVertices = DRAWBUFFER_VTXBUFFER_SIZE / vtxSize;
drawBatch->mIsVertexBufferHead = true;
}
if (needIdxBytes < DRAWBUFFER_IDXBUFFER_SIZE - mIdxByteIdx)
{
drawBatch->mIndices = (uint16*)((uint8*)mIdxBuffer + mIdxByteIdx);
drawBatch->mAllocatedIndices = (DRAWBUFFER_IDXBUFFER_SIZE - mIdxByteIdx) / sizeof(uint16);
drawBatch->mIsIndexBufferHead = false;
}
else
{
mIdxBuffer = mRenderDevice->mPooledIndexBuffers.AllocMemoryBlock();
mIdxByteIdx = 0;
drawBatch->mIndices = (uint16*)mIdxBuffer;
drawBatch->mAllocatedIndices = DRAWBUFFER_IDXBUFFER_SIZE / sizeof(uint16);
drawBatch->mIsIndexBufferHead = true;
}
drawBatch->mAllocatedIndices = std::min(drawBatch->mAllocatedVertices, drawBatch->mAllocatedIndices);
drawBatch->mVtxSize = vtxSize;
mRenderCmdList.PushBack(drawBatch);
mCurDrawBatch = drawBatch;
return drawBatch;
}
void DrawLayer::Draw()
{
BP_ZONE("DrawLayer::Draw");
RenderCmd* curRenderCmd = mRenderCmdList.mHead;
while (curRenderCmd != NULL)
{
curRenderCmd->Render(mRenderDevice, mRenderWindow);
curRenderCmd = curRenderCmd->mNext;
}
}
void DrawLayer::Flush()
{
Draw();
Clear();
}
void DrawLayer::Clear()
{
for (int texIdx = 0; texIdx < MAX_TEXTURES; texIdx++)
mCurTextures[texIdx] = (Texture*) (intptr) -1;
RenderCmd* curBatch = mRenderCmdList.mHead;
while (curBatch != NULL)
{
RenderCmd* nextBatch = curBatch->mNext;
curBatch->Free();
curBatch = nextBatch;
}
/*if ((mIdxBuffer == NULL) || (mCurDrawBatch != NULL))
mIdxBuffer = mRenderDevice->mPooledIndexBuffers.AllocMemoryBlock();
if ((mVtxBuffer == NULL) || (mCurDrawBatch != NULL))
mVtxBuffer = mRenderDevice->mPooledVertexBuffers.AllocMemoryBlock();
if ((mRenderCmdBuffer == NULL) || (mRenderCmdByteIdx != 0))
mRenderCmdBuffer = mRenderDevice->mPooledRenderCmdBuffers.AllocMemoryBlock();
mIdxByteIdx = 0;
mVtxByteIdx = 0;
mRenderCmdByteIdx = 0;*/
mIdxBuffer = NULL;
mVtxByteIdx = 0;
mRenderCmdBuffer = NULL;
mIdxByteIdx = DRAWBUFFER_IDXBUFFER_SIZE;
mVtxByteIdx = DRAWBUFFER_VTXBUFFER_SIZE;
mRenderCmdByteIdx = DRAWBUFFER_CMDBUFFER_SIZE;
mRenderCmdList.Clear();
mCurDrawBatch = NULL;
}
void* DrawLayer::AllocTris(int vtxCount)
{
if (mCurDrawBatch == NULL)
AllocateBatch(0, 0);
return mCurDrawBatch->AllocTris(vtxCount);
}
void* DrawLayer::AllocStrip(int vtxCount)
{
if (mCurDrawBatch == NULL)
AllocateBatch(0, 0);
return mCurDrawBatch->AllocStrip(vtxCount);
}
void DrawLayer::AllocIndexed(int vtxCount, int idxCount, void** verticesOut, uint16** indicesOut, uint16* idxOfsOut)
{
if (mCurDrawBatch == NULL)
AllocateBatch(0, 0);
mCurDrawBatch->AllocIndexed(vtxCount, idxCount, verticesOut, indicesOut, idxOfsOut);
}
void DrawLayer::SetTexture(int texIdx, Texture* texture)
{
if (mCurTextures[texIdx] != texture)
{
QueueRenderCmd(CreateSetTextureCmd(texIdx, texture));
mCurTextures[texIdx] = texture;
}
}
void DrawLayer::SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount)
{
SetShaderConstantData(slotIdx, constData, size);
}
///
BF_EXPORT DrawLayer* BF_CALLTYPE DrawLayer_Create(BFWindow* window)
{
DrawLayer* aDrawLayer = gBFApp->CreateDrawLayer(window);
aDrawLayer->Clear();
return aDrawLayer;
}
BF_EXPORT void BF_CALLTYPE DrawLayer_Delete(DrawLayer* drawLayer)
{
if (drawLayer->mRenderWindow != NULL)
{
drawLayer->mRenderWindow->mDrawLayerList.Remove(drawLayer);
}
delete drawLayer;
}
BF_EXPORT void BF_CALLTYPE DrawLayer_Clear(DrawLayer* drawLayer)
{
drawLayer->Clear();
}
BF_EXPORT void BF_CALLTYPE DrawLayer_Activate(DrawLayer* drawLayer)
{
if (drawLayer->mRenderWindow != NULL)
{
drawLayer->mRenderWindow->SetAsTarget();
}
else
{
gBFApp->mRenderDevice->mCurRenderTarget = NULL;
}
gBFApp->mRenderDevice->mCurDrawLayer = drawLayer;
}
BF_EXPORT void BF_CALLTYPE DrawLayer_DrawToRenderTarget(DrawLayer* drawLayer, TextureSegment* textureSegment)
{
RenderDevice* renderDevice = gBFApp->mRenderDevice;
BP_ZONE("DrawLayer_DrawToRenderTarget DrawPart");
RenderTarget* prevTarget = renderDevice->mCurRenderTarget;
renderDevice->PhysSetRenderState(renderDevice->mDefaultRenderState);
renderDevice->PhysSetRenderTarget(textureSegment->mTexture);
drawLayer->Draw();
renderDevice->mCurRenderTarget = prevTarget;
}