Skip to content

Commit

Permalink
added frame data caching to speed up container drawing in large trees
Browse files Browse the repository at this point in the history
  • Loading branch information
oculometric committed Mar 14, 2024
1 parent 3673221 commit d7aa34c
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 9 deletions.
14 changes: 14 additions & 0 deletions src/gui_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ bool nov_gui_manager::draw_specific(nov_container* container)
// return if this container is invalid
if (container == 0x0) return false;

// first, check if this container has been cached. if it has, then use the cached data, otherwise
// calculate it from scratch
for (nov_frame_cache fc : frame_cache)
{
if (fc.container == container)
{
draw_container(container, fc.frame_data);
return true;
}
}

com_1 << "when drawing frame " << stream::mode::HEX << (uint32_t)container << " found no cached data." << stream::endl;

// return if this container has no parent and is not the root container
if (container->parent == 0x0 && container != root_container) return false;

Expand Down Expand Up @@ -150,6 +163,7 @@ bool nov_gui_manager::draw_specific(nov_container* container)

// now, draw current container and all children
draw_container(current, current_frame_data);
frame_cache.push(nov_frame_cache{ current_frame_data, container });

return true;
}
Expand Down
30 changes: 21 additions & 9 deletions src/include/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,22 @@ class nov_array
// is this object valid/initialised
bool is_valid = false;
public:
struct nov_array_iterator
{
uint32_t index = 0;
nov_array<T>* target = 0x0;

inline void operator++() { index++; }
inline bool operator!=(const nov_array_iterator& other) { return other.index == index; }
inline T operator*() { return (*target)[index]; }
};

/**
* extend the array to have a greater capacity to fit more items in.
* requests memory from malloc and sets up the array container slots ready for them to be `push`ed into
*
* @param new_capacity desired total number of slots in the array (i.e. this function will ensure there
* is this much capacity in the array)
*
* **/
inline void resize(uint32_t new_capacity)
{
Expand Down Expand Up @@ -73,11 +82,10 @@ class nov_array
* access element by index from the array
*
* @param index index into the array to access
*
* **/
inline T& operator[](uint32_t index)
{
if (index >= length) panic(); // crashes the kernel
if (index >= length) { com_1 << "index out of range " << index << stream::endl; panic(); } // crashes the kernel
// step over the linked list until we reach the block which contains the relevant index
nov_array_container* current = first;
uint32_t cumulative = 0;
Expand All @@ -95,11 +103,10 @@ class nov_array
* access element by index from the array
*
* @param index index into the array to access
*
* **/
inline T operator[](uint32_t index) const
{
if (index >= length) panic(); // crashes the kernel
if (index >= length) { com_1 << "index out of range " << index << stream::endl; panic(); } // crashes the kernel
// step over the linked list until we reach the block which contains the relevant index
nov_array_container* current = first;
uint32_t cumulative = 0;
Expand All @@ -117,7 +124,6 @@ class nov_array
* insert an element into the back of the list
*
* @param element element data to insert
*
* **/
inline void push(T element)
{
Expand All @@ -138,19 +144,17 @@ class nov_array
* remove an item from the end of the array, and return its value
*
* @return value of the last item in the array before the pop, or NULL if the array has no elements
*
* **/
inline T pop()
{
if (length == 0) panic(); // crashes the kernel
if (length == 0) { com_1 << "illegal pop attempt" << stream::endl; panic(); } // crashes the kernel
T value = (*this)[length-1];
length--;
return value;
}

/**
* clear the array of all of its items
*
* **/
inline void clear()
{
Expand All @@ -160,6 +164,9 @@ class nov_array
inline uint32_t get_length() const { return length; }
inline uint32_t get_capacity() const { return capacity; }

inline nov_array_iterator begin() { return nov_array_iterator{ 0, this }; }
inline nov_array_iterator end() { return nov_array_iterator{ get_length()-1, this }; }

inline constexpr nov_array(uint32_t _capacity)
{
// clear all values, then request a resize to the desired capacity
Expand Down Expand Up @@ -196,4 +203,9 @@ class nov_array
}
};

template <typename T>
auto begin(nov_array<T>& arr) { return arr.begin(); }
template <typename T>
auto end(nov_array<T>& arr) { return arr.end(); }

}
12 changes: 12 additions & 0 deletions src/include/gui/gui_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector.h>
#include <colour.h>
#include <graphics.h>
#include <array.h>

#define draw_function_stub (const nov_frame_data& frame, const graphics::nov_framebuffer& framebuffer, nov_panel* panel)

Expand Down Expand Up @@ -75,6 +76,15 @@ struct nov_container
nov_fvector2 division;
};

/**
* contains information about a cached frame and the container pointer it is relevant to
* **/
struct nov_frame_cache
{
nov_frame_data frame_data; // cached (pre-calculated) frame data
nov_container* container; // pointer to the container for which this is relevant
};

/**
* computes the frame data for two child frames based on a parent frame. does the maths to
* split the parent in half using the division factor
Expand Down Expand Up @@ -110,6 +120,8 @@ class nov_gui_manager
nov_frame_data root_container_frame;
// information about the current framebuffer being drawn into
graphics::nov_framebuffer framebuffer;
// array of cached information about the container tree
nov_array<nov_frame_cache> frame_cache;

/**
* draw a container, calling draw on the panel inside it if it has one, then drawing its children
Expand Down

0 comments on commit d7aa34c

Please sign in to comment.