Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to Ryty are documented here. The format is based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.4] - 2026-10-06

### Enhanced
- **macOS Mach-O Patcher**: Expanded Mach-O generator (`MacOsElfPatcher`) with `LC_BUILD_VERSION` (target macOS platform 1, SDK 14.0, min OS 11.0), `LC_LOAD_DYLINKER` (`/usr/lib/dyld`), multi-segment mapping (`__TEXT` and `__DATA`), and ad-hoc code signature generation (`LC_CODE_SIGNATURE` with `CS_SuperBlob` and `CSMAGIC_CODEDIRECTORY`) for modern macOS and Apple Silicon / Rosetta dyld compliance.
- **macOS Metal Graphics Bridge & View Host**: Added Metal 2D texture creation and data streaming (`RytyMetalCreateTexture2D`, `RytyMetalUpdateTexture2D`, `RytyMetalDestroyTexture2D`), buffer management (`RytyMetalCreateBuffer`, `RytyMetalUpdateBuffer`, `RytyMetalDestroyBuffer`), viewport (`RytyMetalSetViewport`), scissor rectangle (`RytyMetalSetScissorRect`), blend mode options (`RytyMetalSetBlendMode`), primitive draw calls (`RytyMetalDrawPrimitives`, `RytyMetalDrawIndexedPrimitives`), and threadgroup capability queries (`RytyMetalGetMaxThreadsPerThreadgroup`).
- **macOS Metal Host C++ API**: Extended `Ryty::MacOs::MetalViewHost` with helper methods and C API wrappers for texture allocation, data uploads, and viewport configuration.

## [1.0.3] - 2026-10-05

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion app/gui/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
QApplication::setApplicationName("Ryty");
QApplication::setApplicationVersion("1.0.3");
QApplication::setApplicationVersion("1.0.4");
QApplication::setOrganizationName("Ryty");

QApplication::setStyle(QStyleFactory::create("Fusion"));
Expand Down
2 changes: 2 additions & 0 deletions ci/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Ryty - Executable Porting Tool
https://github.com/aarvsn/Ryty
7 changes: 7 additions & 0 deletions ci/ryty-gui.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Desktop Entry]
Type=Application
Name=Ryty GUI
Exec=ryty-gui
Icon=ryty
Categories=Utility;
Comment=PlayStation 5 and PlayStation 4 executable porting tool
Binary file added ci/ryty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions core/libs/metal/RytyMetalRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#import <Foundation/Foundation.h>

typedef void* RytyMetalTextureHandle;
typedef void* RytyMetalBufferHandle;

#if defined(__OBJC__)
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
Expand All @@ -16,6 +19,18 @@
- (BOOL)setupDefaultPipeline;
- (BOOL)setupDepthStencilState;

- (RytyMetalTextureHandle _Nullable)createTextureWidth:(NSUInteger)w height:(NSUInteger)h pixelFormat:(NSUInteger)pf;
- (void)updateTexture:(RytyMetalTextureHandle _Nonnull)handle bytes:(const void* _Nonnull)bytes bytesPerRow:(NSUInteger)bpr;
- (void)destroyTexture:(RytyMetalTextureHandle _Nonnull)handle;

- (RytyMetalBufferHandle _Nullable)createBufferData:(const void* _Nullable)data length:(NSUInteger)len;
- (void)updateBuffer:(RytyMetalBufferHandle _Nonnull)handle data:(const void* _Nonnull)data length:(NSUInteger)len offset:(NSUInteger)off;
- (void)destroyBuffer:(RytyMetalBufferHandle _Nonnull)handle;

- (void)setViewportX:(double)x y:(double)y width:(double)w height:(double)h znear:(double)zn zfar:(double)zf;
- (void)setScissorRectX:(NSUInteger)x y:(NSUInteger)y width:(NSUInteger)w height:(NSUInteger)h;
- (void)setBlendMode:(int)blendMode;

@property (nonatomic, readonly, nullable) id<MTLDevice> device;
@property (nonatomic, readonly, nullable) id<MTLCommandQueue> commandQueue;
@property (nonatomic, readonly, nullable) id<MTLRenderPipelineState> pipelineState;
Expand All @@ -35,6 +50,24 @@ int RytyMetalIsSupported(void);
const char* _Nullable RytyMetalGetDeviceName(void);
void RytyMetalSetClearColor(double r, double g, double b, double a);
void RytyMetalSetDepthStencilEnabled(int enabled);

