Skip to content

Commit

Permalink
Re-implement Rml::Core::ReleaseCompiledGeometries(). See #84.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikke89 committed Mar 4, 2020
1 parent 6d2f8d1 commit 97682a2
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 17 deletions.
2 changes: 2 additions & 0 deletions CMake/FileList.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ set(Core_HDR_FILES
${PROJECT_SOURCE_DIR}/Source/Core/FontEffectGlow.h
${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.h
${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.h
${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.h
${PROJECT_SOURCE_DIR}/Source/Core/IdNameMap.h
${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.h
${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.h
Expand Down Expand Up @@ -238,6 +239,7 @@ set(Core_SRC_FILES
${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.cpp
${PROJECT_SOURCE_DIR}/Source/Core/FontEngineInterface.cpp
${PROJECT_SOURCE_DIR}/Source/Core/Geometry.cpp
${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.cpp
${PROJECT_SOURCE_DIR}/Source/Core/GeometryUtilities.cpp
${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.cpp
${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.cpp
Expand Down
2 changes: 2 additions & 0 deletions Include/RmlUi/Core/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ RMLUICORE_API EventId RegisterEventType(const String& type, bool interruptible,

/// Forces all texture handles loaded and generated by RmlUi to be released.
RMLUICORE_API void ReleaseTextures();
/// Forces all compiled geometry handles generated by RmlUi to be released.
RMLUICORE_API void ReleaseCompiledGeometry();

}
}
Expand Down
24 changes: 19 additions & 5 deletions Include/RmlUi/Core/Geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "Header.h"
#include "Vertex.h"
#include <stdint.h>

namespace Rml {
namespace Core {
Expand All @@ -39,6 +40,7 @@ class Context;
class Element;
class RenderInterface;
struct Texture;
using GeometryDatabaseHandle = uint32_t;

/**
A helper object for holding an array of vertices and indices, and compiling it as necessary when rendered.
Expand All @@ -51,6 +53,13 @@ class RMLUICORE_API Geometry
public:
Geometry(Element* host_element = nullptr);
Geometry(Context* host_context);

Geometry(const Geometry&) = delete;
Geometry& operator=(const Geometry&) = delete;

Geometry(Geometry&& other);
Geometry& operator=(Geometry&& other);

~Geometry();

/// Set the host element for this geometry; this should be passed in the constructor if possible.
Expand Down Expand Up @@ -79,18 +88,23 @@ class RMLUICORE_API Geometry
void Release(bool clear_buffers = false);

private:
// Move members from another geometry.
void MoveFrom(Geometry& other);

// Returns the host context's render interface.
RenderInterface* GetRenderInterface();

Context* host_context;
Element* host_element;
Context* host_context = nullptr;
Element* host_element = nullptr;

std::vector< Vertex > vertices;
std::vector< int > indices;
const Texture* texture;
const Texture* texture = nullptr;

CompiledGeometryHandle compiled_geometry = 0;
bool compile_attempted = false;

CompiledGeometryHandle compiled_geometry;
bool compile_attempted;
GeometryDatabaseHandle database_handle;
};

using GeometryList = std::vector< Geometry >;
Expand Down
7 changes: 6 additions & 1 deletion Source/Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

#include "EventSpecification.h"
#include "FileInterfaceDefault.h"
#include "GeometryDatabase.h"
#include "PluginRegistry.h"
#include "StyleSheetFactory.h"
#include "TemplateCache.h"
Expand Down Expand Up @@ -322,11 +323,15 @@ EventId RegisterEventType(const String& type, bool interruptible, bool bubbles,
return EventSpecificationInterface::InsertOrReplaceCustom(type, interruptible, bubbles, default_action_phase);
}

// Forces all texture handles loaded and generated by RmlUi to be released.
void ReleaseTextures()
{
TextureDatabase::ReleaseTextures();
}

void ReleaseCompiledGeometry()
{
return GeometryDatabase::ReleaseAll();
}

}
}
42 changes: 31 additions & 11 deletions Source/Core/Geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,54 @@
#include "../../Include/RmlUi/Core/Element.h"
#include "../../Include/RmlUi/Core/Profiling.h"
#include "../../Include/RmlUi/Core/RenderInterface.h"
#include "GeometryDatabase.h"
#include <utility>


namespace Rml {
namespace Core {

Geometry::Geometry(Element* _host_element)
{
host_element = _host_element;
host_context = nullptr;
database_handle = GeometryDatabase::Insert(this);
}

texture = nullptr;
Geometry::Geometry(Context* _host_context)
{
database_handle = GeometryDatabase::Insert(this);
}

compile_attempted = false;
compiled_geometry = 0;
Geometry::Geometry(Geometry&& other)
{
MoveFrom(other);
database_handle = GeometryDatabase::Insert(this);
}

Geometry::Geometry(Context* _host_context)
Geometry& Geometry::operator=(Geometry&& other)
{
host_element = nullptr;
host_context = _host_context;
MoveFrom(other);
// Keep the database handles from construction unchanged, they are tied to the *this* pointer and should not change.
return *this;
}

texture = nullptr;
void Geometry::MoveFrom(Geometry& other)
{
host_context = std::exchange(other.host_context, nullptr);
host_element = std::exchange(other.host_element, nullptr);

compile_attempted = false;
compiled_geometry = 0;
vertices = std::move(other.vertices);
indices = std::move(other.indices);

texture = std::exchange(other.texture, nullptr);

compiled_geometry = std::exchange(other.compiled_geometry, 0);
compile_attempted = std::exchange(other.compile_attempted, false);
}

Geometry::~Geometry()
{
GeometryDatabase::Erase(database_handle);

Release();
}

Expand Down
184 changes: 184 additions & 0 deletions Source/Core/GeometryDatabase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* This source file is part of RmlUi, the HTML/CSS Interface Middleware
*
* For the latest information, see http://github.com/mikke89/RmlUi
*
* Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
* Copyright (c) 2019 The RmlUi Team, and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

#include "GeometryDatabase.h"
#include "../../Include/RmlUi/Core/Geometry.h"
#include <algorithm>

namespace Rml {
namespace Core {
namespace GeometryDatabase {

class Database {
public:
Database() {
constexpr size_t reserve_size = 512;
geometry_list.reserve(reserve_size);
free_list.reserve(reserve_size);
}

~Database() {
#ifdef RMLUI_TESTS_ENABLED
RMLUI_ASSERT(geometry_list.size() == free_list.size());
std::sort(free_list.begin(), free_list.end());
for (size_t i = 0; i < free_list.size(); i++)
{
RMLUI_ASSERT(i == free_list[i]);
}
#endif
}

GeometryDatabaseHandle insert(Geometry* value)
{
GeometryDatabaseHandle handle;
if (free_list.empty())
{
handle = GeometryDatabaseHandle(geometry_list.size());
geometry_list.push_back(value);
}
else
{
handle = free_list.back();
free_list.pop_back();
geometry_list[handle] = value;
}
return handle;
}

void erase(GeometryDatabaseHandle handle)
{
free_list.push_back(handle);
}

// Iterate over every item in the database, skipping free slots.
template<typename Func>
void for_each(Func func)
{
std::sort(free_list.begin(), free_list.end());

size_t i_begin_next = 0;
for (GeometryDatabaseHandle freelist_entry : free_list)
{
const size_t i_end = size_t(freelist_entry);
const size_t i_begin = i_begin_next;
i_begin_next = i_end + 1;

for (size_t i = i_begin; i < i_end; i++)
func(geometry_list[i]);
}

for (size_t i = i_begin_next; i < geometry_list.size(); i++)
func(geometry_list[i]);
}

private:
// List of all active geometry, in addition to free slots.
// Free slots (as defined by the 'free_list') may contain dangling pointers and must not be dereferenced.
std::vector<Geometry*> geometry_list;
// Declares free slots in the 'geometry_list' as indices.
std::vector<GeometryDatabaseHandle> free_list;
};


static Database geometry_database;

GeometryDatabaseHandle Insert(Geometry* geometry)
{
return geometry_database.insert(geometry);
}

void Erase(GeometryDatabaseHandle handle)
{
geometry_database.erase(handle);
}

void ReleaseAll()
{
geometry_database.for_each([](Geometry* geometry) {
geometry->Release();
});
}



#ifdef RMLUI_TESTS_ENABLED

static class TestGeometryDatabase {
private:
std::vector<Geometry> geometry_list;

bool list_database_equivalent()
{
int i = 0;
bool result = true;
GetDatabase().for_each([this, &i, &result](Geometry* geometry) {
result &= (geometry == &geometry_list[i++]);
});
return result;
}

public:
TestGeometryDatabase() : geometry_list(10)
{
bool result = true;

int i = 0;
for (auto& geometry : geometry_list)
geometry.GetIndices().push_back(i++);

result &= list_database_equivalent();

geometry_list.reserve(2000);
result &= list_database_equivalent();

geometry_list.erase(geometry_list.begin() + 5);
result &= list_database_equivalent();

std::swap(geometry_list.front(), geometry_list.back());
geometry_list.pop_back();
result &= list_database_equivalent();

std::swap(geometry_list.front(), geometry_list.back());
result &= list_database_equivalent();

geometry_list.emplace_back();
result &= list_database_equivalent();

geometry_list.clear();
result &= list_database_equivalent();

RMLUI_ASSERT(result);
}

} test_geometry_database;

#endif

}
}
}
Loading

0 comments on commit 97682a2

Please sign in to comment.