add: texture cache

This commit is contained in:
Samuliak 2024-07-02 13:25:05 +02:00
parent 8d94cce537
commit bac3a8e040
6 changed files with 338 additions and 2 deletions

View file

@ -19,8 +19,6 @@ template <typename SurfaceType, size_t capacity, bool evictOnOverflow = 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 evictionIndex;

View file

@ -2,6 +2,9 @@
#include <QuartzCore/QuartzCore.hpp>
#include "renderer.hpp"
#include "texture.hpp"
// HACK: use the OpenGL cache
#include "../renderer_gl/surface_cache.hpp"
class GPU;
@ -30,6 +33,9 @@ class RendererMTL final : public Renderer {
MTL::Device* device;
MTL::CommandQueue* commandQueue;
// Caches
SurfaceCache<Metal::Texture, 256, true> textureCache;
// HACK
MTL::Texture* topScreenTexture;

View file

@ -0,0 +1,72 @@
#pragma once
#include <array>
#include <string>
#include <Metal/Metal.hpp>
#include "PICA/regs.hpp"
#include "boost/icl/interval.hpp"
#include "helpers.hpp"
#include "math_util.hpp"
#include "opengl.hpp"
template <typename T>
using Interval = boost::icl::right_open_interval<T>;
namespace Metal {
struct Texture {
MTL::Device* device;
u32 location;
u32 config; // Magnification/minification filter, wrapping configs, etc
PICA::TextureFmt format;
OpenGL::uvec2 size;
bool valid;
// Range of VRAM taken up by buffer
Interval<u32> range;
MTL::Texture* texture = nullptr;
Texture() : valid(false) {}
Texture(MTL::Device* dev, u32 loc, PICA::TextureFmt format, u32 x, u32 y, u32 config, bool valid = true)
: device(dev), location(loc), format(format), size({x, y}), config(config), valid(valid) {
u64 endLoc = (u64)loc + sizeInBytes();
// Check if start and end are valid here
range = Interval<u32>(loc, (u32)endLoc);
}
// For 2 textures to "match" we only care about their locations, formats, and dimensions to match
// For other things, such as filtering mode, etc, we can just switch the attributes of the cached texture
bool matches(Texture& other) {
return location == other.location && format == other.format &&
size.x() == other.size.x() && size.y() == other.size.y();
}
void allocate();
void setNewConfig(u32 newConfig);
void decodeTexture(std::span<const u8> data);
void free();
u64 sizeInBytes();
u32 decodeTexel(u32 u, u32 v, PICA::TextureFmt fmt, std::span<const u8> data);
// Get the morton interleave offset of a texel based on its U and V values
static u32 mortonInterleave(u32 u, u32 v);
// Get the byte offset of texel (u, v) in the texture
static u32 getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel);
static u32 getSwizzledOffset_4bpp(u32 u, u32 v, u32 width);
// Returns the format of this texture as a string
std::string_view formatToString() {
return PICA::textureFormatToString(format);
}
// Returns the texel at coordinates (u, v) of an ETC1(A4) texture
// TODO: Make hasAlpha a template parameter
u32 getTexelETC(bool hasAlpha, u32 u, u32 v, u32 width, std::span<const u8> data);
u32 decodeETC(u32 alpha, u32 u, u32 v, u64 colourData);
};
} // namespace Metal