diff --git a/source/graphics/Canvas2D.cpp b/source/graphics/Canvas2D.cpp index ffbe7ff5c1..2cb58db1bd 100644 --- a/source/graphics/Canvas2D.cpp +++ b/source/graphics/Canvas2D.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -86,6 +86,15 @@ public: : WidthInPixels(widthInPixels), HeightInPixels(heightInPixels), Scale(scale), DeviceCommandContext(deviceCommandContext) { + constexpr std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1} + }}; + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); } void BindTechIfNeeded() @@ -118,14 +127,7 @@ public: DeviceCommandContext->SetUniform( BindingSlots.translation, Translation.AsFloatArray()); - DeviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - DeviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + DeviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); } void UnbindTech() @@ -163,6 +165,8 @@ public: CVector2D TransformScale; CVector2D Translation; + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; + Renderer::Backend::IDeviceCommandContext* DeviceCommandContext = nullptr; CShaderTechniquePtr Tech; diff --git a/source/graphics/LOSTexture.cpp b/source/graphics/LOSTexture.cpp index 5ce6fb1bb1..d847e8a295 100644 --- a/source/graphics/LOSTexture.cpp +++ b/source/graphics/LOSTexture.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -91,6 +91,16 @@ bool CLOSTexture::CreateShader() return false; } + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1} + }}; + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); + return true; } @@ -186,14 +196,7 @@ void CLOSTexture::InterpolateLOS(Renderer::Backend::IDeviceCommandContext* devic 1.0f, 1.0f }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); diff --git a/source/graphics/LOSTexture.h b/source/graphics/LOSTexture.h index 6c963a78f1..878ef34d0b 100644 --- a/source/graphics/LOSTexture.h +++ b/source/graphics/LOSTexture.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ #include "renderer/backend/Format.h" #include "renderer/backend/IDeviceCommandContext.h" #include "renderer/backend/IFramebuffer.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/backend/ITexture.h" #include @@ -96,6 +97,7 @@ private: size_t m_TextureFormatStride = 0; std::unique_ptr m_Texture, m_SmoothTextures[2]; + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; uint32_t m_WhichTexture = 0; double m_LastTextureRecomputeTime = 0.0; diff --git a/source/graphics/MiniMapTexture.cpp b/source/graphics/MiniMapTexture.cpp index b8e6ccbc7f..01f2b34370 100644 --- a/source/graphics/MiniMapTexture.cpp +++ b/source/graphics/MiniMapTexture.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -81,7 +81,8 @@ unsigned int ScaleColor(unsigned int color, float x) } void DrawTexture( - Renderer::Backend::IDeviceCommandContext* deviceCommandContext) + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* quadVertexInputLayout) { const float quadUVs[] = { @@ -104,14 +105,7 @@ void DrawTexture( -1.0f, -1.0f, }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexInputLayout(quadVertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, quadVertices, std::size(quadVertices) * sizeof(quadVertices[0])); @@ -247,6 +241,17 @@ CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation) } m_VertexArray.Upload(); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1} + }}; + m_QuadVertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); + + const uint32_t stride = m_VertexArray.GetStride(); if (g_VideoMode.GetBackendDevice()->GetCapabilities().instancing) { m_UseInstancing = true; @@ -281,6 +286,32 @@ CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation) m_InstanceVertexArray.Upload(); m_InstanceVertexArray.FreeBackingStore(); + + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + m_InstanceAttributePosition.format, m_InstanceAttributePosition.offset, + m_InstanceVertexArray.GetStride(), + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV1, + m_AttributePos.format, m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1}, + {Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1}, + }}; + m_EntitiesVertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); + } + else + { + const std::array entitiesAttributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePos.format, m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + m_EntitiesVertexInputLayout = g_Renderer.GetVertexInputLayout(entitiesAttributes); } CShaderDefines baseDefines; @@ -530,7 +561,7 @@ void CMiniMapTexture::RenderFinalTexture( baseTransform._14, baseTransform._24, terrainTransform._14, terrainTransform._24); if (m_TerrainTexture) - DrawTexture(deviceCommandContext); + DrawTexture(deviceCommandContext, m_QuadVertexInputLayout); deviceCommandContext->EndPass(); deviceCommandContext->SetGraphicsPipelineState( @@ -552,7 +583,7 @@ void CMiniMapTexture::RenderFinalTexture( shader->GetBindingSlot(str_translation), baseTransform._14, baseTransform._24, territoryTransform._14, territoryTransform._24); - DrawTexture(deviceCommandContext); + DrawTexture(deviceCommandContext, m_QuadVertexInputLayout); deviceCommandContext->EndPass(); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap_los, CShaderDefines()); @@ -574,7 +605,7 @@ void CMiniMapTexture::RenderFinalTexture( shader->GetBindingSlot(str_translation), baseTransform._14, baseTransform._24, losTransform._14, losTransform._24); - DrawTexture(deviceCommandContext); + DrawTexture(deviceCommandContext, m_QuadVertexInputLayout); deviceCommandContext->EndPass(); @@ -800,23 +831,9 @@ void CMiniMapTexture::DrawEntities( const uint32_t stride = m_VertexArray.GetStride(); const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride; + deviceCommandContext->SetVertexInputLayout(m_EntitiesVertexInputLayout); if (m_UseInstancing) { - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - m_InstanceAttributePosition.format, m_InstanceAttributePosition.offset, - m_InstanceVertexArray.GetStride(), - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - m_AttributePos.format, m_AttributePos.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::COLOR, - m_AttributeColor.format, m_AttributeColor.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_INSTANCE, 1); - deviceCommandContext->SetVertexBuffer( 0, m_InstanceVertexArray.GetBuffer(), m_InstanceVertexArray.GetOffset()); deviceCommandContext->SetVertexBuffer( @@ -828,15 +845,6 @@ void CMiniMapTexture::DrawEntities( } else { - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - m_AttributePos.format, m_AttributePos.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::COLOR, - m_AttributeColor.format, m_AttributeColor.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexBuffer( 0, m_VertexArray.GetBuffer(), firstVertexOffset); deviceCommandContext->SetIndexBuffer(m_IndexArray.GetBuffer()); diff --git a/source/graphics/MiniMapTexture.h b/source/graphics/MiniMapTexture.h index a8456e65c5..b3acfd7002 100644 --- a/source/graphics/MiniMapTexture.h +++ b/source/graphics/MiniMapTexture.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,6 +23,7 @@ #include "graphics/Texture.h" #include "maths/Vector2D.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/backend/ITexture.h" #include "renderer/VertexArray.h" @@ -114,6 +115,9 @@ private: float m_ShallowPassageHeight = 0.0f; float m_WaterHeight = 0.0f; + Renderer::Backend::IVertexInputLayout* m_QuadVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* m_EntitiesVertexInputLayout = nullptr; + VertexIndexArray m_IndexArray; VertexArray m_VertexArray; VertexArray::Attribute m_AttributePos; diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp index 77dca14644..06aafda6af 100644 --- a/source/graphics/ParticleEmitter.cpp +++ b/source/graphics/ParticleEmitter.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -77,6 +77,23 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) : } m_IndexArray.Upload(); m_IndexArray.FreeBackingStore(); + + const uint32_t stride = m_VertexArray.GetStride(); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePos.format, m_AttributePos.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::COLOR, + m_AttributeColor.format, m_AttributeColor.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + m_AttributeUV.format, m_AttributeUV.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV1, + m_AttributeAxis.format, m_AttributeAxis.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + }}; + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); } void CParticleEmitter::UpdateArrayData(int frameNumber) @@ -215,22 +232,7 @@ void CParticleEmitter::RenderArray( const uint32_t stride = m_VertexArray.GetStride(); const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - m_AttributePos.format, m_AttributePos.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::COLOR, - m_AttributeColor.format, m_AttributeColor.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - m_AttributeUV.format, m_AttributeUV.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - m_AttributeAxis.format, m_AttributeAxis.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBuffer( 0, m_VertexArray.GetBuffer(), firstVertexOffset); diff --git a/source/graphics/ParticleEmitter.h b/source/graphics/ParticleEmitter.h index 87541de265..67486d7488 100644 --- a/source/graphics/ParticleEmitter.h +++ b/source/graphics/ParticleEmitter.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -177,6 +177,8 @@ private: VertexArray::Attribute m_AttributeUV; VertexArray::Attribute m_AttributeColor; + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; + int m_LastFrameNumber; }; diff --git a/source/renderer/DebugRenderer.cpp b/source/renderer/DebugRenderer.cpp index 54917f8566..dcadde646d 100644 --- a/source/renderer/DebugRenderer.cpp +++ b/source/renderer/DebugRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,6 +35,16 @@ #include +void CDebugRenderer::Initialize() +{ + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); +} + void CDebugRenderer::DrawLine( const CVector3D& from, const CVector3D& to, const CColor& color, const float width, const bool depthTestEnabled) @@ -99,10 +109,7 @@ void CDebugRenderer::DrawLine( #undef ADD - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); @@ -156,10 +163,7 @@ void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, con #undef ADD - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); @@ -237,10 +241,7 @@ void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& colo ADD(intermediatePoints[3]); } - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); @@ -260,10 +261,7 @@ void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& colo ADD(farPoints[nextI]); } - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); @@ -323,10 +321,7 @@ void CDebugRenderer::DrawBoundingBox( #undef ADD_FACE - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, data.data(), data.size() * sizeof(data[0])); @@ -379,10 +374,7 @@ void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color, bool wi #undef ADD_VERT - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, data.data(), data.size() * sizeof(data[0])); diff --git a/source/renderer/DebugRenderer.h b/source/renderer/DebugRenderer.h index 84ee8a0f61..d84972b6db 100644 --- a/source/renderer/DebugRenderer.h +++ b/source/renderer/DebugRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "graphics/ShaderTechniquePtr.h" #include "ps/CStrIntern.h" +#include "renderer/backend/IShaderProgram.h" #include #include @@ -37,6 +38,8 @@ struct CColor; class CDebugRenderer { public: + void Initialize(); + /** * Render the line in world space. */ @@ -91,6 +94,8 @@ private: }; std::unordered_map m_ShaderTechniqueMapping; + + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; }; #endif // INCLUDED_DEBUGRENDERER diff --git a/source/renderer/DecalRData.cpp b/source/renderer/DecalRData.cpp index 87d2c4a31d..e2559f7cfe 100644 --- a/source/renderer/DecalRData.cpp +++ b/source/renderer/DecalRData.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -76,6 +76,27 @@ struct SDecalBatchComparator } // anonymous namespace +// static +Renderer::Backend::IVertexInputLayout* CDecalRData::GetVertexInputLayout() +{ + const uint32_t stride = sizeof(SDecalVertex); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SDecalVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SDecalVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(SDecalVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); +} + CDecalRData::CDecalRData(CModelDecal* decal, CSimulation2* simulation) : m_Decal(decal), m_Simulation(simulation) { @@ -96,6 +117,7 @@ void CDecalRData::Update(CSimulation2* simulation) void CDecalRData::RenderDecals( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const std::vector& decals, const CShaderDefines& context, ShadowMap* shadow) { PROFILE3("render terrain decals"); @@ -224,23 +246,7 @@ void CDecalRData::RenderDecals( lastVB = batch.vertices->m_Owner; ENSURE(!lastVB->GetBuffer()->IsDynamic()); - const uint32_t stride = sizeof(SDecalVertex); - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SDecalVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::NORMAL, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SDecalVertex, m_Normal), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(SDecalVertex, m_UV), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); deviceCommandContext->SetVertexBuffer( 0, batch.vertices->m_Owner->GetBuffer(), 0); diff --git a/source/renderer/DecalRData.h b/source/renderer/DecalRData.h index 2c195b32d8..4729dbbdd1 100644 --- a/source/renderer/DecalRData.h +++ b/source/renderer/DecalRData.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ #include "maths/Vector2D.h" #include "maths/Vector3D.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/VertexBufferManager.h" #include @@ -37,10 +38,13 @@ public: CDecalRData(CModelDecal* decal, CSimulation2* simulation); ~CDecalRData(); + static Renderer::Backend::IVertexInputLayout* GetVertexInputLayout(); + void Update(CSimulation2* simulation); static void RenderDecals( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const std::vector& decals, const CShaderDefines& context, ShadowMap* shadow); CModelDecal* GetDecal() { return m_Decal; } diff --git a/source/renderer/HWLightingModelRenderer.cpp b/source/renderer/HWLightingModelRenderer.cpp index 003120265a..f02d3a4c11 100644 --- a/source/renderer/HWLightingModelRenderer.cpp +++ b/source/renderer/HWLightingModelRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,10 +27,19 @@ #include "lib/bits.h" #include "lib/sysdep/rtl.h" #include "maths/Vector3D.h" +#include "ps/containers/StaticVector.h" #include "renderer/Renderer.h" #include "renderer/RenderModifiers.h" #include "renderer/VertexArray.h" +namespace +{ + +constexpr uint32_t MODEL_VERTEX_ATTRIBUTE_STRIDE = 32; +constexpr uint32_t MODEL_VERTEX_ATTRIBUTE_POSITION_OFFSET = 16; +constexpr uint32_t MODEL_VERTEX_ATTRIBUTE_NORMAL_OFFSET = 0; + +} // anonymous namespace struct ShaderModelDef : public CModelDefRPrivate { @@ -43,6 +52,8 @@ struct ShaderModelDef : public CModelDefRPrivate /// The number of UVs is determined by the model std::vector m_UVs; + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; + ShaderModelDef(const CModelDefPtr& mdef); }; @@ -77,6 +88,31 @@ ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef) ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator()); m_IndexArray.Upload(); m_IndexArray.FreeBackingStore(); + + const uint32_t stride = m_Array.GetStride(); + PS::StaticVector attributes{ + {Renderer::Backend::VertexAttributeStream::UV0, + m_UVs[0].format, m_UVs[0].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + MODEL_VERTEX_ATTRIBUTE_POSITION_OFFSET, MODEL_VERTEX_ATTRIBUTE_STRIDE, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1}, + {Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + MODEL_VERTEX_ATTRIBUTE_NORMAL_OFFSET, MODEL_VERTEX_ATTRIBUTE_STRIDE, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1} + }; + + if (mdef->GetNumUVsPerVertex() >= 2) + { + attributes.push_back({ + Renderer::Backend::VertexAttributeStream::UV1, + m_UVs[1].format, m_UVs[1].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}); + } + + m_VertexInputLayout = g_Renderer.GetVertexInputLayout({attributes.begin(), attributes.end()}); } @@ -147,6 +183,13 @@ CModelRData* ShaderModelVertexRenderer::CreateModelData(const void* key, CModel* ENSURE(shadermodel->m_Normal.offset % 16 == 0); ENSURE(shadermodel->m_Array.GetStride() % 16 == 0); + // We assume that the vertex input layout is the same for all models with the + // same ShaderModelDef. + // TODO: we need a more strict way to guarantee that. + ENSURE(shadermodel->m_Array.GetStride() == MODEL_VERTEX_ATTRIBUTE_STRIDE); + ENSURE(shadermodel->m_Position.offset == MODEL_VERTEX_ATTRIBUTE_POSITION_OFFSET); + ENSURE(shadermodel->m_Normal.offset == MODEL_VERTEX_ATTRIBUTE_NORMAL_OFFSET); + return shadermodel; } @@ -195,23 +238,11 @@ void ShaderModelVertexRenderer::PrepareModelDef( ENSURE(m->shadermodeldef); + deviceCommandContext->SetVertexInputLayout(m->shadermodeldef->m_VertexInputLayout); + const uint32_t stride = m->shadermodeldef->m_Array.GetStride(); const uint32_t firstVertexOffset = m->shadermodeldef->m_Array.GetOffset() * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - m->shadermodeldef->m_UVs[0].format, - m->shadermodeldef->m_UVs[0].offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - if (def.GetNumUVsPerVertex() >= 2) - { - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - m->shadermodeldef->m_UVs[1].format, - m->shadermodeldef->m_UVs[1].offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - } - deviceCommandContext->SetVertexBuffer( 0, m->shadermodeldef->m_Array.GetBuffer(), firstVertexOffset); } @@ -227,17 +258,6 @@ void ShaderModelVertexRenderer::RenderModel( const uint32_t stride = shadermodel->m_Array.GetStride(); const uint32_t firstVertexOffset = shadermodel->m_Array.GetOffset() * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - shadermodel->m_Position.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::NORMAL, - Renderer::Backend::Format::R32G32B32_SFLOAT, - shadermodel->m_Normal.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); - deviceCommandContext->SetVertexBuffer( 1, shadermodel->m_Array.GetBuffer(), firstVertexOffset); deviceCommandContext->SetIndexBuffer(m->shadermodeldef->m_IndexArray.GetBuffer()); diff --git a/source/renderer/InstancingModelRenderer.cpp b/source/renderer/InstancingModelRenderer.cpp index 3981c08772..9b3c229093 100644 --- a/source/renderer/InstancingModelRenderer.cpp +++ b/source/renderer/InstancingModelRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,6 +25,7 @@ #include "maths/Vector3D.h" #include "maths/Vector4D.h" #include "ps/CLogger.h" +#include "ps/containers/StaticVector.h" #include "ps/CStrInternStatic.h" #include "renderer/Renderer.h" #include "renderer/RenderModifiers.h" @@ -47,6 +48,8 @@ struct IModelDef : public CModelDefRPrivate /// The number of UVs is determined by the model std::vector m_UVs; + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; + /// Indices are the same for all models, so share them VertexIndexArray m_IndexArray; @@ -234,8 +237,52 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT m_IndexArray.Upload(); m_IndexArray.FreeBackingStore(); } -} + const uint32_t stride = m_Array.GetStride(); + constexpr size_t MAX_UV = 2; + + PS::StaticVector attributes{ + {Renderer::Backend::VertexAttributeStream::POSITION, + m_Position.format, m_Position.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::NORMAL, + m_Normal.format, m_Normal.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }; + + for (size_t uv = 0; uv < std::min(MAX_UV, mdef->GetNumUVsPerVertex()); ++uv) + { + const Renderer::Backend::VertexAttributeStream stream = + static_cast( + static_cast(Renderer::Backend::VertexAttributeStream::UV0) + uv); + attributes.push_back({ + stream, m_UVs[uv].format, m_UVs[uv].offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}); + } + + // GPU skinning requires extra attributes to compute positions/normals. + if (gpuSkinning) + { + attributes.push_back({ + Renderer::Backend::VertexAttributeStream::UV2, + m_BlendJoints.format, m_BlendJoints.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}); + attributes.push_back({ + Renderer::Backend::VertexAttributeStream::UV3, + m_BlendWeights.format, m_BlendWeights.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}); + } + + if (calculateTangents) + { + attributes.push_back({ + Renderer::Backend::VertexAttributeStream::UV4, + m_Tangent.format, m_Tangent.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}); + } + + m_VertexInputLayout = g_Renderer.GetVertexInputLayout({attributes.begin(), attributes.end()}); +} struct InstancingModelRendererInternals { @@ -307,58 +354,13 @@ void InstancingModelRenderer::PrepareModelDef( m->imodeldef = (IModelDef*)def.GetRenderData(m); ENSURE(m->imodeldef); + deviceCommandContext->SetVertexInputLayout(m->imodeldef->m_VertexInputLayout); + deviceCommandContext->SetIndexBuffer(m->imodeldef->m_IndexArray.GetBuffer()); const uint32_t stride = m->imodeldef->m_Array.GetStride(); const uint32_t firstVertexOffset = m->imodeldef->m_Array.GetOffset() * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - m->imodeldef->m_Position.format, - m->imodeldef->m_Position.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::NORMAL, - m->imodeldef->m_Normal.format, - m->imodeldef->m_Normal.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - - constexpr size_t MAX_UV = 2; - for (size_t uv = 0; uv < std::min(MAX_UV, def.GetNumUVsPerVertex()); ++uv) - { - const Renderer::Backend::VertexAttributeStream stream = - static_cast( - static_cast(Renderer::Backend::VertexAttributeStream::UV0) + uv); - deviceCommandContext->SetVertexAttributeFormat( - stream, m->imodeldef->m_UVs[uv].format, - m->imodeldef->m_UVs[uv].offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - } - - // GPU skinning requires extra attributes to compute positions/normals. - if (m->gpuSkinning) - { - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV2, - m->imodeldef->m_BlendJoints.format, - m->imodeldef->m_BlendJoints.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV3, - m->imodeldef->m_BlendWeights.format, - m->imodeldef->m_BlendWeights.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - } - - if (m->calculateTangents) - { - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV4, - m->imodeldef->m_Tangent.format, - m->imodeldef->m_Tangent.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - } - deviceCommandContext->SetVertexBuffer( 0, m->imodeldef->m_Array.GetBuffer(), firstVertexOffset); } diff --git a/source/renderer/OverlayRenderer.cpp b/source/renderer/OverlayRenderer.cpp index 199e73e826..4f8b7fc185 100644 --- a/source/renderer/OverlayRenderer.cpp +++ b/source/renderer/OverlayRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -188,6 +188,12 @@ struct OverlayRendererInternals Shader shaderForegroundOverlay; Shader shaderOverlaySolid; + Renderer::Backend::IVertexInputLayout* quadVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* foregroundVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* sphereVertexInputLayout = nullptr; + + Renderer::Backend::IVertexInputLayout* texturedLineVertexInputLayout = nullptr; + // Geometry for a unit sphere std::vector sphereVertexes; std::vector sphereIndexes; @@ -262,6 +268,39 @@ void OverlayRendererInternals::Initialize() CreateShader(str_foreground_overlay, {}); shaderOverlaySolid = CreateShader(str_overlay_solid, {}); + + const uint32_t quadStride = quadVertices.GetStride(); + const std::array quadAttributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + quadAttributePos.format, quadAttributePos.offset, quadStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::COLOR, + quadAttributeColor.format, quadAttributeColor.offset, quadStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + quadAttributeUV.format, quadAttributeUV.offset, quadStride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + quadVertexInputLayout = g_Renderer.GetVertexInputLayout(quadAttributes); + + const std::array foregroundAttributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1} + }}; + foregroundVertexInputLayout = g_Renderer.GetVertexInputLayout(foregroundAttributes); + + const std::array shpereAttributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + sphereVertexInputLayout = g_Renderer.GetVertexInputLayout(shpereAttributes); + + texturedLineVertexInputLayout = CTexturedLineRData::GetVertexInputLayout(); } OverlayRenderer::OverlayRenderer() @@ -535,7 +574,8 @@ void OverlayRenderer::RenderTexturedOverlayLines( continue; ENSURE(line->m_RenderData); - line->m_RenderData->Render(deviceCommandContext, *line, shader); + line->m_RenderData->Render( + deviceCommandContext, m->texturedLineVertexInputLayout, *line, shader); } } @@ -571,18 +611,7 @@ void OverlayRenderer::RenderQuadOverlays( const uint32_t vertexStride = m->quadVertices.GetStride(); const uint32_t firstVertexOffset = m->quadVertices.GetOffset() * vertexStride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - m->quadAttributePos.format, m->quadAttributePos.offset, vertexStride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::COLOR, - m->quadAttributeColor.format, m->quadAttributeColor.offset, vertexStride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - m->quadAttributeUV.format, m->quadAttributeUV.offset, vertexStride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m->quadVertexInputLayout); deviceCommandContext->SetVertexBuffer( 0, m->quadVertices.GetBuffer(), firstVertexOffset); @@ -650,14 +679,7 @@ void OverlayRenderer::RenderForegroundOverlays( {0.0f, 0.0f}, }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexInputLayout(m->foregroundVertexInputLayout); deviceCommandContext->SetVertexBufferData( 1, &uvs[0], std::size(uvs) * sizeof(uvs[0])); @@ -783,10 +805,7 @@ void OverlayRenderer::RenderSphereOverlays( m->GenerateSphere(); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m->sphereVertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, m->sphereVertexes.data(), m->sphereVertexes.size() * sizeof(m->sphereVertexes[0])); diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp index d6aacc037c..bcc48de0e0 100644 --- a/source/renderer/PatchRData.cpp +++ b/source/renderer/PatchRData.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -64,6 +64,145 @@ const ssize_t BlendOffsets[9][2] = { { 0, 0 } }; +// static +Renderer::Backend::IVertexInputLayout* CPatchRData::GetBaseVertexInputLayout() +{ + const uint32_t stride = sizeof(SBaseVertex); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); +} + +// static +Renderer::Backend::IVertexInputLayout* CPatchRData::GetBlendVertexInputLayout() +{ + const uint32_t stride = sizeof(SBlendVertex); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBlendVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBlendVertex, m_Normal), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBlendVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(SBlendVertex, m_AlphaUVs), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); +} + +// static +Renderer::Backend::IVertexInputLayout* CPatchRData::GetStreamVertexInputLayout( + const bool bindPositionAsTexCoord) +{ + const uint32_t stride = sizeof(SBaseVertex); + if (bindPositionAsTexCoord) + { + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); + } + else + { + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SBaseVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); + } +} + +// static +Renderer::Backend::IVertexInputLayout* CPatchRData::GetSideVertexInputLayout() +{ + const uint32_t stride = sizeof(SSideVertex); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SSideVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); +} + +// static +Renderer::Backend::IVertexInputLayout* CPatchRData::GetWaterSurfaceVertexInputLayout( + const bool bindWaterData) +{ + const uint32_t stride = sizeof(SWaterVertex); + if (bindWaterData) + { + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SWaterVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + // UV1 will be used only in case of bindWaterData. + {Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(SWaterVertex, m_WaterData), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); + } + else + { + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SWaterVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); + } +} + +// static +Renderer::Backend::IVertexInputLayout* CPatchRData::GetWaterShoreVertexInputLayout() +{ + const uint32_t stride = sizeof(SWaterVertex); + const std::array attributes{ { + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SWaterVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(SWaterVertex, m_WaterData), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); +} + CPatchRData::CPatchRData(CPatch* patch, CSimulation2* simulation) : m_Patch(patch), m_Simulation(simulation) { @@ -716,6 +855,7 @@ using ShaderTechniqueBatches = PooledBatchMap& patches, const CShaderDefines& context, ShadowMap* shadow) { PROFILE3("render terrain bases"); @@ -817,23 +957,7 @@ void CPatchRData::RenderBases( { ENSURE(!itv->first->GetBuffer()->IsDynamic()); - const uint32_t stride = sizeof(SBaseVertex); - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::NORMAL, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Normal), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); deviceCommandContext->SetVertexBuffer(0, itv->first->GetBuffer(), 0); @@ -891,6 +1015,7 @@ struct SBlendStackItem void CPatchRData::RenderBlends( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow) { PROFILE3("render terrain blends"); @@ -1065,28 +1190,7 @@ void CPatchRData::RenderBlends( ENSURE(!itv->first->GetBuffer()->IsDynamic()); - const uint32_t stride = sizeof(SBlendVertex); - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBlendVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::NORMAL, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBlendVertex, m_Normal), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBlendVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(SBlendVertex, m_AlphaUVs), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); deviceCommandContext->SetVertexBuffer(0, itv->first->GetBuffer(), 0); } @@ -1114,7 +1218,8 @@ void CPatchRData::RenderBlends( void CPatchRData::RenderStreams( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - const std::vector& patches, const bool bindPositionAsTexCoord) + Renderer::Backend::IVertexInputLayout* vertexInputLayout, + const std::vector& patches) { PROFILE3("render terrain streams"); @@ -1143,21 +1248,7 @@ void CPatchRData::RenderStreams( PROFILE_END("compute batches"); - const uint32_t stride = sizeof(SBaseVertex); - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - if (bindPositionAsTexCoord) - { - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SBaseVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - } + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); // Render each batch for (const std::pair& streamBatch : batches) @@ -1216,6 +1307,7 @@ void CPatchRData::RenderOutline() void CPatchRData::RenderSides( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const std::vector& patches) { PROFILE3("render terrain sides"); @@ -1224,12 +1316,7 @@ void CPatchRData::RenderSides( if (patches.empty()) return; - const uint32_t stride = sizeof(SSideVertex); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SSideVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); CVertexBuffer* lastVB = nullptr; for (CPatchRData* patch : patches) @@ -1481,7 +1568,7 @@ void CPatchRData::BuildWater() void CPatchRData::RenderWaterSurface( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - const bool bindWaterData) + Renderer::Backend::IVertexInputLayout* vertexInputLayout) { ASSERT(m_UpdateFlags == 0); @@ -1494,19 +1581,7 @@ void CPatchRData::RenderWaterSurface( const uint32_t stride = sizeof(SWaterVertex); const uint32_t firstVertexOffset = m_VBWater->m_Index * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SWaterVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - if (bindWaterData) - { - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(SWaterVertex, m_WaterData), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - } + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); deviceCommandContext->SetVertexBuffer( 0, m_VBWater->m_Owner->GetBuffer(), firstVertexOffset); @@ -1519,7 +1594,8 @@ void CPatchRData::RenderWaterSurface( } void CPatchRData::RenderWaterShore( - Renderer::Backend::IDeviceCommandContext* deviceCommandContext) + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout) { ASSERT(m_UpdateFlags == 0); @@ -1532,16 +1608,7 @@ void CPatchRData::RenderWaterShore( const uint32_t stride = sizeof(SWaterVertex); const uint32_t firstVertexOffset = m_VBWaterShore->m_Index * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SWaterVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(SWaterVertex, m_WaterData), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); deviceCommandContext->SetVertexBuffer( 0, m_VBWaterShore->m_Owner->GetBuffer(), firstVertexOffset); diff --git a/source/renderer/PatchRData.h b/source/renderer/PatchRData.h index b50bad966b..e7b78c6249 100644 --- a/source/renderer/PatchRData.h +++ b/source/renderer/PatchRData.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -44,15 +44,26 @@ public: CPatchRData(CPatch* patch, CSimulation2* simulation); ~CPatchRData(); + static Renderer::Backend::IVertexInputLayout* GetBaseVertexInputLayout(); + static Renderer::Backend::IVertexInputLayout* GetBlendVertexInputLayout(); + static Renderer::Backend::IVertexInputLayout* GetStreamVertexInputLayout( + const bool bindPositionAsTexCoord); + static Renderer::Backend::IVertexInputLayout* GetSideVertexInputLayout(); + + static Renderer::Backend::IVertexInputLayout* GetWaterSurfaceVertexInputLayout( + const bool bindWaterData); + static Renderer::Backend::IVertexInputLayout* GetWaterShoreVertexInputLayout(); + void Update(CSimulation2* simulation); void RenderOutline(); void RenderPriorities(CTextRenderer& textRenderer); void RenderWaterSurface( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - const bool bindWaterData); + Renderer::Backend::IVertexInputLayout* vertexInputLayout); void RenderWaterShore( - Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout); CPatch* GetPatch() { return m_Patch; } @@ -60,15 +71,19 @@ public: static void RenderBases( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow); static void RenderBlends( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow); static void RenderStreams( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - const std::vector& patches, const bool bindPositionAsTexCoord); + Renderer::Backend::IVertexInputLayout* vertexInputLayout, + const std::vector& patches); static void RenderSides( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const std::vector& patches); static void PrepareShader(ShadowMap* shadow); diff --git a/source/renderer/PostprocManager.cpp b/source/renderer/PostprocManager.cpp index dd4a9ed56c..4cd1f91df5 100644 --- a/source/renderer/PostprocManager.cpp +++ b/source/renderer/PostprocManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -87,6 +87,16 @@ void CPostprocManager::Initialize() if (m_IsInitialized) return; + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1}, + }}; + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); + const uint32_t maxSamples = g_VideoMode.GetBackendDevice()->GetCapabilities().maxSampleCount; const uint32_t possibleSampleCounts[] = {2, 4, 8, 16}; std::copy_if( @@ -259,14 +269,7 @@ void CPostprocManager::ApplyBlurDownscale2x( 1.0f, 1.0f }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); @@ -329,14 +332,7 @@ void CPostprocManager::ApplyBlurGauss( 1.0f, 1.0f }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); @@ -368,14 +364,7 @@ void CPostprocManager::ApplyBlurGauss( deviceCommandContext->SetUniform( shader->GetBindingSlot(str_texSize), inWidth, inHeight); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); @@ -498,14 +487,7 @@ void CPostprocManager::ApplyEffect( 1.0f, 1.0f }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 1); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, quadVerts, std::size(quadVerts) * sizeof(quadVerts[0])); diff --git a/source/renderer/PostprocManager.h b/source/renderer/PostprocManager.h index 683cfe15cd..f52698341d 100644 --- a/source/renderer/PostprocManager.h +++ b/source/renderer/PostprocManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ #include "ps/CStr.h" #include "renderer/backend/IFramebuffer.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/backend/ITexture.h" #include @@ -118,6 +119,8 @@ private: // Indicates which of the ping-pong buffers is used for reading and which for drawing. bool m_WhichBuffer; + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; + // The name and shader technique we are using. "default" name means no technique is used // (i.e. while we do allocate the buffers, no effects are rendered). CStrW m_PostProcEffect; diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index 5d30a85575..e482702db9 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,6 +27,7 @@ #include "graphics/TerrainTextureManager.h" #include "i18n/L10n.h" #include "lib/allocators/shared_ptr.h" +#include "lib/hash.h" #include "lib/tex/tex.h" #include "gui/GUIManager.h" #include "ps/CConsole.h" @@ -271,6 +272,15 @@ public: CFontManager fontManager; + struct VertexAttributesHash + { + size_t operator()(const std::vector& attributes) const; + }; + + std::unordered_map< + std::vector, + std::unique_ptr, VertexAttributesHash> vertexInputLayouts; + Internals() : IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats), deviceCommandContext(g_VideoMode.GetBackendDevice()->CreateCommandContext()), @@ -279,6 +289,23 @@ public: } }; +size_t CRenderer::Internals::VertexAttributesHash::operator()( + const std::vector& attributes) const +{ + size_t seed = 0; + hash_combine(seed, attributes.size()); + for (const Renderer::Backend::SVertexAttributeFormat& attribute : attributes) + { + hash_combine(seed, attribute.stream); + hash_combine(seed, attribute.format); + hash_combine(seed, attribute.offset); + hash_combine(seed, attribute.stride); + hash_combine(seed, attribute.rate); + hash_combine(seed, attribute.bindingSlot); + } + return seed; +} + CRenderer::CRenderer() { TIMER(L"InitRenderer"); @@ -336,6 +363,8 @@ bool CRenderer::Open(int width, int height) // Validate the currently selected render path SetRenderPath(g_RenderingOptions.GetRenderPath()); + m->debugRenderer.Initialize(); + if (m->postprocManager.IsEnabled()) m->postprocManager.Initialize(); @@ -853,3 +882,13 @@ Renderer::Backend::IDeviceCommandContext* CRenderer::GetDeviceCommandContext() { return m->deviceCommandContext.get(); } + +Renderer::Backend::IVertexInputLayout* CRenderer::GetVertexInputLayout( + const PS::span attributes) +{ + const auto [it, inserted] = m->vertexInputLayouts.emplace( + std::vector{attributes.begin(), attributes.end()}, nullptr); + if (inserted) + it->second = g_VideoMode.GetBackendDevice()->CreateVertexInputLayout(attributes); + return it->second.get(); +} diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index 1935b1dcc6..643869d3e5 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,8 +21,10 @@ #include "graphics/Camera.h" #include "graphics/ShaderDefines.h" #include "graphics/ShaderProgramPtr.h" +#include "ps/containers/Span.h" #include "ps/Singleton.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/RenderingOptions.h" #include "renderer/Scene.h" @@ -132,6 +134,16 @@ public: Renderer::Backend::IDeviceCommandContext* GetDeviceCommandContext(); + /** + * Returns a cached vertex input layout. The renderer owns the layout to be + * able to share it between different clients. As backend should have + * as few different layouts as possible. + * The function isn't cheap so it should be called as rarely as possible. + * TODO: we need to make VertexArray less error prone by passing layout. + */ + Renderer::Backend::IVertexInputLayout* GetVertexInputLayout( + const PS::span attributes); + protected: friend class CPatchRData; friend class CDecalRData; diff --git a/source/renderer/SceneRenderer.cpp b/source/renderer/SceneRenderer.cpp index 1dec77e4d7..b069344ae8 100644 --- a/source/renderer/SceneRenderer.cpp +++ b/source/renderer/SceneRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -268,6 +268,8 @@ void CSceneRenderer::Initialize() { // Let component renderers perform one-time initialization after graphics capabilities and // the shader path have been determined. + m->waterManager.Initialize(); + m->terrainRenderer.Initialize(); m->overlayRenderer.Initialize(); } diff --git a/source/renderer/SilhouetteRenderer.cpp b/source/renderer/SilhouetteRenderer.cpp index 4cca3fc396..d7d757a07e 100644 --- a/source/renderer/SilhouetteRenderer.cpp +++ b/source/renderer/SilhouetteRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -478,6 +478,13 @@ void SilhouetteRenderer::RenderDebugOverlays( pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; }); + + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); } deviceCommandContext->BeginPass(); @@ -503,10 +510,7 @@ void SilhouetteRenderer::RenderDebugOverlays( r.x0, r.y1, }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, sizeof(float) * 2, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, vertices, std::size(vertices) * sizeof(vertices[0])); diff --git a/source/renderer/SilhouetteRenderer.h b/source/renderer/SilhouetteRenderer.h index d1a4802757..9228538238 100644 --- a/source/renderer/SilhouetteRenderer.h +++ b/source/renderer/SilhouetteRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ #include "graphics/ShaderTechniquePtr.h" #include "maths/BoundingBoxAligned.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" class CCamera; class CModel; @@ -78,6 +79,7 @@ private: std::vector m_DebugSpheres; CShaderTechniquePtr m_ShaderTech; + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; }; #endif // INCLUDED_SILHOUETTERENDERER diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp index 8598f894f5..1709c9d9d9 100644 --- a/source/renderer/SkyManager.cpp +++ b/source/renderer/SkyManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -249,14 +249,7 @@ void SkyManager::RenderSky( const uint32_t stride = m_VertexArray.GetStride(); const uint32_t firstVertexOffset = m_VertexArray.GetOffset() * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, m_AttributePosition.format, - m_AttributePosition.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, m_AttributeUV.format, - m_AttributeUV.offset, stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBuffer( 0, m_VertexArray.GetBuffer(), firstVertexOffset); @@ -343,4 +336,15 @@ void SkyManager::CreateSkyCube() m_VertexArray.Upload(); m_VertexArray.FreeBackingStore(); + + const uint32_t stride = m_VertexArray.GetStride(); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + m_AttributePosition.format, m_AttributePosition.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + m_AttributeUV.format, m_AttributeUV.offset, stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); } diff --git a/source/renderer/SkyManager.h b/source/renderer/SkyManager.h index 316d555eb2..db09031fdf 100644 --- a/source/renderer/SkyManager.h +++ b/source/renderer/SkyManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include "graphics/Texture.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/backend/ITexture.h" #include "renderer/VertexArray.h" @@ -107,6 +108,8 @@ private: VertexArray m_VertexArray; VertexArray::Attribute m_AttributePosition; VertexArray::Attribute m_AttributeUV; + + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; }; diff --git a/source/renderer/TerrainOverlay.cpp b/source/renderer/TerrainOverlay.cpp index f5439206e6..fdb5c99f6d 100644 --- a/source/renderer/TerrainOverlay.cpp +++ b/source/renderer/TerrainOverlay.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -148,6 +148,14 @@ TerrainOverlay::TerrainOverlay( m_OverlayTechOutline = CreateOverlayOutlineShaderTechnique(false); m_OverlayTechOutlineHidden = CreateOverlayOutlineShaderTechnique(true); + + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + + m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); } void TerrainOverlay::StartRender() @@ -254,10 +262,7 @@ void TerrainOverlay::RenderTile( deviceCommandContext->SetUniform( overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); @@ -308,10 +313,7 @@ void TerrainOverlay::RenderTileOutline( deviceCommandContext->SetUniform( overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_VertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); diff --git a/source/renderer/TerrainOverlay.h b/source/renderer/TerrainOverlay.h index 8322133b2c..b8337b2399 100644 --- a/source/renderer/TerrainOverlay.h +++ b/source/renderer/TerrainOverlay.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "graphics/ShaderTechniquePtr.h" #include "renderer/backend/ITexture.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/backend/PipelineState.h" struct CColor; @@ -184,6 +185,8 @@ private: CShaderTechniquePtr m_OverlayTechTile, m_OverlayTechTileHidden; CShaderTechniquePtr m_OverlayTechOutline, m_OverlayTechOutlineHidden; + + Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr; }; /** diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 6c47ac99e5..2def274c5f 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -83,6 +83,19 @@ struct TerrainRendererInternals CShaderTechniquePtr shaderTechniqueSolid, shaderTechniqueSolidDepthTest; + Renderer::Backend::IVertexInputLayout* overlayVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* decalsVertexInputLayout = nullptr; + + Renderer::Backend::IVertexInputLayout* baseVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* blendVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* streamVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* streamWithPositionAsTexCoordVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* sideVertexInputLayout = nullptr; + + Renderer::Backend::IVertexInputLayout* waterSurfaceVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* waterSurfaceWithDataVertexInputLayout = nullptr; + Renderer::Backend::IVertexInputLayout* waterShoreVertexInputLayout = nullptr; + CSimulation2* simulation; }; @@ -101,6 +114,32 @@ TerrainRenderer::~TerrainRenderer() delete m; } +void TerrainRenderer::Initialize() +{ + const std::array overlayAttributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + m->overlayVertexInputLayout = g_Renderer.GetVertexInputLayout(overlayAttributes); + + m->decalsVertexInputLayout = CDecalRData::GetVertexInputLayout(); + + m->baseVertexInputLayout = CPatchRData::GetBaseVertexInputLayout(); + m->blendVertexInputLayout = CPatchRData::GetBlendVertexInputLayout(); + m->streamVertexInputLayout = CPatchRData::GetStreamVertexInputLayout(false); + m->streamWithPositionAsTexCoordVertexInputLayout = + CPatchRData::GetStreamVertexInputLayout(true); + m->sideVertexInputLayout = CPatchRData::GetSideVertexInputLayout(); + + m->waterSurfaceVertexInputLayout = CPatchRData::GetWaterSurfaceVertexInputLayout(false); + m->waterSurfaceWithDataVertexInputLayout = CPatchRData::GetWaterSurfaceVertexInputLayout(true); + m->waterShoreVertexInputLayout = CPatchRData::GetWaterShoreVertexInputLayout(); +} + void TerrainRenderer::SetSimulation(CSimulation2* simulation) { m->simulation = simulation; @@ -190,7 +229,8 @@ void TerrainRenderer::RenderTerrainOverlayTexture( debugOverlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( debugOverlayShader->GetBindingSlot(str_textureTransform), textureTransform.AsFloatArray()); - CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, true); + CPatchRData::RenderStreams( + deviceCommandContext, m->streamWithPositionAsTexCoordVertexInputLayout, visiblePatches); // To make the overlay visible over water, render an additional map-sized // water-height patch. @@ -211,14 +251,7 @@ void TerrainRenderer::RenderTerrainOverlayTexture( waterBounds[0].X, height, waterBounds[1].Z }; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m->overlayVertexInputLayout); deviceCommandContext->SetVertexBufferData( 0, waterPos, std::size(waterPos) * sizeof(waterPos[0])); @@ -312,16 +345,20 @@ void TerrainRenderer::RenderTerrainShader( deviceCommandContext->SetUniform( shaderSolid->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 1.0f); - CPatchRData::RenderSides(deviceCommandContext, visiblePatches); + CPatchRData::RenderSides( + deviceCommandContext, m->sideVertexInputLayout, visiblePatches); deviceCommandContext->EndPass(); - CPatchRData::RenderBases(deviceCommandContext, visiblePatches, context, shadow); + CPatchRData::RenderBases( + deviceCommandContext, m->baseVertexInputLayout, visiblePatches, context, shadow); // render blend passes for each patch - CPatchRData::RenderBlends(deviceCommandContext, visiblePatches, context, shadow); + CPatchRData::RenderBlends( + deviceCommandContext, m->blendVertexInputLayout, visiblePatches, context, shadow); - CDecalRData::RenderDecals(deviceCommandContext, visibleDecals, context, shadow); + CDecalRData::RenderDecals( + deviceCommandContext, m->decalsVertexInputLayout, visibleDecals, context, shadow); } /////////////////////////////////////////////////////////////////// @@ -352,7 +389,8 @@ void TerrainRenderer::RenderPatches( deviceCommandContext->SetUniform( solidShader->GetBindingSlot(str_color), color.AsFloatArray()); - CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, false); + CPatchRData::RenderStreams( + deviceCommandContext, m->streamVertexInputLayout, visiblePatches); deviceCommandContext->EndPass(); } @@ -606,9 +644,10 @@ bool TerrainRenderer::RenderFancyWater( for (CPatchRData* data : m->visiblePatches[cullGroup]) { - data->RenderWaterSurface(deviceCommandContext, true); + data->RenderWaterSurface( + deviceCommandContext, m->waterSurfaceWithDataVertexInputLayout); if (waterManager.m_WaterFancyEffects) - data->RenderWaterShore(deviceCommandContext); + data->RenderWaterShore(deviceCommandContext, m->waterShoreVertexInputLayout); } deviceCommandContext->EndPass(); @@ -659,11 +698,10 @@ void TerrainRenderer::RenderSimpleWater( deviceCommandContext->SetUniform( waterSimpleShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray()); - std::vector& visiblePatches = m->visiblePatches[cullGroup]; - for (size_t i = 0; i < visiblePatches.size(); ++i) + for (CPatchRData* data : m->visiblePatches[cullGroup]) { - CPatchRData* data = visiblePatches[i]; - data->RenderWaterSurface(deviceCommandContext, false); + data->RenderWaterSurface( + deviceCommandContext, m->waterSurfaceVertexInputLayout); } deviceCommandContext->EndPass(); @@ -722,7 +760,7 @@ void TerrainRenderer::RenderWaterFoamOccluders( dummyShader->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 0.0f); for (CPatchRData* data : m->visiblePatches[cullGroup]) - data->RenderWaterShore(deviceCommandContext); + data->RenderWaterShore(deviceCommandContext, m->waterShoreVertexInputLayout); deviceCommandContext->EndPass(); diff --git a/source/renderer/TerrainRenderer.h b/source/renderer/TerrainRenderer.h index c5d2e8a9dd..75daa50146 100644 --- a/source/renderer/TerrainRenderer.h +++ b/source/renderer/TerrainRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -54,6 +54,8 @@ public: TerrainRenderer(); ~TerrainRenderer(); + void Initialize(); + /** * Set the simulation context for this frame. * Call at start of frame, before any other Submits. diff --git a/source/renderer/TexturedLineRData.cpp b/source/renderer/TexturedLineRData.cpp index 1e0b403ae7..94c4402f0a 100644 --- a/source/renderer/TexturedLineRData.cpp +++ b/source/renderer/TexturedLineRData.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,8 +35,30 @@ * because it allows you to work with variable amounts of vertices and indices more easily. New code should prefer * to use VertexArray where possible, though. */ +// static +Renderer::Backend::IVertexInputLayout* CTexturedLineRData::GetVertexInputLayout() +{ + const uint32_t stride = sizeof(CTexturedLineRData::SVertex); + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(CTexturedLineRData::SVertex, m_Position), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(CTexturedLineRData::SVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(CTexturedLineRData::SVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + return g_Renderer.GetVertexInputLayout(attributes); +} + void CTexturedLineRData::Render( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const SOverlayTexturedLine& line, Renderer::Backend::IShaderProgram* shader) { if (!m_VB || !m_VBIndices) @@ -57,23 +79,7 @@ void CTexturedLineRData::Render( deviceCommandContext->SetUniform( shader->GetBindingSlot(str_objectColor), line.m_Color.AsFloatArray()); - const uint32_t stride = sizeof(CTexturedLineRData::SVertex); - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(CTexturedLineRData::SVertex, m_Position), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(CTexturedLineRData::SVertex, m_UV), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(CTexturedLineRData::SVertex, m_UV), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(vertexInputLayout); deviceCommandContext->SetVertexBuffer(0, m_VB->m_Owner->GetBuffer(), 0); diff --git a/source/renderer/TexturedLineRData.h b/source/renderer/TexturedLineRData.h index a8b59e4bfe..5af90974ca 100644 --- a/source/renderer/TexturedLineRData.h +++ b/source/renderer/TexturedLineRData.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include "graphics/TextureManager.h" #include "maths/BoundingBoxAligned.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/VertexBufferManager.h" class CFrustum; @@ -47,12 +48,14 @@ class CTexturedLineRData : public CRenderData NONCOPYABLE(CTexturedLineRData); public: - CTexturedLineRData() = default; ~CTexturedLineRData() = default; + static Renderer::Backend::IVertexInputLayout* GetVertexInputLayout(); + void Update(const SOverlayTexturedLine& line); void Render(Renderer::Backend::IDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IVertexInputLayout* vertexInputLayout, const SOverlayTexturedLine& line, Renderer::Backend::IShaderProgram* shader); bool IsVisibleInFrustum(const CFrustum& frustum) const; diff --git a/source/renderer/VertexArray.cpp b/source/renderer/VertexArray.cpp index 1095fab1b4..e4aef539bd 100644 --- a/source/renderer/VertexArray.cpp +++ b/source/renderer/VertexArray.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,7 +31,7 @@ namespace { -size_t GetAttributeSize(const Renderer::Backend::Format format) +uint32_t GetAttributeSize(const Renderer::Backend::Format format) { switch (format) { @@ -209,7 +209,7 @@ VertexArrayIterator VertexArray::Attribute::GetIterator() co return vertexArray->MakeIterator(this); } -static size_t RoundStride(size_t stride) +static uint32_t RoundStride(uint32_t stride) { if (stride <= 0) return 0; @@ -238,7 +238,7 @@ void VertexArray::Layout() if (attr->format == Renderer::Backend::Format::UNDEFINED) continue; - const size_t attrSize = GetAttributeSize(attr->format); + const uint32_t attrSize = GetAttributeSize(attr->format); ENSURE(attrSize > 0); attr->offset = m_Stride; diff --git a/source/renderer/VertexArray.h b/source/renderer/VertexArray.h index 595be3f86d..645123d847 100644 --- a/source/renderer/VertexArray.h +++ b/source/renderer/VertexArray.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -142,7 +142,7 @@ public: Renderer::Backend::Format format = Renderer::Backend::Format::UNDEFINED; // Offset (in bytes) into a vertex structure (filled in by Layout()) - size_t offset = 0; + uint32_t offset = 0; VertexArray* vertexArray = nullptr; @@ -169,7 +169,7 @@ public: void AddAttribute(Attribute* attr); size_t GetNumberOfVertices() const { return m_NumberOfVertices; } - size_t GetStride() const { return m_Stride; } + uint32_t GetStride() const { return m_Stride; } // Layout the vertex array format and create backing buffer in RAM. // You must call Layout() after changing the number of vertices or @@ -208,7 +208,7 @@ private: std::vector m_Attributes; CVertexBufferManager::Handle m_VB; - size_t m_Stride; + uint32_t m_Stride; char* m_BackingStore; // 16-byte aligned, to allow fast SSE access }; diff --git a/source/renderer/WaterManager.cpp b/source/renderer/WaterManager.cpp index 14c5306cd3..717ea9dc01 100644 --- a/source/renderer/WaterManager.cpp +++ b/source/renderer/WaterManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -128,6 +128,39 @@ WaterManager::~WaterManager() m_RefrFboDepthTexture.reset(); } +void WaterManager::Initialize() +{ + const uint32_t stride = sizeof(SWavesVertex); + + const std::array attributes{{ + {Renderer::Backend::VertexAttributeStream::POSITION, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SWavesVertex, m_BasePosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::NORMAL, + Renderer::Backend::Format::R32G32_SFLOAT, + offsetof(SWavesVertex, m_PerpVect), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV0, + Renderer::Backend::Format::R8G8_UINT, + offsetof(SWavesVertex, m_UV), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + + {Renderer::Backend::VertexAttributeStream::UV1, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SWavesVertex, m_ApexPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV2, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SWavesVertex, m_SplashPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}, + {Renderer::Backend::VertexAttributeStream::UV3, + Renderer::Backend::Format::R32G32B32_SFLOAT, + offsetof(SWavesVertex, m_RetreatPosition), stride, + Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0} + }}; + m_ShoreVertexInputLayout = g_Renderer.GetVertexInputLayout(attributes); +} /////////////////////////////////////////////////////////////////// // Progressive load of water textures @@ -872,37 +905,7 @@ void WaterManager::RenderWaves( const uint32_t stride = sizeof(SWavesVertex); const uint32_t firstVertexOffset = VBchunk->m_Index * stride; - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SWavesVertex, m_BasePosition), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::NORMAL, - Renderer::Backend::Format::R32G32_SFLOAT, - offsetof(SWavesVertex, m_PerpVect), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R8G8_UINT, - offsetof(SWavesVertex, m_UV), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV1, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SWavesVertex, m_ApexPosition), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV2, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SWavesVertex, m_SplashPosition), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV3, - Renderer::Backend::Format::R32G32B32_SFLOAT, - offsetof(SWavesVertex, m_RetreatPosition), stride, - Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); + deviceCommandContext->SetVertexInputLayout(m_ShoreVertexInputLayout); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_translation), m_ShoreWaves[a]->m_TimeDiff); diff --git a/source/renderer/WaterManager.h b/source/renderer/WaterManager.h index 43997aebf5..ba642db475 100644 --- a/source/renderer/WaterManager.h +++ b/source/renderer/WaterManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include "maths/Vector2D.h" #include "renderer/backend/IDeviceCommandContext.h" #include "renderer/backend/IFramebuffer.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/backend/ITexture.h" #include "renderer/VertexBufferManager.h" @@ -60,6 +61,8 @@ public: // Waves indices buffer. Only one since All Wave Objects have the same. CVertexBufferManager::Handle m_ShoreWavesVBIndices; + Renderer::Backend::IVertexInputLayout* m_ShoreVertexInputLayout = nullptr; + size_t m_MapSize; ssize_t m_TexSize; @@ -129,6 +132,8 @@ public: WaterManager(); ~WaterManager(); + void Initialize(); + /** * LoadWaterTextures: Load water textures from within the * progressive load framework. diff --git a/source/renderer/backend/IDevice.h b/source/renderer/backend/IDevice.h index 5eec59f649..add6b86f41 100644 --- a/source/renderer/backend/IDevice.h +++ b/source/renderer/backend/IDevice.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,6 +19,7 @@ #define INCLUDED_RENDERER_BACKEND_IDEVICE #include "graphics/Color.h" +#include "ps/containers/Span.h" #include "renderer/backend/Backend.h" #include "renderer/backend/Format.h" #include "renderer/backend/IBuffer.h" @@ -82,6 +83,13 @@ public: virtual std::unique_ptr CreateGraphicsPipelineState( const SGraphicsPipelineStateDesc& pipelineStateDesc) = 0; + /** + * Creates a vertex input layout. It's recommended to use as few different + * layouts as posible. + */ + virtual std::unique_ptr CreateVertexInputLayout( + const PS::span attributes) = 0; + virtual std::unique_ptr CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, diff --git a/source/renderer/backend/IDeviceCommandContext.h b/source/renderer/backend/IDeviceCommandContext.h index c3c6c41ee5..4b2ba35bca 100644 --- a/source/renderer/backend/IDeviceCommandContext.h +++ b/source/renderer/backend/IDeviceCommandContext.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -40,6 +40,10 @@ class ITexture; class IDeviceCommandContext : public IDeviceObject { public: + /** + * Binds the graphics pipeline state. It should be called only inside a + * framebuffer pass and as rarely as possible. + */ virtual void SetGraphicsPipelineState(IGraphicsPipelineState* pipelineState) = 0; virtual void BlitFramebuffer( @@ -95,13 +99,14 @@ public: virtual void SetScissors(const uint32_t scissorCount, const Rect* scissors) = 0; virtual void SetViewports(const uint32_t viewportCount, const Rect* viewports) = 0; - virtual void SetVertexAttributeFormat( - const VertexAttributeStream stream, - const Format format, - const uint32_t offset, - const uint32_t stride, - const VertexAttributeRate rate, - const uint32_t bindingSlot) = 0; + /** + * Binds the vertex input layout. It should be compatible with the shader + * program's one. It should be called only inside a framebuffer pass and as + * rarely as possible. + */ + virtual void SetVertexInputLayout( + IVertexInputLayout* vertexInputLayout) = 0; + virtual void SetVertexBuffer( const uint32_t bindingSlot, IBuffer* buffer, const uint32_t offset) = 0; virtual void SetVertexBufferData( diff --git a/source/renderer/backend/IShaderProgram.h b/source/renderer/backend/IShaderProgram.h index 2284a2de9a..94bff6fda8 100644 --- a/source/renderer/backend/IShaderProgram.h +++ b/source/renderer/backend/IShaderProgram.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "lib/file/vfs/vfs_path.h" #include "ps/CStrIntern.h" +#include "renderer/backend/Format.h" #include "renderer/backend/IDeviceObject.h" namespace Renderer @@ -49,6 +50,30 @@ enum class VertexAttributeRate : uint32_t PER_INSTANCE }; +struct SVertexAttributeFormat +{ + VertexAttributeStream stream; + Format format; + uint32_t offset; + uint32_t stride; + VertexAttributeRate rate; + uint32_t bindingSlot; + + constexpr bool operator==(const SVertexAttributeFormat& other) const noexcept + { + return stream == other.stream && format == other.format && + offset == other.offset && stride == other.stride && + rate == other.rate && bindingSlot == other.bindingSlot; + } +}; + +/** + * IVertexInputLayout stores precompiled list of vertex attributes. + */ +class IVertexInputLayout : public IDeviceObject +{ +}; + /** * IShaderProgram is a container for multiple shaders of different types. */ diff --git a/source/renderer/backend/dummy/Device.cpp b/source/renderer/backend/dummy/Device.cpp index 07e5dd887a..5163b58cf4 100644 --- a/source/renderer/backend/dummy/Device.cpp +++ b/source/renderer/backend/dummy/Device.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -80,6 +80,12 @@ std::unique_ptr CDevice::CreateGraphicsPipelineState( return CGraphicsPipelineState::Create(this, pipelineStateDesc); } +std::unique_ptr CDevice::CreateVertexInputLayout( + const PS::span UNUSED(attributes)) +{ + return nullptr; +} + std::unique_ptr CDevice::CreateTexture( const char* UNUSED(name), const CTexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, diff --git a/source/renderer/backend/dummy/Device.h b/source/renderer/backend/dummy/Device.h index fb949da5ae..d5657b0eaa 100644 --- a/source/renderer/backend/dummy/Device.h +++ b/source/renderer/backend/dummy/Device.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -58,6 +58,9 @@ public: std::unique_ptr CreateGraphicsPipelineState( const SGraphicsPipelineStateDesc& pipelineStateDesc) override; + std::unique_ptr CreateVertexInputLayout( + const PS::span attributes) override; + std::unique_ptr CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, diff --git a/source/renderer/backend/dummy/DeviceCommandContext.cpp b/source/renderer/backend/dummy/DeviceCommandContext.cpp index 53f4d1f817..cb455ef968 100644 --- a/source/renderer/backend/dummy/DeviceCommandContext.cpp +++ b/source/renderer/backend/dummy/DeviceCommandContext.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -128,9 +128,7 @@ void CDeviceCommandContext::SetViewports(const uint32_t, const Rect*) { } -void CDeviceCommandContext::SetVertexAttributeFormat( - const VertexAttributeStream, const Format, - const uint32_t, const uint32_t, const VertexAttributeRate, const uint32_t) +void CDeviceCommandContext::SetVertexInputLayout(IVertexInputLayout*) { } diff --git a/source/renderer/backend/dummy/DeviceCommandContext.h b/source/renderer/backend/dummy/DeviceCommandContext.h index f291c4e80c..84679cc9c2 100644 --- a/source/renderer/backend/dummy/DeviceCommandContext.h +++ b/source/renderer/backend/dummy/DeviceCommandContext.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -78,13 +78,9 @@ public: void SetScissors(const uint32_t scissorCount, const Rect* scissors) override; void SetViewports(const uint32_t viewportCount, const Rect* viewports) override; - void SetVertexAttributeFormat( - const VertexAttributeStream stream, - const Format format, - const uint32_t offset, - const uint32_t stride, - const VertexAttributeRate rate, - const uint32_t bindingSlot) override; + void SetVertexInputLayout( + IVertexInputLayout* vertexInputLayout) override; + void SetVertexBuffer( const uint32_t bindingSlot, IBuffer* buffer, const uint32_t offset) override; void SetVertexBufferData( diff --git a/source/renderer/backend/gl/Device.cpp b/source/renderer/backend/gl/Device.cpp index d62410e081..8e42726feb 100644 --- a/source/renderer/backend/gl/Device.cpp +++ b/source/renderer/backend/gl/Device.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -875,6 +875,12 @@ std::unique_ptr CDevice::CreateGraphicsPipelineState( return CGraphicsPipelineState::Create(this, pipelineStateDesc); } +std::unique_ptr CDevice::CreateVertexInputLayout( + const PS::span attributes) +{ + return std::make_unique(this, attributes); +} + std::unique_ptr CDevice::CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, diff --git a/source/renderer/backend/gl/Device.h b/source/renderer/backend/gl/Device.h index 5fe163500e..c248498363 100644 --- a/source/renderer/backend/gl/Device.h +++ b/source/renderer/backend/gl/Device.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -71,6 +71,9 @@ public: std::unique_ptr CreateGraphicsPipelineState( const SGraphicsPipelineStateDesc& pipelineStateDesc) override; + std::unique_ptr CreateVertexInputLayout( + const PS::span attributes) override; + CDeviceCommandContext* GetActiveCommandContext() { return m_ActiveCommandContext; } std::unique_ptr CreateTexture( diff --git a/source/renderer/backend/gl/DeviceCommandContext.cpp b/source/renderer/backend/gl/DeviceCommandContext.cpp index 53d8d3c66c..c3e7281e76 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.cpp +++ b/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -968,26 +968,26 @@ void CDeviceCommandContext::SetViewports(const uint32_t viewportCount, const Rec ogl_WarnIfError(); } -void CDeviceCommandContext::SetVertexAttributeFormat( - const VertexAttributeStream stream, - const Format format, - const uint32_t offset, - const uint32_t stride, - const VertexAttributeRate rate, - const uint32_t bindingSlot) +void CDeviceCommandContext::SetVertexInputLayout( + IVertexInputLayout* vertexInputLayout) { - const uint32_t index = static_cast(stream); - ENSURE(index < m_VertexAttributeFormat.size()); - ENSURE(bindingSlot < m_VertexAttributeFormat.size()); - if (!m_VertexAttributeFormat[index].active) - return; - m_VertexAttributeFormat[index].format = format; - m_VertexAttributeFormat[index].offset = offset; - m_VertexAttributeFormat[index].stride = stride; - m_VertexAttributeFormat[index].rate = rate; - m_VertexAttributeFormat[index].bindingSlot = bindingSlot; + ENSURE(vertexInputLayout); + for (const SVertexAttributeFormat& attribute : vertexInputLayout->As()->GetAttributes()) + { + const uint32_t index = static_cast(attribute.stream); + ENSURE(index < m_VertexAttributeFormat.size()); + ENSURE(attribute.bindingSlot < m_VertexAttributeFormat.size()); + if (!m_VertexAttributeFormat[index].active) + continue; - m_VertexAttributeFormat[index].initialized = true; + m_VertexAttributeFormat[index].format = attribute.format; + m_VertexAttributeFormat[index].offset = attribute.offset; + m_VertexAttributeFormat[index].stride = attribute.stride; + m_VertexAttributeFormat[index].rate = attribute.rate; + m_VertexAttributeFormat[index].bindingSlot = attribute.bindingSlot; + + m_VertexAttributeFormat[index].initialized = true; + } } void CDeviceCommandContext::SetVertexBuffer( diff --git a/source/renderer/backend/gl/DeviceCommandContext.h b/source/renderer/backend/gl/DeviceCommandContext.h index 6a9135ed8f..db113fdbbe 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.h +++ b/source/renderer/backend/gl/DeviceCommandContext.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -87,13 +87,9 @@ public: void SetScissors(const uint32_t scissorCount, const Rect* scissors) override; void SetViewports(const uint32_t viewportCount, const Rect* viewports) override; - void SetVertexAttributeFormat( - const VertexAttributeStream stream, - const Format format, - const uint32_t offset, - const uint32_t stride, - const VertexAttributeRate rate, - const uint32_t bindingSlot) override; + void SetVertexInputLayout( + IVertexInputLayout* vertexInputLayout) override; + void SetVertexBuffer( const uint32_t bindingSlot, IBuffer* buffer, const uint32_t offset) override; void SetVertexBufferData( diff --git a/source/renderer/backend/gl/ShaderProgram.cpp b/source/renderer/backend/gl/ShaderProgram.cpp index c76b04a79c..a86bbfd7d8 100644 --- a/source/renderer/backend/gl/ShaderProgram.cpp +++ b/source/renderer/backend/gl/ShaderProgram.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -266,6 +266,11 @@ std::tuple GetElementTypeAndCountFromString(const CStr& s } // anonymous namespace +IDevice* CVertexInputLayout::GetDevice() +{ + return m_Device; +} + #if !CONFIG2_GLES class CShaderProgramARB final : public CShaderProgram diff --git a/source/renderer/backend/gl/ShaderProgram.h b/source/renderer/backend/gl/ShaderProgram.h index 6af45e7d81..1f3305fd6d 100644 --- a/source/renderer/backend/gl/ShaderProgram.h +++ b/source/renderer/backend/gl/ShaderProgram.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "lib/ogl.h" #include "lib/file/vfs/vfs_path.h" +#include "ps/containers/Span.h" #include "ps/CStrForward.h" #include "renderer/backend/Format.h" #include "renderer/backend/gl/Texture.h" @@ -45,6 +46,31 @@ namespace GL class CDevice; +class CVertexInputLayout : public IVertexInputLayout +{ +public: + CVertexInputLayout(CDevice* device, const PS::span attributes) + : m_Device(device), m_Attributes(attributes.begin(), attributes.end()) + { + for (const SVertexAttributeFormat& attribute : m_Attributes) + { + ENSURE(attribute.format != Format::UNDEFINED); + ENSURE(attribute.stride > 0); + } + } + + ~CVertexInputLayout() override = default; + + IDevice* GetDevice() override; + + const std::vector& GetAttributes() const noexcept { return m_Attributes; } + +private: + CDevice* m_Device = nullptr; + + std::vector m_Attributes; +}; + /** * A compiled vertex+fragment shader program. * The implementation may use GL_ARB_{vertex,fragment}_program (ARB assembly syntax) diff --git a/source/renderer/backend/vulkan/Device.cpp b/source/renderer/backend/vulkan/Device.cpp index f362396577..00e29dd1d7 100644 --- a/source/renderer/backend/vulkan/Device.cpp +++ b/source/renderer/backend/vulkan/Device.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -86,6 +86,13 @@ std::unique_ptr CDevice::CreateGraphicsPipelineState( return nullptr; } +std::unique_ptr CDevice::CreateVertexInputLayout( + const PS::span attributes) +{ + UNUSED2(attributes); + return nullptr; +} + std::unique_ptr CDevice::CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, diff --git a/source/renderer/backend/vulkan/Device.h b/source/renderer/backend/vulkan/Device.h index 985d4aac82..2a67bf34e5 100644 --- a/source/renderer/backend/vulkan/Device.h +++ b/source/renderer/backend/vulkan/Device.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -59,6 +59,9 @@ public: std::unique_ptr CreateGraphicsPipelineState( const SGraphicsPipelineStateDesc& pipelineStateDesc) override; + std::unique_ptr CreateVertexInputLayout( + const PS::span attributes) override; + std::unique_ptr CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height,