mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-07-05 23:02:58 +12:00
Use multimap for indexing surfaces (#771)
Some checks are pending
Android Build / x64 (release) (push) Waiting to run
Android Build / arm64 (release) (push) Waiting to run
HTTP Server Build / build (push) Waiting to run
Hydra Core Build / Windows (push) Waiting to run
Hydra Core Build / MacOS (push) Waiting to run
Hydra Core Build / Linux (push) Waiting to run
Hydra Core Build / Android-x64 (push) Waiting to run
Hydra Core Build / ARM-Libretro (push) Waiting to run
Linux AppImage Build / build (push) Waiting to run
Linux Build / build (push) Waiting to run
MacOS Build / MacOS-arm64 (push) Waiting to run
MacOS Build / MacOS-x86_64 (push) Waiting to run
MacOS Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Windows (push) Waiting to run
Qt Build / MacOS-arm64 (push) Waiting to run
Qt Build / MacOS-x86_64 (push) Waiting to run
Qt Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Linux (push) Waiting to run
Windows Build / build (push) Waiting to run
iOS Simulator Build / build (push) Waiting to run
Some checks are pending
Android Build / x64 (release) (push) Waiting to run
Android Build / arm64 (release) (push) Waiting to run
HTTP Server Build / build (push) Waiting to run
Hydra Core Build / Windows (push) Waiting to run
Hydra Core Build / MacOS (push) Waiting to run
Hydra Core Build / Linux (push) Waiting to run
Hydra Core Build / Android-x64 (push) Waiting to run
Hydra Core Build / ARM-Libretro (push) Waiting to run
Linux AppImage Build / build (push) Waiting to run
Linux Build / build (push) Waiting to run
MacOS Build / MacOS-arm64 (push) Waiting to run
MacOS Build / MacOS-x86_64 (push) Waiting to run
MacOS Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Windows (push) Waiting to run
Qt Build / MacOS-arm64 (push) Waiting to run
Qt Build / MacOS-x86_64 (push) Waiting to run
Qt Build / MacOS-Universal (push) Blocked by required conditions
Qt Build / Linux (push) Waiting to run
Windows Build / build (push) Waiting to run
iOS Simulator Build / build (push) Waiting to run
* Use an std::map for faster texture cache lookup * Surface cache: Use map instead of multimap, optimize `find` to perform tree scan * Add comments
This commit is contained in:
parent
80840b6c5e
commit
d06f600b3a
2 changed files with 69 additions and 38 deletions
|
@ -1,6 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <array>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "surfaces.hpp"
|
#include "surfaces.hpp"
|
||||||
#include "textures.hpp"
|
#include "textures.hpp"
|
||||||
|
|
||||||
|
@ -17,41 +20,69 @@
|
||||||
// - A "location" member which tells us which location in 3DS memory this surface occupies
|
// - A "location" member which tells us which location in 3DS memory this surface occupies
|
||||||
template <typename SurfaceType, size_t capacity, bool evictOnOverflow = false>
|
template <typename SurfaceType, size_t capacity, bool evictOnOverflow = false>
|
||||||
class SurfaceCache {
|
class SurfaceCache {
|
||||||
// Vanilla std::optional can't hold actual references
|
// Vanilla std::optional can't hold actual references
|
||||||
using OptionalRef = std::optional<std::reference_wrapper<SurfaceType>>;
|
using OptionalRef = std::optional<std::reference_wrapper<SurfaceType>>;
|
||||||
|
|
||||||
size_t size;
|
size_t size = 0;
|
||||||
size_t evictionIndex;
|
size_t evictionIndex = 0;
|
||||||
std::array<SurfaceType, capacity> buffer;
|
std::array<SurfaceType, capacity> buffer;
|
||||||
|
|
||||||
public:
|
// Map from address to a surface in the above buffer.
|
||||||
void reset() {
|
// Several cached surfaces may have the same starting address, so we use a multimap.
|
||||||
size = 0;
|
std::multimap<u32, SurfaceType*> surfaceMap;
|
||||||
evictionIndex = 0;
|
|
||||||
for (auto& e : buffer) { // Free the VRAM of all surfaces
|
|
||||||
e.free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OptionalRef find(SurfaceType& other) {
|
// Adds a surface to our map
|
||||||
for (auto& e : buffer) {
|
void indexSurface(SurfaceType& surface) { surfaceMap.emplace(surface.location, &surface); }
|
||||||
if (e.matches(other) && e.valid)
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
// Removes a surface from our map
|
||||||
}
|
void unindexSurface(SurfaceType& surface) {
|
||||||
|
auto range = surfaceMap.equal_range(surface.location);
|
||||||
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
|
if (it->second == &surface) {
|
||||||
|
surfaceMap.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OptionalRef findFromAddress(u32 address) {
|
public:
|
||||||
for (auto& e : buffer) {
|
void reset() {
|
||||||
if (e.location <= address && e.location + e.sizeInBytes() > address && e.valid)
|
size = 0;
|
||||||
return e;
|
evictionIndex = 0;
|
||||||
}
|
surfaceMap.clear();
|
||||||
|
|
||||||
return std::nullopt;
|
// Free the memory of all surfaces
|
||||||
}
|
for (auto& e : buffer) {
|
||||||
|
e.free();
|
||||||
|
e.valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a surface object to the cache and returns it
|
// Use our map to only scan the surfaces with the same starting location
|
||||||
|
OptionalRef find(SurfaceType& other) {
|
||||||
|
auto range = surfaceMap.equal_range(other.location);
|
||||||
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
|
SurfaceType* candidate = it->second;
|
||||||
|
if (candidate->valid && candidate->matches(other)) {
|
||||||
|
return *candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionalRef findFromAddress(u32 address) {
|
||||||
|
for (auto it = surfaceMap.begin(); it != surfaceMap.end(); ++it) {
|
||||||
|
SurfaceType* surface = it->second;
|
||||||
|
if (surface->valid && surface->location <= address && surface->location + surface->sizeInBytes() > address) {
|
||||||
|
return *surface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a surface object to the cache and returns it
|
||||||
SurfaceType& add(const SurfaceType& surface) {
|
SurfaceType& add(const SurfaceType& surface) {
|
||||||
if (size >= capacity) {
|
if (size >= capacity) {
|
||||||
if constexpr (evictOnOverflow) { // Do a ring buffer if evictOnOverflow is true
|
if constexpr (evictOnOverflow) { // Do a ring buffer if evictOnOverflow is true
|
||||||
|
@ -60,12 +91,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& e = buffer[evictionIndex];
|
auto& e = buffer[evictionIndex];
|
||||||
|
unindexSurface(e);
|
||||||
evictionIndex = (evictionIndex + 1) % capacity;
|
evictionIndex = (evictionIndex + 1) % capacity;
|
||||||
|
|
||||||
e.valid = false;
|
e.valid = false;
|
||||||
e.free();
|
e.free();
|
||||||
e = surface;
|
e = surface;
|
||||||
e.allocate();
|
e.allocate();
|
||||||
|
indexSurface(e);
|
||||||
return e;
|
return e;
|
||||||
} else {
|
} else {
|
||||||
Helpers::panic("Surface cache full! Add emptying!");
|
Helpers::panic("Surface cache full! Add emptying!");
|
||||||
|
@ -74,12 +107,14 @@ public:
|
||||||
|
|
||||||
size++;
|
size++;
|
||||||
|
|
||||||
// Find an existing surface we completely invalidate and overwrite it with the new surface
|
// See if any existing surface fully overlaps
|
||||||
for (auto& e : buffer) {
|
for (auto& e : buffer) {
|
||||||
if (e.valid && e.range.lower() >= surface.range.lower() && e.range.upper() <= surface.range.upper()) {
|
if (e.valid && e.range.lower() >= surface.range.lower() && e.range.upper() <= surface.range.upper()) {
|
||||||
|
unindexSurface(e);
|
||||||
e.free();
|
e.free();
|
||||||
e = surface;
|
e = surface;
|
||||||
e.allocate();
|
e.allocate();
|
||||||
|
indexSurface(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,6 +124,7 @@ public:
|
||||||
if (!e.valid) {
|
if (!e.valid) {
|
||||||
e = surface;
|
e = surface;
|
||||||
e.allocate();
|
e.allocate();
|
||||||
|
indexSurface(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,11 +133,6 @@ public:
|
||||||
Helpers::panic("Couldn't add surface to cache\n");
|
Helpers::panic("Couldn't add surface to cache\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceType& operator[](size_t i) {
|
SurfaceType& operator[](size_t i) { return buffer[i]; }
|
||||||
return buffer[i];
|
const SurfaceType& operator[](size_t i) const { return buffer[i]; }
|
||||||
}
|
|
||||||
|
|
||||||
const SurfaceType& operator[](size_t i) const {
|
|
||||||
return buffer[i];
|
|
||||||
}
|
|
||||||
};
|
};
|
Loading…
Add table
Add a link
Reference in a new issue