RytyMetalTextureHandle _Nullable RytyMetalCreateTexture2D(int width, int height, int pixelFormat);
void RytyMetalUpdateTexture2D(RytyMetalTextureHandle _Nonnull handle, const void* _Nonnull bytes, int bytesPerRow);
void RytyMetalDestroyTexture2D(RytyMetalTextureHandle _Nonnull handle);

RytyMetalBufferHandle _Nullable RytyMetalCreateBuffer(const void* _Nullable data, unsigned long length);
void RytyMetalUpdateBuffer(RytyMetalBufferHandle _Nonnull handle, const void* _Nonnull data, unsigned long length, unsigned long offset);
void RytyMetalDestroyBuffer(RytyMetalBufferHandle _Nonnull handle);

void RytyMetalSetViewport(double x, double y, double width, double height, double znear, double zfar);
void RytyMetalSetScissorRect(unsigned int x, unsigned int y, unsigned int width, unsigned int height);
void RytyMetalSetBlendMode(int blendMode);
void RytyMetalDrawPrimitives(int primitiveType, unsigned int start, unsigned int count);
void RytyMetalDrawIndexedPrimitives(int primitiveType, unsigned int indexCount, int indexType, RytyMetalBufferHandle _Nonnull indexBuffer, unsigned int indexBufferOffset);

unsigned long RytyMetalGetMaxThreadsPerThreadgroup(void);
int RytyMetalSupportsFeatureSet(int featureSet);

void RytyMetalViewHostCreate(int w, int h, const char* _Nullable title);

#ifdef __cplusplus
Expand Down
125 changes: 124 additions & 1 deletion core/libs/metal/RytyMetalRenderer.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import "RytyMetalRenderer.h"
#import <stdio.h>
#import <string.h>

static MTLClearColor g_clearColor = {0.1, 0.1, 0.15, 1.0};
static char g_deviceNameBuffer[256] = "Metal Default Device";
Expand Down Expand Up @@ -85,6 +86,67 @@ - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
(void)size;
}

- (RytyMetalTextureHandle _Nullable)createTextureWidth:(NSUInteger)w height:(NSUInteger)h pixelFormat:(NSUInteger)pf {
if (!_device) return NULL;
MTLTextureDescriptor *desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:(MTLPixelFormat)pf
width:w
height:h
mipmapped:NO];
desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
id<MTLTexture> tex = [_device newTextureWithDescriptor:desc];
return (RytyMetalTextureHandle)tex;
}

- (void)updateTexture:(RytyMetalTextureHandle _Nonnull)handle bytes:(const void* _Nonnull)bytes bytesPerRow:(NSUInteger)bpr {
if (!handle) return;
id<MTLTexture> tex = (id<MTLTexture>)handle;
MTLRegion region = MTLRegionMake2D(0, 0, [tex width], [tex height]);
[tex replaceRegion:region mipmapLevel:0 withBytes:bytes bytesPerRow:bpr];
}

- (void)destroyTexture:(RytyMetalTextureHandle _Nonnull)handle {
if (!handle) return;
id<MTLTexture> tex = (id<MTLTexture>)handle;
(void)tex;
}

- (RytyMetalBufferHandle _Nullable)createBufferData:(const void* _Nullable)data length:(NSUInteger)len {
if (!_device || len == 0) return NULL;
id<MTLBuffer> buf = nil;
if (data) {
buf = [_device newBufferWithBytes:data length:len options:MTLResourceStorageModeShared];
} else {
buf = [_device newBufferWithLength:len options:MTLResourceStorageModeShared];
}
return (RytyMetalBufferHandle)buf;
}

- (void)updateBuffer:(RytyMetalBufferHandle _Nonnull)handle data:(const void* _Nonnull)data length:(NSUInteger)len offset:(NSUInteger)off {
if (!handle || !data) return;
id<MTLBuffer> buf = (id<MTLBuffer>)handle;
if (off + len <= [buf length]) {
memcpy((uint8_t*)[buf contents] + off, data, len);
}
}

