Index: binaries/data/mods/public/gui/credits/texts/programming.json =================================================================== --- binaries/data/mods/public/gui/credits/texts/programming.json +++ 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: source/renderer/VertexBuffer.h =================================================================== --- source/renderer/VertexBuffer.h +++ 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,7 @@ #include "lib/res/graphics/ogl_tex.h" -#include +#include #include /** @@ -102,7 +102,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 +145,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::deque m_FreeList; /// List of allocated chunks - std::list m_AllocList; + std::deque 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 +158,7 @@ GLenum m_Usage; /// Buffer target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER) GLenum m_Target; + bool m_HasNeededChunks; }; #endif Index: source/renderer/VertexBuffer.cpp =================================================================== --- source/renderer/VertexBuffer.cpp +++ 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 @@ -20,13 +20,18 @@ */ #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 "VertexBufferManager.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 +40,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; @@ -79,20 +84,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 +114,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::deque::iterator best_iter = m_FreeList.end(); + for (std::deque::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; @@ -162,32 +165,22 @@ // Update total free count before potentially modifying this chunk's count m_FreeVertices += chunk->m_Count; - m_AllocList.remove(chunk); - - typedef std::list::iterator Iter; + m_AllocList.erase(std::find(m_AllocList.begin(), m_AllocList.end(), chunk)); // 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 - // from the list, and repeat until no more are found - bool coalesced; - do + // from the list + for (std::deque::iterator iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) { - coalesced = false; - for (Iter iter = m_FreeList.begin(); iter != m_FreeList.end(); ++iter) + if ((*iter)->m_Index == chunk->m_Index + chunk->m_Count + || (*iter)->m_Index + (*iter)->m_Count == chunk->m_Index) { - if ((*iter)->m_Index == chunk->m_Index + chunk->m_Count - || (*iter)->m_Index + (*iter)->m_Count == chunk->m_Index) - { - chunk->m_Index = std::min(chunk->m_Index, (*iter)->m_Index); - chunk->m_Count += (*iter)->m_Count; - delete *iter; - m_FreeList.erase(iter); - coalesced = true; - break; - } + chunk->m_Index = std::min(chunk->m_Index, (*iter)->m_Index); + chunk->m_Count += (*iter)->m_Count; + delete *iter; + iter = std::prev(m_FreeList.erase(iter)); } } - while (coalesced); m_FreeList.push_front(chunk); } @@ -234,6 +227,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 +290,20 @@ 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 +338,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; +}