metal: Implement SDL_LockTexture for non-YUV textures.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m
index 6a31e2c..272ae6d 100644
--- a/src/render/metal/SDL_render_metal.m
+++ b/src/render/metal/SDL_render_metal.m
@@ -155,6 +155,9 @@ typedef struct METAL_ShaderPipelines
@property (nonatomic, assign) BOOL nv12;
@property (nonatomic, assign) size_t conversionBufferOffset;
@property (nonatomic, assign) BOOL hasdata;
+
+ @property (nonatomic, retain) id<MTLBuffer> lockedbuffer;
+ @property (nonatomic, assign) SDL_Rect lockedrect;
@end
@implementation METAL_TextureData
@@ -783,15 +786,72 @@ METAL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
static int
METAL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, void **pixels, int *pitch)
-{
- return SDL_Unsupported(); // !!! FIXME: write me
-}
+{ @autoreleasepool {
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
+
+ if (texturedata.yuv || texturedata.nv12) {
+ /* FIXME: write me */
+ return SDL_Unsupported();
+ }
+
+ *pitch = SDL_BYTESPERPIXEL(texture->format) * rect->w;
+
+ texturedata.lockedrect = *rect;
+ texturedata.lockedbuffer = [data.mtldevice newBufferWithLength:(*pitch)*rect->h options:MTLResourceStorageModeShared];
+ if (texturedata.lockedbuffer == nil) {
+ return SDL_OutOfMemory();
+ }
+
+ *pixels = [texturedata.lockedbuffer contents];
+
+ return 0;
+}}
static void
METAL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
-{
- // !!! FIXME: write me
-}
+{ @autoreleasepool {
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
+ SDL_Rect rect = texturedata.lockedrect;
+
+ if (texturedata.lockedbuffer == nil) {
+ return;
+ }
+
+ if (data.mtlcmdencoder != nil) {
+ [data.mtlcmdencoder endEncoding];
+ data.mtlcmdencoder = nil;
+ }
+
+ if (data.mtlcmdbuffer == nil) {
+ data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
+ }
+
+ id<MTLBlitCommandEncoder> blitcmd = [data.mtlcmdbuffer blitCommandEncoder];
+
+ [blitcmd copyFromBuffer:texturedata.lockedbuffer
+ sourceOffset:0
+ sourceBytesPerRow:SDL_BYTESPERPIXEL(texture->format) * rect.w
+ sourceBytesPerImage:0
+ sourceSize:MTLSizeMake(rect.w, rect.h, 1)
+ toTexture:texturedata.mtltexture
+ destinationSlice:0
+ destinationLevel:0
+ destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
+
+ [blitcmd endEncoding];
+
+ [data.mtlcmdbuffer commit];
+ data.mtlcmdbuffer = nil;
+
+#if !__has_feature(objc_arc)
+ [texturedata.lockedbuffer release];
+#endif
+
+ texturedata.lockedbuffer = nil;
+ texturedata.hasdata = YES;
+}}
static int
METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)