mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
Additionally made the surface cache search hit for any address that lies in the surface. This should allow multiple races to be done in Mario Kart and fixes the intro video.
87 lines
3 KiB
C++
87 lines
3 KiB
C++
#pragma once
|
|
#include <functional>
|
|
#include <optional>
|
|
#include "surfaces.hpp"
|
|
#include "textures.hpp"
|
|
|
|
// Surface cache class that can fit "capacity" instances of the "SurfaceType" class of surfaces
|
|
// SurfaceType *must* have all of the following.
|
|
// - An "allocate" function that allocates GL resources for the surfaces. On overflow it will panic
|
|
// if evict_on_overflow is false, or kick out the oldest item if it is true.
|
|
// - A "free" function that frees up all resources the surface is taking up
|
|
// - A "matches" function that, when provided with a SurfaceType object reference
|
|
// Will tell us if the 2 surfaces match (Only as far as location in VRAM, format, dimensions, etc)
|
|
// Are concerned. We could overload the == operator, but that implies full equality
|
|
// Including equality of the allocated OpenGL resources, which we don't want
|
|
// - A "valid" member that tells us whether the function is still valid or not
|
|
// - A "location" member which tells us which location in 3DS memory this surface occupies
|
|
template <typename SurfaceType, size_t capacity, bool evict_on_overflow=false>
|
|
class SurfaceCache {
|
|
// Vanilla std::optional can't hold actual references
|
|
using OptionalRef = std::optional<std::reference_wrapper<SurfaceType>>;
|
|
static_assert(std::is_same<SurfaceType, ColourBuffer>() || std::is_same<SurfaceType, DepthBuffer>() ||
|
|
std::is_same<SurfaceType, Texture>(), "Invalid surface type");
|
|
|
|
size_t size;
|
|
size_t eviction_index;
|
|
std::array<SurfaceType, capacity> buffer;
|
|
|
|
public:
|
|
void reset() {
|
|
size = 0;
|
|
eviction_index=0;
|
|
for (auto& e : buffer) { // Free the VRAM of all surfaces
|
|
e.free();
|
|
}
|
|
}
|
|
|
|
OptionalRef find(SurfaceType& other) {
|
|
for (auto& e : buffer) {
|
|
if (e.matches(other) && e.valid)
|
|
return e;
|
|
}
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
OptionalRef findFromAddress(u32 address) {
|
|
for (auto& e : buffer) {
|
|
if (e.location <= address && e.location+e.sizeInBytes() > address && e.valid)
|
|
return e;
|
|
}
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
// Adds a surface object to the cache and returns it
|
|
SurfaceType& add(const SurfaceType& surface) {
|
|
if (size >= capacity) {
|
|
if(evict_on_overflow){
|
|
auto & e = buffer[eviction_index % size];
|
|
eviction_index++;
|
|
e.free();
|
|
e.valid = false;
|
|
e = surface;
|
|
e.allocate();
|
|
return e;
|
|
}else Helpers::panic("Surface cache full! Add emptying!");
|
|
}
|
|
size++;
|
|
|
|
// Find an invalid entry in the cache and overwrite it with the new surface
|
|
for (auto& e : buffer) {
|
|
if (!e.valid) {
|
|
e = surface;
|
|
e.allocate();
|
|
return e;
|
|
}
|
|
}
|
|
|
|
// This should be unreachable but helps to panic anyways
|
|
Helpers::panic("Couldn't add surface to cache\n");
|
|
}
|
|
|
|
SurfaceType& operator[](size_t i) {
|
|
return buffer[i];
|
|
}
|
|
};
|