diff --git a/include/renderer_mtl/mtl_render_target.hpp b/include/renderer_mtl/mtl_render_target.hpp index 90be3bde..73be45f4 100644 --- a/include/renderer_mtl/mtl_render_target.hpp +++ b/include/renderer_mtl/mtl_render_target.hpp @@ -41,7 +41,7 @@ struct RenderTarget { 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}; + return Math::Rect{x0, size.y() - y0, x0 + width, size.y() - height - y0}; } // For 2 textures to "match" we only care about their locations, formats, and dimensions to match diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 03696f39..0a790035 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -376,6 +376,13 @@ void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, nextRenderPassName = "Display transfer"; beginRenderPassIfNeeded(renderPassDescriptor, false, destFramebuffer->texture); renderCommandEncoder->setRenderPipelineState(blitPipeline); + + // Viewport + renderCommandEncoder->setViewport(MTL::Viewport{double(destRect.left), double(destRect.bottom), double(destRect.right - destRect.left), double(destRect.top - destRect.bottom), 0.0, 1.0}); + float srcRectNDC[4] = {srcRect.left / (float)srcFramebuffer->size.u(), srcRect.bottom / (float)srcFramebuffer->size.v(), (srcRect.right - srcRect.left) / (float)srcFramebuffer->size.u(), (srcRect.top - srcRect.bottom) / (float)srcFramebuffer->size.v()}; + + // Bind resources + renderCommandEncoder->setVertexBytes(&srcRectNDC, sizeof(srcRectNDC), 0); renderCommandEncoder->setFragmentTexture(srcFramebuffer->texture, 0); renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0); @@ -460,6 +467,13 @@ void RendererMTL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 nextRenderPassName = "Texture copy"; beginRenderPassIfNeeded(renderPassDescriptor, false, destFramebuffer->texture); renderCommandEncoder->setRenderPipelineState(blitPipeline); + + // Viewport + renderCommandEncoder->setViewport(MTL::Viewport{double(destRect.left), double(destRect.bottom), double(destRect.right - destRect.left), double(destRect.top - destRect.bottom), 0.0, 1.0}); + float srcRectNDC[4] = {srcRect.left / (float)srcFramebuffer->size.u(), srcRect.bottom / (float)srcFramebuffer->size.v(), (srcRect.right - srcRect.left) / (float)srcFramebuffer->size.u(), (srcRect.top - srcRect.bottom) / (float)srcFramebuffer->size.v()}; + + // Bind resources + renderCommandEncoder->setVertexBytes(&srcRectNDC, sizeof(srcRectNDC), 0); renderCommandEncoder->setFragmentTexture(srcFramebuffer->texture, 0); renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0); @@ -563,6 +577,15 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::spansetVertexBuffer(buffer.buffer, buffer.offset, VERTEX_BUFFER_BINDING_INDEX); } + // Viewport + const u32 viewportX = regs[PICA::InternalRegs::ViewportXY] & 0x3ff; + const u32 viewportY = (regs[PICA::InternalRegs::ViewportXY] >> 16) & 0x3ff; + const u32 viewportWidth = Floats::f24::fromRaw(regs[PICA::InternalRegs::ViewportWidth] & 0xffffff).toFloat32() * 2.0f; + const u32 viewportHeight = Floats::f24::fromRaw(regs[PICA::InternalRegs::ViewportHeight] & 0xffffff).toFloat32() * 2.0f; + const auto rect = colorRenderTarget->getSubRect(colourBufferLoc, fbSize[0], fbSize[1]); + MTL::Viewport viewport{double(rect.left + viewportX), double(rect.bottom + viewportY), double(viewportWidth), double(viewportHeight), 0.0, 1.0}; + renderCommandEncoder->setViewport(viewport); + // Blend color if (pipelineHash.blendEnabled) { u32 constantColor = regs[PICA::InternalRegs::BlendColour]; diff --git a/src/host_shaders/metal_shaders.metal b/src/host_shaders/metal_shaders.metal index 1d4151c6..f1884873 100644 --- a/src/host_shaders/metal_shaders.metal +++ b/src/host_shaders/metal_shaders.metal @@ -32,11 +32,17 @@ fragment float4 fragmentDisplay(BasicVertexOut in [[stage_in]], texture2d return tex.sample(samplr, in.uv); } -vertex BasicVertexOut vertexBlit(uint vid [[vertex_id]]) { +struct NDCViewport { + float2 offset; + float2 scale; +}; + +vertex BasicVertexOut vertexBlit(uint vid [[vertex_id]], constant NDCViewport& viewport [[buffer(0)]]) { BasicVertexOut out; out.uv = float2((vid << 1) & 2, vid & 2); out.position = float4(out.uv * 2.0 - 1.0, 0.0, 1.0); out.position.y = -out.position.y; + out.uv = out.uv * viewport.scale + viewport.offset; return out; }