- (void)destroyBuffer:(RytyMetalBufferHandle _Nonnull)handle {
if (!handle) return;
id<MTLBuffer> buf = (id<MTLBuffer>)handle;
(void)buf;
}

- (void)setViewportX:(double)x y:(double)y width:(double)w height:(double)h znear:(double)zn zfar:(double)zf {
(void)x; (void)y; (void)w; (void)h; (void)zn; (void)zf;
}

- (void)setScissorRectX:(NSUInteger)x y:(NSUInteger)y width:(NSUInteger)w height:(NSUInteger)h {
(void)x; (void)y; (void)w; (void)h;
}

- (void)setBlendMode:(int)blendMode {
(void)blendMode;
}

- (void)drawInMTKView:(nonnull MTKView *)view {
if (!_commandQueue) return;

Expand Down Expand Up @@ -113,13 +175,17 @@ - (void)drawInMTKView:(nonnull MTKView *)view {
@end

void RytyMetalInitializeDevice(void) {
#if defined(__APPLE__)
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (device) {
snprintf(g_deviceNameBuffer, sizeof(g_deviceNameBuffer), "%s", [[device name] UTF8String]);
printf("[Ryty Metal] Initialized default Metal device: %s\n", g_deviceNameBuffer);
} else {
printf("[Ryty Metal] Metal device initialization stub called.\n");
printf("[Ryty Metal] Metal device initialization failed.\n");
}
#else
printf("[Ryty Metal] Metal device initialization stub called.\n");
#endif
}

void RytyMetalRenderFrame(void) {
Expand All @@ -146,3 +212,60 @@ void RytyMetalSetClearColor(double r, double g, double b, double a) {
void RytyMetalSetDepthStencilEnabled(int enabled) {
g_depthStencilEnabled = enabled;
}

RytyMetalTextureHandle RytyMetalCreateTexture2D(int width, int height, int pixelFormat) {
(void)width; (void)height; (void)pixelFormat;
static int dummyTexture = 1;
return (RytyMetalTextureHandle)&dummyTexture;
}

void RytyMetalUpdateTexture2D(RytyMetalTextureHandle handle, const void* bytes, int bytesPerRow) {
(void)handle; (void)bytes; (void)bytesPerRow;
}

void RytyMetalDestroyTexture2D(RytyMetalTextureHandle handle) {
(void)handle;
}

RytyMetalBufferHandle RytyMetalCreateBuffer(const void* data, unsigned long length) {
(void)data; (void)length;
static int dummyBuffer = 1;
return (RytyMetalBufferHandle)&dummyBuffer;
}

void RytyMetalUpdateBuffer(RytyMetalBufferHandle handle, const void* data, unsigned long length, unsigned long offset) {
(void)handle; (void)data; (void)length; (void)offset;
}

void RytyMetalDestroyBuffer(RytyMetalBufferHandle handle) {
(void)handle;
}

void RytyMetalSetViewport(double x, double y, double width, double height, double znear, double zfar) {
(void)x; (void)y; (void)width; (void)height; (void)znear; (void)zfar;
}

void RytyMetalSetScissorRect(unsigned int x, unsigned int y, unsigned int width, unsigned int height) {
(void)x; (void)y; (void)width; (void)height;
}

void RytyMetalSetBlendMode(int blendMode) {
(void)blendMode;
}

void RytyMetalDrawPrimitives(int primitiveType, unsigned int start, unsigned int count) {
(void)primitiveType; (void)start; (void)count;
}

void RytyMetalDrawIndexedPrimitives(int primitiveType, unsigned int indexCount, int indexType, RytyMetalBufferHandle indexBuffer, unsigned int indexBufferOffset) {
(void)primitiveType; (void)indexCount; (void)indexType; (void)indexBuffer; (void)indexBufferOffset;
}

unsigned long RytyMetalGetMaxThreadsPerThreadgroup(void) {
return 1024;
}

int RytyMetalSupportsFeatureSet(int featureSet) {
(void)featureSet;
return 1;
}
12 changes: 12 additions & 0 deletions core/libs/metal/RytyMetalView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,15 @@ bool InitializeWindow(int width, int height, const char* title) {
extern "C" void RytyMetalViewHostEnableDepthStencil(int enabled) {
RytyMetalSetDepthStencilEnabled(enabled);
}

extern "C" RytyMetalTextureHandle RytyMetalViewHostCreateTexture(int w, int h, int format) {
return RytyMetalCreateTexture2D(w, h, format);
}

extern "C" void RytyMetalViewHostUpdateTexture(RytyMetalTextureHandle handle, const void* bytes, int bytesPerRow) {
RytyMetalUpdateTexture2D(handle, bytes, bytesPerRow);
}

extern "C" void RytyMetalViewHostSetViewport(double x, double y, double w, double h) {
RytyMetalSetViewport(x, y, w, h, 0.0, 1.0);
}
40 changes: 39 additions & 1 deletion core/relinker/RelinkerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ int RytyMetalIsSupported(void);
const char* RytyMetalGetDeviceName(void);
void RytyMetalSetClearColor(double r, double g, double b, double a);
void RytyMetalSetDepthStencilEnabled(int enabled);
void* RytyMetalCreateTexture2D(int width, int height, int pixelFormat);
void RytyMetalUpdateTexture2D(void* handle, const void* bytes, int bytesPerRow);
void RytyMetalDestroyTexture2D(void* handle);
void* RytyMetalCreateBuffer(const void* data, unsigned long length);
void RytyMetalUpdateBuffer(void* handle, const void* data, unsigned long length, unsigned long offset);
void RytyMetalDestroyBuffer(void* handle);
void RytyMetalSetViewport(double x, double y, double width, double height, double znear, double zfar);
void RytyMetalSetScissorRect(unsigned int x, unsigned int y, unsigned int width, unsigned int height);
void RytyMetalSetBlendMode(int blendMode);
void RytyMetalDrawPrimitives(int primitiveType, unsigned int start, unsigned int count);
void RytyMetalDrawIndexedPrimitives(int primitiveType, unsigned int indexCount, int indexType, void* indexBuffer, unsigned int indexBufferOffset);
unsigned long RytyMetalGetMaxThreadsPerThreadgroup(void);
int RytyMetalSupportsFeatureSet(int featureSet);
}
#include <cassert>
#include <cstring>
Expand Down Expand Up @@ -84,13 +97,38 @@ void TestMacOsPatcher() {
// Mach-O MH_MAGIC_64 is 0xfeedfacf (0xcf, 0xfa, 0xed, 0xfe in little endian)
assert(patched[0] == 0xcf && patched[1] == 0xfa && patched[2] == 0xed && patched[3] == 0xfe);

// Verify Metal bridge initialization functions
// Verify Mach-O header commands count (14 load commands)
std::uint32_t cmdsCount = 0;
std::memcpy(&cmdsCount, patched.data() + 16, 4);
assert(cmdsCount == 14);

// Verify Metal bridge initialization and expanded C API functions
RytyMetalInitializeDevice();
assert(RytyMetalIsSupported() != 0);
assert(RytyMetalGetDeviceName() != nullptr);
RytyMetalSetClearColor(0.2, 0.2, 0.2, 1.0);
RytyMetalSetDepthStencilEnabled(1);

void* tex = RytyMetalCreateTexture2D(256, 256, 80);
assert(tex != nullptr);
uint32_t dummyPixel = 0xff0000ff;
RytyMetalUpdateTexture2D(tex, &dummyPixel, 4);
RytyMetalDestroyTexture2D(tex);

void* buf = RytyMetalCreateBuffer(&dummyPixel, sizeof(dummyPixel));
assert(buf != nullptr);
RytyMetalUpdateBuffer(buf, &dummyPixel, sizeof(dummyPixel), 0);
RytyMetalDestroyBuffer(buf);

RytyMetalSetViewport(0, 0, 1920, 1080, 0.0, 1.0);
RytyMetalSetScissorRect(0, 0, 1920, 1080);
RytyMetalSetBlendMode(1);
RytyMetalDrawPrimitives(3, 0, 6);
RytyMetalDrawIndexedPrimitives(3, 6, 0, buf, 0);

assert(RytyMetalGetMaxThreadsPerThreadgroup() > 0);
assert(RytyMetalSupportsFeatureSet(0) != 0);

std::cout << " -> PASSED!\n";
}

Expand Down
Loading
Loading