#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; bool fits = (idxCount + mIdxIdx <= mAllocatedIndices) && (vtxCount + mVtxIdx <= mAllocatedVertices); if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (!fits)) { if ((mVtxIdx > 0) || (!fits)) { DrawBatch* nextBatch = AllocateChainedBatch(vtxCount, idxCount); 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; bool fits = (idxCount + mIdxIdx <= mAllocatedIndices) && (vtxCount + mVtxIdx <= mAllocatedVertices); if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (!fits)) { if ((mVtxIdx > 0) || (!fits)) { DrawBatch* nextBatch = AllocateChainedBatch(vtxCount, idxCount); 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) { bool fits = (idxCount + mIdxIdx <= mAllocatedIndices) && (vtxCount + mVtxIdx <= mAllocatedVertices); if ((mRenderState != gBFApp->mRenderDevice->mCurRenderState) || (!fits)) { if ((mVtxIdx > 0) || (!fits)) { 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() { } 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; minIdxCount = BF_MAX(minIdxCount, 512); minVtxCount = BF_MAX(minIdxCount, 512); 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 usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount) { SetShaderConstantData(usageIdx, 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(); drawLayer->Clear(); renderDevice->mCurRenderTarget = prevTarget; }