Graphics: Remove sprite limit

This commit is contained in:
Lynix 2019-03-31 16:31:02 +02:00
parent 03e2bfb833
commit 0ca823f9a6
5 changed files with 347 additions and 258 deletions

View File

@ -51,8 +51,16 @@ namespace Nz
int textureOverlay; int textureOverlay;
}; };
struct SpriteBatch
{
std::size_t spriteCount;
const Material* material;
const Texture* overlayTexture;
Recti scissorRect;
};
mutable std::unordered_map<const Shader*, ShaderUniforms> m_shaderUniforms; mutable std::unordered_map<const Shader*, ShaderUniforms> m_shaderUniforms;
mutable std::vector<std::pair<const VertexStruct_XYZ_Color_UV*, std::size_t>> m_spriteChains; mutable std::vector<SpriteBatch> m_spriteBatches;
Buffer m_vertexBuffer; Buffer m_vertexBuffer;
RenderStates m_clearStates; RenderStates m_clearStates;
ShaderRef m_clearShader; ShaderRef m_clearShader;

View File

@ -61,8 +61,16 @@ namespace Nz
int textureOverlay; int textureOverlay;
}; };
struct SpriteBatch
{
std::size_t spriteCount;
const Material* material;
const Texture* overlayTexture;
Recti scissorRect;
};
mutable std::unordered_map<const Shader*, ShaderUniforms> m_shaderUniforms; mutable std::unordered_map<const Shader*, ShaderUniforms> m_shaderUniforms;
mutable std::vector<std::pair<const VertexStruct_XYZ_Color_UV*, std::size_t>> m_spriteChains; mutable std::vector<SpriteBatch> m_spriteBatches;
Buffer m_vertexBuffer; Buffer m_vertexBuffer;
RenderStates m_clearStates; RenderStates m_clearStates;
ShaderRef m_clearShader; ShaderRef m_clearShader;

View File

