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 +#include +#include +#include "PICA/regs.hpp" +#include "boost/icl/interval.hpp" +#include "helpers.hpp" +#include "math_util.hpp" +#include "opengl.hpp" + +template +using Interval = boost::icl::right_open_interval; + +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 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(loc, (u32)endLoc); + } + + Math::Rect 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{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 colorRenderTargetCache; + SurfaceCache depthStencilRenderTargetCache; SurfaceCache 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& 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);