From 4a7b7e7df1e6c1b3ef6aab35a6f749a2d2f36509 Mon Sep 17 00:00:00 2001 From: Vladislav Belov Date: Tue, 4 Aug 2026 23:06:10 +0200 Subject: [PATCH] Removes smart pointers from ModelRenderer We don't need to use pointers because we know lifetimes of all renderers. And its list statically defined. A new renderer should follow DOD and use a separate submission list with a separate inplace renderer. --- source/renderer/CPUSkinnedModelRenderer.h | 4 +- source/renderer/GPUSkinnedModelRenderer.h | 4 +- source/renderer/InstancingModelRenderer.h | 2 +- source/renderer/ModelRenderer.cpp | 6 +- source/renderer/ModelRenderer.h | 10 +- source/renderer/SceneRenderer.cpp | 115 +++++++++++++--------- 6 files changed, 78 insertions(+), 63 deletions(-) diff --git a/source/renderer/CPUSkinnedModelRenderer.h b/source/renderer/CPUSkinnedModelRenderer.h index 20c4692fbb..26a4b62896 100644 --- a/source/renderer/CPUSkinnedModelRenderer.h +++ b/source/renderer/CPUSkinnedModelRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -33,7 +33,7 @@ namespace Renderer::Backend { class IDeviceCommandContext; } * This computes and binds per-vertex data; the modifier is responsible * for setting any shader uniforms etc. */ -class CPUSkinnedModelVertexRenderer : public ModelVertexRenderer +class CPUSkinnedModelVertexRenderer final : public ModelVertexRenderer { public: CPUSkinnedModelVertexRenderer(); diff --git a/source/renderer/GPUSkinnedModelRenderer.h b/source/renderer/GPUSkinnedModelRenderer.h index 8ae233ef5c..cdd9f4f20c 100644 --- a/source/renderer/GPUSkinnedModelRenderer.h +++ b/source/renderer/GPUSkinnedModelRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2025 Wildfire Games. +/* Copyright (C) 2026 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,7 +34,7 @@ namespace Renderer::Backend { class IShaderProgram; } * This computes and binds per-vertex data; the modifier is responsible * for setting any shader uniforms etc. */ -class GPUSkinnedModelModelRenderer : public ModelVertexRenderer +class GPUSkinnedModelModelRenderer final : public ModelVertexRenderer { public: GPUSkinnedModelModelRenderer(); diff --git a/source/renderer/InstancingModelRenderer.h b/source/renderer/InstancingModelRenderer.h index 7863aea923..0d2768a763 100644 --- a/source/renderer/InstancingModelRenderer.h +++ b/source/renderer/InstancingModelRenderer.h @@ -34,7 +34,7 @@ struct InstancingModelRendererInternals; * This computes and binds per-vertex data; the modifier is responsible * for setting any shader uniforms etc (including the instancing transform). */ -class InstancingModelRenderer : public ModelVertexRenderer +class InstancingModelRenderer final : public ModelVertexRenderer { public: InstancingModelRenderer(); diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index 97d02a74fc..73d2ff0c67 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -306,7 +306,7 @@ struct SMRCompareTechBucket void ModelRenderer::Render( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - ModelVertexRenderer& modelVertexRenderer, const RenderModifierPtr& modifier, const CShaderDefines& context, + ModelVertexRenderer& modelVertexRenderer, RenderModifier& modifier, const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode, std::span submissions) { if (submissions.empty()) @@ -573,7 +573,7 @@ void ModelRenderer::Render( Renderer::Backend::IShaderProgram* shader = currentTech->GetShader(pass); - modifier->BeginPass(deviceCommandContext, shader); + modifier.BeginPass(deviceCommandContext, shader); // TODO: Use a more generic approach to handle bound queries. bool boundTime = false; @@ -703,7 +703,7 @@ void ModelRenderer::Render( } } - modifier->PrepareModel(deviceCommandContext, model); + modifier.PrepareModel(deviceCommandContext, model); CModelRData* rdata = static_cast(model->GetRenderData()); ENSURE(rdata->GetKey() == &modelVertexRenderer); diff --git a/source/renderer/ModelRenderer.h b/source/renderer/ModelRenderer.h index d45b1d5779..b0c944a2dd 100644 --- a/source/renderer/ModelRenderer.h +++ b/source/renderer/ModelRenderer.h @@ -40,14 +40,8 @@ namespace Renderer::Backend { class IDeviceCommandContext; } struct SColor4ub; template class VertexArrayIterator; -class RenderModifier; -typedef std::shared_ptr RenderModifierPtr; - -class LitRenderModifier; -typedef std::shared_ptr LitRenderModifierPtr; - class ModelVertexRenderer; -typedef std::shared_ptr ModelVertexRendererPtr; +class RenderModifier; /** * Class CModelRData: Render data that is maintained per CModel. @@ -108,7 +102,7 @@ public: */ void Render( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - ModelVertexRenderer& modelVertexRenderer, const RenderModifierPtr& modifier, const CShaderDefines& context, + ModelVertexRenderer& modelVertexRenderer, RenderModifier& modifier, const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode, std::span submissions); /** diff --git a/source/renderer/SceneRenderer.cpp b/source/renderer/SceneRenderer.cpp index 9bbaac375c..5b7cf1c4bd 100644 --- a/source/renderer/SceneRenderer.cpp +++ b/source/renderer/SceneRenderer.cpp @@ -68,6 +68,7 @@ #include #include +#include struct SScreenRect { @@ -115,7 +116,7 @@ public: SilhouetteRenderer silhouetteRenderer; - /// Various model renderers + // Various model renderers struct Models { // Submitted models are split on two axes: @@ -127,10 +128,12 @@ public: struct Submissions { - ModelVertexRenderer* modelVertexRenderer{nullptr}; std::vector submissions[CSceneRenderer::CULL_MAX]; }; + // Unskinned submissions should be prepared and rendered with + // VertexInstancingShader. Skinned - with Vertex*SkinningShader + // depending on whether GPU skinning is enabled. Submissions OpaqueSkinned; Submissions OpaqueUnskinned; Submissions TransparentSkinned; @@ -138,11 +141,15 @@ public: ModelRenderer modelRenderer; - ModelVertexRendererPtr VertexInstancingShader; - ModelVertexRendererPtr VertexCPUSkinningShader; - ModelVertexRendererPtr VertexGPUSkinningShader; + InstancingModelRenderer VertexInstancingShader; + CPUSkinnedModelVertexRenderer VertexCPUSkinningShader; + // We can't create GPU skinning renderer for renderer devices without + // its support. + std::optional VertexGPUSkinningShader; - LitRenderModifierPtr ModShader; + ShaderRenderModifier ModShader; + + bool GPUSkinningEnabled{false}; } Model; CShaderDefines globalContext; @@ -157,12 +164,21 @@ public: { PROFILE3("upload models"); + ModelVertexRenderer& modelVertexSkinningRenderer{ + Model.GPUSkinningEnabled + ? static_cast(*Model.VertexGPUSkinningShader) + : static_cast(Model.VertexCPUSkinningShader)}; + for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { - Model.OpaqueSkinned.modelVertexRenderer->UploadModelsData(deviceCommandContext, Model.OpaqueSkinned.submissions[cullGroup]); - Model.TransparentSkinned.modelVertexRenderer->UploadModelsData(deviceCommandContext, Model.TransparentSkinned.submissions[cullGroup]); - Model.OpaqueUnskinned.modelVertexRenderer->UploadModelsData(deviceCommandContext, Model.OpaqueUnskinned.submissions[cullGroup]); - Model.TransparentUnskinned.modelVertexRenderer->UploadModelsData(deviceCommandContext, Model.TransparentUnskinned.submissions[cullGroup]); + modelVertexSkinningRenderer.UploadModelsData(deviceCommandContext, Model.OpaqueSkinned.submissions[cullGroup]); + modelVertexSkinningRenderer.UploadModelsData(deviceCommandContext, Model.TransparentSkinned.submissions[cullGroup]); + } + + for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) + { + Model.VertexInstancingShader.UploadModelsData(deviceCommandContext, Model.OpaqueUnskinned.submissions[cullGroup]); + Model.VertexInstancingShader.UploadModelsData(deviceCommandContext, Model.TransparentUnskinned.submissions[cullGroup]); } } @@ -178,12 +194,21 @@ public: { PROFILE3("prepare models"); + ModelVertexRenderer& modelVertexSkinningRenderer{ + Model.GPUSkinningEnabled + ? static_cast(*Model.VertexGPUSkinningShader) + : static_cast(Model.VertexCPUSkinningShader)}; + for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { - PrepareModels(deviceCommandContext, *Model.OpaqueSkinned.modelVertexRenderer, Model.OpaqueSkinned.submissions[cullGroup]); - PrepareModels(deviceCommandContext, *Model.TransparentSkinned.modelVertexRenderer, Model.TransparentSkinned.submissions[cullGroup]); - PrepareModels(deviceCommandContext, *Model.OpaqueUnskinned.modelVertexRenderer, Model.OpaqueUnskinned.submissions[cullGroup]); - PrepareModels(deviceCommandContext, *Model.TransparentUnskinned.modelVertexRenderer, Model.TransparentUnskinned.submissions[cullGroup]); + PrepareModels(deviceCommandContext, modelVertexSkinningRenderer, Model.OpaqueSkinned.submissions[cullGroup]); + PrepareModels(deviceCommandContext, modelVertexSkinningRenderer, Model.TransparentSkinned.submissions[cullGroup]); + } + + for (int cullGroup{0}; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) + { + PrepareModels(deviceCommandContext, Model.VertexInstancingShader, Model.OpaqueUnskinned.submissions[cullGroup]); + PrepareModels(deviceCommandContext, Model.VertexInstancingShader, Model.TransparentUnskinned.submissions[cullGroup]); } } @@ -242,14 +267,19 @@ public: Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode) { + ModelVertexRenderer& modelVertexSkinningRenderer{ + Model.GPUSkinningEnabled + ? static_cast(*Model.VertexGPUSkinningShader) + : static_cast(Model.VertexCPUSkinningShader)}; + CShaderDefines contextSkinned = context; - if (g_RenderingOptions.GetGPUSkinning()) + if (Model.GPUSkinningEnabled) contextSkinned.Add(str_USE_INSTANCING, str_1); - Model.modelRenderer.Render(deviceCommandContext, *Model.OpaqueSkinned.modelVertexRenderer, Model.ModShader, contextSkinned, cullGroup, flags, renderMode, Model.OpaqueSkinned.submissions[cullGroup]); + Model.modelRenderer.Render(deviceCommandContext, modelVertexSkinningRenderer, Model.ModShader, contextSkinned, cullGroup, flags, renderMode, Model.OpaqueSkinned.submissions[cullGroup]); CShaderDefines contextUnskinned = context; contextUnskinned.Add(str_USE_INSTANCING, str_1); - Model.modelRenderer.Render(deviceCommandContext, *Model.OpaqueUnskinned.modelVertexRenderer, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode, Model.OpaqueUnskinned.submissions[cullGroup]); + Model.modelRenderer.Render(deviceCommandContext, Model.VertexInstancingShader, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode, Model.OpaqueUnskinned.submissions[cullGroup]); } /** @@ -259,14 +289,19 @@ public: Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode) { + ModelVertexRenderer& modelVertexSkinningRenderer{ + Model.GPUSkinningEnabled + ? static_cast(*Model.VertexGPUSkinningShader) + : static_cast(Model.VertexCPUSkinningShader)}; + CShaderDefines contextSkinned = context; - if (g_RenderingOptions.GetGPUSkinning()) + if (Model.GPUSkinningEnabled) contextSkinned.Add(str_USE_INSTANCING, str_1); - Model.modelRenderer.Render(deviceCommandContext, *Model.TransparentSkinned.modelVertexRenderer, Model.ModShader, contextSkinned, cullGroup, flags, renderMode, Model.TransparentSkinned.submissions[cullGroup]); + Model.modelRenderer.Render(deviceCommandContext, modelVertexSkinningRenderer, Model.ModShader, contextSkinned, cullGroup, flags, renderMode, Model.TransparentSkinned.submissions[cullGroup]); CShaderDefines contextUnskinned = context; contextUnskinned.Add(str_USE_INSTANCING, str_1); - Model.modelRenderer.Render(deviceCommandContext, *Model.TransparentUnskinned.modelVertexRenderer, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode, Model.TransparentUnskinned.submissions[cullGroup]); + Model.modelRenderer.Render(deviceCommandContext, Model.VertexInstancingShader, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode, Model.TransparentUnskinned.submissions[cullGroup]); } }; @@ -319,26 +354,12 @@ void CSceneRenderer::ReloadShaders([[maybe_unused]] Renderer::Backend::IDevice* m->globalContext.Add(str_RENDER_DEBUG_MODE, RenderDebugModeEnum::ToString(g_RenderingOptions.GetRenderDebugMode())); - m->Model.ModShader = LitRenderModifierPtr(new ShaderRenderModifier()); - - m->Model.VertexCPUSkinningShader = ModelVertexRendererPtr(new CPUSkinnedModelVertexRenderer()); - m->Model.VertexInstancingShader = ModelVertexRendererPtr(new InstancingModelRenderer()); - - if (g_RenderingOptions.GetGPUSkinning()) + m->Model.GPUSkinningEnabled = g_RenderingOptions.GetGPUSkinning(); + if (m->Model.GPUSkinningEnabled) { - m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new GPUSkinnedModelModelRenderer()); - m->Model.OpaqueSkinned.modelVertexRenderer = m->Model.VertexGPUSkinningShader.get(); - m->Model.TransparentSkinned.modelVertexRenderer = m->Model.VertexGPUSkinningShader.get(); + if (!m->Model.VertexGPUSkinningShader.has_value()) + m->Model.VertexGPUSkinningShader.emplace(); } - else - { - m->Model.VertexGPUSkinningShader.reset(); - m->Model.OpaqueSkinned.modelVertexRenderer = m->Model.VertexCPUSkinningShader.get(); - m->Model.TransparentSkinned.modelVertexRenderer = m->Model.VertexCPUSkinningShader.get(); - } - - m->Model.OpaqueUnskinned.modelVertexRenderer = m->Model.VertexInstancingShader.get(); - m->Model.TransparentUnskinned.modelVertexRenderer = m->Model.VertexInstancingShader.get(); } void CSceneRenderer::Initialize() @@ -362,8 +383,8 @@ void CSceneRenderer::Resize(int /*width*/, int /*height*/) void CSceneRenderer::BeginFrame() { // choose model renderers for this frame - m->Model.ModShader->SetShadowMap(&m->shadow); - m->Model.ModShader->SetLightEnv(m_LightEnv); + m->Model.ModShader.SetShadowMap(&m->shadow); + m->Model.ModShader.SetLightEnv(m_LightEnv); } void CSceneRenderer::SetSimulation(CSimulation2* simulation) @@ -1095,23 +1116,23 @@ void CSceneRenderer::SubmitNonRecursive(CModel* model) const bool requiresSkinning{model->GetModelDef()->GetNumBones() != 0}; ModelVertexRenderer& modelVertexSkinningRenderer{ - g_RenderingOptions.GetGPUSkinning() ? *m->Model.VertexGPUSkinningShader : *m->Model.VertexCPUSkinningShader}; - ModelVertexRenderer& modelVertexRenderer{ - requiresSkinning ? modelVertexSkinningRenderer : *m->Model.VertexInstancingShader}; + m->Model.GPUSkinningEnabled + ? static_cast(*m->Model.VertexGPUSkinningShader) + : static_cast(m->Model.VertexCPUSkinningShader)}; if (model->GetMaterial().UsesAlphaBlending()) { if (requiresSkinning) - m->Submit(m_CurrentCullGroup, modelVertexRenderer, m->Model.TransparentSkinned, model); + m->Submit(m_CurrentCullGroup, modelVertexSkinningRenderer, m->Model.TransparentSkinned, model); else - m->Submit(m_CurrentCullGroup, modelVertexRenderer, m->Model.TransparentUnskinned, model); + m->Submit(m_CurrentCullGroup, m->Model.VertexInstancingShader, m->Model.TransparentUnskinned, model); } else { if (requiresSkinning) - m->Submit(m_CurrentCullGroup, modelVertexRenderer, m->Model.OpaqueSkinned, model); + m->Submit(m_CurrentCullGroup, modelVertexSkinningRenderer, m->Model.OpaqueSkinned, model); else - m->Submit(m_CurrentCullGroup, modelVertexRenderer, m->Model.OpaqueUnskinned, model); + m->Submit(m_CurrentCullGroup, m->Model.VertexInstancingShader, m->Model.OpaqueUnskinned, model); } }