Index: binaries/data/mods/public/shaders/glsl/model_common.vs =================================================================== --- binaries/data/mods/public/shaders/glsl/model_common.vs +++ binaries/data/mods/public/shaders/glsl/model_common.vs @@ -1,4 +1,5 @@ #version 120 +#extension GL_ARB_draw_instanced : enable uniform mat4 transform; uniform vec3 cameraPos; @@ -12,6 +13,7 @@ uniform vec2 losTransform; uniform mat4 shadowTransform; uniform mat4 instancingTransform; +uniform mat4 instancingTransformReal[32]; #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF uniform vec4 shadowScale; @@ -64,7 +66,6 @@ attribute vec4 a_skinWeights; #endif - vec4 fakeCos(vec4 x) { vec4 tri = abs(fract(x + 0.5) * 2.0 - 1.0); @@ -85,16 +86,16 @@ n += vec3(m * vec4(a_normal, 0.0)) * a_skinWeights[i]; } } - vec4 position = instancingTransform * vec4(p, 1.0); - mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); + vec4 position = instancingTransformReal[gl_InstanceIDARB] * vec4(p, 1.0); + mat3 normalMatrix = mat3(instancingTransformReal[gl_InstanceIDARB][0].xyz, instancingTransformReal[gl_InstanceIDARB][1].xyz, instancingTransformReal[gl_InstanceIDARB][2].xyz); vec3 normal = normalMatrix * normalize(n); #if (USE_NORMAL_MAP || USE_PARALLAX) vec3 tangent = normalMatrix * a_tangent.xyz; #endif #else #if (USE_INSTANCING) - vec4 position = instancingTransform * vec4(a_vertex, 1.0); - mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); + vec4 position = instancingTransformReal[gl_InstanceIDARB] * vec4(a_vertex, 1.0); + mat3 normalMatrix = mat3(instancingTransformReal[gl_InstanceIDARB][0].xyz, instancingTransformReal[gl_InstanceIDARB][1].xyz, instancingTransformReal[gl_InstanceIDARB][2].xyz); vec3 normal = normalMatrix * a_normal; #if (USE_NORMAL_MAP || USE_PARALLAX) vec3 tangent = normalMatrix * a_tangent.xyz; @@ -110,7 +111,7 @@ vec2 wind = windData.xy; // fractional part of model position, clamped to >.4 - vec4 modelPos = instancingTransform[3]; + vec4 modelPos = instancingTransformReal[gl_InstanceIDARB][3]; modelPos = fract(modelPos); modelPos = clamp(modelPos, 0.4, 1.0); @@ -121,7 +122,7 @@ // these determine the speed of the wind's "cosine" waves. cosVec.w = 0.0; cosVec.x = sim_time.x * modelPos[0] + position.x; - cosVec.y = sim_time.x * modelPos[2] / 3.0 + instancingTransform[3][0]; + cosVec.y = sim_time.x * modelPos[2] / 3.0 + instancingTransformReal[gl_InstanceIDARB][3][0]; cosVec.z = sim_time.x * abswind / 4.0 + position.z; // calculate "cosines" in parallel, using a smoothed triangle wave Index: source/lib/external_libraries/glext_funcs.h =================================================================== --- source/lib/external_libraries/glext_funcs.h +++ source/lib/external_libraries/glext_funcs.h @@ -359,6 +359,9 @@ FUNC2(void, glBindFragDataLocationEXT, glBindFragDataLocation, "3.0", (GLuint program, GLuint colorNumber, const char *name)) FUNC2(GLint, glGetFragDataLocationEXT, glGetFragDataLocation, "3.0", (GLuint program, const char *name)) +// GL_ARB_draw_instanced / GL 3.3 +FUNC2(void, glDrawElementsInstancedARB, glDrawElementsInstanced, "3.3", (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount)) + // GL_ARB_occlusion_query / GL1.5: FUNC2(void, glGenQueriesARB, glGenQueries, "1.5", (GLsizei n, GLuint *ids)) FUNC2(void, glDeleteQueriesARB, glDeleteQueries, "1.5", (GLsizei n, const GLuint *ids)) Index: source/ps/CStrInternStatic.h =================================================================== --- source/ps/CStrInternStatic.h +++ source/ps/CStrInternStatic.h @@ -101,6 +101,7 @@ X(hdr) X(height) X(instancingTransform) +X2(instancingTransformReal, "instancingTransformReal[0]") X(losMap) X(losMatrix) X(losTex) Index: source/renderer/InstancingModelRenderer.h =================================================================== --- source/renderer/InstancingModelRenderer.h +++ source/renderer/InstancingModelRenderer.h @@ -45,7 +45,9 @@ void BeginPass(int streamflags); void EndPass(int streamflags); void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def); + bool CanInstance() { return true; } void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data); + void RenderInstancedModel(const CShaderProgramPtr& shader, const std::vector& model); protected: InstancingModelRendererInternals* m; Index: source/renderer/InstancingModelRenderer.cpp =================================================================== --- source/renderer/InstancingModelRenderer.cpp +++ source/renderer/InstancingModelRenderer.cpp @@ -382,3 +382,52 @@ g_Renderer.m_Stats.m_ModelTris += numFaces; } + +static std::vector uniforms; + +void InstancingModelRenderer::RenderInstancedModel(const CShaderProgramPtr& shader, const std::vector& models) +{ + if (g_Renderer.m_SkipSubmit) + return; + + if (m->gpuSkinning) + { + LOGWARNING("todo"); + return; + } + const CModelDefPtr& mdldef = models.front()->GetModelDef(); + size_t numFaces = mdldef->GetNumFaces(); + + // Set up a uniform + uniforms.reserve(32); + + if (models.size() == 1) + { + shader->Uniform(str_instancingTransformReal, 1, &models[0]->GetTransform()); + glDrawElements(GL_TRIANGLES, + (GLsizei)numFaces*3, + GL_UNSIGNED_SHORT, + m->imodeldefIndexBase); + g_Renderer.m_Stats.m_DrawCalls++; + g_Renderer.m_Stats.m_ModelTris += numFaces; + return; + } + size_t i = 0; + while (i < models.size()) + { + uniforms.clear(); + size_t u = 0; + for (;i < models.size() && u < 32; ++i, ++u) + uniforms.emplace_back(models[i]->GetTransform()); + + shader->Uniform(str_instancingTransformReal, u, uniforms.data()); + glDrawElementsInstancedARB(GL_TRIANGLES, + (GLsizei)numFaces*3, + GL_UNSIGNED_SHORT, + m->imodeldefIndexBase, u); + g_Renderer.m_Stats.m_DrawCalls++; + g_Renderer.m_Stats.m_ModelTris += numFaces * u; + } + + +} Index: source/renderer/ModelRenderer.cpp =================================================================== --- source/renderer/ModelRenderer.cpp +++ source/renderer/ModelRenderer.cpp @@ -298,6 +298,11 @@ if (b->GetMaterial().GetDiffuseTexture() < a->GetMaterial().GetDiffuseTexture()) return false; + if (a->GetPlayerID() < b->GetPlayerID()) + return true; + if (b->GetPlayerID() < a->GetPlayerID()) + return false; + return a->GetMaterial().GetStaticUniforms() < b->GetMaterial().GetStaticUniforms(); } }; @@ -654,15 +659,26 @@ CModelDef* currentModeldef = NULL; CShaderUniforms currentStaticUniforms; - +#ifdef DEBUG_BIND + LOGWARNING("technique pass"); +#endif + std::vector keptModels; for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx) { CModel** models = techBuckets[idx].models; size_t numModels = techBuckets[idx].numModels; +#ifdef DEBUG_BIND + LOGWARNING("Bucket: %i models", numModels); +#endif + keptModels.reserve(32); for (size_t i = 0; i < numModels; ++i) { CModel* model = models[i]; +#ifdef DEBUG_BIND + LOGWARNING("model %s", model->GetModelDef()->GetName().string8()); +#endif + if (flags && !(model->GetFlags() & flags)) continue; @@ -700,6 +716,13 @@ CTexture* newTex = samp.Sampler.get(); if (texBindings[s].Active() && newTex != currentTexs[s]) { +#ifdef DEBUG_BIND + LOGWARNING("binding sampler %i", s); +#endif + if (keptModels.size()) + m->vertexRenderer->RenderInstancedModel(shader, keptModels); + keptModels.clear(); + shader->BindTexture(texBindings[s], newTex->GetHandle()); currentTexs[s] = newTex; } @@ -709,6 +732,13 @@ CModelDef* newModeldef = model->GetModelDef().get(); if (newModeldef != currentModeldef) { +#ifdef DEBUG_BIND + LOGWARNING("binding model def"); +#endif + if (keptModels.size()) + m->vertexRenderer->RenderInstancedModel(shader, keptModels); + keptModels.clear(); + currentModeldef = newModeldef; m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); } @@ -717,49 +747,95 @@ CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms(); if (newStaticUniforms != currentStaticUniforms) { +#ifdef DEBUG_BIND + LOGWARNING("binding uniforms"); +#endif + if (keptModels.size()) + m->vertexRenderer->RenderInstancedModel(shader, keptModels); + keptModels.clear(); + currentStaticUniforms = newStaticUniforms; currentStaticUniforms.BindUniforms(shader); } const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries(); - for (size_t q = 0; q < renderQueries.GetSize(); ++q) - { - CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); - if (rq.first == RQUERY_TIME) - { - CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); - if (binding.Active()) - { - double time = g_Renderer.GetTimeManager().GetGlobalTime(); - shader->Uniform(binding, time, 0.0f, 0.0f, 0.0f); - } - } - else if (rq.first == RQUERY_WATER_TEX) - { - WaterManager* WaterMgr = g_Renderer.GetWaterManager(); - double time = WaterMgr->m_WaterTexTimer; - double period = 1.6; - int curTex = static_cast(time * 60.0 / period) % 60; - - if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) - shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); - else - shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); - } - else if (rq.first == RQUERY_SKY_CUBE) - { - shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); - } - } - - modifier->PrepareModel(shader, model); - CModelRData* rdata = static_cast(model->GetRenderData()); ENSURE(rdata->GetKey() == m->vertexRenderer.get()); + if (m->vertexRenderer->CanInstance()) + { + if (keptModels.size() == 0) + { + for (size_t q = 0; q < renderQueries.GetSize(); ++q) + { + CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); + if (rq.first == RQUERY_TIME) + { + CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); + if (binding.Active()) + { + double time = g_Renderer.GetTimeManager().GetGlobalTime(); + shader->Uniform(binding, time, 0.0f, 0.0f, 0.0f); + } + } + else if (rq.first == RQUERY_WATER_TEX) + { + WaterManager* WaterMgr = g_Renderer.GetWaterManager(); + double time = WaterMgr->m_WaterTexTimer; + double period = 1.6; + int curTex = static_cast(time * 60.0 / period) % 60; + if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) + shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); + else + shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); + } + else if (rq.first == RQUERY_SKY_CUBE) + { + shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); + } + } - m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); + modifier->PrepareModel(shader, model); + } + keptModels.push_back(model); + } + else + { + for (size_t q = 0; q < renderQueries.GetSize(); ++q) + { + CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); + if (rq.first == RQUERY_TIME) + { + CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); + if (binding.Active()) + { + double time = g_Renderer.GetTimeManager().GetGlobalTime(); + shader->Uniform(binding, time, 0.0f, 0.0f, 0.0f); + } + } + else if (rq.first == RQUERY_WATER_TEX) + { + WaterManager* WaterMgr = g_Renderer.GetWaterManager(); + double time = WaterMgr->m_WaterTexTimer; + double period = 1.6; + int curTex = static_cast(time * 60.0 / period) % 60; + if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) + shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); + else + shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); + } + else if (rq.first == RQUERY_SKY_CUBE) + { + shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); + } + } + modifier->PrepareModel(shader, model); + m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); + } } + if (keptModels.size()) + m->vertexRenderer->RenderInstancedModel(shader, keptModels); + keptModels.clear(); } m->vertexRenderer->EndPass(streamflags); Index: source/renderer/ModelVertexRenderer.h =================================================================== --- source/renderer/ModelVertexRenderer.h +++ source/renderer/ModelVertexRenderer.h @@ -133,6 +133,7 @@ */ virtual void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) = 0; + virtual bool CanInstance() { return false; } /** * RenderModel: Invoke the rendering commands for the given model. @@ -154,6 +155,7 @@ * succeed. */ virtual void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) = 0; + virtual void RenderInstancedModel(const CShaderProgramPtr& shader, const std::vector& model) {}; }; Index: source/renderer/RenderModifiers.cpp =================================================================== --- source/renderer/RenderModifiers.cpp +++ source/renderer/RenderModifiers.cpp @@ -110,9 +110,6 @@ void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel* model) { - if (m_BindingInstancingTransform.Active()) - shader->Uniform(m_BindingInstancingTransform, model->GetTransform()); - if (m_BindingShadingColor.Active()) shader->Uniform(m_BindingShadingColor, model->GetShadingColor());