From 53c9611ac26449ad7782cafaa77b950d264b47ba Mon Sep 17 00:00:00 2001 From: Samuliak <samuliak77@gmail.com> Date: Tue, 2 Jul 2024 16:06:20 +0200 Subject: [PATCH] add: render target caches --- include/renderer_mtl/render_target.hpp | 77 ++++++++++++++++++++++++++ include/renderer_mtl/renderer_mtl.hpp | 3 + src/core/renderer_mtl/renderer_mtl.cpp | 4 ++ src/core/renderer_mtl/texture.cpp | 2 +- 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 include/renderer_mtl/render_target.hpp diff --git a/include/renderer_mtl/render_target.hpp b/include/renderer_mtl/render_target.hpp new file mode 100644 index 00000000..26c356a6 --- /dev/null +++ b/include/renderer_mtl/render_target.hpp @@ -0,0 +1,77 @@ +#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 RenderTarget { + MTL::Device* device; + + u32 location; + PICA::TextureFmt format; + OpenGL::uvec2 size; + bool valid; + + // Range of VRAM taken up by buffer + Interval<u32> range; + + MTL::Texture* texture = nullptr; + + RenderTarget() : valid(false) {} + + RenderTarget(MTL::Device* dev, u32 loc, PICA::TextureFmt format, u32 x, u32 y, bool valid = true) + : device(dev), location(loc), format(format), size({x, y}), valid(valid) { + + u64 endLoc = (u64)loc + sizeInBytes(); + // Check if start and end are valid here + range = Interval<u32>(loc, (u32)endLoc); + } + + Math::Rect<u32> getSubRect(u32 inputAddress, u32 width, u32 height) { + const u32 startOffset = (inputAddress - location) / sizePerPixel(format); + const u32 x0 = (startOffset % (size.x() * 8)) / 8; + const u32 y0 = (startOffset / (size.x() * 8)) * 8; + return Math::Rect<u32>{x0, y0, x0 + width, y0 + height}; + } + + // 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() { + MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::alloc()->init(); + descriptor->setTextureType(MTL::TextureType2D); + descriptor->setPixelFormat(MTL::PixelFormatRGBA8Unorm); + descriptor->setWidth(size.u()); + descriptor->setHeight(size.v()); + descriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead); + descriptor->setStorageMode(MTL::StorageModePrivate); + texture = device->newTexture(descriptor); + } + + void free() { + valid = false; + + if (texture) { + texture->release(); + } + } + + u64 sizeInBytes() { + return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format); + } +}; + +} // namespace Metal diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index 56415bc8..4e67cdec 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -3,6 +3,7 @@ #include "renderer.hpp" #include "texture.hpp" +#include "render_target.hpp" // HACK: use the OpenGL cache #include "../renderer_gl/surface_cache.hpp" @@ -34,6 +35,8 @@ class RendererMTL final : public Renderer { MTL::CommandQueue* commandQueue; // Caches + SurfaceCache<Metal::Texture, 16, true> colorRenderTargetCache; + SurfaceCache<Metal::Texture, 16, true> depthStencilRenderTargetCache; SurfaceCache<Metal::Texture, 256, true> textureCache; // HACK diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 93b821c1..e0fc1c3a 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -18,6 +18,8 @@ RendererMTL::RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, RendererMTL::~RendererMTL() {} void RendererMTL::reset() { + colorRenderTargetCache.reset(); + depthStencilRenderTargetCache.reset(); textureCache.reset(); // TODO: implement @@ -233,6 +235,8 @@ void RendererMTL::screenshot(const std::string& name) { } void RendererMTL::deinitGraphicsContext() { + colorRenderTargetCache.reset(); + depthStencilRenderTargetCache.reset(); textureCache.reset(); // TODO: implement diff --git a/src/core/renderer_mtl/texture.cpp b/src/core/renderer_mtl/texture.cpp index df3866ac..f50fdca7 100644 --- a/src/core/renderer_mtl/texture.cpp +++ b/src/core/renderer_mtl/texture.cpp @@ -12,7 +12,7 @@ void Texture::allocate() { descriptor->setPixelFormat(MTL::PixelFormatRGBA8Unorm); descriptor->setWidth(size.u()); descriptor->setHeight(size.v()); - descriptor->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite); + descriptor->setUsage(MTL::TextureUsageShaderRead); descriptor->setStorageMode(MTL::StorageModeShared); // TODO: use private + staging buffers? texture = device->newTexture(descriptor);