Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/renderer/PatchRData.cpp
Show First 20 Lines • Show All 709 Lines • ▼ Show 20 Lines | |||||
using IndexBufferBatches = PooledBatchMap<CVertexBuffer*, BatchElements>; | using IndexBufferBatches = PooledBatchMap<CVertexBuffer*, BatchElements>; | ||||
// Group batches by vertex buffer | // Group batches by vertex buffer | ||||
using VertexBufferBatches = PooledBatchMap<CVertexBuffer*, IndexBufferBatches>; | using VertexBufferBatches = PooledBatchMap<CVertexBuffer*, IndexBufferBatches>; | ||||
// Group batches by texture | // Group batches by texture | ||||
using TextureBatches = PooledBatchMap<CTerrainTextureEntry*, VertexBufferBatches>; | using TextureBatches = PooledBatchMap<CTerrainTextureEntry*, VertexBufferBatches>; | ||||
// Group batches by shaders. | |||||
using ShaderTechniqueBatches = PooledBatchMap<CShaderTechniquePtr, TextureBatches>; | |||||
void CPatchRData::RenderBases( | void CPatchRData::RenderBases( | ||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow) | const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow) | ||||
{ | { | ||||
Arena arena; | Arena arena; | ||||
TextureBatches batches(TextureBatches::key_compare(), (TextureBatches::allocator_type(arena))); | ShaderTechniqueBatches batches(ShaderTechniqueBatches::key_compare(), (ShaderTechniqueBatches::allocator_type(arena))); | ||||
PROFILE_START("compute batches"); | PROFILE_START("compute batches"); | ||||
// Collect all the patches' base splats into their appropriate batches | // Collect all the patches' base splats into their appropriate batches | ||||
for (size_t i = 0; i < patches.size(); ++i) | for (size_t i = 0; i < patches.size(); ++i) | ||||
{ | { | ||||
CPatchRData* patch = patches[i]; | CPatchRData* patch = patches[i]; | ||||
for (size_t j = 0; j < patch->m_Splats.size(); ++j) | for (size_t j = 0; j < patch->m_Splats.size(); ++j) | ||||
{ | { | ||||
SSplat& splat = patch->m_Splats[j]; | SSplat& splat = patch->m_Splats[j]; | ||||
const CMaterial& material = splat.m_Texture->GetMaterial(); | |||||
if (material.GetShaderEffect().empty()) | |||||
{ | |||||
LOGERROR("Terrain renderer failed to load shader effect.\n"); | |||||
continue; | |||||
} | |||||
CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect( | |||||
material.GetShaderEffect(), context, material.GetShaderDefines(0)); | |||||
BatchElements& batch = PooledPairGet( | BatchElements& batch = PooledPairGet( | ||||
PooledMapGet( | PooledMapGet( | ||||
PooledMapGet(batches, splat.m_Texture, arena), | PooledMapGet( | ||||
PooledMapGet(batches, techBase, arena), | |||||
splat.m_Texture, arena | |||||
), | |||||
patch->m_VBBase->m_Owner, arena | patch->m_VBBase->m_Owner, arena | ||||
), | ), | ||||
patch->m_VBBaseIndices->m_Owner, arena | patch->m_VBBaseIndices->m_Owner, arena | ||||
); | ); | ||||
batch.first.push_back(splat.m_IndexCount); | batch.first.push_back(splat.m_IndexCount); | ||||
u8* indexBase = patch->m_VBBaseIndices->m_Owner->GetBindAddress(); | u8* indexBase = patch->m_VBBaseIndices->m_Owner->GetBindAddress(); | ||||
batch.second.push_back(indexBase + sizeof(u16)*(patch->m_VBBaseIndices->m_Index + splat.m_IndexStart)); | batch.second.push_back(indexBase + sizeof(u16)*(patch->m_VBBaseIndices->m_Index + splat.m_IndexStart)); | ||||
} | } | ||||
} | } | ||||
PROFILE_END("compute batches"); | PROFILE_END("compute batches"); | ||||
// Render each batch | // Render each batch | ||||
for (TextureBatches::iterator itt = batches.begin(); itt != batches.end(); ++itt) | for (ShaderTechniqueBatches::iterator itTech = batches.begin(); itTech != batches.end(); ++itTech) | ||||
{ | |||||
if (itt->first->GetMaterial().GetShaderEffect().empty()) | |||||
{ | { | ||||
LOGERROR("Terrain renderer failed to load shader effect.\n"); | const CShaderTechniquePtr& techBase = itTech->first; | ||||
continue; | |||||
} | |||||
CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect(itt->first->GetMaterial().GetShaderEffect(), | |||||
context, itt->first->GetMaterial().GetShaderDefines(0)); | |||||
const int numPasses = techBase->GetNumPasses(); | const int numPasses = techBase->GetNumPasses(); | ||||
for (int pass = 0; pass < numPasses; ++pass) | for (int pass = 0; pass < numPasses; ++pass) | ||||
{ | { | ||||
techBase->BeginPass(pass); | techBase->BeginPass(pass); | ||||
TerrainRenderer::PrepareShader(techBase->GetShader(), shadow); | |||||
const CShaderProgramPtr& shader = techBase->GetShader(pass); | const CShaderProgramPtr& shader = techBase->GetShader(pass); | ||||
TerrainRenderer::PrepareShader(shader, shadow); | |||||
TextureBatches& textureBatches = itTech->second; | |||||
for (TextureBatches::iterator itt = textureBatches.begin(); itt != textureBatches.end(); ++itt) | |||||
{ | |||||
if (itt->first->GetMaterial().GetSamplers().size() != 0) | if (itt->first->GetMaterial().GetSamplers().size() != 0) | ||||
{ | { | ||||
const CMaterial::SamplersVector& samplers = itt->first->GetMaterial().GetSamplers(); | const CMaterial::SamplersVector& samplers = itt->first->GetMaterial().GetSamplers(); | ||||
size_t samplersNum = samplers.size(); | for(const CMaterial::TextureSampler& samp : samplers) | ||||
for (size_t s = 0; s < samplersNum; ++s) | |||||
{ | |||||
const CMaterial::TextureSampler& samp = samplers[s]; | |||||
shader->BindTexture(samp.Name, samp.Sampler); | shader->BindTexture(samp.Name, samp.Sampler); | ||||
} | |||||
itt->first->GetMaterial().GetStaticUniforms().BindUniforms(shader); | itt->first->GetMaterial().GetStaticUniforms().BindUniforms(shader); | ||||
float c = itt->first->GetTextureMatrix()[0]; | float c = itt->first->GetTextureMatrix()[0]; | ||||
float ms = itt->first->GetTextureMatrix()[8]; | float ms = itt->first->GetTextureMatrix()[8]; | ||||
shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); | shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()); | shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()); | ||||
} | } | ||||
for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv) | for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv) | ||||
{ | { | ||||
GLsizei stride = sizeof(SBaseVertex); | GLsizei stride = sizeof(SBaseVertex); | ||||
SBaseVertex *base = (SBaseVertex *)itv->first->Bind(); | SBaseVertex *base = (SBaseVertex *)itv->first->Bind(); | ||||
shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); | shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); | ||||
shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); | shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); | ||||
shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); | shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); | ||||
shader->AssertPointersBound(); | shader->AssertPointersBound(); | ||||
for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) | for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) | ||||
{ | { | ||||
it->first->Bind(); | it->first->Bind(); | ||||
BatchElements& batch = it->second; | BatchElements& batch = it->second; | ||||
if (!g_Renderer.m_SkipSubmit) | if (!g_Renderer.m_SkipSubmit) | ||||
{ | { | ||||
// Don't use glMultiDrawElements here since it doesn't have a significant | // Don't use glMultiDrawElements here since it doesn't have a significant | ||||
// performance impact and it suffers from various driver bugs (e.g. it breaks | // performance impact and it suffers from various driver bugs (e.g. it breaks | ||||
// in Mesa 7.10 swrast with index VBOs) | // in Mesa 7.10 swrast with index VBOs) | ||||
for (size_t i = 0; i < batch.first.size(); ++i) | for (size_t i = 0; i < batch.first.size(); ++i) | ||||
glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); | glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); | ||||
} | } | ||||
g_Renderer.m_Stats.m_DrawCalls++; | g_Renderer.m_Stats.m_DrawCalls++; | ||||
g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; | g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; | ||||
} | } | ||||
} | } | ||||
} | |||||
techBase->EndPass(); | techBase->EndPass(); | ||||
} | } | ||||
} | } | ||||
CVertexBuffer::Unbind(); | CVertexBuffer::Unbind(); | ||||
} | } | ||||
/** | /** | ||||
* Helper structure for RenderBlends. | * Helper structure for RenderBlends. | ||||
*/ | */ | ||||
struct SBlendBatch | struct SBlendBatch | ||||
{ | { | ||||
SBlendBatch(Arena& arena) : | SBlendBatch(Arena& arena) : | ||||
m_Batches(VertexBufferBatches::key_compare(), VertexBufferBatches::allocator_type(arena)) | m_Batches(VertexBufferBatches::key_compare(), VertexBufferBatches::allocator_type(arena)) | ||||
{ | { | ||||
} | } | ||||
CTerrainTextureEntry* m_Texture; | CTerrainTextureEntry* m_Texture; | ||||
CShaderTechniquePtr m_ShaderTech; | |||||
VertexBufferBatches m_Batches; | VertexBufferBatches m_Batches; | ||||
}; | }; | ||||
/** | /** | ||||
* Helper structure for RenderBlends. | * Helper structure for RenderBlends. | ||||
*/ | */ | ||||
struct SBlendStackItem | struct SBlendStackItem | ||||
{ | { | ||||
SBlendStackItem(CVertexBuffer::VBChunk* v, CVertexBuffer::VBChunk* i, | SBlendStackItem(CVertexBuffer::VBChunk* v, CVertexBuffer::VBChunk* i, | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | for (size_t k = 0; k < blendStacks.size(); ++k) | ||||
} | } | ||||
} | } | ||||
if (bestStackSize == 0) | if (bestStackSize == 0) | ||||
break; | break; | ||||
SBlendBatch layer(arena); | SBlendBatch layer(arena); | ||||
layer.m_Texture = bestTex; | layer.m_Texture = bestTex; | ||||
if (!bestTex->GetMaterial().GetSamplers().empty()) | |||||
{ | |||||
layer.m_ShaderTech = g_Renderer.GetShaderManager().LoadEffect( | |||||
bestTex->GetMaterial().GetShaderEffect(), contextBlend, bestTex->GetMaterial().GetShaderDefines(0)); | |||||
} | |||||
batches.push_back(layer); | batches.push_back(layer); | ||||
} | } | ||||
PROFILE_END("compute batches"); | PROFILE_END("compute batches"); | ||||
CVertexBuffer* lastVB = NULL; | glEnable(GL_BLEND); | ||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
for (BatchesStack::iterator itt = batches.begin(); itt != batches.end(); ++itt) | CVertexBuffer* lastVB = nullptr; | ||||
CShaderProgramPtr previousShader; | |||||
for (BatchesStack::iterator itTechBegin = batches.begin(), itTechEnd = batches.begin(); itTechBegin != batches.end(); itTechBegin = itTechEnd) | |||||
{ | { | ||||
if (itt->m_Texture->GetMaterial().GetSamplers().size() == 0) | while (itTechEnd != batches.end() && itTechEnd->m_ShaderTech == itTechBegin->m_ShaderTech) | ||||
continue; | ++itTechEnd; | ||||
CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect(itt->m_Texture->GetMaterial().GetShaderEffect(), contextBlend, itt->m_Texture->GetMaterial().GetShaderDefines(0)); | const CShaderTechniquePtr& techBase = itTechBegin->m_ShaderTech; | ||||
const int numPasses = techBase->GetNumPasses(); | const int numPasses = techBase->GetNumPasses(); | ||||
CShaderProgramPtr previousShader; | |||||
for (int pass = 0; pass < numPasses; ++pass) | for (int pass = 0; pass < numPasses; ++pass) | ||||
{ | { | ||||
techBase->BeginPass(pass); | techBase->BeginPass(pass); | ||||
TerrainRenderer::PrepareShader(techBase->GetShader(), shadow); | |||||
glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
const CShaderProgramPtr& shader = techBase->GetShader(pass); | const CShaderProgramPtr& shader = techBase->GetShader(pass); | ||||
TerrainRenderer::PrepareShader(shader, shadow); | |||||
if (itt->m_Texture) | for (BatchesStack::iterator itt = itTechBegin; itt != itTechEnd; ++itt) | ||||
{ | { | ||||
const CMaterial::SamplersVector& samplers = itt->m_Texture->GetMaterial().GetSamplers(); | if (itt->m_Texture->GetMaterial().GetSamplers().empty()) | ||||
size_t samplersNum = samplers.size(); | continue; | ||||
for (size_t s = 0; s < samplersNum; ++s) | if (itt->m_Texture) | ||||
{ | { | ||||
const CMaterial::TextureSampler& samp = samplers[s]; | const CMaterial::SamplersVector& samplers = itt->m_Texture->GetMaterial().GetSamplers(); | ||||
for (const CMaterial::TextureSampler& samp : samplers) | |||||
shader->BindTexture(samp.Name, samp.Sampler); | shader->BindTexture(samp.Name, samp.Sampler); | ||||
} | |||||
shader->BindTexture(str_blendTex, itt->m_Texture->m_TerrainAlpha->second.m_hCompositeAlphaMap); | shader->BindTexture(str_blendTex, itt->m_Texture->m_TerrainAlpha->second.m_hCompositeAlphaMap); | ||||
itt->m_Texture->GetMaterial().GetStaticUniforms().BindUniforms(shader); | itt->m_Texture->GetMaterial().GetStaticUniforms().BindUniforms(shader); | ||||
float c = itt->m_Texture->GetTextureMatrix()[0]; | float c = itt->m_Texture->GetTextureMatrix()[0]; | ||||
float ms = itt->m_Texture->GetTextureMatrix()[8]; | float ms = itt->m_Texture->GetTextureMatrix()[8]; | ||||
shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); | shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()); | shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()); | ||||
} | } | ||||
for (VertexBufferBatches::iterator itv = itt->m_Batches.begin(); itv != itt->m_Batches.end(); ++itv) | for (VertexBufferBatches::iterator itv = itt->m_Batches.begin(); itv != itt->m_Batches.end(); ++itv) | ||||
{ | { | ||||
// Rebind the VB only if it changed since the last batch | // Rebind the VB only if it changed since the last batch | ||||
if (itv->first != lastVB || shader != previousShader) | if (itv->first != lastVB || shader != previousShader) | ||||
{ | { | ||||
lastVB = itv->first; | lastVB = itv->first; | ||||
previousShader = shader; | previousShader = shader; | ||||
GLsizei stride = sizeof(SBlendVertex); | GLsizei stride = sizeof(SBlendVertex); | ||||
SBlendVertex *base = (SBlendVertex *)itv->first->Bind(); | SBlendVertex *base = (SBlendVertex *)itv->first->Bind(); | ||||
shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); | shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); | ||||
shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); | shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); | ||||
shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); | shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); | ||||
shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &base->m_AlphaUVs[0]); | shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &base->m_AlphaUVs[0]); | ||||
} | } | ||||
shader->AssertPointersBound(); | shader->AssertPointersBound(); | ||||
for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) | for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) | ||||
{ | { | ||||
it->first->Bind(); | it->first->Bind(); | ||||
BatchElements& batch = it->second; | BatchElements& batch = it->second; | ||||
if (!g_Renderer.m_SkipSubmit) | if (!g_Renderer.m_SkipSubmit) | ||||
{ | { | ||||
for (size_t i = 0; i < batch.first.size(); ++i) | for (size_t i = 0; i < batch.first.size(); ++i) | ||||
glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); | glDrawElements(GL_TRIANGLES, batch.first[i], GL_UNSIGNED_SHORT, batch.second[i]); | ||||
} | } | ||||
g_Renderer.m_Stats.m_DrawCalls++; | g_Renderer.m_Stats.m_DrawCalls++; | ||||
g_Renderer.m_Stats.m_BlendSplats++; | g_Renderer.m_Stats.m_BlendSplats++; | ||||
g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; | g_Renderer.m_Stats.m_TerrainTris += std::accumulate(batch.first.begin(), batch.first.end(), 0) / 3; | ||||
} | } | ||||
} | } | ||||
} | |||||
glDisable(GL_BLEND); | |||||
techBase->EndPass(); | techBase->EndPass(); | ||||
} | } | ||||
} | } | ||||
glDisable(GL_BLEND); | |||||
CVertexBuffer::Unbind(); | CVertexBuffer::Unbind(); | ||||
} | } | ||||
void CPatchRData::RenderStreams(const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader, int streamflags) | void CPatchRData::RenderStreams(const std::vector<CPatchRData*>& patches, const CShaderProgramPtr& shader, int streamflags) | ||||
{ | { | ||||
// Each batch has a list of index counts, and a list of pointers-to-first-indexes | // Each batch has a list of index counts, and a list of pointers-to-first-indexes | ||||
using StreamBatchElements = std::pair<std::vector<GLint>, std::vector<void*> > ; | using StreamBatchElements = std::pair<std::vector<GLint>, std::vector<void*> > ; | ||||
▲ Show 20 Lines • Show All 415 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator