Index: ps/trunk/source/graphics/MiniMapTexture.cpp =================================================================== --- ps/trunk/source/graphics/MiniMapTexture.cpp +++ ps/trunk/source/graphics/MiniMapTexture.cpp @@ -122,7 +122,8 @@ } // anonymous namespace CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation) - : m_Simulation(simulation), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW) + : m_Simulation(simulation), m_IndexArray(false), + m_VertexArray(Renderer::Backend::GL::CBuffer::Type::VERTEX, true) { // Register Relax NG validator. CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng"); @@ -146,10 +147,10 @@ m_AttributeColor.elems = 4; m_VertexArray.AddAttribute(&m_AttributeColor); - m_VertexArray.SetNumVertices(MAX_ENTITIES_DRAWN); + m_VertexArray.SetNumberOfVertices(MAX_ENTITIES_DRAWN); m_VertexArray.Layout(); - m_IndexArray.SetNumVertices(MAX_ENTITIES_DRAWN); + m_IndexArray.SetNumberOfVertices(MAX_ENTITIES_DRAWN); m_IndexArray.Layout(); VertexArrayIterator index = m_IndexArray.GetIterator(); for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i) @@ -498,8 +499,8 @@ glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif - u8* indexBase = m_IndexArray.Bind(); - u8* base = m_VertexArray.Bind(); + u8* indexBase = m_IndexArray.Bind(deviceCommandContext); + u8* base = m_VertexArray.Bind(deviceCommandContext); const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); @@ -509,7 +510,7 @@ glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); g_Renderer.GetStats().m_DrawCalls++; - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); #if !CONFIG2_GLES glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); Index: ps/trunk/source/graphics/ParticleEmitter.h =================================================================== --- ps/trunk/source/graphics/ParticleEmitter.h +++ ps/trunk/source/graphics/ParticleEmitter.h @@ -128,7 +128,9 @@ /** * Draw the vertex array. */ - void RenderArray(const CShaderProgramPtr& shader); + void RenderArray( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader); /** * Stop this emitter emitting new particles, and pass responsibility for rendering Index: ps/trunk/source/graphics/ParticleEmitter.cpp =================================================================== --- ps/trunk/source/graphics/ParticleEmitter.cpp +++ ps/trunk/source/graphics/ParticleEmitter.cpp @@ -32,8 +32,8 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) : m_Type(type), m_Active(true), m_NextParticleIdx(0), m_EmissionRoundingError(0.f), m_LastUpdateTime(type->m_Manager.GetCurrentTime()), - m_IndexArray(GL_STATIC_DRAW), - m_VertexArray(GL_DYNAMIC_DRAW), + m_IndexArray(false), + m_VertexArray(Renderer::Backend::GL::CBuffer::Type::VERTEX, true), m_LastFrameNumber(-1) { // If we should start with particles fully emitted, pretend that we @@ -64,10 +64,10 @@ m_AttributeColor.elems = 4; m_VertexArray.AddAttribute(&m_AttributeColor); - m_VertexArray.SetNumVertices(m_Type->m_MaxParticles * 4); + m_VertexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 4); m_VertexArray.Layout(); - m_IndexArray.SetNumVertices(m_Type->m_MaxParticles * 6); + m_IndexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 6); m_IndexArray.Layout(); VertexArrayIterator index = m_IndexArray.GetIterator(); for (u16 i = 0; i < m_Type->m_MaxParticles; ++i) @@ -196,15 +196,17 @@ shader->BindTexture(str_baseTex, m_Type->m_Texture->GetBackendTexture()); } -void CParticleEmitter::RenderArray(const CShaderProgramPtr& shader) +void CParticleEmitter::RenderArray( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader) { // Some drivers apparently don't like count=0 in glDrawArrays here, // so skip all drawing in that case if (m_Particles.empty()) return; - u8* indexBase = m_IndexArray.Bind(); - u8* base = m_VertexArray.Bind(); + u8* indexBase = m_IndexArray.Bind(deviceCommandContext); + u8* base = m_VertexArray.Bind(deviceCommandContext); GLsizei stride = (GLsizei)m_VertexArray.GetStride(); Index: ps/trunk/source/renderer/DecalRData.cpp =================================================================== --- ps/trunk/source/renderer/DecalRData.cpp +++ ps/trunk/source/renderer/DecalRData.cpp @@ -198,7 +198,7 @@ { lastVB = batch.vertices->m_Owner; const GLsizei stride = sizeof(SDecalVertex); - SDecalVertex* base = (SDecalVertex*)batch.vertices->m_Owner->Bind(); + SDecalVertex* base = (SDecalVertex*)batch.vertices->m_Owner->Bind(deviceCommandContext); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); @@ -210,7 +210,7 @@ if (lastIB != batch.indices->m_Owner) { lastIB = batch.indices->m_Owner; - batch.indices->m_Owner->Bind(); + batch.indices->m_Owner->Bind(deviceCommandContext); } u8* indexBase = nullptr; @@ -225,7 +225,7 @@ } } - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } void CDecalRData::BuildVertexData() @@ -279,7 +279,11 @@ } if (!m_VBDecals || m_VBDecals->m_Count != vertices.size()) - m_VBDecals = g_VBMan.AllocateChunk(sizeof(SDecalVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); + { + m_VBDecals = g_VBMan.AllocateChunk( + sizeof(SDecalVertex), vertices.size(), + Renderer::Backend::GL::CBuffer::Type::VERTEX, false); + } m_VBDecals->m_Owner->UpdateChunkVertices(m_VBDecals.Get(), vertices.data()); std::vector indices((i1 - i0) * (j1 - j0) * 6); @@ -317,6 +321,10 @@ // Construct vertex buffer. if (!m_VBDecalsIndices || m_VBDecalsIndices->m_Count != indices.size()) - m_VBDecalsIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); + { + m_VBDecalsIndices = g_VBMan.AllocateChunk( + sizeof(u16), indices.size(), + Renderer::Backend::GL::CBuffer::Type::INDEX, false); + } m_VBDecalsIndices->m_Owner->UpdateChunkVertices(m_VBDecalsIndices.Get(), indices.data()); } Index: ps/trunk/source/renderer/HWLightingModelRenderer.h =================================================================== --- ps/trunk/source/renderer/HWLightingModelRenderer.h +++ ps/trunk/source/renderer/HWLightingModelRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,14 +36,18 @@ ShaderModelVertexRenderer(); ~ShaderModelVertexRenderer(); - // Implementations - CModelRData* CreateModelData(const void* key, CModel* model); - void UpdateModelData(CModel* model, CModelRData* data, int updateflags); - - void BeginPass(int streamflags); - void EndPass(int streamflags); - void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def); - void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data); + CModelRData* CreateModelData(const void* key, CModel* model) override; + void UpdateModelData(CModel* model, CModelRData* data, int updateflags) override; + + void BeginPass(int streamflags) override; + void EndPass( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int streamflags) override; + void PrepareModelDef( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) override; + void RenderModel( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) override; protected: struct ShaderModelRendererInternals; Index: ps/trunk/source/renderer/HWLightingModelRenderer.cpp =================================================================== --- ps/trunk/source/renderer/HWLightingModelRenderer.cpp +++ ps/trunk/source/renderer/HWLightingModelRenderer.cpp @@ -17,18 +17,17 @@ #include "precompiled.h" -#include "lib/bits.h" -#include "lib/ogl.h" -#include "lib/sysdep/rtl.h" -#include "maths/Vector3D.h" +#include "renderer/HWLightingModelRenderer.h" #include "graphics/Color.h" #include "graphics/LightEnv.h" #include "graphics/Model.h" #include "graphics/ModelDef.h" #include "graphics/ShaderProgram.h" - -#include "renderer/HWLightingModelRenderer.h" +#include "lib/bits.h" +#include "lib/ogl.h" +#include "lib/sysdep/rtl.h" +#include "maths/Vector3D.h" #include "renderer/Renderer.h" #include "renderer/RenderModifiers.h" #include "renderer/VertexArray.h" @@ -50,7 +49,8 @@ ShaderModelDef::ShaderModelDef(const CModelDefPtr& mdef) - : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW) + : m_IndexArray(false), + m_Array(Renderer::Backend::GL::CBuffer::Type::VERTEX, false) { size_t numVertices = mdef->GetNumVertices(); @@ -62,7 +62,7 @@ m_Array.AddAttribute(&m_UVs[i]); } - m_Array.SetNumVertices(numVertices); + m_Array.SetNumberOfVertices(numVertices); m_Array.Layout(); for (size_t i = 0; i < mdef->GetNumUVsPerVertex(); ++i) @@ -74,7 +74,7 @@ m_Array.Upload(); m_Array.FreeBackingStore(); - m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3); + m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces()*3); m_IndexArray.Layout(); ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator()); m_IndexArray.Upload(); @@ -91,7 +91,10 @@ VertexArray::Attribute m_Position; VertexArray::Attribute m_Normal; - ShaderModel(const void* key) : CModelRData(key), m_Array(GL_DYNAMIC_DRAW) { } + ShaderModel(const void* key) + : CModelRData(key), + m_Array(Renderer::Backend::GL::CBuffer::Type::VERTEX, true) + {} }; @@ -140,7 +143,7 @@ shadermodel->m_Normal.elems = 4; shadermodel->m_Array.AddAttribute(&shadermodel->m_Normal); - shadermodel->m_Array.SetNumVertices(mdef->GetNumVertices()); + shadermodel->m_Array.SetNumberOfVertices(mdef->GetNumVertices()); shadermodel->m_Array.Layout(); // Verify alignment @@ -180,20 +183,23 @@ } // Cleanup one rendering pass -void ShaderModelVertexRenderer::EndPass(int UNUSED(streamflags)) +void ShaderModelVertexRenderer::EndPass( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int UNUSED(streamflags)) { - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } // Prepare UV coordinates for this modeldef -void ShaderModelVertexRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) +void ShaderModelVertexRenderer::PrepareModelDef( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) { m->shadermodeldef = (ShaderModelDef*)def.GetRenderData(m); ENSURE(m->shadermodeldef); - u8* base = m->shadermodeldef->m_Array.Bind(); + u8* base = m->shadermodeldef->m_Array.Bind(deviceCommandContext); GLsizei stride = (GLsizei)m->shadermodeldef->m_Array.GetStride(); if (streamflags & STREAM_UV0) @@ -205,15 +211,17 @@ // Render one model -void ShaderModelVertexRenderer::RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) +void ShaderModelVertexRenderer::RenderModel( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) { const CModelDefPtr& mdldef = model->GetModelDef(); ShaderModel* shadermodel = static_cast(data); - u8* base = shadermodel->m_Array.Bind(); + u8* base = shadermodel->m_Array.Bind(deviceCommandContext); GLsizei stride = (GLsizei)shadermodel->m_Array.GetStride(); - u8* indexBase = m->shadermodeldef->m_IndexArray.Bind(); + u8* indexBase = m->shadermodeldef->m_IndexArray.Bind(deviceCommandContext); if (streamflags & STREAM_POS) shader->VertexPointer(3, GL_FLOAT, stride, base + shadermodel->m_Position.offset); Index: ps/trunk/source/renderer/InstancingModelRenderer.h =================================================================== --- ps/trunk/source/renderer/InstancingModelRenderer.h +++ ps/trunk/source/renderer/InstancingModelRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -43,9 +43,14 @@ void UpdateModelData(CModel* model, CModelRData* data, int updateflags); void BeginPass(int streamflags); - void EndPass(int streamflags); - void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def); - void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data); + void EndPass( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + int streamflags); + void PrepareModelDef( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, const CModelDef& def); + void RenderModel(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data); protected: InstancingModelRendererInternals* m; Index: ps/trunk/source/renderer/InstancingModelRenderer.cpp =================================================================== --- ps/trunk/source/renderer/InstancingModelRenderer.cpp +++ ps/trunk/source/renderer/InstancingModelRenderer.cpp @@ -56,7 +56,7 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateTangents) - : m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW) + : m_IndexArray(false), m_Array(Renderer::Backend::GL::CBuffer::Type::VERTEX, false) { size_t numVertices = mdef->GetNumVertices(); @@ -129,7 +129,7 @@ // Copy the model data to graphics memory:- - m_Array.SetNumVertices(numVertices2); + m_Array.SetNumberOfVertices(numVertices2); m_Array.Layout(); VertexArrayIterator Position = m_Position.GetIterator(); @@ -181,7 +181,7 @@ m_Array.Upload(); m_Array.FreeBackingStore(); - m_IndexArray.SetNumVertices(mdef->GetNumFaces() * 3); + m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces() * 3); m_IndexArray.Layout(); VertexArrayIterator Indices = m_IndexArray.GetIterator(); @@ -203,7 +203,7 @@ { // Upload model without calculating tangents:- - m_Array.SetNumVertices(numVertices); + m_Array.SetNumberOfVertices(numVertices); m_Array.Layout(); VertexArrayIterator Position = m_Position.GetIterator(); @@ -235,7 +235,7 @@ m_Array.Upload(); m_Array.FreeBackingStore(); - m_IndexArray.SetNumVertices(mdef->GetNumFaces()*3); + m_IndexArray.SetNumberOfVertices(mdef->GetNumFaces()*3); m_IndexArray.Layout(); ModelRenderer::BuildIndices(mdef, m_IndexArray.GetIterator()); m_IndexArray.Upload(); @@ -307,23 +307,27 @@ } // Cleanup rendering pass. -void InstancingModelRenderer::EndPass(int UNUSED(streamflags)) +void InstancingModelRenderer::EndPass( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + int UNUSED(streamflags)) { - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } // Prepare UV coordinates for this modeldef -void InstancingModelRenderer::PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) +void InstancingModelRenderer::PrepareModelDef( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) { m->imodeldef = (IModelDef*)def.GetRenderData(m); ENSURE(m->imodeldef); - u8* base = m->imodeldef->m_Array.Bind(); + u8* base = m->imodeldef->m_Array.Bind(deviceCommandContext); GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride(); - m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind(); + m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind(deviceCommandContext); if (streamflags & STREAM_POS) shader->VertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset); @@ -356,7 +360,9 @@ // Render one model -void InstancingModelRenderer::RenderModel(const CShaderProgramPtr& shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data)) +void InstancingModelRenderer::RenderModel( + Renderer::Backend::GL::CDeviceCommandContext* UNUSED(deviceCommandContext), + const CShaderProgramPtr& shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data)) { const CModelDefPtr& mdldef = model->GetModelDef(); @@ -378,7 +384,7 @@ #if CONFIG2_GLES glDrawElements(GL_TRIANGLES, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase); #else - glDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)m->imodeldef->m_Array.GetNumVertices()-1, + glDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)m->imodeldef->m_Array.GetNumberOfVertices()-1, (GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase); #endif Index: ps/trunk/source/renderer/ModelRenderer.cpp =================================================================== --- ps/trunk/source/renderer/ModelRenderer.cpp +++ ps/trunk/source/renderer/ModelRenderer.cpp @@ -704,7 +704,7 @@ if (newModeldef != currentModeldef) { currentModeldef = newModeldef; - m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); + m->vertexRenderer->PrepareModelDef(deviceCommandContext, shader, streamflags, *currentModeldef); } // Bind all uniforms when any change @@ -753,11 +753,11 @@ CModelRData* rdata = static_cast(model->GetRenderData()); ENSURE(rdata->GetKey() == m->vertexRenderer.get()); - m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); + m->vertexRenderer->RenderModel(deviceCommandContext, shader, streamflags, model, rdata); } } - m->vertexRenderer->EndPass(streamflags); + m->vertexRenderer->EndPass(deviceCommandContext, streamflags); currentTech->EndPass(pass); } Index: ps/trunk/source/renderer/ModelVertexRenderer.h =================================================================== --- ps/trunk/source/renderer/ModelVertexRenderer.h +++ ps/trunk/source/renderer/ModelVertexRenderer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2022 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 "graphics/MeshManager.h" #include "graphics/ShaderProgramPtr.h" +#include "renderer/backend/gl/DeviceCommandContext.h" class CModel; class CModelRData; @@ -114,7 +115,7 @@ * This equals the streamflags parameter passed on the last call to * BeginPass. */ - virtual void EndPass(int streamflags) = 0; + virtual void EndPass(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int streamflags) = 0; /** @@ -131,7 +132,9 @@ * BeginPass. * @param def The model definition. */ - virtual void PrepareModelDef(const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) = 0; + virtual void PrepareModelDef( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) = 0; /** @@ -153,7 +156,9 @@ * that use the same CModelDef object and the same texture must * succeed. */ - virtual void RenderModel(const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) = 0; + virtual void RenderModel( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) = 0; }; Index: ps/trunk/source/renderer/OverlayRenderer.cpp =================================================================== --- ps/trunk/source/renderer/OverlayRenderer.cpp +++ ps/trunk/source/renderer/OverlayRenderer.cpp @@ -154,7 +154,8 @@ const float OverlayRenderer::OVERLAY_VOFFSET = 0.2f; OverlayRendererInternals::OverlayRendererInternals() - : quadVertices(GL_DYNAMIC_DRAW), quadIndices(GL_STATIC_DRAW) + : quadVertices(Renderer::Backend::GL::CBuffer::Type::VERTEX, true), + quadIndices(false) { quadAttributePos.elems = 3; quadAttributePos.type = GL_FLOAT; @@ -183,10 +184,10 @@ // only at this point can we safely allocate VBOs (in contrast to e.g. in the constructor), // because their creation depends on the shader path, which is not reliably set before this point. - quadVertices.SetNumVertices(MAX_QUAD_OVERLAYS * 4); + quadVertices.SetNumberOfVertices(MAX_QUAD_OVERLAYS * 4); quadVertices.Layout(); // allocate backing store - quadIndices.SetNumVertices(MAX_QUAD_OVERLAYS * 6); + quadIndices.SetNumberOfVertices(MAX_QUAD_OVERLAYS * 6); quadIndices.Layout(); // allocate backing store // Since the quads in the vertex array are independent and always consist of exactly 4 vertices per quad, the @@ -480,7 +481,7 @@ deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0); - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } void OverlayRenderer::RenderTexturedOverlayLines( @@ -551,8 +552,8 @@ shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); // Base offsets (in bytes) of the two backing stores relative to their owner VBO - u8* indexBase = m->quadIndices.Bind(); - u8* vertexBase = m->quadVertices.Bind(); + u8* indexBase = m->quadIndices.Bind(deviceCommandContext); + u8* vertexBase = m->quadVertices.Bind(deviceCommandContext); GLsizei indexStride = m->quadIndices.GetStride(); GLsizei vertexStride = m->quadVertices.GetStride(); @@ -599,7 +600,7 @@ deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0); - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); #if !CONFIG2_GLES if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) Index: ps/trunk/source/renderer/ParticleRenderer.cpp =================================================================== --- ps/trunk/source/renderer/ParticleRenderer.cpp +++ ps/trunk/source/renderer/ParticleRenderer.cpp @@ -158,13 +158,13 @@ shader->Uniform(str_modelViewMatrix, g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse()); } emitter->Bind(deviceCommandContext, lastTech->GetShader()); - emitter->RenderArray(lastTech->GetShader()); + emitter->RenderArray(deviceCommandContext, lastTech->GetShader()); } if (lastTech) lastTech->EndPass(); - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } void ParticleRenderer::RenderBounds(int cullGroup) Index: ps/trunk/source/renderer/PatchRData.h =================================================================== --- ps/trunk/source/renderer/PatchRData.h +++ ps/trunk/source/renderer/PatchRData.h @@ -48,8 +48,12 @@ void RenderOutline(); void RenderPriorities(CTextRenderer& textRenderer); - void RenderWaterSurface(const CShaderProgramPtr& shader, const bool bindWaterData); - void RenderWaterShore(const CShaderProgramPtr& shader); + void RenderWaterSurface( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, const bool bindWaterData); + void RenderWaterShore( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader); CPatch* GetPatch() { return m_Patch; } @@ -61,8 +65,12 @@ static void RenderBlends( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow); - static void RenderStreams(const std::vector& patches, const CShaderProgramPtr& shader, int streamflags); - static void RenderSides(const std::vector& patches, const CShaderProgramPtr& shader); + static void RenderStreams( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const std::vector& patches, const CShaderProgramPtr& shader, int streamflags); + static void RenderSides( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const std::vector& patches, const CShaderProgramPtr& shader); static void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow); Index: ps/trunk/source/renderer/PatchRData.cpp =================================================================== --- ps/trunk/source/renderer/PatchRData.cpp +++ ps/trunk/source/renderer/PatchRData.cpp @@ -281,14 +281,20 @@ { // Construct vertex buffer - m_VBBlends = g_VBMan.AllocateChunk(sizeof(SBlendVertex), blendVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + m_VBBlends = g_VBMan.AllocateChunk( + sizeof(SBlendVertex), blendVertices.size(), + Renderer::Backend::GL::CBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::TERRAIN); m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends.Get(), &blendVertices[0]); // Update the indices to include the base offset of the vertex data for (size_t k = 0; k < blendIndices.size(); ++k) blendIndices[k] += static_cast(m_VBBlends->m_Index); - m_VBBlendIndices = g_VBMan.AllocateChunk(sizeof(u16), blendIndices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + m_VBBlendIndices = g_VBMan.AllocateChunk( + sizeof(u16), blendIndices.size(), + Renderer::Backend::GL::CBuffer::Type::INDEX, false, + nullptr, CVertexBufferManager::Group::TERRAIN); m_VBBlendIndices->m_Owner->UpdateChunkVertices(m_VBBlendIndices.Get(), &blendIndices[0]); } } @@ -489,7 +495,9 @@ ENSURE(indices.size()); // Construct vertex buffer - m_VBBaseIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + m_VBBaseIndices = g_VBMan.AllocateChunk( + sizeof(u16), indices.size(), + Renderer::Backend::GL::CBuffer::Type::INDEX, false, nullptr, CVertexBufferManager::Group::TERRAIN); m_VBBaseIndices->m_Owner->UpdateChunkVertices(m_VBBaseIndices.Get(), &indices[0]); } @@ -532,7 +540,12 @@ // upload to vertex buffer if (!m_VBBase) - m_VBBase = g_VBMan.AllocateChunk(sizeof(SBaseVertex), vsize * vsize, GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::TERRAIN); + { + m_VBBase = g_VBMan.AllocateChunk( + sizeof(SBaseVertex), vsize * vsize, + Renderer::Backend::GL::CBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::TERRAIN); + } m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase.Get(), &vertices[0]); } @@ -614,7 +627,12 @@ return; if (!m_VBSides) - m_VBSides = g_VBMan.AllocateChunk(sizeof(SSideVertex), sideVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::DEFAULT); + { + m_VBSides = g_VBMan.AllocateChunk( + sizeof(SSideVertex), sideVertices.size(), + Renderer::Backend::GL::CBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::DEFAULT); + } m_VBSides->m_Owner->UpdateChunkVertices(m_VBSides.Get(), &sideVertices[0]); } @@ -779,7 +797,7 @@ for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv) { GLsizei stride = sizeof(SBaseVertex); - SBaseVertex *base = (SBaseVertex *)itv->first->Bind(); + SBaseVertex *base = (SBaseVertex *)itv->first->Bind(deviceCommandContext); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); shader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, &base->m_Position[0]); @@ -788,7 +806,7 @@ for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { - it->first->Bind(); + it->first->Bind(deviceCommandContext); BatchElements& batch = it->second; @@ -807,7 +825,7 @@ } } - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } /** @@ -1006,7 +1024,7 @@ lastVB = itv->first; previousShader = shader; GLsizei stride = sizeof(SBlendVertex); - SBlendVertex *base = (SBlendVertex *)itv->first->Bind(); + SBlendVertex *base = (SBlendVertex *)itv->first->Bind(deviceCommandContext); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]); shader->NormalPointer(GL_FLOAT, stride, &base->m_Normal[0]); @@ -1018,7 +1036,7 @@ for (IndexBufferBatches::iterator it = itv->second.begin(); it != itv->second.end(); ++it) { - it->first->Bind(); + it->first->Bind(deviceCommandContext); BatchElements& batch = it->second; @@ -1035,10 +1053,12 @@ } } - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } -void CPatchRData::RenderStreams(const std::vector& patches, const CShaderProgramPtr& shader, int streamflags) +void CPatchRData::RenderStreams( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const std::vector& patches, const CShaderProgramPtr& shader, int streamflags) { PROFILE3("render terrain streams"); @@ -1074,7 +1094,7 @@ for (const std::pair& streamBatch : batches) { GLsizei stride = sizeof(SBaseVertex); - SBaseVertex *base = (SBaseVertex *)streamBatch.first->Bind(); + SBaseVertex *base = (SBaseVertex *)streamBatch.first->Bind(deviceCommandContext); shader->VertexPointer(3, GL_FLOAT, stride, &base->m_Position); if (streamflags & STREAM_POSTOUV0) @@ -1086,7 +1106,7 @@ for (const std::pair& batchIndexBuffer : streamBatch.second) { - batchIndexBuffer.first->Bind(); + batchIndexBuffer.first->Bind(deviceCommandContext); const StreamBatchElements& batch = batchIndexBuffer.second; @@ -1098,7 +1118,7 @@ } } - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } void CPatchRData::RenderOutline() @@ -1133,7 +1153,9 @@ g_Renderer.GetDebugRenderer().DrawLine(line, CColor(0.0f, 0.0f, 1.0f, 1.0f), 0.1f); } -void CPatchRData::RenderSides(const std::vector& patches, const CShaderProgramPtr& shader) +void CPatchRData::RenderSides( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const std::vector& patches, const CShaderProgramPtr& shader) { PROFILE3("render terrain sides"); @@ -1146,7 +1168,7 @@ if (lastVB != patch->m_VBSides->m_Owner) { lastVB = patch->m_VBSides->m_Owner; - SSideVertex *base = (SSideVertex*)patch->m_VBSides->m_Owner->Bind(); + SSideVertex *base = (SSideVertex*)patch->m_VBSides->m_Owner->Bind(deviceCommandContext); // setup data pointers GLsizei stride = sizeof(SSideVertex); @@ -1162,7 +1184,7 @@ g_Renderer.m_Stats.m_TerrainTris += patch->m_VBSides->m_Count - 2; } - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } void CPatchRData::RenderPriorities(CTextRenderer& textRenderer) @@ -1362,32 +1384,46 @@ // No vertex buffers if no data generated if (!water_indices.empty()) { - m_VBWater = g_VBMan.AllocateChunk(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWater = g_VBMan.AllocateChunk( + sizeof(SWaterVertex), water_vertex_data.size(), + Renderer::Backend::GL::CBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater.Get(), &water_vertex_data[0]); - m_VBWaterIndices = g_VBMan.AllocateChunk(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWaterIndices = g_VBMan.AllocateChunk( + sizeof(GLushort), water_indices.size(), + Renderer::Backend::GL::CBuffer::Type::INDEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices.Get(), &water_indices[0]); } if (!water_indices_shore.empty()) { - m_VBWaterShore = g_VBMan.AllocateChunk(sizeof(SWaterVertex), water_vertex_data_shore.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWaterShore = g_VBMan.AllocateChunk( + sizeof(SWaterVertex), water_vertex_data_shore.size(), + Renderer::Backend::GL::CBuffer::Type::VERTEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWaterShore->m_Owner->UpdateChunkVertices(m_VBWaterShore.Get(), &water_vertex_data_shore[0]); // Construct indices buffer - m_VBWaterIndicesShore = g_VBMan.AllocateChunk(sizeof(GLushort), water_indices_shore.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, nullptr, CVertexBufferManager::Group::WATER); + m_VBWaterIndicesShore = g_VBMan.AllocateChunk( + sizeof(GLushort), water_indices_shore.size(), + Renderer::Backend::GL::CBuffer::Type::INDEX, false, + nullptr, CVertexBufferManager::Group::WATER); m_VBWaterIndicesShore->m_Owner->UpdateChunkVertices(m_VBWaterIndicesShore.Get(), &water_indices_shore[0]); } } -void CPatchRData::RenderWaterSurface(const CShaderProgramPtr& shader, const bool bindWaterData) +void CPatchRData::RenderWaterSurface( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader, const bool bindWaterData) { ASSERT(m_UpdateFlags == 0); if (!m_VBWater) return; - SWaterVertex* base = reinterpret_cast(m_VBWater->m_Owner->Bind()); + SWaterVertex* base = reinterpret_cast(m_VBWater->m_Owner->Bind(deviceCommandContext)); // Setup data pointers. const GLsizei stride = sizeof(SWaterVertex); @@ -1397,7 +1433,7 @@ shader->AssertPointersBound(); - u8* indexBase = m_VBWaterIndices->m_Owner->Bind(); + u8* indexBase = m_VBWaterIndices->m_Owner->Bind(deviceCommandContext); glDrawElements( GL_TRIANGLES, static_cast(m_VBWaterIndices->m_Count), GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndices->m_Index)); @@ -1405,17 +1441,19 @@ g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 3; - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } -void CPatchRData::RenderWaterShore(const CShaderProgramPtr& shader) +void CPatchRData::RenderWaterShore( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + const CShaderProgramPtr& shader) { ASSERT(m_UpdateFlags == 0); if (!m_VBWaterShore) return; - SWaterVertex* base = reinterpret_cast(m_VBWaterShore->m_Owner->Bind()); + SWaterVertex* base = reinterpret_cast(m_VBWaterShore->m_Owner->Bind(deviceCommandContext)); const GLsizei stride = sizeof(SWaterVertex); shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWaterShore->m_Index].m_Position); @@ -1423,12 +1461,12 @@ shader->AssertPointersBound(); - u8* indexBase = m_VBWaterIndicesShore->m_Owner->Bind(); + u8* indexBase = m_VBWaterIndicesShore->m_Owner->Bind(deviceCommandContext); glDrawElements(GL_TRIANGLES, static_cast(m_VBWaterIndicesShore->m_Count), GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndicesShore->m_Index)); g_Renderer.m_Stats.m_DrawCalls++; g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndicesShore->m_Count / 3; - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } Index: ps/trunk/source/renderer/TerrainRenderer.cpp =================================================================== --- ps/trunk/source/renderer/TerrainRenderer.cpp +++ ps/trunk/source/renderer/TerrainRenderer.cpp @@ -186,7 +186,7 @@ debugOverlayShader->BindTexture(str_baseTex, texture); debugOverlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); debugOverlayShader->Uniform(str_textureTransform, textureMatrix); - CPatchRData::RenderStreams(visiblePatches, debugOverlayShader, STREAM_POS | STREAM_POSTOUV0); + CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, debugOverlayShader, STREAM_POS | STREAM_POSTOUV0); // To make the overlay visible over water, render an additional map-sized // water-height patch. @@ -269,7 +269,7 @@ shaderSolid->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f); - CPatchRData::RenderSides(visiblePatches, shaderSolid); + CPatchRData::RenderSides(deviceCommandContext, visiblePatches, shaderSolid); techSolid->EndPass(); @@ -315,7 +315,7 @@ solidShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); solidShader->Uniform(str_color, color); - CPatchRData::RenderStreams(visiblePatches, solidShader, STREAM_POS); + CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, solidShader, STREAM_POS); solidTech->EndPass(); #endif } @@ -499,9 +499,9 @@ for (CPatchRData* data : m->visiblePatches[cullGroup]) { - data->RenderWaterSurface(fancyWaterShader, true); + data->RenderWaterSurface(deviceCommandContext, fancyWaterShader, true); if (waterManager.m_WaterFancyEffects) - data->RenderWaterShore(fancyWaterShader); + data->RenderWaterShore(deviceCommandContext, fancyWaterShader); } m->fancyWaterTech->EndPass(); @@ -552,7 +552,7 @@ for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; - data->RenderWaterSurface(waterSimpleShader, false); + data->RenderWaterSurface(deviceCommandContext, waterSimpleShader, false); } deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); @@ -603,7 +603,7 @@ dummyShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f); for (CPatchRData* data : m->visiblePatches[cullGroup]) - data->RenderWaterShore(dummyShader); + data->RenderWaterShore(deviceCommandContext, dummyShader); dummyTech->EndPass(); deviceCommandContext->SetFramebuffer( Index: ps/trunk/source/renderer/TexturedLineRData.cpp =================================================================== --- ps/trunk/source/renderer/TexturedLineRData.cpp +++ ps/trunk/source/renderer/TexturedLineRData.cpp @@ -53,7 +53,8 @@ shader->Uniform(str_objectColor, line.m_Color); GLsizei stride = sizeof(CTexturedLineRData::SVertex); - CTexturedLineRData::SVertex* vertexBase = reinterpret_cast(m_VB->m_Owner->Bind()); + CTexturedLineRData::SVertex* vertexBase = + reinterpret_cast(m_VB->m_Owner->Bind(deviceCommandContext)); if (streamFlags & STREAM_POS) shader->VertexPointer(3, GL_FLOAT, stride, &vertexBase->m_Position[0]); @@ -64,7 +65,7 @@ if (streamFlags & STREAM_UV1) shader->TexCoordPointer(GL_TEXTURE1, 2, GL_FLOAT, stride, &vertexBase->m_UVs[0]); - u8* indexBase = m_VBIndices->m_Owner->Bind(); + u8* indexBase = m_VBIndices->m_Owner->Bind(deviceCommandContext); shader->AssertPointersBound(); glDrawElements(GL_TRIANGLES, m_VBIndices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*m_VBIndices->m_Index); @@ -309,7 +310,8 @@ for (const SVertex& vertex : vertices) m_BoundingBox += vertex.m_Position; - m_VB = g_VBMan.AllocateChunk(sizeof(SVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); + m_VB = g_VBMan.AllocateChunk( + sizeof(SVertex), vertices.size(), Renderer::Backend::GL::CBuffer::Type::VERTEX, false); if (m_VB) // allocation might fail (e.g. due to too many vertices) { m_VB->m_Owner->UpdateChunkVertices(m_VB.Get(), &vertices[0]); // copy data into VBO @@ -317,7 +319,8 @@ for (size_t k = 0; k < indices.size(); ++k) indices[k] += static_cast(m_VB->m_Index); - m_VBIndices = g_VBMan.AllocateChunk(sizeof(u16), indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); + m_VBIndices = g_VBMan.AllocateChunk( + sizeof(u16), indices.size(), Renderer::Backend::GL::CBuffer::Type::INDEX, false); if (m_VBIndices) m_VBIndices->m_Owner->UpdateChunkVertices(m_VBIndices.Get(), &indices[0]); } Index: ps/trunk/source/renderer/VertexArray.h =================================================================== --- ps/trunk/source/renderer/VertexArray.h +++ ps/trunk/source/renderer/VertexArray.h @@ -18,6 +18,8 @@ #ifndef INCLUDED_VERTEXARRAY #define INCLUDED_VERTEXARRAY +#include "renderer/backend/gl/Buffer.h" +#include "renderer/backend/gl/DeviceCommandContext.h" #include "renderer/VertexBufferManager.h" #include @@ -159,15 +161,16 @@ }; public: - VertexArray(GLenum usage, GLenum target = GL_ARRAY_BUFFER); + VertexArray( + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic); ~VertexArray(); // Set the number of vertices stored in the array - void SetNumVertices(size_t num); + void SetNumberOfVertices(const size_t numberOfVertices); // Add vertex attributes void AddAttribute(Attribute* attr); - size_t GetNumVertices() const { return m_NumVertices; } + size_t GetNumberOfVertices() const { return m_NumberOfVertices; } size_t GetStride() const { return m_Stride; } // Layout the vertex array format and create backing buffer in RAM. @@ -181,7 +184,7 @@ // Make this vertex array's data available for the next series of calls to Bind void PrepareForRendering(); // Bind this array, returns the base address for calls to glVertexPointer etc. - u8* Bind(); + u8* Bind(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); // If you know for certain that you'll never have to change the data again, // call this to free some memory. @@ -197,9 +200,9 @@ return VertexArrayIterator(m_BackingStore + attr->offset, m_Stride); } - GLenum m_Usage; - GLenum m_Target; - size_t m_NumVertices; + Renderer::Backend::GL::CBuffer::Type m_Type; + bool m_Dynamic; + size_t m_NumberOfVertices; std::vector m_Attributes; CVertexBufferManager::Handle m_VB; @@ -216,7 +219,7 @@ class VertexIndexArray : public VertexArray { public: - VertexIndexArray(GLenum usage); + VertexIndexArray(const bool dynamic); /// Gets the iterator over the (only) attribute in this array, i.e. a u16. VertexArrayIterator GetIterator() const; Index: ps/trunk/source/renderer/VertexArray.cpp =================================================================== --- ps/trunk/source/renderer/VertexArray.cpp +++ ps/trunk/source/renderer/VertexArray.cpp @@ -30,11 +30,11 @@ #include "renderer/VertexBufferManager.h" -VertexArray::VertexArray(GLenum usage, GLenum target) +VertexArray::VertexArray( + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic) + : m_Type(type), m_Dynamic(dynamic) { - m_Usage = usage; - m_Target = target; - m_NumVertices = 0; + m_NumberOfVertices = 0; m_BackingStore = 0; m_Stride = 0; @@ -55,13 +55,13 @@ } // Set the number of vertices stored in the array -void VertexArray::SetNumVertices(size_t num) +void VertexArray::SetNumberOfVertices(const size_t numberOfVertices) { - if (num == m_NumVertices) + if (numberOfVertices == m_NumberOfVertices) return; Free(); - m_NumVertices = num; + m_NumberOfVertices = numberOfVertices; } // Add vertex attributes like Position, Normal, UV @@ -215,8 +215,6 @@ m_Stride = 0; - //debug_printf("Layouting VertexArray\n"); - for (ssize_t idx = m_Attributes.size()-1; idx >= 0; --idx) { Attribute* attr = m_Attributes[idx]; @@ -250,19 +248,15 @@ m_Stride += attrSize; - if (m_Target == GL_ARRAY_BUFFER) + if (m_Type == Renderer::Backend::GL::CBuffer::Type::VERTEX) m_Stride = Align<4>(m_Stride); - - //debug_printf("%i: offset: %u\n", idx, attr->offset); } - if (m_Target == GL_ARRAY_BUFFER) + if (m_Type == Renderer::Backend::GL::CBuffer::Type::VERTEX) m_Stride = RoundStride(m_Stride); - //debug_printf("Stride: %u\n", m_Stride); - if (m_Stride) - m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumVertices, 16); + m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumberOfVertices, 16); } void VertexArray::PrepareForRendering() @@ -277,7 +271,10 @@ ENSURE(m_BackingStore); if (!m_VB) - m_VB = g_VBMan.AllocateChunk(m_Stride, m_NumVertices, m_Usage, m_Target, m_BackingStore); + { + m_VB = g_VBMan.AllocateChunk( + m_Stride, m_NumberOfVertices, m_Type, m_Dynamic, m_BackingStore); + } if (!m_VB) { @@ -290,12 +287,13 @@ // Bind this array, returns the base address for calls to glVertexPointer etc. -u8* VertexArray::Bind() +u8* VertexArray::Bind( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { if (!m_VB) return NULL; - u8* base = m_VB->m_Owner->Bind(); + u8* base = m_VB->m_Owner->Bind(deviceCommandContext); base += m_VB->m_Index*m_Stride; return base; } @@ -305,16 +303,14 @@ void VertexArray::FreeBackingStore() { // In streaming modes, the backing store must be retained - ENSURE(!CVertexBuffer::UseStreaming(m_Usage)); + ENSURE(!CVertexBuffer::UseStreaming(m_Dynamic)); rtl_FreeAligned(m_BackingStore); m_BackingStore = 0; } - - -VertexIndexArray::VertexIndexArray(GLenum usage) : - VertexArray(usage, GL_ELEMENT_ARRAY_BUFFER) +VertexIndexArray::VertexIndexArray(const bool dynamic) : + VertexArray(Renderer::Backend::GL::CBuffer::Type::INDEX, dynamic) { m_Attr.type = GL_UNSIGNED_SHORT; m_Attr.elems = 1; Index: ps/trunk/source/renderer/VertexBuffer.h =================================================================== --- ps/trunk/source/renderer/VertexBuffer.h +++ ps/trunk/source/renderer/VertexBuffer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,8 +22,10 @@ #ifndef INCLUDED_VERTEXBUFFER #define INCLUDED_VERTEXBUFFER -#include "lib/ogl.h" +#include "renderer/backend/gl/Buffer.h" +#include "renderer/backend/gl/DeviceCommandContext.h" +#include #include /** @@ -87,16 +89,22 @@ public: // constructor, destructor - CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target); - CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target, size_t maximumBufferSize); + CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic); + CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic, + const size_t maximumBufferSize); ~CVertexBuffer(); /// Bind to this buffer; return pointer to address required as parameter /// to glVertexPointer ( + etc) calls - u8* Bind(); + u8* Bind(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); /// Unbind any currently-bound buffer, so glVertexPointer etc calls will not attempt to use it - static void Unbind(); + static void Unbind( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); /// Make the vertex data available for the next call to Bind() void PrepareForRendering(VBChunk* chunk); @@ -109,7 +117,9 @@ size_t GetBytesAllocated() const; /// Returns true if this vertex buffer is compatible with the specified vertex type and intended usage. - bool CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target) const; + bool CompatibleVertexType( + const size_t vertexSize, const Renderer::Backend::GL::CBuffer::Type type, + const bool dynamic) const; void DumpStatus() const; @@ -120,23 +130,23 @@ * so we will re-upload the entire buffer every frame using glMapBuffer. * This requires the buffer's owner to hold onto its backing store. * - * If false, we assume it will change rarely, and use glSubBufferData to + * If false, we assume it will change rarely, and use direct upload to * update it incrementally. The backing store can be freed to save memory. */ - static bool UseStreaming(GLenum usage); + static bool UseStreaming(const bool dynamic); -protected: +private: friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager /// Try to allocate a buffer of given number of vertices (each of given size), /// and with the given type - return null if no free chunks available - VBChunk* Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore); + VBChunk* Allocate( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic, + void* backingStore); /// Return given chunk to this buffer void Release(VBChunk* chunk); - -private: - /// Vertex size of this vertex buffer size_t m_VertexSize; /// Number of vertices of above size in this buffer @@ -147,13 +157,10 @@ std::vector m_AllocList; /// Available free vertices - total of all free vertices in the free list size_t m_FreeVertices; - /// Handle to the actual GL vertex buffer object - GLuint m_Handle; - /// Usage type of the buffer (GL_STATIC_DRAW etc) - GLenum m_Usage; - /// Buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER) - GLenum m_Target; + + std::unique_ptr m_Buffer; + bool m_HasNeededChunks; }; -#endif +#endif // INCLUDED_VERTEXBUFFER Index: ps/trunk/source/renderer/VertexBuffer.cpp =================================================================== --- ps/trunk/source/renderer/VertexBuffer.cpp +++ ps/trunk/source/renderer/VertexBuffer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,11 +21,14 @@ #include "lib/ogl.h" #include "lib/sysdep/cpu.h" -#include "Renderer.h" #include "ps/CLogger.h" #include "ps/Errors.h" +#include "ps/VideoMode.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/Renderer.h" #include +#include #include // Absolute maximum (bytewise) size of each GL vertex buffer object. @@ -34,32 +37,34 @@ // TODO: measure what influence this has on performance constexpr std::size_t MAX_VB_SIZE_BYTES = 4 * 1024 * 1024; -CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target) - : CVertexBuffer(vertexSize, usage, target, MAX_VB_SIZE_BYTES) +CVertexBuffer::CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic) + : CVertexBuffer(name, vertexSize, type, dynamic, MAX_VB_SIZE_BYTES) { } -CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target, size_t maximumBufferSize) - : m_VertexSize(vertexSize), m_Handle(0), m_Usage(usage), m_Target(target), m_HasNeededChunks(false) +CVertexBuffer::CVertexBuffer( + const char* name, const size_t vertexSize, + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic, + const size_t maximumBufferSize) + : m_VertexSize(vertexSize), m_HasNeededChunks(false) { size_t size = maximumBufferSize; - if (target == GL_ARRAY_BUFFER) // vertex data buffer + if (type == Renderer::Backend::GL::CBuffer::Type::VERTEX) { // We want to store 16-bit indices to any vertex in a buffer, so the // buffer must never be bigger than vertexSize*64K bytes since we can // address at most 64K of them with 16-bit indices - size = std::min(size, vertexSize*65536); + size = std::min(size, vertexSize * 65536); } // store max/free vertex counts m_MaxVertices = m_FreeVertices = size / vertexSize; - // allocate raw buffer - glGenBuffersARB(1, &m_Handle); - glBindBufferARB(m_Target, m_Handle); - glBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, 0, m_Usage); - glBindBufferARB(m_Target, 0); + m_Buffer = g_VideoMode.GetBackendDevice()->CreateBuffer( + name, type, m_MaxVertices * m_VertexSize, dynamic); // create sole free chunk VBChunk* chunk = new VBChunk; @@ -74,46 +79,50 @@ // Must have released all chunks before destroying the buffer ENSURE(m_AllocList.empty()); - if (m_Handle) - glDeleteBuffersARB(1, &m_Handle); + m_Buffer.reset(); for (VBChunk* const& chunk : m_FreeList) delete chunk; } - -bool CVertexBuffer::CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target) const +bool CVertexBuffer::CompatibleVertexType( + const size_t vertexSize, const Renderer::Backend::GL::CBuffer::Type type, + const bool dynamic) const { - return usage == m_Usage && target == m_Target && vertexSize == m_VertexSize; + ENSURE(m_Buffer); + return type == m_Buffer->GetType() && dynamic == m_Buffer->IsDynamic() && vertexSize == m_VertexSize; } /////////////////////////////////////////////////////////////////////////////// // Allocate: try to allocate a buffer of given number of vertices (each of // given size), with the given type, and using the given texture - return null // if no free chunks available -CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore) +CVertexBuffer::VBChunk* CVertexBuffer::Allocate( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::GL::CBuffer::Type type, const bool dynamic, + void* backingStore) { // check this is the right kind of buffer - if (!CompatibleVertexType(vertexSize, usage, target)) + if (!CompatibleVertexType(vertexSize, type, dynamic)) return nullptr; - if (UseStreaming(usage)) + if (UseStreaming(dynamic)) ENSURE(backingStore != nullptr); // quick check there's enough vertices spare to allocate - if (numVertices > m_FreeVertices) + if (numberOfVertices > m_FreeVertices) return nullptr; // trawl free list looking for first free chunk with enough space std::vector::iterator best_iter = m_FreeList.end(); for (std::vector::iterator iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) { - if (numVertices == (*iter)->m_Count) + if (numberOfVertices == (*iter)->m_Count) { best_iter = iter; break; } - else if (numVertices < (*iter)->m_Count && (best_iter == m_FreeList.end() || (*best_iter)->m_Count < (*iter)->m_Count)) + else if (numberOfVertices < (*iter)->m_Count && (best_iter == m_FreeList.end() || (*best_iter)->m_Count < (*iter)->m_Count)) best_iter = iter; } @@ -131,17 +140,17 @@ // split chunk into two; - allocate a new chunk using all unused vertices in the // found chunk, and add it to the free list - if (chunk->m_Count > numVertices) + if (chunk->m_Count > numberOfVertices) { VBChunk* newchunk = new VBChunk; newchunk->m_Owner = this; - newchunk->m_Count = chunk->m_Count - numVertices; - newchunk->m_Index = chunk->m_Index + numVertices; + newchunk->m_Count = chunk->m_Count - numberOfVertices; + newchunk->m_Index = chunk->m_Index + numberOfVertices; m_FreeList.emplace_back(newchunk); m_FreeVertices += newchunk->m_Count; // resize given chunk - chunk->m_Count = numVertices; + chunk->m_Count = numberOfVertices; } // return found chunk @@ -195,8 +204,8 @@ // UpdateChunkVertices: update vertex data for given chunk void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk, void* data) { - ENSURE(m_Handle); - if (UseStreaming(m_Usage)) + ENSURE(m_Buffer); + if (UseStreaming(m_Buffer->IsDynamic())) { // The VBO is now out of sync with the backing store chunk->m_Dirty = true; @@ -207,23 +216,24 @@ } else { - glBindBufferARB(m_Target, m_Handle); - glBufferSubDataARB(m_Target, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize, data); - glBindBufferARB(m_Target, 0); + g_Renderer.GetDeviceCommandContext()->UploadBufferRegion( + m_Buffer.get(), data, chunk->m_Index * m_VertexSize, chunk->m_Count * m_VertexSize); } } /////////////////////////////////////////////////////////////////////////////// // Bind: bind to this buffer; return pointer to address required as parameter // to glVertexPointer ( + etc) calls -u8* CVertexBuffer::Bind() +u8* CVertexBuffer::Bind( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { - glBindBufferARB(m_Target, m_Handle); - - if (UseStreaming(m_Usage)) + if (UseStreaming(m_Buffer->IsDynamic())) { if (!m_HasNeededChunks) + { + deviceCommandContext->BindBuffer(m_Buffer->GetType(), m_Buffer.get()); return nullptr; + } // If any chunks are out of sync with the current VBO, and are // needed for rendering this frame, we'll need to re-upload the VBO @@ -239,29 +249,13 @@ if (needUpload) { - // Tell the driver that it can reallocate the whole VBO - glBufferDataARB(m_Target, m_MaxVertices * m_VertexSize, NULL, m_Usage); - - // (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used - // here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with - // current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do - // the explicit glBufferData.) - - while (true) + deviceCommandContext->UploadBuffer(m_Buffer.get(), [&](u8* mappedData) { - void* p = glMapBufferARB(m_Target, GL_WRITE_ONLY); - if (p == NULL) - { - // This shouldn't happen unless we run out of virtual address space - LOGERROR("glMapBuffer failed"); - break; - } - #ifndef NDEBUG // To help detect bugs where PrepareForRendering() was not called, // force all not-needed data to 0, so things won't get rendered // with undefined (but possibly still correct-looking) data. - memset(p, 0, m_MaxVertices * m_VertexSize); + memset(mappedData, 0, m_MaxVertices * m_VertexSize); #endif // Copy only the chunks we need. (This condition is helpful when @@ -270,15 +264,8 @@ // the rest.) for (VBChunk* const& chunk : m_AllocList) if (chunk->m_Needed) - memcpy((u8 *)p + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize); - - if (glUnmapBufferARB(m_Target) == GL_TRUE) - break; - - // Unmap might fail on e.g. resolution switches, so just try again - // and hope it will eventually succeed - debug_printf("glUnmapBuffer failed, trying again...\n"); - } + std::memcpy(mappedData + chunk->m_Index * m_VertexSize, chunk->m_BackingStore, chunk->m_Count * m_VertexSize); + }); // Anything we just uploaded is clean; anything else is dirty // since the rest of the VBO content is now undefined @@ -302,14 +289,18 @@ m_HasNeededChunks = false; } + deviceCommandContext->BindBuffer(m_Buffer->GetType(), m_Buffer.get()); return nullptr; } -void CVertexBuffer::Unbind() +void CVertexBuffer::Unbind( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { - glBindBufferARB(GL_ARRAY_BUFFER, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); + deviceCommandContext->BindBuffer( + Renderer::Backend::GL::CBuffer::Type::VERTEX, nullptr); + deviceCommandContext->BindBuffer( + Renderer::Backend::GL::CBuffer::Type::INDEX, nullptr); } size_t CVertexBuffer::GetBytesReserved() const @@ -335,9 +326,9 @@ debug_printf("max size = %d\n", static_cast(maxSize)); } -bool CVertexBuffer::UseStreaming(GLenum usage) +bool CVertexBuffer::UseStreaming(const bool dynamic) { - return usage == GL_DYNAMIC_DRAW || usage == GL_STREAM_DRAW; + return dynamic; } void CVertexBuffer::PrepareForRendering(VBChunk* chunk) Index: ps/trunk/source/renderer/VertexBufferManager.h =================================================================== --- ps/trunk/source/renderer/VertexBufferManager.h +++ ps/trunk/source/renderer/VertexBufferManager.h @@ -88,7 +88,10 @@ * lifetime of the VBChunk * @return chunk, or empty handle if no free chunks available */ - Handle AllocateChunk(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore = nullptr, Group group = Group::DEFAULT); + Handle AllocateChunk( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::GL::CBuffer::Type type, + const bool dynamic, void* backingStore = nullptr, Group group = Group::DEFAULT); /// Returns the given @p chunk to its owning buffer void Release(CVertexBuffer::VBChunk* chunk); Index: ps/trunk/source/renderer/VertexBufferManager.cpp =================================================================== --- ps/trunk/source/renderer/VertexBufferManager.cpp +++ ps/trunk/source/renderer/VertexBufferManager.cpp @@ -74,15 +74,14 @@ * given size), with the given type, and using the given texture - return null * if no free chunks available */ -CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk(size_t vertexSize, size_t numVertices, GLenum usage, GLenum target, void* backingStore, Group group) +CVertexBufferManager::Handle CVertexBufferManager::AllocateChunk( + const size_t vertexSize, const size_t numberOfVertices, + const Renderer::Backend::GL::CBuffer::Type type, + const bool dynamic, void* backingStore, Group group) { CVertexBuffer::VBChunk* result = nullptr; - ENSURE(usage == GL_STREAM_DRAW || usage == GL_STATIC_DRAW || usage == GL_DYNAMIC_DRAW); - - ENSURE(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER); - - if (CVertexBuffer::UseStreaming(usage)) + if (CVertexBuffer::UseStreaming(dynamic)) ENSURE(backingStore != NULL); // TODO, RC - run some sanity checks on allocation request @@ -93,7 +92,7 @@ debug_printf("\n============================\n# allocate vsize=%zu nverts=%zu\n\n", vertexSize, numVertices); for (const std::unique_ptr& buffer : buffers) { - if (buffer->CompatibleVertexType(vertexSize, usage, target)) + if (buffer->CompatibleVertexType(vertexSize, type, dynamic)) { debug_printf("%p\n", buffer.get()); buffer->DumpStatus(); @@ -105,7 +104,7 @@ // satisfy the allocation for (const std::unique_ptr& buffer : buffers) { - result = buffer->Allocate(vertexSize, numVertices, usage, target, backingStore); + result = buffer->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore); if (result) return Handle(result); } @@ -113,14 +112,14 @@ // got this far; need to allocate a new buffer buffers.emplace_back( group == Group::DEFAULT - ? std::make_unique(vertexSize, usage, target) + ? std::make_unique("VertexBuffer (Default)", vertexSize, type, dynamic) // Reduces the buffer size for not so frequent buffers. - : std::make_unique(vertexSize, usage, target, 1024 * 1024)); - result = buffers.back()->Allocate(vertexSize, numVertices, usage, target, backingStore); + : std::make_unique("VertexBuffer", vertexSize, type, dynamic, 1024 * 1024)); + result = buffers.back()->Allocate(vertexSize, numberOfVertices, type, dynamic, backingStore); if (!result) { - LOGERROR("Failed to create VBOs (%zu*%zu)", vertexSize, numVertices); + LOGERROR("Failed to create VBOs (%zu*%zu)", vertexSize, numberOfVertices); return Handle(); } Index: ps/trunk/source/renderer/WaterManager.cpp =================================================================== --- ps/trunk/source/renderer/WaterManager.cpp +++ ps/trunk/source/renderer/WaterManager.cpp @@ -532,7 +532,7 @@ // Generic indexes, max-length m_ShoreWavesVBIndices = g_VBMan.AllocateChunk( sizeof(GLushort), water_indices.size(), - GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER, + Renderer::Backend::GL::CBuffer::Type::INDEX, false, nullptr, CVertexBufferManager::Group::WATER); m_ShoreWavesVBIndices->m_Owner->UpdateChunkVertices(m_ShoreWavesVBIndices.Get(), &water_indices[0]); @@ -753,7 +753,7 @@ shoreWave->m_VBVertices = g_VBMan.AllocateChunk( sizeof(SWavesVertex), vertices.size(), - GL_STATIC_DRAW, GL_ARRAY_BUFFER, + Renderer::Backend::GL::CBuffer::Type::VERTEX, false, nullptr, CVertexBufferManager::Group::WATER); shoreWave->m_VBVertices->m_Owner->UpdateChunkVertices(shoreWave->m_VBVertices.Get(), &vertices[0]); @@ -798,7 +798,7 @@ continue; CVertexBuffer::VBChunk* VBchunk = m_ShoreWaves[a]->m_VBVertices.Get(); - SWavesVertex* base = (SWavesVertex*)VBchunk->m_Owner->Bind(); + SWavesVertex* base = (SWavesVertex*)VBchunk->m_Owner->Bind(deviceCommandContext); // setup data pointers GLsizei stride = sizeof(SWavesVertex); @@ -815,7 +815,7 @@ shader->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff); shader->Uniform(str_width, (int)m_ShoreWaves[a]->m_Width); - u8* indexBase = m_ShoreWavesVBIndices->m_Owner->Bind(); + u8* indexBase = m_ShoreWavesVBIndices->m_Owner->Bind(deviceCommandContext); glDrawElements(GL_TRIANGLES, (GLsizei) (m_ShoreWaves[a]->m_Width-1)*(7*6), GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_ShoreWavesVBIndices->m_Index)); @@ -825,7 +825,7 @@ //g_Renderer.m_Stats.m_DrawCalls++; //g_Renderer.m_Stats.m_WaterTris += m_ShoreWaves_VBIndices->m_Count / 3; - CVertexBuffer::Unbind(); + CVertexBuffer::Unbind(deviceCommandContext); } tech->EndPass(); deviceCommandContext->SetFramebuffer( Index: ps/trunk/source/renderer/backend/gl/Buffer.h =================================================================== --- ps/trunk/source/renderer/backend/gl/Buffer.h +++ ps/trunk/source/renderer/backend/gl/Buffer.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_BUFFER +#define INCLUDED_RENDERER_BACKEND_GL_BUFFER + +#include "lib/ogl.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; + +class CBuffer +{ +public: + enum class Type + { + VERTEX, + INDEX + }; + + ~CBuffer(); + + Type GetType() const { return m_Type; } + uint32_t GetSize() const { return m_Size; } + bool IsDynamic() const { return m_Dynamic; } + + GLuint GetHandle() { return m_Handle; } + +private: + friend class CDevice; + + static std::unique_ptr Create( + CDevice* device, const char* name, + const Type type, const uint32_t size, const bool dynamic); + + CBuffer(); + + CDevice* m_Device = nullptr; + Type m_Type = Type::VERTEX; + uint32_t m_Size = 0; + bool m_Dynamic = false; + GLuint m_Handle = 0; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_BUFFER Index: ps/trunk/source/renderer/backend/gl/Buffer.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Buffer.cpp +++ ps/trunk/source/renderer/backend/gl/Buffer.cpp @@ -0,0 +1,73 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Buffer.h" + +#include "lib/code_annotation.h" +#include "lib/config2.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/Texture.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +// static +std::unique_ptr CBuffer::Create( + CDevice* device, const char* name, + const Type type, const uint32_t size, const bool dynamic) +{ + std::unique_ptr buffer(new CBuffer()); + buffer->m_Device = device; + buffer->m_Type = type; + buffer->m_Size = size; + buffer->m_Dynamic = dynamic; + glGenBuffersARB(1, &buffer->m_Handle); + const GLenum target = type == Type::INDEX ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER; + glBindBufferARB(target, buffer->m_Handle); + glBufferDataARB(target, size, nullptr, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +#if KHR_DEBUG_ENABLED && !CONFIG2_GLES + glObjectLabel(GL_BUFFER, buffer->m_Handle, -1, name); +#else + UNUSED2(name); +#endif + glBindBufferARB(target, 0); + return buffer; +} + +CBuffer::CBuffer() = default; + +CBuffer::~CBuffer() +{ + if (m_Handle) + glDeleteBuffersARB(1, &m_Handle); +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer Index: ps/trunk/source/renderer/backend/gl/Device.h =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.h +++ ps/trunk/source/renderer/backend/gl/Device.h @@ -19,7 +19,9 @@ #define INCLUDED_RENDERER_BACKEND_GL_DEVICE #include "renderer/backend/Format.h" +#include "renderer/backend/gl/Buffer.h" #include "renderer/backend/gl/Framebuffer.h" +#include "renderer/backend/gl/Texture.h" #include "scriptinterface/ScriptForward.h" #include @@ -39,7 +41,6 @@ { class CDeviceCommandContext; -class CTexture; class CDevice { @@ -83,6 +84,9 @@ const Format format, const uint32_t width, const uint32_t height, const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1); + std::unique_ptr CreateBuffer( + const char* name, const CBuffer::Type type, const uint32_t size, const bool dynamic); + void Present(); bool IsFormatSupported(const Format format) const; Index: ps/trunk/source/renderer/backend/gl/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.cpp +++ ps/trunk/source/renderer/backend/gl/Device.cpp @@ -213,6 +213,10 @@ // and irrelevant (was never widespread). capabilities.S3TC = ogl_HaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", nullptr) == 0; #endif +#if CONFIG2_GLES + capabilities.multisampling = false; + capabilities.maxSampleCount = 1; +#else capabilities.multisampling = ogl_HaveVersion(3, 3) && ogl_HaveExtension("GL_ARB_multisample") && @@ -223,6 +227,7 @@ glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); capabilities.maxSampleCount = maxSamples; } +#endif capabilities.anisotropicFiltering = ogl_HaveExtension("GL_EXT_texture_filter_anisotropic"); if (capabilities.anisotropicFiltering) { @@ -652,6 +657,12 @@ format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount); } +std::unique_ptr CDevice::CreateBuffer( + const char* name, const CBuffer::Type type, const uint32_t size, const bool dynamic) +{ + return CBuffer::Create(this, name, type, size, dynamic); +} + void CDevice::Present() { if (m_Window) Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h @@ -20,10 +20,12 @@ #include "lib/ogl.h" #include "renderer/backend/Format.h" +#include "renderer/backend/gl/Buffer.h" #include "renderer/backend/PipelineState.h" #include #include +#include #include #include #include @@ -65,6 +67,15 @@ const uint32_t width, const uint32_t height, const uint32_t level = 0, const uint32_t layer = 0); + using UploadBufferFunction = std::function; + void UploadBuffer(CBuffer* buffer, const void* data, const uint32_t dataSize); + void UploadBuffer(CBuffer* buffer, const UploadBufferFunction& uploadFunction); + void UploadBufferRegion( + CBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize); + void UploadBufferRegion( + CBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize, + const UploadBufferFunction& uploadFunction); + // TODO: maybe we should add a more common type, like CRectI. struct ScissorRect { @@ -75,6 +86,7 @@ // TODO: remove direct binding after moving shaders. void BindTexture(const uint32_t unit, const GLenum target, const GLuint handle); + void BindBuffer(const CBuffer::Type type, CBuffer* buffer); void Flush(); Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -19,12 +19,15 @@ #include "DeviceCommandContext.h" +#include "ps/CLogger.h" +#include "renderer/backend/gl/Buffer.h" #include "renderer/backend/gl/Device.h" #include "renderer/backend/gl/Framebuffer.h" #include "renderer/backend/gl/Mapping.h" #include "renderer/backend/gl/Texture.h" #include +#include #include namespace Renderer @@ -87,6 +90,47 @@ glStencilMask(stencilWriteMask); } +GLenum BufferTypeToGLTarget(const CBuffer::Type type) +{ + GLenum target = GL_ARRAY_BUFFER; + switch (type) + { + case CBuffer::Type::VERTEX: + target = GL_ARRAY_BUFFER; + break; + case CBuffer::Type::INDEX: + target = GL_ELEMENT_ARRAY_BUFFER; + break; + }; + return target; +} + +void UploadBufferRegionImpl( + const GLenum target, const uint32_t dataOffset, const uint32_t dataSize, + const CDeviceCommandContext::UploadBufferFunction& uploadFunction) +{ + ENSURE(dataOffset < dataSize); + while (true) + { + void* mappedData = glMapBufferARB(target, GL_WRITE_ONLY); + if (mappedData == nullptr) + { + // This shouldn't happen unless we run out of virtual address space + LOGERROR("glMapBuffer failed"); + break; + } + + uploadFunction(static_cast(mappedData) + dataOffset); + + if (glUnmapBufferARB(target) == GL_TRUE) + break; + + // Unmap might fail on e.g. resolution switches, so just try again + // and hope it will eventually succeed + LOGMESSAGE("glUnmapBuffer failed, trying again...\n"); + } +} + } // anonymous namespace // static @@ -240,6 +284,58 @@ debug_warn("Unsupported type"); } +void CDeviceCommandContext::UploadBuffer(CBuffer* buffer, const void* data, const uint32_t dataSize) +{ + UploadBufferRegion(buffer, data, dataSize, 0); +} + +void CDeviceCommandContext::UploadBuffer( + CBuffer* buffer, const UploadBufferFunction& uploadFunction) +{ + UploadBufferRegion(buffer, 0, buffer->GetSize(), uploadFunction); +} + +void CDeviceCommandContext::UploadBufferRegion( + CBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize) +{ + ENSURE(data); + ENSURE(dataOffset + dataSize <= buffer->GetSize()); + const GLenum target = BufferTypeToGLTarget(buffer->GetType()); + glBindBufferARB(target, buffer->GetHandle()); + if (buffer->IsDynamic()) + { + // Tell the driver that it can reallocate the whole VBO + glBufferDataARB(target, buffer->GetSize(), nullptr, buffer->IsDynamic() ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + + // (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used + // here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with + // current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do + // the explicit glBufferData.) + + UploadBufferRegion(buffer, dataOffset, dataSize, [data, dataOffset, dataSize](u8* mappedData) + { + std::memcpy(mappedData, data, dataSize); + }); + } + else + { + glBufferSubDataARB(target, dataOffset, dataSize, data); + } + glBindBufferARB(target, 0); +} + +void CDeviceCommandContext::UploadBufferRegion( + CBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize, + const UploadBufferFunction& uploadFunction) +{ + ENSURE(dataOffset + dataSize <= buffer->GetSize()); + const GLenum target = BufferTypeToGLTarget(buffer->GetType()); + glBindBufferARB(target, buffer->GetHandle()); + ENSURE(buffer->IsDynamic()); + UploadBufferRegionImpl(target, dataOffset, dataSize, uploadFunction); + glBindBufferARB(target, 0); +} + void CDeviceCommandContext::BindTexture(const uint32_t unit, const GLenum target, const GLuint handle) { ENSURE(unit < m_BoundTextures.size()); @@ -262,6 +358,12 @@ m_BoundTextures[unit] = {target, handle}; } +void CDeviceCommandContext::BindBuffer(const CBuffer::Type type, CBuffer* buffer) +{ + ENSURE(!buffer || type == buffer->GetType()); + glBindBufferARB(BufferTypeToGLTarget(type), buffer ? buffer->GetHandle() : 0); +} + void CDeviceCommandContext::Flush() { ResetStates();