@ -29,8 +29,8 @@ namespace Nz
Vector2f uv; Vector2f uv;
}; };
UInt32 s_maxQuads = std::numeric_limits<UInt16>::max() / 6; constexpr UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB constexpr UInt32 s_maxQuadPerDraw = s_vertexBufferSize / sizeof(VertexLayout_XYZ_Color_UV);
} }
/*! /*!
@ -468,62 +468,9 @@ namespace Nz
const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
Renderer::SetIndexBuffer(&s_quadIndexBuffer); const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuadPerDraw, m_spriteBuffer.GetVertexCount() / 4);
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
Renderer::SetVertexBuffer(&m_spriteBuffer);
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
m_spriteChains.clear();
auto Commit = [&]()
{
std::size_t spriteChainCount = m_spriteChains.size();
if (spriteChainCount > 0)
{
std::size_t spriteChain = 0; // Which chain of sprites are we treating
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
do
{
// We open the buffer in writing mode
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
std::size_t spriteCount = 0;
do
{
const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first;
std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second;
std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset);
std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
vertices += count * 4;
spriteCount += count;
spriteChainOffset += count;
// Have we treated the entire chain ?
if (spriteChainOffset == currentChainSpriteCount)
{
spriteChain++;
spriteChainOffset = 0;
}
}
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
vertexMapper.Unmap();
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
}
while (spriteChain < spriteChainCount);
}
m_spriteChains.clear();
};
const Material* lastMaterial = nullptr; const Material* lastMaterial = nullptr;
const MaterialPipeline* lastPipeline = nullptr; const MaterialPipeline* lastPipeline = nullptr;
const Shader* lastShader = nullptr; const Shader* lastShader = nullptr;
@ -533,18 +480,19 @@ namespace Nz
const MaterialPipeline::Instance* pipelineInstance = nullptr; const MaterialPipeline::Instance* pipelineInstance = nullptr;
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) Renderer::SetIndexBuffer(&s_quadIndexBuffer);
{ Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; Renderer::SetVertexBuffer(&m_spriteBuffer);
if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) auto Draw = [&]()
{ {
Commit(); unsigned int firstIndex = 0;
for (const auto& batch : m_spriteBatches)
const MaterialPipeline* pipeline = basicSprites.material->GetPipeline();
if (lastPipeline != pipeline)
{ {
pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); const MaterialPipeline* pipeline = batch.material->GetPipeline();
if (pipeline != lastPipeline)
{
pipelineInstance = &batch.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
const Shader* shader = pipelineInstance->uberInstance->GetShader(); const Shader* shader = pipelineInstance->uberInstance->GetShader();
if (shader != lastShader) if (shader != lastShader)
@ -566,33 +514,105 @@ namespace Nz
lastPipeline = pipeline; lastPipeline = pipeline;
} }
if (lastMaterial != basicSprites.material) if (batch.material != lastMaterial)
{ {
basicSprites.material->Apply(*pipelineInstance); batch.material->Apply(*pipelineInstance);
Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler()); Renderer::SetTextureSampler(overlayTextureUnit, batch.material->GetDiffuseSampler());
lastMaterial = batch.material;
}
if (batch.overlayTexture != lastOverlay)
{
Renderer::SetTexture(overlayTextureUnit, batch.overlayTexture);
lastOverlay = batch.overlayTexture;
}
if (batch.material->IsScissorTestEnabled() && batch.scissorRect != lastScissorRect)
{
Renderer::SetScissorRect(batch.scissorRect);
lastScissorRect = batch.scissorRect;
}
unsigned int indexCount = batch.spriteCount * 6;
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount);
firstIndex += indexCount;
}
};
m_spriteBatches.clear();
{
BufferMapper<VertexBuffer> vertexMapper;
VertexStruct_XYZ_Color_UV* vertices = nullptr;
std::size_t remainingSprite = maxSpriteCount;
const Material* lastMaterial = nullptr;
const Texture* lastOverlay = nullptr;
Recti lastScissorRect = Recti(-1, -1);
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList)
{
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
const VertexStruct_XYZ_Color_UV* spriteVertices = basicSprites.vertices;
std::size_t spriteCount = basicSprites.spriteCount;
for (;;)
{
if (m_spriteBatches.empty() || basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
{
m_spriteBatches.emplace_back();
SpriteBatch& newBatch = m_spriteBatches.back();
newBatch.material = basicSprites.material;
newBatch.overlayTexture = overlayTexture;
newBatch.scissorRect = scissorRect;
newBatch.spriteCount = 0;
lastMaterial = basicSprites.material; lastMaterial = basicSprites.material;
}
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
if (overlayTexture != lastOverlay)
{
Renderer::SetTexture(overlayTextureUnit, overlayTexture);
lastOverlay = overlayTexture; lastOverlay = overlayTexture;
}
if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
{
Renderer::SetScissorRect(scissorRect);
lastScissorRect = scissorRect; lastScissorRect = scissorRect;
} }
SpriteBatch& currentBatch = m_spriteBatches.back();
if (!vertices)
{
vertexMapper.Map(m_spriteBuffer, BufferAccess_DiscardAndWrite);
vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
} }
m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount); std::size_t processedSpriteCount = std::min(remainingSprite, spriteCount);
std::size_t processedVertices = processedSpriteCount * 4;
std::memcpy(vertices, spriteVertices, processedVertices * sizeof(VertexStruct_XYZ_Color_UV));
vertices += processedVertices;
spriteVertices += processedVertices;
currentBatch.spriteCount += processedSpriteCount;
spriteCount -= processedSpriteCount;
remainingSprite -= processedSpriteCount;
if (remainingSprite == 0)
{
vertexMapper.Unmap();
vertices = nullptr;
Draw();
remainingSprite = maxSpriteCount;
m_spriteBatches.clear();
} }
Commit(); if (spriteCount == 0)
break;
}
}
}
Draw();
} }
const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const
@ -631,12 +651,12 @@ namespace Nz
{ {
ErrorFlags flags(ErrorFlag_ThrowException, true); ErrorFlags flags(ErrorFlag_ThrowException, true);
s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0); s_quadIndexBuffer.Reset(true, s_maxQuadPerDraw * 6, DataStorage_Hardware, 0);
BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly);
UInt16* indices = static_cast<UInt16*>(mapper.GetPointer()); UInt32* indices = static_cast<UInt32*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxQuads; ++i) for (UInt32 i = 0; i < s_maxQuadPerDraw; ++i)
{ {
*indices++ = i * 4 + 0; *indices++ = i * 4 + 0;
*indices++ = i * 4 + 2; *indices++ = i * 4 + 2;

View File

@ -31,8 +31,8 @@ namespace Nz
Vector2f uv; Vector2f uv;
}; };
unsigned int s_maxQuads = std::numeric_limits<UInt16>::max() / 6; constexpr UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB constexpr UInt32 s_maxQuadPerDraw = s_vertexBufferSize / sizeof(VertexLayout_XYZ_Color_UV);
} }
/*! /*!
@ -148,12 +148,12 @@ namespace Nz
{ {
ErrorFlags flags(ErrorFlag_ThrowException, true); ErrorFlags flags(ErrorFlag_ThrowException, true);
s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0); s_quadIndexBuffer.Reset(true, s_maxQuadPerDraw * 6, DataStorage_Hardware, 0);
BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly);
UInt16* indices = static_cast<UInt16*>(mapper.GetPointer()); UInt32* indices = static_cast<UInt32*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxQuads; ++i) for (UInt32 i = 0; i < s_maxQuadPerDraw; ++i)
{ {
*indices++ = i * 4 + 0; *indices++ = i * 4 + 0;
*indices++ = i * 4 + 2; *indices++ = i * 4 + 2;
@ -486,62 +486,9 @@ namespace Nz
const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
Renderer::SetIndexBuffer(&s_quadIndexBuffer); const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuadPerDraw, m_spriteBuffer.GetVertexCount() / 4);
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
Renderer::SetVertexBuffer(&m_spriteBuffer);
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
m_spriteChains.clear();
auto Commit = [&]()
{
std::size_t spriteChainCount = m_spriteChains.size();
if (spriteChainCount > 0)
{
std::size_t spriteChain = 0; // Which chain of sprites are we treating
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
do
{
// We open the buffer in writing mode
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
std::size_t spriteCount = 0;
do
{
const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first;
std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second;
std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset);
std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
vertices += count * 4;
spriteCount += count;
spriteChainOffset += count;
// Have we treated the entire chain ?
if (spriteChainOffset == currentChainSpriteCount)
{
spriteChain++;
spriteChainOffset = 0;
}
}
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
vertexMapper.Unmap();
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
}
while (spriteChain < spriteChainCount);
}
m_spriteChains.clear();
};
const Material* lastMaterial = nullptr; const Material* lastMaterial = nullptr;
const MaterialPipeline* lastPipeline = nullptr; const MaterialPipeline* lastPipeline = nullptr;
const Shader* lastShader = nullptr; const Shader* lastShader = nullptr;
@ -551,18 +498,19 @@ namespace Nz
const MaterialPipeline::Instance* pipelineInstance = nullptr; const MaterialPipeline::Instance* pipelineInstance = nullptr;
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) Renderer::SetIndexBuffer(&s_quadIndexBuffer);
{ Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; Renderer::SetVertexBuffer(&m_spriteBuffer);
if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) auto Draw = [&]()
{ {
Commit(); unsigned int firstIndex = 0;
for (const auto& batch : m_spriteBatches)
const MaterialPipeline* pipeline = basicSprites.material->GetPipeline();
if (lastPipeline != pipeline)
{ {
pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); const MaterialPipeline* pipeline = batch.material->GetPipeline();
if (pipeline != lastPipeline)
{
pipelineInstance = &batch.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
const Shader* shader = pipelineInstance->uberInstance->GetShader(); const Shader* shader = pipelineInstance->uberInstance->GetShader();
if (shader != lastShader) if (shader != lastShader)
@ -582,33 +530,105 @@ namespace Nz
lastPipeline = pipeline; lastPipeline = pipeline;
} }
if (lastMaterial != basicSprites.material) if (batch.material != lastMaterial)
{ {
basicSprites.material->Apply(*pipelineInstance); batch.material->Apply(*pipelineInstance);
Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler()); Renderer::SetTextureSampler(overlayTextureUnit, batch.material->GetDiffuseSampler());
lastMaterial = batch.material;
}
if (batch.overlayTexture != lastOverlay)
{
Renderer::SetTexture(overlayTextureUnit, batch.overlayTexture);
lastOverlay = batch.overlayTexture;
}
if (batch.material->IsScissorTestEnabled() && batch.scissorRect != lastScissorRect)
{
Renderer::SetScissorRect(batch.scissorRect);
lastScissorRect = batch.scissorRect;
}
unsigned int indexCount = batch.spriteCount * 6;
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount);
firstIndex += indexCount;
}
};
m_spriteBatches.clear();
{
BufferMapper<VertexBuffer> vertexMapper;
VertexStruct_XYZ_Color_UV* vertices = nullptr;
std::size_t remainingSprite = maxSpriteCount;
const Material* lastMaterial = nullptr;
const Texture* lastOverlay = nullptr;
Recti lastScissorRect = Recti(-1, -1);
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList)
{
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
const VertexStruct_XYZ_Color_UV* spriteVertices = basicSprites.vertices;
std::size_t spriteCount = basicSprites.spriteCount;
for (;;)
{
if (m_spriteBatches.empty() || basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
{
m_spriteBatches.emplace_back();
SpriteBatch& newBatch = m_spriteBatches.back();
newBatch.material = basicSprites.material;
newBatch.overlayTexture = overlayTexture;
newBatch.scissorRect = scissorRect;
newBatch.spriteCount = 0;
lastMaterial = basicSprites.material; lastMaterial = basicSprites.material;
}
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
if (overlayTexture != lastOverlay)
{
Renderer::SetTexture(overlayTextureUnit, overlayTexture);
lastOverlay = overlayTexture; lastOverlay = overlayTexture;
}
if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
{
Renderer::SetScissorRect(scissorRect);
lastScissorRect = scissorRect; lastScissorRect = scissorRect;
} }
SpriteBatch& currentBatch = m_spriteBatches.back();
if (!vertices)
{
vertexMapper.Map(m_spriteBuffer, BufferAccess_DiscardAndWrite);
vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
} }
m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount); std::size_t processedSpriteCount = std::min(remainingSprite, spriteCount);
std::size_t processedVertices = processedSpriteCount * 4;
std::memcpy(vertices, spriteVertices, processedVertices * sizeof(VertexStruct_XYZ_Color_UV));
vertices += processedVertices;
spriteVertices += processedVertices;
currentBatch.spriteCount += processedSpriteCount;
spriteCount -= processedSpriteCount;
remainingSprite -= processedSpriteCount;
if (remainingSprite == 0)
{
vertexMapper.Unmap();
vertices = nullptr;
Draw();
remainingSprite = maxSpriteCount;
m_spriteBatches.clear();
} }
Commit(); if (spriteCount == 0)
break;
}
}
}
Draw();
} }
/*! /*!

View File

@ -32,8 +32,8 @@ namespace Nz
Vector2f uv; Vector2f uv;
}; };
UInt32 s_maxQuads = std::numeric_limits<UInt16>::max() / 6; constexpr UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB constexpr UInt32 s_maxQuadPerDraw = s_vertexBufferSize / sizeof(VertexLayout_XYZ_Color_UV);
} }
/*! /*!
@ -175,12 +175,12 @@ namespace Nz
{ {
ErrorFlags flags(ErrorFlag_ThrowException, true); ErrorFlags flags(ErrorFlag_ThrowException, true);
s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0); s_quadIndexBuffer.Reset(true, s_maxQuadPerDraw * 6, DataStorage_Hardware, 0);
BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); BufferMapper<IndexBuffer> mapper(s_quadIndexBuffer, BufferAccess_WriteOnly);
UInt16* indices = static_cast<UInt16*>(mapper.GetPointer()); UInt32* indices = static_cast<UInt32*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxQuads; ++i) for (UInt32 i = 0; i < s_maxQuadPerDraw; ++i)
{ {
*indices++ = i * 4 + 0; *indices++ = i * 4 + 0;
*indices++ = i * 4 + 2; *indices++ = i * 4 + 2;
@ -618,52 +618,9 @@ namespace Nz
const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); const RenderTarget* renderTarget = sceneData.viewer->GetTarget();
Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize()));
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuadPerDraw, m_spriteBuffer.GetVertexCount() / 4);
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
m_spriteBatches.clear();
{
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
std::size_t remainingSprite = maxSpriteCount;
const Material* lastMaterial = nullptr;
const Texture* lastOverlay = nullptr;
Recti lastScissorRect = Recti(-1, -1);
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList)
{
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
if (basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
{
m_spriteBatches.emplace_back();
SpriteBatch& newBatch = m_spriteBatches.back();
newBatch.material = basicSprites.material;
newBatch.overlayTexture = overlayTexture;
newBatch.scissorRect = scissorRect;
newBatch.spriteCount = 0;
lastMaterial = basicSprites.material;
lastOverlay = overlayTexture;
lastScissorRect = scissorRect;
}
SpriteBatch& currentBatch = m_spriteBatches.back();
std::size_t spriteCount = std::min(remainingSprite, basicSprites.spriteCount);
std::memcpy(vertices, basicSprites.vertices, spriteCount * 4 * sizeof(VertexStruct_XYZ_Color_UV));
vertices += spriteCount * 4;
currentBatch.spriteCount += spriteCount;
remainingSprite -= spriteCount;
if (remainingSprite == 0)
break;
}
}
const Material* lastMaterial = nullptr; const Material* lastMaterial = nullptr;
const MaterialPipeline* lastPipeline = nullptr; const MaterialPipeline* lastPipeline = nullptr;
const Shader* lastShader = nullptr; const Shader* lastShader = nullptr;
@ -677,6 +634,8 @@ namespace Nz
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
Renderer::SetVertexBuffer(&m_spriteBuffer); Renderer::SetVertexBuffer(&m_spriteBuffer);
auto Draw = [&]()
{
unsigned int firstIndex = 0; unsigned int firstIndex = 0;
for (const auto& batch : m_spriteBatches) for (const auto& batch : m_spriteBatches)
{ {
@ -730,6 +689,80 @@ namespace Nz
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount); Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount);
firstIndex += indexCount; firstIndex += indexCount;
} }
};
m_spriteBatches.clear();
{
BufferMapper<VertexBuffer> vertexMapper;
VertexStruct_XYZ_Color_UV* vertices = nullptr;
std::size_t remainingSprite = maxSpriteCount;
const Material* lastMaterial = nullptr;
const Texture* lastOverlay = nullptr;
Recti lastScissorRect = Recti(-1, -1);
for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList)
{
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
const VertexStruct_XYZ_Color_UV* spriteVertices = basicSprites.vertices;
std::size_t spriteCount = basicSprites.spriteCount;
for (;;)
{
if (m_spriteBatches.empty() || basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
{
m_spriteBatches.emplace_back();
SpriteBatch& newBatch = m_spriteBatches.back();
newBatch.material = basicSprites.material;
newBatch.overlayTexture = overlayTexture;
newBatch.scissorRect = scissorRect;
newBatch.spriteCount = 0;
lastMaterial = basicSprites.material;
lastOverlay = overlayTexture;
lastScissorRect = scissorRect;
}
SpriteBatch& currentBatch = m_spriteBatches.back();
if (!vertices)
{
vertexMapper.Map(m_spriteBuffer, BufferAccess_DiscardAndWrite);
vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
}
std::size_t processedSpriteCount = std::min(remainingSprite, spriteCount);
std::size_t processedVertices = processedSpriteCount * 4;
std::memcpy(vertices, spriteVertices, processedVertices * sizeof(VertexStruct_XYZ_Color_UV));
vertices += processedVertices;
spriteVertices += processedVertices;
currentBatch.spriteCount += processedSpriteCount;
spriteCount -= processedSpriteCount;
remainingSprite -= processedSpriteCount;
if (remainingSprite == 0)
{
vertexMapper.Unmap();
vertices = nullptr;
Draw();
remainingSprite = maxSpriteCount;
m_spriteBatches.clear();
}
if (spriteCount == 0)
break;
}
}
}
Draw();
} }
const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const