mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-16 18:59:48 +12:00
use proper render targets
This commit is contained in:
parent
53c9611ac2
commit
56262c2c24
4 changed files with 130 additions and 31 deletions
|
@ -17,7 +17,7 @@ struct RenderTarget {
|
||||||
MTL::Device* device;
|
MTL::Device* device;
|
||||||
|
|
||||||
u32 location;
|
u32 location;
|
||||||
PICA::TextureFmt format;
|
PICA::ColorFmt format;
|
||||||
OpenGL::uvec2 size;
|
OpenGL::uvec2 size;
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ struct RenderTarget {
|
||||||
|
|
||||||
RenderTarget() : valid(false) {}
|
RenderTarget() : valid(false) {}
|
||||||
|
|
||||||
RenderTarget(MTL::Device* dev, u32 loc, PICA::TextureFmt format, u32 x, u32 y, bool valid = true)
|
RenderTarget(MTL::Device* dev, u32 loc, PICA::ColorFmt format, u32 x, u32 y, bool valid = true)
|
||||||
: device(dev), location(loc), format(format), size({x, y}), valid(valid) {
|
: device(dev), location(loc), format(format), size({x, y}), valid(valid) {
|
||||||
|
|
||||||
u64 endLoc = (u64)loc + sizeInBytes();
|
u64 endLoc = (u64)loc + sizeInBytes();
|
||||||
|
@ -45,7 +45,7 @@ struct RenderTarget {
|
||||||
|
|
||||||
// For 2 textures to "match" we only care about their locations, formats, and dimensions to match
|
// 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
|
// For other things, such as filtering mode, etc, we can just switch the attributes of the cached texture
|
||||||
bool matches(Texture& other) {
|
bool matches(RenderTarget& other) {
|
||||||
return location == other.location && format == other.format &&
|
return location == other.location && format == other.format &&
|
||||||
size.x() == other.size.x() && size.y() == other.size.y();
|
size.x() == other.size.x() && size.y() == other.size.y();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,13 +35,10 @@ class RendererMTL final : public Renderer {
|
||||||
MTL::CommandQueue* commandQueue;
|
MTL::CommandQueue* commandQueue;
|
||||||
|
|
||||||
// Caches
|
// Caches
|
||||||
SurfaceCache<Metal::Texture, 16, true> colorRenderTargetCache;
|
SurfaceCache<Metal::RenderTarget, 16, true> colorRenderTargetCache;
|
||||||
SurfaceCache<Metal::Texture, 16, true> depthStencilRenderTargetCache;
|
SurfaceCache<Metal::RenderTarget, 16, true> depthStencilRenderTargetCache;
|
||||||
SurfaceCache<Metal::Texture, 256, true> textureCache;
|
SurfaceCache<Metal::Texture, 256, true> textureCache;
|
||||||
|
|
||||||
// HACK
|
|
||||||
MTL::Texture* topScreenTexture;
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
MTL::SamplerState* basicSampler;
|
MTL::SamplerState* basicSampler;
|
||||||
|
|
||||||
|
@ -58,6 +55,7 @@ class RendererMTL final : public Renderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<Metal::RenderTarget> getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true);
|
||||||
MTL::Texture* getTexture(Metal::Texture& tex);
|
MTL::Texture* getTexture(Metal::Texture& tex);
|
||||||
void setupTextureEnvState(MTL::RenderCommandEncoder* encoder);
|
void setupTextureEnvState(MTL::RenderCommandEncoder* encoder);
|
||||||
void bindTexturesToSlots(MTL::RenderCommandEncoder* encoder);
|
void bindTexturesToSlots(MTL::RenderCommandEncoder* encoder);
|
||||||
|
|
|
@ -515,7 +515,7 @@ void RendererGL::display() {
|
||||||
const u32 bottomActiveFb = externalRegs[Framebuffer1Select] & 1;
|
const u32 bottomActiveFb = externalRegs[Framebuffer1Select] & 1;
|
||||||
const u32 bottomScreenAddr = externalRegs[bottomActiveFb == 0 ? Framebuffer1AFirstAddr : Framebuffer1ASecondAddr];
|
const u32 bottomScreenAddr = externalRegs[bottomActiveFb == 0 ? Framebuffer1AFirstAddr : Framebuffer1ASecondAddr];
|
||||||
auto bottomScreen = colourBufferCache.findFromAddress(bottomScreenAddr);
|
auto bottomScreen = colourBufferCache.findFromAddress(bottomScreenAddr);
|
||||||
|
|
||||||
if (bottomScreen) {
|
if (bottomScreen) {
|
||||||
bottomScreen->get().texture.bind();
|
bottomScreen->get().texture.bind();
|
||||||
OpenGL::setViewport(40, 0, 320, 240);
|
OpenGL::setViewport(40, 0, 320, 240);
|
||||||
|
@ -812,4 +812,4 @@ void RendererGL::deinitGraphicsContext() {
|
||||||
// All other GL objects should be invalidated automatically and be recreated by the next call to initGraphicsContext
|
// All other GL objects should be invalidated automatically and be recreated by the next call to initGraphicsContext
|
||||||
// TODO: Make it so that depth and colour buffers get written back to 3DS memory
|
// TODO: Make it so that depth and colour buffers get written back to 3DS memory
|
||||||
printf("RendererGL::DeinitGraphicsContext called\n");
|
printf("RendererGL::DeinitGraphicsContext called\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,15 @@ CMRC_DECLARE(RendererMTL);
|
||||||
// Bind the vertex buffer to binding 30 so that it doesn't occupy the lower indices
|
// Bind the vertex buffer to binding 30 so that it doesn't occupy the lower indices
|
||||||
#define VERTEX_BUFFER_BINDING_INDEX 30
|
#define VERTEX_BUFFER_BINDING_INDEX 30
|
||||||
|
|
||||||
|
// HACK: redefinition...
|
||||||
|
PICA::ColorFmt ToColorFormat(u32 format) {
|
||||||
|
switch (format) {
|
||||||
|
case 2: return PICA::ColorFmt::RGB565;
|
||||||
|
case 3: return PICA::ColorFmt::RGBA5551;
|
||||||
|
default: return static_cast<PICA::ColorFmt>(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RendererMTL::RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs)
|
RendererMTL::RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs)
|
||||||
: Renderer(gpu, internalRegs, externalRegs) {}
|
: Renderer(gpu, internalRegs, externalRegs) {}
|
||||||
RendererMTL::~RendererMTL() {}
|
RendererMTL::~RendererMTL() {}
|
||||||
|
@ -32,18 +41,46 @@ void RendererMTL::display() {
|
||||||
CA::MetalDrawable* drawable = metalLayer->nextDrawable();
|
CA::MetalDrawable* drawable = metalLayer->nextDrawable();
|
||||||
|
|
||||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||||
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
|
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
|
||||||
colorAttachment->setTexture(drawable->texture());
|
colorAttachment->setTexture(drawable->texture());
|
||||||
colorAttachment->setLoadAction(MTL::LoadActionDontCare);
|
colorAttachment->setLoadAction(MTL::LoadActionDontCare);
|
||||||
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||||
|
|
||||||
MTL::RenderCommandEncoder* renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
MTL::RenderCommandEncoder* renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
||||||
renderCommandEncoder->setRenderPipelineState(displayPipeline);
|
renderCommandEncoder->setRenderPipelineState(displayPipeline);
|
||||||
renderCommandEncoder->setFragmentTexture(topScreenTexture, 0);
|
renderCommandEncoder->setFragmentSamplerState(basicSampler, 0);
|
||||||
renderCommandEncoder->setFragmentSamplerState(basicSampler, 0);
|
|
||||||
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
|
||||||
|
|
||||||
renderCommandEncoder->endEncoding();
|
using namespace PICA::ExternalRegs;
|
||||||
|
|
||||||
|
// Top screen
|
||||||
|
{
|
||||||
|
const u32 topActiveFb = externalRegs[Framebuffer0Select] & 1;
|
||||||
|
const u32 topScreenAddr = externalRegs[topActiveFb == 0 ? Framebuffer0AFirstAddr : Framebuffer0ASecondAddr];
|
||||||
|
auto topScreen = colorRenderTargetCache.findFromAddress(topScreenAddr);
|
||||||
|
|
||||||
|
if (topScreen.has_value()) {
|
||||||
|
renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0);
|
||||||
|
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||||
|
} else {
|
||||||
|
Helpers::warn("Top screen not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom screen
|
||||||
|
{
|
||||||
|
const u32 bottomActiveFb = externalRegs[Framebuffer1Select] & 1;
|
||||||
|
const u32 bottomScreenAddr = externalRegs[bottomActiveFb == 0 ? Framebuffer1AFirstAddr : Framebuffer1ASecondAddr];
|
||||||
|
auto bottomScreen = colorRenderTargetCache.findFromAddress(bottomScreenAddr);
|
||||||
|
|
||||||
|
if (bottomScreen.has_value()) {
|
||||||
|
renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0);
|
||||||
|
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||||
|
} else {
|
||||||
|
Helpers::warn("Bottom screen not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCommandEncoder->endEncoding();
|
||||||
|
|
||||||
commandBuffer->presentDrawable(drawable);
|
commandBuffer->presentDrawable(drawable);
|
||||||
commandBuffer->commit();
|
commandBuffer->commit();
|
||||||
|
@ -58,15 +95,6 @@ void RendererMTL::initGraphicsContext(SDL_Window* window) {
|
||||||
metalLayer->setDevice(device);
|
metalLayer->setDevice(device);
|
||||||
commandQueue = device->newCommandQueue();
|
commandQueue = device->newCommandQueue();
|
||||||
|
|
||||||
// HACK
|
|
||||||
MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::alloc()->init();
|
|
||||||
descriptor->setTextureType(MTL::TextureType2D);
|
|
||||||
descriptor->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
|
|
||||||
descriptor->setWidth(400);
|
|
||||||
descriptor->setHeight(240);
|
|
||||||
descriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead);
|
|
||||||
topScreenTexture = device->newTexture(descriptor);
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
|
MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
|
||||||
basicSampler = device->newSamplerState(samplerDescriptor);
|
basicSampler = device->newSamplerState(samplerDescriptor);
|
||||||
|
@ -110,7 +138,7 @@ void RendererMTL::initGraphicsContext(SDL_Window* window) {
|
||||||
drawPipelineDescriptor->setFragmentFunction(fragmentDrawFunction);
|
drawPipelineDescriptor->setFragmentFunction(fragmentDrawFunction);
|
||||||
// HACK
|
// HACK
|
||||||
auto* drawColorAttachment = drawPipelineDescriptor->colorAttachments()->object(0);
|
auto* drawColorAttachment = drawPipelineDescriptor->colorAttachments()->object(0);
|
||||||
drawColorAttachment->setPixelFormat(topScreenTexture->pixelFormat());
|
drawColorAttachment->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
|
||||||
drawColorAttachment->setBlendingEnabled(true);
|
drawColorAttachment->setBlendingEnabled(true);
|
||||||
drawColorAttachment->setSourceRGBBlendFactor(MTL::BlendFactorSourceAlpha);
|
drawColorAttachment->setSourceRGBBlendFactor(MTL::BlendFactorSourceAlpha);
|
||||||
drawColorAttachment->setDestinationRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha);
|
drawColorAttachment->setDestinationRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha);
|
||||||
|
@ -187,6 +215,58 @@ void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 c
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) {
|
void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) {
|
||||||
|
createCommandBufferIfNeeded();
|
||||||
|
|
||||||
|
const u32 inputWidth = inputSize & 0xffff;
|
||||||
|
const u32 inputHeight = inputSize >> 16;
|
||||||
|
const auto inputFormat = ToColorFormat(Helpers::getBits<8, 3>(flags));
|
||||||
|
const auto outputFormat = ToColorFormat(Helpers::getBits<12, 3>(flags));
|
||||||
|
const bool verticalFlip = flags & 1;
|
||||||
|
const PICA::Scaling scaling = static_cast<PICA::Scaling>(Helpers::getBits<24, 2>(flags));
|
||||||
|
|
||||||
|
u32 outputWidth = outputSize & 0xffff;
|
||||||
|
u32 outputHeight = outputSize >> 16;
|
||||||
|
|
||||||
|
auto srcFramebuffer = getColorRenderTarget(inputAddr, inputFormat, inputWidth, outputHeight);
|
||||||
|
Math::Rect<u32> srcRect = srcFramebuffer->getSubRect(inputAddr, outputWidth, outputHeight);
|
||||||
|
|
||||||
|
if (verticalFlip) {
|
||||||
|
std::swap(srcRect.bottom, srcRect.top);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply scaling for the destination rectangle.
|
||||||
|
if (scaling == PICA::Scaling::X || scaling == PICA::Scaling::XY) {
|
||||||
|
outputWidth >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scaling == PICA::Scaling::XY) {
|
||||||
|
outputHeight >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto destFramebuffer = getColorRenderTarget(outputAddr, outputFormat, outputWidth, outputHeight);
|
||||||
|
Math::Rect<u32> destRect = destFramebuffer->getSubRect(outputAddr, outputWidth, outputHeight);
|
||||||
|
|
||||||
|
if (inputWidth != outputWidth) {
|
||||||
|
// Helpers::warn("Strided display transfer is not handled correctly!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: respect regions
|
||||||
|
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||||
|
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
|
||||||
|
colorAttachment->setTexture(destFramebuffer->texture);
|
||||||
|
colorAttachment->setLoadAction(MTL::LoadActionClear);
|
||||||
|
colorAttachment->setClearColor(MTL::ClearColor{0.0, 0.0, 0.0, 1.0});
|
||||||
|
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||||
|
|
||||||
|
MTL::RenderCommandEncoder* renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
||||||
|
renderCommandEncoder->setRenderPipelineState(displayPipeline);
|
||||||
|
renderCommandEncoder->setFragmentTexture(srcFramebuffer->texture, 0);
|
||||||
|
renderCommandEncoder->setFragmentSamplerState(basicSampler, 0);
|
||||||
|
|
||||||
|
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||||
|
|
||||||
|
renderCommandEncoder->endEncoding();
|
||||||
|
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
Helpers::warn("RendererMTL::displayTransfer not implemented");
|
Helpers::warn("RendererMTL::displayTransfer not implemented");
|
||||||
}
|
}
|
||||||
|
@ -199,10 +279,12 @@ void RendererMTL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32
|
||||||
void RendererMTL::drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) {
|
void RendererMTL::drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) {
|
||||||
createCommandBufferIfNeeded();
|
createCommandBufferIfNeeded();
|
||||||
|
|
||||||
|
MTL::Texture* renderTarget = getColorRenderTarget(colourBufferLoc, colourBufferFormat, fbSize[0], fbSize[1])->texture;
|
||||||
|
|
||||||
// TODO: don't begin a new render pass every time
|
// TODO: don't begin a new render pass every time
|
||||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||||
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
|
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
|
||||||
colorAttachment->setTexture(topScreenTexture);
|
colorAttachment->setTexture(renderTarget);
|
||||||
colorAttachment->setLoadAction(MTL::LoadActionLoad);
|
colorAttachment->setLoadAction(MTL::LoadActionLoad);
|
||||||
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||||
|
|
||||||
|
@ -243,6 +325,25 @@ void RendererMTL::deinitGraphicsContext() {
|
||||||
Helpers::warn("RendererMTL::deinitGraphicsContext not implemented");
|
Helpers::warn("RendererMTL::deinitGraphicsContext not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<Metal::RenderTarget> RendererMTL::getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound) {
|
||||||
|
// Try to find an already existing buffer that contains the provided address
|
||||||
|
// This is a more relaxed check compared to getColourFBO as display transfer/texcopy may refer to
|
||||||
|
// subrect of a surface and in case of texcopy we don't know the format of the surface.
|
||||||
|
auto buffer = colorRenderTargetCache.findFromAddress(addr);
|
||||||
|
if (buffer.has_value()) {
|
||||||
|
return buffer.value().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!createIfnotFound) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise create and cache a new buffer.
|
||||||
|
Metal::RenderTarget sampleBuffer(device, addr, format, width, height);
|
||||||
|
|
||||||
|
return colorRenderTargetCache.add(sampleBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
MTL::Texture* RendererMTL::getTexture(Metal::Texture& tex) {
|
MTL::Texture* RendererMTL::getTexture(Metal::Texture& tex) {
|
||||||
auto buffer = textureCache.find(tex);
|
auto buffer = textureCache.find(tex);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue