4#include <TargetConditionals.h>
5#import <CoreFoundation/CoreFoundation.h>
8#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
10#import <MetalKit/MetalKit.h>
24#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
25MTLPixelFormat GetMetalPixelFormatForSDL(uint32_t format) {
27 case SDL_PIXELFORMAT_ARGB8888:
28 case SDL_PIXELFORMAT_BGRA8888:
29 return MTLPixelFormatBGRA8Unorm;
30 case SDL_PIXELFORMAT_RGBA8888:
31 case SDL_PIXELFORMAT_ABGR8888:
32 return MTLPixelFormatRGBA8Unorm;
34 return MTLPixelFormatRGBA8Unorm;
38int BytesPerPixel(MTLPixelFormat format) {
40 case MTLPixelFormatBGRA8Unorm:
41 case MTLPixelFormatRGBA8Unorm:
57#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
59 LOG_WARN(
"MetalRenderer",
"Metal view not attached");
63 id<MTLDevice> device = view.device;
65 device = MTLCreateSystemDefaultDevice();
69 LOG_WARN(
"MetalRenderer",
"Failed to create Metal device");
73 id<MTLCommandQueue> queue = [device newCommandQueue];
91#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
97 id<MTLDevice> device = view.device;
99 device = MTLCreateSystemDefaultDevice();
100 view.device = device;
106#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
107 MTLPixelFormat default_format = MTLPixelFormatRGBA8Unorm;
109 MTLPixelFormat default_format = MTLPixelFormatBGRA8Unorm;
111 MTLTextureDescriptor* descriptor =
112 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:default_format
116 descriptor.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
117 descriptor.storageMode = MTLStorageModeShared;
119 id<MTLTexture> texture = [device newTextureWithDescriptor:descriptor];
120 return texture ? (__bridge_retained
void*)texture :
nullptr;
131#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
138 id<MTLDevice> device = view.device;
140 device = MTLCreateSystemDefaultDevice();
141 view.device = device;
147 MTLPixelFormat pixel_format = GetMetalPixelFormatForSDL(format);
148 MTLTextureDescriptor* descriptor =
149 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixel_format
153 descriptor.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
154 descriptor.storageMode = MTLStorageModeShared;
156 id<MTLTexture> texture = [device newTextureWithDescriptor:descriptor];
157 return texture ? (__bridge_retained
void*)texture :
nullptr;
166#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
171 SDL_Surface* surface = bitmap.
surface();
172 if (!surface || !surface->pixels || surface->w <= 0 || surface->h <= 0) {
176 id<MTLTexture> metal_texture = (__bridge id<MTLTexture>)texture;
177 const MTLPixelFormat pixel_format = metal_texture.pixelFormat;
180 uint32_t target_format = SDL_PIXELFORMAT_RGBA32;
181 if (pixel_format == MTLPixelFormatBGRA8Unorm) {
182 target_format = SDL_PIXELFORMAT_BGRA32;
185 auto converted_surface =
186 std::unique_ptr<SDL_Surface, util::SDL_Surface_Deleter>(
188 if (!converted_surface || !converted_surface->pixels) {
194 {
static_cast<NSUInteger
>(converted_surface->w),
195 static_cast<NSUInteger
>(converted_surface->h),
197 [metal_texture replaceRegion:region
199 withBytes:converted_surface->pixels
200 bytesPerRow:converted_surface->pitch];
215#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
223 void** pixels,
int* pitch) {
224#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
225 if (!texture || !pixels || !pitch) {
229 id<MTLTexture> metal_texture = (__bridge id<MTLTexture>)texture;
230 const int width =
static_cast<int>(metal_texture.width);
231 const int height =
static_cast<int>(metal_texture.height);
232 const int bytes_per_pixel = BytesPerPixel(metal_texture.pixelFormat);
233 const int row_pitch = width * bytes_per_pixel;
234 if (row_pitch <= 0 || height <= 0) {
239 staging.width = width;
240 staging.height = height;
241 staging.pitch = row_pitch;
242 staging.data.resize(
static_cast<size_t>(row_pitch) *
243 static_cast<size_t>(height));
252 *pixels = staging.data.data();
265#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
274 id<MTLTexture> metal_texture = (__bridge id<MTLTexture>)texture;
275 auto& staging = it->second;
276 if (staging.data.empty()) {
282 {
static_cast<NSUInteger
>(staging.width),
283 static_cast<NSUInteger
>(staging.height),
285 [metal_texture replaceRegion:region
287 withBytes:staging.data.data()
288 bytesPerRow:staging.pitch];
301 const SDL_Rect* dstrect) {
302#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
307 id<MTLTexture> source = (__bridge id<MTLTexture>)texture;
310 int src_x = srcrect ? srcrect->x : 0;
311 int src_y = srcrect ? srcrect->y : 0;
312 int src_w = srcrect ? srcrect->w :
static_cast<int>(source.width);
313 int src_h = srcrect ? srcrect->h :
static_cast<int>(source.height);
315 int dst_x = dstrect ? dstrect->x : 0;
316 int dst_y = dstrect ? dstrect->y : 0;
318 src_w = std::min(src_w,
static_cast<int>(source.width) - src_x);
319 src_h = std::min(src_h,
static_cast<int>(source.height) - src_y);
321 if (src_w <= 0 || src_h <= 0) {
325 MTLOrigin src_origin = {
static_cast<NSUInteger
>(src_x),
326 static_cast<NSUInteger
>(src_y),
328 MTLSize src_size = {
static_cast<NSUInteger
>(src_w),
329 static_cast<NSUInteger
>(src_h),
331 MTLOrigin dst_origin = {
static_cast<NSUInteger
>(dst_x),
332 static_cast<NSUInteger
>(dst_y),
335 id<MTLCommandQueue> queue = (__bridge id<MTLCommandQueue>)
command_queue_;
336 id<MTLCommandBuffer> command_buffer = [queue commandBuffer];
337 id<MTLBlitCommandEncoder> blit = [command_buffer blitCommandEncoder];
338 [blit copyFromTexture:source
341 sourceOrigin:src_origin
346 destinationOrigin:dst_origin];
348 [command_buffer commit];
349 [command_buffer waitUntilCompleted];
Represents a bitmap image optimized for SNES ROM hacking.
SDL_Surface * surface() const
#define LOG_WARN(category, format,...)
void * TextureHandle
An abstract handle representing a texture.
SDL2/SDL3 compatibility layer.