mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-09-12 20:42:00 +00:00
Merge branch 'master' into preempt-threads
This commit is contained in:
commit
5bdaa1f04f
28 changed files with 196 additions and 77 deletions
4
.github/workflows/Android_Build.yml
vendored
4
.github/workflows/Android_Build.yml
vendored
|
@ -39,7 +39,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
2
.github/workflows/HTTP_Build.yml
vendored
2
.github/workflows/HTTP_Build.yml
vendored
|
@ -32,7 +32,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
8
.github/workflows/Hydra_Build.yml
vendored
8
.github/workflows/Hydra_Build.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
2
.github/workflows/Linux_AppImage_Build.yml
vendored
2
.github/workflows/Linux_AppImage_Build.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
2
.github/workflows/Linux_Build.yml
vendored
2
.github/workflows/Linux_Build.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
2
.github/workflows/MacOS_Build.yml
vendored
2
.github/workflows/MacOS_Build.yml
vendored
|
@ -27,7 +27,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
6
.github/workflows/Qt_Build.yml
vendored
6
.github/workflows/Qt_Build.yml
vendored
|
@ -28,7 +28,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
2
.github/workflows/Windows_Build.yml
vendored
2
.github/workflows/Windows_Build.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
2
.github/workflows/iOS_Build.yml
vendored
2
.github/workflows/iOS_Build.yml
vendored
|
@ -31,7 +31,7 @@ jobs:
|
||||||
- name: Setup Vulkan SDK
|
- name: Setup Vulkan SDK
|
||||||
uses: humbletim/setup-vulkan-sdk@main
|
uses: humbletim/setup-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
vulkan-query-version: 1.3.296.0
|
vulkan-query-version: latest
|
||||||
vulkan-use-cache: true
|
vulkan-use-cache: true
|
||||||
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang
|
||||||
|
|
||||||
|
|
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -70,3 +70,12 @@ fb.bat
|
||||||
|
|
||||||
config.toml
|
config.toml
|
||||||
CMakeSettings.json
|
CMakeSettings.json
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
|
||||||
|
# KDevelop files
|
||||||
|
*.kdev4
|
||||||
|
# IDEA/Clion files
|
||||||
|
.idea/
|
||||||
|
# VSC files
|
||||||
|
/.vscode/
|
|
@ -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);
|
|
@ -53,10 +53,12 @@ class Renderer {
|
||||||
|
|
||||||
// Should hw renderers hash textures? Stored separately from emulatorConfig because we'll be accessing it constantly, might be merged eventually
|
// Should hw renderers hash textures? Stored separately from emulatorConfig because we'll be accessing it constantly, might be merged eventually
|
||||||
bool hashTextures = false;
|
bool hashTextures = false;
|
||||||
|
bool outputSizeChanged = true;
|
||||||
|
|
||||||
EmulatorConfig* emulatorConfig = nullptr;
|
EmulatorConfig* emulatorConfig = nullptr;
|
||||||
|
|
||||||
void doSoftwareTextureCopy(u32 inputAddr, u32 outputAddr, u32 copySize, u32 inputWidth, u32 inputGap, u32 outputWidth, u32 outputGap);
|
void doSoftwareTextureCopy(u32 inputAddr, u32 outputAddr, u32 copySize, u32 inputWidth, u32 inputGap, u32 outputWidth, u32 outputGap);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Renderer(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs);
|
Renderer(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs);
|
||||||
virtual ~Renderer();
|
virtual ~Renderer();
|
||||||
|
@ -121,6 +123,7 @@ class Renderer {
|
||||||
void setDepthBufferLoc(u32 loc) { depthBufferLoc = loc; }
|
void setDepthBufferLoc(u32 loc) { depthBufferLoc = loc; }
|
||||||
|
|
||||||
void setOutputSize(u32 width, u32 height) {
|
void setOutputSize(u32 width, u32 height) {
|
||||||
|
outputSizeChanged = true;
|
||||||
outputWindowWidth = width;
|
outputWindowWidth = width;
|
||||||
outputWindowHeight = height;
|
outputWindowHeight = height;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ class RendererGL final : public Renderer {
|
||||||
OpenGL::VertexArray hwShaderVAO;
|
OpenGL::VertexArray hwShaderVAO;
|
||||||
OpenGL::VertexBuffer vbo;
|
OpenGL::VertexBuffer vbo;
|
||||||
|
|
||||||
// Data
|
// Data that will be uploaded to the ubershader
|
||||||
struct {
|
struct {
|
||||||
// TEV configuration uniform locations
|
// TEV configuration uniform locations
|
||||||
GLint textureEnvSourceLoc = -1;
|
GLint textureEnvSourceLoc = -1;
|
||||||
|
@ -146,6 +146,15 @@ class RendererGL final : public Renderer {
|
||||||
PICA::ShaderGen::FragmentGenerator fragShaderGen;
|
PICA::ShaderGen::FragmentGenerator fragShaderGen;
|
||||||
OpenGL::Driver driverInfo;
|
OpenGL::Driver driverInfo;
|
||||||
|
|
||||||
|
// Information about the final 3DS screen -> Window blit, accounting for things like scaling and shifting the output based on
|
||||||
|
// the window's dimensions.
|
||||||
|
struct {
|
||||||
|
int destX = 0;
|
||||||
|
int destY = 0;
|
||||||
|
int destWidth = 400;
|
||||||
|
int destHeight = 480;
|
||||||
|
} blitInfo;
|
||||||
|
|
||||||
MAKE_LOG_FUNCTION(log, rendererLogger)
|
MAKE_LOG_FUNCTION(log, rendererLogger)
|
||||||
void setupBlending();
|
void setupBlending();
|
||||||
void setupStencilTest(bool stencilEnable);
|
void setupStencilTest(bool stencilEnable);
|
||||||
|
|
|
@ -88,6 +88,16 @@ class RendererMTL final : public Renderer {
|
||||||
MTL::Texture* lastColorTexture = nullptr;
|
MTL::Texture* lastColorTexture = nullptr;
|
||||||
MTL::Texture* lastDepthTexture = nullptr;
|
MTL::Texture* lastDepthTexture = nullptr;
|
||||||
|
|
||||||
|
// Information about the final 3DS screen -> Window blit, accounting for things like scaling and shifting the output based on
|
||||||
|
// the window's dimensions.
|
||||||
|
struct {
|
||||||
|
float topScreenX = 0;
|
||||||
|
float topScreenY = 0;
|
||||||
|
float bottomScreenX = 40;
|
||||||
|
float bottomScreenY = 240;
|
||||||
|
float scale = 1.0;
|
||||||
|
} blitInfo;
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
std::string nextRenderPassName;
|
std::string nextRenderPassName;
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(
|
VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType,
|
vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity, vk::DebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData
|
const vk::DebugUtilsMessengerCallbackDataEXT* callbackData, void* userData
|
||||||
);
|
);
|
||||||
|
|
||||||
void setObjectName(vk::Device device, vk::ObjectType objectType, const void* objectHandle, const char* format, ...);
|
void setObjectName(vk::Device device, vk::ObjectType objectType, const void* objectHandle, const char* format, ...);
|
||||||
|
|
|
@ -27,6 +27,7 @@ static constexpr Xmm scratch2 = xmm1;
|
||||||
static constexpr Xmm src1_xmm = xmm2;
|
static constexpr Xmm src1_xmm = xmm2;
|
||||||
static constexpr Xmm src2_xmm = xmm3;
|
static constexpr Xmm src2_xmm = xmm3;
|
||||||
static constexpr Xmm src3_xmm = xmm4;
|
static constexpr Xmm src3_xmm = xmm4;
|
||||||
|
static constexpr Xmm scratch3 = xmm5;
|
||||||
|
|
||||||
#if defined(PANDA3DS_MS_ABI)
|
#if defined(PANDA3DS_MS_ABI)
|
||||||
// Register that points to PICA state. Must be volatile for the aforementioned reasons
|
// Register that points to PICA state. Must be volatile for the aforementioned reasons
|
||||||
|
@ -382,20 +383,12 @@ void ShaderEmitter::storeRegister(Xmm source, const PICAShader& shader, u32 dest
|
||||||
(((writeMask & 0b0010) ? 0 : 1) << 4) |
|
(((writeMask & 0b0010) ? 0 : 1) << 4) |
|
||||||
(((writeMask & 0b0001) ? 2 : 3) << 6);
|
(((writeMask & 0b0001) ? 2 : 3) << 6);
|
||||||
|
|
||||||
// Reorder instructions based on whether the source == scratch1. This is to avoid overwriting scratch1 if it's the source,
|
movaps(scratch3, xword[statePointer + offset]);
|
||||||
// While also having the memory load come first to mitigate execution hazards and give the load more time to complete before reading if possible
|
movaps(scratch2, source);
|
||||||
if (source != scratch1) {
|
unpckhps(scratch2, scratch3); // Unpack X/Y components of source and destination
|
||||||
movaps(scratch1, xword[statePointer + offset]);
|
unpcklps(scratch3, source); // Unpack Z/W components of source and destination
|
||||||
movaps(scratch2, source);
|
shufps(scratch3, scratch2, selector); // "merge-shuffle" dest and source using selecto
|
||||||
} else {
|
movaps(xword[statePointer + offset], scratch3); // Write back
|
||||||
movaps(scratch2, source);
|
|
||||||
movaps(scratch1, xword[statePointer + offset]);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpckhps(scratch2, scratch1); // Unpack X/Y components of source and destination
|
|
||||||
unpcklps(scratch1, source); // Unpack Z/W components of source and destination
|
|
||||||
shufps(scratch1, scratch2, selector); // "merge-shuffle" dest and source using selecto
|
|
||||||
movaps(xword[statePointer + offset], scratch1); // Write back
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ namespace FileOps {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::handleFileOperation(u32 messagePointer, Handle file) {
|
void Kernel::handleFileOperation(u32 messagePointer, Handle file) {
|
||||||
const u32 cmd = mem.read32(messagePointer);
|
const u32 cmd = mem.read32(messagePointer);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
@ -89,6 +88,7 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
|
||||||
if (file->fd) {
|
if (file->fd) {
|
||||||
std::unique_ptr<u8[]> data(new u8[size]);
|
std::unique_ptr<u8[]> data(new u8[size]);
|
||||||
IOFile f(file->fd);
|
IOFile f(file->fd);
|
||||||
|
f.seek(offset);
|
||||||
|
|
||||||
auto [success, bytesRead] = f.readBytes(data.get(), size);
|
auto [success, bytesRead] = f.readBytes(data.get(), size);
|
||||||
|
|
||||||
|
@ -146,6 +146,7 @@ void Kernel::writeFile(u32 messagePointer, Handle fileHandle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IOFile f(file->fd);
|
IOFile f(file->fd);
|
||||||
|
f.seek(offset);
|
||||||
auto [success, bytesWritten] = f.writeBytes(data.get(), size);
|
auto [success, bytesWritten] = f.writeBytes(data.get(), size);
|
||||||
|
|
||||||
// TODO: Should this check only the byte?
|
// TODO: Should this check only the byte?
|
||||||
|
|
|
@ -582,7 +582,33 @@ void RendererGL::display() {
|
||||||
if constexpr (!Helpers::isHydraCore()) {
|
if constexpr (!Helpers::isHydraCore()) {
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
screenFramebuffer.bind(OpenGL::ReadFramebuffer);
|
screenFramebuffer.bind(OpenGL::ReadFramebuffer);
|
||||||
glBlitFramebuffer(0, 0, 400, 480, 0, 0, outputWindowWidth, outputWindowHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
||||||
|
if (outputSizeChanged) {
|
||||||
|
outputSizeChanged = false;
|
||||||
|
|
||||||
|
const float srcAspect = 400.0f / 480.0f; // 3DS aspect ratio
|
||||||
|
const float dstAspect = float(outputWindowWidth) / float(outputWindowHeight);
|
||||||
|
|
||||||
|
blitInfo.destWidth = outputWindowWidth;
|
||||||
|
blitInfo.destHeight = outputWindowHeight;
|
||||||
|
blitInfo.destX = 0;
|
||||||
|
blitInfo.destY = 0;
|
||||||
|
|
||||||
|
if (dstAspect > srcAspect) {
|
||||||
|
// Window is wider than source
|
||||||
|
blitInfo.destWidth = int(outputWindowHeight * srcAspect + 0.5f);
|
||||||
|
blitInfo.destX = (outputWindowWidth - blitInfo.destWidth) / 2;
|
||||||
|
} else {
|
||||||
|
// Window is taller than source
|
||||||
|
blitInfo.destHeight = int(outputWindowWidth / srcAspect + 0.5f);
|
||||||
|
blitInfo.destY = (outputWindowHeight - blitInfo.destHeight) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glBlitFramebuffer(
|
||||||
|
0, 0, 400, 480, blitInfo.destX, blitInfo.destY, blitInfo.destX + blitInfo.destWidth, blitInfo.destY + blitInfo.destHeight,
|
||||||
|
GL_COLOR_BUFFER_BIT, GL_LINEAR
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -103,16 +103,44 @@ void RendererMTL::display() {
|
||||||
renderCommandEncoder->setRenderPipelineState(displayPipeline);
|
renderCommandEncoder->setRenderPipelineState(displayPipeline);
|
||||||
renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0);
|
renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0);
|
||||||
|
|
||||||
|
if (outputSizeChanged) {
|
||||||
|
outputSizeChanged = false;
|
||||||
|
|
||||||
|
const float srcAspect = 400.0 / 480.0;
|
||||||
|
const float destAspect = float(outputWindowWidth) / float(outputWindowHeight);
|
||||||
|
int destX = 0, destY = 0, destWidth = outputWindowWidth, destHeight = outputWindowHeight;
|
||||||
|
|
||||||
|
if (destAspect > srcAspect) {
|
||||||
|
// Window is wider than source
|
||||||
|
destWidth = int(outputWindowHeight * srcAspect + 0.5f);
|
||||||
|
destX = (outputWindowWidth - destWidth) / 2;
|
||||||
|
} else {
|
||||||
|
// Window is taller than source
|
||||||
|
destHeight = int(outputWindowWidth / srcAspect + 0.5f);
|
||||||
|
destY = (outputWindowHeight - destHeight) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
blitInfo.scale = float(destWidth) / 400.0f;
|
||||||
|
blitInfo.topScreenX = float(destX);
|
||||||
|
blitInfo.topScreenY = float(destY + (destHeight - int(480 * blitInfo.scale)) / 2);
|
||||||
|
blitInfo.bottomScreenX = float(destX) + 40 * blitInfo.scale;
|
||||||
|
blitInfo.bottomScreenY = blitInfo.topScreenY + 240 * blitInfo.scale;
|
||||||
|
}
|
||||||
|
|
||||||
// Top screen
|
// Top screen
|
||||||
if (topScreen) {
|
if (topScreen) {
|
||||||
renderCommandEncoder->setViewport(MTL::Viewport{0, 0, 400, 240, 0.0f, 1.0f});
|
renderCommandEncoder->setViewport(
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom screen
|
// Bottom screen
|
||||||
if (bottomScreen) {
|
if (bottomScreen) {
|
||||||
renderCommandEncoder->setViewport(MTL::Viewport{40, 240, 320, 240, 0.0f, 1.0f});
|
renderCommandEncoder->setViewport(
|
||||||
|
MTL::Viewport{blitInfo.bottomScreenX, blitInfo.bottomScreenY, 320 * blitInfo.scale, 240 * blitInfo.scale, 0.0f, 1.0f}
|
||||||
|
);
|
||||||
renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0);
|
renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0);
|
||||||
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,8 @@ namespace Vulkan {
|
||||||
}
|
}
|
||||||
|
|
||||||
VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(
|
VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType,
|
vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity, vk::DebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData
|
const vk::DebugUtilsMessengerCallbackDataEXT* callbackData, void* userData
|
||||||
) {
|
) {
|
||||||
debugMessageCallback(
|
debugMessageCallback(
|
||||||
vk::DebugUtilsMessageSeverityFlagBitsEXT(messageSeverity), vk::DebugUtilsMessageTypeFlagsEXT(messageType), *callbackData
|
vk::DebugUtilsMessageSeverityFlagBitsEXT(messageSeverity), vk::DebugUtilsMessageTypeFlagsEXT(messageType), *callbackData
|
||||||
|
@ -70,7 +70,7 @@ namespace Vulkan {
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GPU_DEBUG_INFO
|
#ifdef GPU_DEBUG_INFO
|
||||||
void setObjectName(vk::Device device, vk::ObjectType objectType, const void* objectHandle, const char* format, ...) {
|
void setObjectName(vk::Device device, vk::ObjectType objectType, const void* objectHandle, const char* format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
|
@ -66,7 +66,10 @@ void GPUService::handleSyncRequest(u32 messagePointer) {
|
||||||
case ServiceCommands::WriteHwRegs: writeHwRegs(messagePointer); break;
|
case ServiceCommands::WriteHwRegs: writeHwRegs(messagePointer); break;
|
||||||
case ServiceCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break;
|
case ServiceCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break;
|
||||||
case ServiceCommands::InvalidateDataCache: invalidateDataCache(messagePointer); break;
|
case ServiceCommands::InvalidateDataCache: invalidateDataCache(messagePointer); break;
|
||||||
default: Helpers::panic("GPU service requested. Command: %08X\n", command);
|
default:
|
||||||
|
Helpers::warn("GPU service requested. Command: %08X\n", command);
|
||||||
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -415,9 +415,8 @@ void MainWindow::dispatchMessage(const EmulatorMessage& message) {
|
||||||
case MessageType::SetScreenSize: {
|
case MessageType::SetScreenSize: {
|
||||||
const u32 width = message.screenSize.width;
|
const u32 width = message.screenSize.width;
|
||||||
const u32 height = message.screenSize.height;
|
const u32 height = message.screenSize.height;
|
||||||
|
|
||||||
emu->setOutputSize(width, height);
|
|
||||||
screen->resizeSurface(width, height);
|
screen->resizeSurface(width, height);
|
||||||
|
emu->setOutputSize(width, height);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,7 +565,10 @@ void MainWindow::handleScreenResize(u32 width, u32 height) {
|
||||||
message.screenSize.width = width;
|
message.screenSize.width = width;
|
||||||
message.screenSize.height = height;
|
message.screenSize.height = height;
|
||||||
|
|
||||||
sendMessage(message);
|
if (messageQueueMutex.try_lock()) {
|
||||||
|
messageQueue.push_back(message);
|
||||||
|
messageQueueMutex.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::initControllers() {
|
void MainWindow::initControllers() {
|
||||||
|
|
|
@ -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,21 +3,35 @@ 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
|
||||||
|
@ -28,7 +42,7 @@ class DocumentViewController: UIViewController, DocumentDelegate {
|
||||||
emulatorLock.unlock()
|
emulatorLock.unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func show() {
|
func show() {
|
||||||
documentPicker.displayPicker()
|
documentPicker.displayPicker()
|
||||||
}
|
}
|
||||||
|
@ -36,25 +50,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) {
|
|
||||||
// No update needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateUIViewController(_ uiViewController: DocumentViewController, context: Context) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -65,16 +69,34 @@ struct ContentView: UIViewRepresentable {
|
||||||
|
|
||||||
mtkView.framebufferOnly = false
|
mtkView.framebufferOnly = false
|
||||||
mtkView.drawableSize = mtkView.frame.size
|
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