mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-07-02 13:26:24 +12:00
Metal renderer & iOS frontend fixes
This commit is contained in:
parent
630952f36b
commit
adcd03d31e
8 changed files with 71 additions and 36 deletions
|
@ -1,7 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Foundation/Foundation.h>
|
#include <Foundation/Foundation.h>
|
||||||
#include <QuartzCore/QuartzCore.h>
|
#include <QuartzCore/QuartzCore.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void iosCreateEmulator();
|
void iosCreateEmulator();
|
||||||
void iosLoadROM(NSString* pathNS);
|
void iosLoadROM(NSString* pathNS);
|
||||||
void iosRunFrame(CAMetalLayer* layer);
|
void iosRunFrame(CAMetalLayer* layer);
|
||||||
|
void iosSetOutputSize(uint32_t width, uint32_t height);
|
|
@ -40,7 +40,13 @@ namespace PICA {
|
||||||
};
|
};
|
||||||
|
|
||||||
void checkForMTLPixelFormatSupport(MTL::Device* device) {
|
void checkForMTLPixelFormatSupport(MTL::Device* device) {
|
||||||
if (!device->supportsFamily(MTL::GPUFamilyApple1)) {
|
#ifndef PANDA3DS_IOS_SIMULATOR
|
||||||
|
const bool supportsApple1 = device->supportsFamily(MTL::GPUFamilyApple1);
|
||||||
|
#else
|
||||||
|
// iOS simulator claims to support Apple1, yet doesn't support a bunch of texture formats from it...
|
||||||
|
const bool supportsApple1 = false;
|
||||||
|
#endif
|
||||||
|
if (!supportsApple1) {
|
||||||
mtlPixelFormatInfos[2] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelA1BGR5ToRGBA8};
|
mtlPixelFormatInfos[2] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelA1BGR5ToRGBA8};
|
||||||
mtlPixelFormatInfos[3] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelB5G6R5ToRGBA8};
|
mtlPixelFormatInfos[3] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelB5G6R5ToRGBA8};
|
||||||
mtlPixelFormatInfos[4] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelABGR4ToRGBA8};
|
mtlPixelFormatInfos[4] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelABGR4ToRGBA8};
|
||||||
|
|
|
@ -130,7 +130,7 @@ void RendererMTL::display() {
|
||||||
// Top screen
|
// Top screen
|
||||||
if (topScreen) {
|
if (topScreen) {
|
||||||
renderCommandEncoder->setViewport(
|
renderCommandEncoder->setViewport(
|
||||||
MTL::Viewport{blitInfo.topScreenX, blitInfo.topScreenY + 240 * blitInfo.scale, 400 * blitInfo.scale, 240 * blitInfo.scale, 0.0f, 1.0f}
|
MTL::Viewport{blitInfo.topScreenX, blitInfo.topScreenY, 400 * blitInfo.scale, 240 * blitInfo.scale, 0.0f, 1.0f}
|
||||||
);
|
);
|
||||||
renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0);
|
renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0);
|
||||||
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||||
|
|
|
@ -10,8 +10,8 @@ struct BasicVertexOut {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NDCViewport {
|
struct NDCViewport {
|
||||||
float2 offset;
|
float2 offset;
|
||||||
float2 scale;
|
float2 scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
vertex BasicVertexOut vertexBlit(uint vid [[vertex_id]], constant NDCViewport& viewport [[buffer(0)]]) {
|
vertex BasicVertexOut vertexBlit(uint vid [[vertex_id]], constant NDCViewport& viewport [[buffer(0)]]) {
|
||||||
|
|
|
@ -33,6 +33,10 @@ IOS_EXPORT void iosRunFrame(CAMetalLayer* layer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IOS_EXPORT void iosLoadROM(NSString* pathNS) {
|
IOS_EXPORT void iosLoadROM(NSString* pathNS) {
|
||||||
auto path = std::filesystem::path([pathNS UTF8String]);
|
auto path = std::filesystem::path([pathNS UTF8String]);
|
||||||
emulator->loadROM(path);
|
emulator->loadROM(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOS_EXPORT void iosSetOutputSize(uint32_t width, uint32_t height) {
|
||||||
|
emulator->setOutputSize(width, height);
|
||||||
}
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Foundation/Foundation.h>
|
#include <Foundation/Foundation.h>
|
||||||
#include <QuartzCore/QuartzCore.h>
|
#include <QuartzCore/QuartzCore.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void iosCreateEmulator();
|
void iosCreateEmulator();
|
||||||
void iosLoadROM(NSString* pathNS);
|
void iosLoadROM(NSString* pathNS);
|
||||||
void iosRunFrame(CAMetalLayer* layer);
|
void iosRunFrame(CAMetalLayer* layer);
|
||||||
|
void iosSetOutputSize(uint32_t width, uint32_t height);
|
Binary file not shown.
|
@ -3,27 +3,42 @@ import SwiftUI
|
||||||
import MetalKit
|
import MetalKit
|
||||||
import Darwin
|
import Darwin
|
||||||
|
|
||||||
|
final class DrawableSize {
|
||||||
|
var width: UInt32 = 0
|
||||||
|
var height: UInt32 = 0
|
||||||
|
var sizeChanged = false
|
||||||
|
}
|
||||||
|
|
||||||
var emulatorLock = NSLock()
|
var emulatorLock = NSLock()
|
||||||
|
var drawableSize = DrawableSize()
|
||||||
|
|
||||||
|
class ResizeAwareMTKView: MTKView {
|
||||||
|
var onResize: ((CGSize) -> Void)?
|
||||||
|
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
onResize?(self.drawableSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DocumentViewController: UIViewController, DocumentDelegate {
|
class DocumentViewController: UIViewController, DocumentDelegate {
|
||||||
var documentPicker: DocumentPicker!
|
var documentPicker: DocumentPicker!
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
/// set up the document picker
|
|
||||||
documentPicker = DocumentPicker(presentationController: self, delegate: self)
|
documentPicker = DocumentPicker(presentationController: self, delegate: self)
|
||||||
/// When the view loads (ie user opens the app) show the file picker
|
/// When the view loads (ie user opens the app) show the file picker
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// callback from the document picker
|
/// Callback from the document picker
|
||||||
func didPickDocument(document: Document?) {
|
func didPickDocument(document: Document?) {
|
||||||
if let pickedDoc = document {
|
if let pickedDoc = document {
|
||||||
let fileURL = pickedDoc.fileURL
|
let fileURL = pickedDoc.fileURL
|
||||||
|
|
||||||
print("Loading ROM", fileURL)
|
print("Loading ROM", fileURL)
|
||||||
emulatorLock.lock()
|
emulatorLock.lock()
|
||||||
|
print(fileURL.path(percentEncoded: false))
|
||||||
iosLoadROM(fileURL.path(percentEncoded: false))
|
iosLoadROM(fileURL.path(percentEncoded: false))
|
||||||
emulatorLock.unlock()
|
emulatorLock.unlock()
|
||||||
}
|
}
|
||||||
|
@ -36,25 +51,15 @@ class DocumentViewController: UIViewController, DocumentDelegate {
|
||||||
|
|
||||||
struct DocumentView: UIViewControllerRepresentable {
|
struct DocumentView: UIViewControllerRepresentable {
|
||||||
func makeUIViewController(context: Context) -> DocumentViewController {
|
func makeUIViewController(context: Context) -> DocumentViewController {
|
||||||
return DocumentViewController()
|
DocumentViewController()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIViewController(_ uiViewController: DocumentViewController, context: Context) {
|
func updateUIViewController(_ uiViewController: DocumentViewController, context: Context) {}
|
||||||
// No update needed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentView: UIViewRepresentable {
|
struct ContentView: UIViewRepresentable {
|
||||||
@State var showFileImporter = true
|
func makeUIView(context: Context) -> ResizeAwareMTKView {
|
||||||
|
let mtkView = ResizeAwareMTKView()
|
||||||
/*
|
|
||||||
func makeCoordinator() -> Renderer {
|
|
||||||
Renderer(self)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func makeUIView(context: UIViewRepresentableContext<ContentView>) -> MTKView {
|
|
||||||
let mtkView = MTKView()
|
|
||||||
mtkView.preferredFramesPerSecond = 60
|
mtkView.preferredFramesPerSecond = 60
|
||||||
mtkView.enableSetNeedsDisplay = true
|
mtkView.enableSetNeedsDisplay = true
|
||||||
mtkView.isPaused = true
|
mtkView.isPaused = true
|
||||||
|
@ -64,17 +69,34 @@ struct ContentView: UIViewRepresentable {
|
||||||
}
|
}
|
||||||
|
|
||||||
mtkView.framebufferOnly = false
|
mtkView.framebufferOnly = false
|
||||||
mtkView.drawableSize = mtkView.frame.size
|
|
||||||
|
mtkView.onResize = { newDrawableSize in
|
||||||
|
let newWidth = UInt32(newDrawableSize.width)
|
||||||
|
let newHeight = UInt32(newDrawableSize.height)
|
||||||
|
|
||||||
|
emulatorLock.lock()
|
||||||
|
if drawableSize.width != newWidth || drawableSize.height != newHeight {
|
||||||
|
drawableSize.width = newWidth
|
||||||
|
drawableSize.height = newHeight
|
||||||
|
drawableSize.sizeChanged = true
|
||||||
|
}
|
||||||
|
emulatorLock.unlock()
|
||||||
|
}
|
||||||
|
|
||||||
let dispatchQueue = DispatchQueue(label: "QueueIdentification", qos: .background)
|
let dispatchQueue = DispatchQueue(label: "QueueIdentification", qos: .background)
|
||||||
let metalLayer = mtkView.layer as! CAMetalLayer;
|
let metalLayer = mtkView.layer as! CAMetalLayer
|
||||||
|
|
||||||
dispatchQueue.async{
|
dispatchQueue.async {
|
||||||
iosCreateEmulator()
|
iosCreateEmulator()
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
emulatorLock.lock()
|
emulatorLock.lock()
|
||||||
iosRunFrame(metalLayer);
|
if drawableSize.sizeChanged {
|
||||||
|
drawableSize.sizeChanged = false
|
||||||
|
iosSetOutputSize(drawableSize.width, drawableSize.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
iosRunFrame(metalLayer)
|
||||||
emulatorLock.unlock()
|
emulatorLock.unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,14 +104,13 @@ struct ContentView: UIViewRepresentable {
|
||||||
return mtkView
|
return mtkView
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIView(_ uiView: MTKView, context: UIViewRepresentableContext<ContentView>) {
|
func updateUIView(_ uiView: ResizeAwareMTKView, context: Context) {}
|
||||||
print("Updating MTKView");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
struct ContentView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
DocumentView();
|
DocumentView()
|
||||||
ContentView();
|
ContentView()
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue