Graphics/ForwardRenderTechnique: Optimize sprite rendering
This commit is contained in:
parent
056bd0efdd
commit
e9f0bdeb25
|
|
@ -83,9 +83,17 @@ 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<LightIndex> m_lights;
|
mutable std::vector<LightIndex> m_lights;
|
||||||
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;
|
||||||
mutable BasicRenderQueue m_renderQueue;
|
mutable BasicRenderQueue m_renderQueue;
|
||||||
TextureRef m_whiteCubemap;
|
TextureRef m_whiteCubemap;
|
||||||
|
|
|
||||||
|
|
@ -618,61 +618,51 @@ 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);
|
|
||||||
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);
|
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||||
|
|
||||||
m_spriteChains.clear();
|
m_spriteBatches.clear();
|
||||||
|
|
||||||
auto Commit = [&]()
|
|
||||||
{
|
{
|
||||||
std::size_t spriteChainCount = m_spriteChains.size();
|
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||||
if (spriteChainCount > 0)
|
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)
|
||||||
{
|
{
|
||||||
std::size_t spriteChain = 0; // Which chain of sprites are we treating
|
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
|
||||||
std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
|
||||||
|
if (basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
||||||
do
|
|
||||||
{
|
{
|
||||||
// We open the buffer in writing mode
|
m_spriteBatches.emplace_back();
|
||||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
SpriteBatch& newBatch = m_spriteBatches.back();
|
||||||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
newBatch.material = basicSprites.material;
|
||||||
|
newBatch.overlayTexture = overlayTexture;
|
||||||
|
newBatch.scissorRect = scissorRect;
|
||||||
|
newBatch.spriteCount = 0;
|
||||||
|
|
||||||
std::size_t spriteCount = 0;
|
lastMaterial = basicSprites.material;
|
||||||
|
lastOverlay = overlayTexture;
|
||||||
do
|
lastScissorRect = scissorRect;
|
||||||
{
|
|
||||||
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();
|
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;
|
||||||
|
|
@ -683,66 +673,63 @@ 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());
|
||||||
|
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||||
|
|
||||||
|
unsigned int firstIndex = 0;
|
||||||
|
for (const auto& batch : m_spriteBatches)
|
||||||
{
|
{
|
||||||
const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect;
|
const MaterialPipeline* pipeline = batch.material->GetPipeline();
|
||||||
|
if (pipeline != lastPipeline)
|
||||||
if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect))
|
|
||||||
{
|
{
|
||||||
Commit();
|
pipelineInstance = &batch.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||||
|
|
||||||
const MaterialPipeline* pipeline = basicSprites.material->GetPipeline();
|
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||||
if (lastPipeline != pipeline)
|
if (shader != lastShader)
|
||||||
{
|
{
|
||||||
pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
// Index of uniforms in the shader
|
||||||
|
shaderUniforms = GetShaderUniforms(shader);
|
||||||
|
|
||||||
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
// Ambient color of the scene
|
||||||
if (shader != lastShader)
|
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||||
{
|
// Position of the camera
|
||||||
// Index of uniforms in the shader
|
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||||
shaderUniforms = GetShaderUniforms(shader);
|
|
||||||
|
|
||||||
// Ambient color of the scene
|
// Overlay texture unit
|
||||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
||||||
// Position of the camera
|
|
||||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
|
||||||
|
|
||||||
// Overlay texture unit
|
lastShader = shader;
|
||||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
|
||||||
|
|
||||||
lastShader = shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPipeline = pipeline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastMaterial != basicSprites.material)
|
lastPipeline = pipeline;
|
||||||
{
|
|
||||||
basicSprites.material->Apply(*pipelineInstance);
|
|
||||||
|
|
||||||
Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler());
|
|
||||||
|
|
||||||
lastMaterial = basicSprites.material;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get();
|
|
||||||
if (overlayTexture != lastOverlay)
|
|
||||||
{
|
|
||||||
Renderer::SetTexture(overlayTextureUnit, overlayTexture);
|
|
||||||
lastOverlay = overlayTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)
|
|
||||||
{
|
|
||||||
Renderer::SetScissorRect(scissorRect);
|
|
||||||
lastScissorRect = scissorRect;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount);
|
if (batch.material != lastMaterial)
|
||||||
}
|
{
|
||||||
|
batch.material->Apply(*pipelineInstance);
|
||||||
|
|
||||||
Commit();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const
|
const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue