Index: ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json =================================================================== --- ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json +++ ps/trunk/binaries/data/mods/public/gui/credits/texts/programming.json @@ -66,6 +66,7 @@ { "name": "Daniel Trevitz" }, { "nick": "Dariost", "name": "Dario Ostuni" }, { "nick": "Dave", "name": "David Protasowski" }, + { "name": "David Marshall" }, { "nick": "dax", "name": "Dacian Fiordean" }, { "nick": "deebee", "name": "Deepak Anthony" }, { "nick": "Deiz" }, 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) 2015 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,7 +24,6 @@ #include "lib/res/graphics/ogl_tex.h" -#include #include /** @@ -102,7 +101,7 @@ static void Unbind(); /// Make the vertex data available for the next call to Bind() - void PrepareForRendering(VBChunk* chunk) { chunk->m_Needed = true; } + void PrepareForRendering(VBChunk* chunk); /// Update vertex data for given chunk. Transfers the provided data to the actual OpenGL vertex buffer. void UpdateChunkVertices(VBChunk* chunk, void* data); @@ -145,9 +144,9 @@ /// Number of vertices of above size in this buffer size_t m_MaxVertices; /// List of free chunks in this buffer - std::list m_FreeList; + std::vector m_FreeList; /// List of allocated chunks - std::list m_AllocList; + 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 @@ -158,6 +157,7 @@ GLenum m_Usage; /// Buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER) GLenum m_Target; + bool m_HasNeededChunks; }; #endif 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) 2016 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,18 +15,18 @@ * along with 0 A.D. If not, see . */ -/* - * encapsulation of VBOs with sharing - */ - #include "precompiled.h" -#include "ps/Errors.h" + +#include "VertexBuffer.h" + #include "lib/ogl.h" #include "lib/sysdep/cpu.h" #include "Renderer.h" -#include "VertexBuffer.h" -#include "VertexBufferManager.h" #include "ps/CLogger.h" +#include "ps/Errors.h" + +#include +#include // Absolute maximum (bytewise) size of each GL vertex buffer object. // Make it large enough for the maximum feasible mesh size (64K vertexes, @@ -35,7 +35,7 @@ #define MAX_VB_SIZE_BYTES (4*1024*1024) CVertexBuffer::CVertexBuffer(size_t vertexSize, GLenum usage, GLenum target) - : m_VertexSize(vertexSize), m_Handle(0), m_SysMem(0), m_Usage(usage), m_Target(target) + : m_VertexSize(vertexSize), m_Handle(0), m_SysMem(0), m_Usage(usage), m_Target(target), m_HasNeededChunks(false) { size_t size = MAX_VB_SIZE_BYTES; @@ -68,7 +68,7 @@ chunk->m_Owner = this; chunk->m_Count = m_FreeVertices; chunk->m_Index = 0; - m_FreeList.push_front(chunk); + m_FreeList.emplace_back(chunk); } CVertexBuffer::~CVertexBuffer() @@ -79,20 +79,16 @@ if (m_Handle) pglDeleteBuffersARB(1, &m_Handle); - delete[] m_SysMem; + SAFE_ARRAY_DELETE(m_SysMem); - typedef std::list::iterator Iter; - for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) - delete *iter; + for (VBChunk* const& chunk : m_FreeList) + delete chunk; } bool CVertexBuffer::CompatibleVertexType(size_t vertexSize, GLenum usage, GLenum target) { - if (usage != m_Usage || target != m_Target || vertexSize != m_VertexSize) - return false; - - return true; + return usage == m_Usage && target == m_Target && vertexSize == m_VertexSize; } /////////////////////////////////////////////////////////////////////////////// @@ -113,23 +109,25 @@ return 0; // trawl free list looking for first free chunk with enough space - VBChunk* chunk = 0; - typedef std::list::iterator Iter; - for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) { - if (numVertices <= (*iter)->m_Count) { - chunk = *iter; - // remove this chunk from the free list - m_FreeList.erase(iter); - m_FreeVertices -= chunk->m_Count; - // no need to search further .. + 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) + { + best_iter = iter; break; } + else if (numVertices < (*iter)->m_Count && (best_iter == m_FreeList.end() || (*best_iter)->m_Count < (*iter)->m_Count)) + best_iter = iter; } - if (!chunk) { - // no big enough spare chunk available - return 0; - } + // We could not find a large enough chunk. + if (best_iter == m_FreeList.end()) + return nullptr; + + VBChunk* chunk = *best_iter; + m_FreeList.erase(best_iter); + m_FreeVertices -= chunk->m_Count; chunk->m_BackingStore = backingStore; chunk->m_Dirty = false; @@ -143,7 +141,7 @@ newchunk->m_Owner = this; newchunk->m_Count = chunk->m_Count - numVertices; newchunk->m_Index = chunk->m_Index + numVertices; - m_FreeList.push_front(newchunk); + m_FreeList.emplace_back(newchunk); m_FreeVertices += newchunk->m_Count; // resize given chunk @@ -162,9 +160,9 @@ // Update total free count before potentially modifying this chunk's count m_FreeVertices += chunk->m_Count; - m_AllocList.remove(chunk); + m_AllocList.erase(std::find(m_AllocList.begin(), m_AllocList.end(), chunk)); - typedef std::list::iterator Iter; + typedef std::vector::iterator Iter; // Coalesce with any free-list items that are adjacent to this chunk; // merge the found chunk with the new one, and remove the old one @@ -189,7 +187,7 @@ } while (coalesced); - m_FreeList.push_front(chunk); + m_FreeList.emplace_back(chunk); } /////////////////////////////////////////////////////////////////////////////// @@ -234,6 +232,9 @@ if (UseStreaming(m_Usage)) { + if (!m_HasNeededChunks) + 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 bool needUpload = false; @@ -294,15 +295,22 @@ for (VBChunk* const& chunk : m_AllocList) { if (chunk->m_Needed) + { chunk->m_Dirty = false; + chunk->m_Needed = false; + } else chunk->m_Dirty = true; } } + else + { + // Reset the flags for the next phase. + for (VBChunk* const& chunk : m_AllocList) + chunk->m_Needed = false; + } - // Reset the flags for the next phase - for (VBChunk* const& chunk : m_AllocList) - chunk->m_Needed = false; + m_HasNeededChunks = false; } return (u8*)0; @@ -337,19 +345,24 @@ void CVertexBuffer::DumpStatus() { - debug_printf("freeverts = %d\n", (int)m_FreeVertices); + debug_printf("freeverts = %d\n", static_cast(m_FreeVertices)); size_t maxSize = 0; - typedef std::list::iterator Iter; - for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) + for (VBChunk* const& chunk : m_FreeList) { - debug_printf("free chunk %p: size=%d\n", (void *)*iter, (int)((*iter)->m_Count)); - maxSize = std::max((*iter)->m_Count, maxSize); + debug_printf("free chunk %p: size=%d\n", static_cast(chunk), static_cast(chunk->m_Count)); + maxSize = std::max(chunk->m_Count, maxSize); } - debug_printf("max size = %d\n", (int)maxSize); + debug_printf("max size = %d\n", static_cast(maxSize)); } bool CVertexBuffer::UseStreaming(GLenum usage) { return (usage == GL_DYNAMIC_DRAW || usage == GL_STREAM_DRAW); } + +void CVertexBuffer::PrepareForRendering(VBChunk* chunk) +{ + chunk->m_Needed = true; + m_HasNeededChunks = true; +}