Skip to content

Latest commit

 

History

History
848 lines (726 loc) · 33.9 KB

SDL_render_metal.m

File metadata and controls

848 lines (726 loc) · 33.9 KB
 
1
2
/*
Simple DirectMedia Layer
Dec 8, 2017
Dec 8, 2017
3
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
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
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_RENDER_METAL && !SDL_RENDER_DISABLED
#include "SDL_hints.h"
#include "SDL_log.h"
#include "SDL_assert.h"
#include "SDL_syswm.h"
#include "../SDL_sysrender.h"
Dec 8, 2017
Dec 8, 2017
31
#ifdef __MACOSX__
32
#include <Cocoa/Cocoa.h>
Dec 8, 2017
Dec 8, 2017
33
34
35
#else
#include "../../video/uikit/SDL_uikitmetalview.h"
#endif
36
37
38
#include <Metal/Metal.h>
#include <QuartzCore/CAMetalLayer.h>
Dec 8, 2017
Dec 8, 2017
39
40
41
42
43
44
/* Regenerate these with build-metal-shaders.sh */
#ifdef __MACOSX__
#include "SDL_shaders_metal_osx.h"
#else
#include "SDL_shaders_metal_ios.h"
#endif
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
/* Apple Metal renderer implementation */
static SDL_Renderer *METAL_CreateRenderer(SDL_Window * window, Uint32 flags);
static void METAL_WindowEvent(SDL_Renderer * renderer,
const SDL_WindowEvent *event);
static int METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
static int METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static int METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels,
int pitch);
static int METAL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect,
const Uint8 *Yplane, int Ypitch,
const Uint8 *Uplane, int Upitch,
const Uint8 *Vplane, int Vpitch);
static int METAL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, void **pixels, int *pitch);
static void METAL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static int METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
static int METAL_UpdateViewport(SDL_Renderer * renderer);
static int METAL_UpdateClipRect(SDL_Renderer * renderer);
static int METAL_RenderClear(SDL_Renderer * renderer);
static int METAL_RenderDrawPoints(SDL_Renderer * renderer,
const SDL_FPoint * points, int count);
static int METAL_RenderDrawLines(SDL_Renderer * renderer,
const SDL_FPoint * points, int count);
static int METAL_RenderFillRects(SDL_Renderer * renderer,
const SDL_FRect * rects, int count);
static int METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect);
static int METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 pixel_format, void * pixels, int pitch);
static void METAL_RenderPresent(SDL_Renderer * renderer);
static void METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static void METAL_DestroyRenderer(SDL_Renderer * renderer);
Dec 8, 2017
Dec 8, 2017
84
85
static void *METAL_GetMetalLayer(SDL_Renderer * renderer);
static void *METAL_GetMetalCommandEncoder(SDL_Renderer * renderer);
86
87
88
89
90
91
92
93
SDL_RenderDriver METAL_RenderDriver = {
METAL_CreateRenderer,
{
"metal",
(SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
2,
{SDL_PIXELFORMAT_ARGB8888, SDL_PIXELFORMAT_ABGR8888},
Dec 9, 2017
Dec 9, 2017
94
95
96
97
98
// !!! FIXME: how do you query Metal for this?
// (the weakest GPU supported by Metal on iOS has 4k texture max, and
// other models might be 2x or 4x more. On macOS, it's 16k across the
// board right now.)
Dec 9, 2017
Dec 9, 2017
99
100
101
102
103
104
#ifdef __MACOSX__
16384, 16384
#else
4096, 4096
#endif
}
Dec 8, 2017
Dec 8, 2017
107
@interface METAL_RenderData : NSObject
Dec 8, 2017
Dec 8, 2017
108
109
110
111
112
113
114
115
@property (nonatomic, assign) BOOL beginScene;
@property (nonatomic, retain) id<MTLDevice> mtldevice;
@property (nonatomic, retain) id<MTLCommandQueue> mtlcmdqueue;
@property (nonatomic, retain) id<MTLCommandBuffer> mtlcmdbuffer;
@property (nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
@property (nonatomic, retain) id<MTLLibrary> mtllibrary;
@property (nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
@property (nonatomic, retain) NSMutableArray *mtlpipelineprims;
Dec 9, 2017
Dec 9, 2017
116
117
@property (nonatomic, retain) NSMutableArray *mtlpipelinecopynearest;
@property (nonatomic, retain) NSMutableArray *mtlpipelinecopylinear;
Dec 8, 2017
Dec 8, 2017
118
119
120
@property (nonatomic, retain) id<MTLBuffer> mtlbufclearverts;
@property (nonatomic, retain) CAMetalLayer *mtllayer;
@property (nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
Dec 8, 2017
Dec 8, 2017
121
122
123
124
@end
@implementation METAL_RenderData
@end
Dec 9, 2017
Dec 9, 2017
126
127
128
129
130
131
132
133
@interface METAL_TextureData : NSObject
@property (nonatomic, retain) id<MTLTexture> mtltexture;
@property (nonatomic, retain) NSMutableArray *mtlpipeline;
@end
@implementation METAL_TextureData
@end
134
135
136
static int
IsMetalAvailable(const SDL_SysWMinfo *syswm)
{
Dec 8, 2017
Dec 8, 2017
137
138
if (syswm->subsystem != SDL_SYSWM_COCOA && syswm->subsystem != SDL_SYSWM_UIKIT) {
return SDL_SetError("Metal render target only supports Cocoa and UIKit video targets at the moment.");
139
140
141
}
// this checks a weak symbol.
Dec 8, 2017
Dec 8, 2017
142
#if (defined(__MACOSX__) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101100))
143
144
145
146
147
148
149
150
151
152
153
154
if (MTLCreateSystemDefaultDevice == NULL) { // probably on 10.10 or lower.
return SDL_SetError("Metal framework not available on this system");
}
#endif
return 0;
}
static id<MTLRenderPipelineState>
MakePipelineState(METAL_RenderData *data, NSString *label, NSString *vertfn,
NSString *fragfn, const SDL_BlendMode blendmode)
{
Dec 8, 2017
Dec 8, 2017
155
156
id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:vertfn];
id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:fragfn];
157
158
159
160
161
162
SDL_assert(mtlvertfn != nil);
SDL_assert(mtlfragfn != nil);
MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
mtlpipedesc.vertexFunction = mtlvertfn;
mtlpipedesc.fragmentFunction = mtlfragfn;
Dec 8, 2017
Dec 8, 2017
163
mtlpipedesc.colorAttachments[0].pixelFormat = data.mtllayer.pixelFormat;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
switch (blendmode) {
case SDL_BLENDMODE_BLEND:
mtlpipedesc.colorAttachments[0].blendingEnabled = YES;
mtlpipedesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
mtlpipedesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
mtlpipedesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
mtlpipedesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
mtlpipedesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
mtlpipedesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
break;
case SDL_BLENDMODE_ADD:
mtlpipedesc.colorAttachments[0].blendingEnabled = YES;
mtlpipedesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
mtlpipedesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
mtlpipedesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
mtlpipedesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne;
mtlpipedesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorZero;
mtlpipedesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne;
break;
case SDL_BLENDMODE_MOD:
mtlpipedesc.colorAttachments[0].blendingEnabled = YES;
mtlpipedesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
mtlpipedesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
mtlpipedesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorZero;
mtlpipedesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorSourceColor;
mtlpipedesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorZero;
mtlpipedesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne;
break;
Dec 8, 2017
Dec 8, 2017
195
196
197
198
default:
mtlpipedesc.colorAttachments[0].blendingEnabled = NO;
break;
199
200
201
202
203
}
mtlpipedesc.label = label;
NSError *err = nil;
Dec 8, 2017
Dec 8, 2017
204
id<MTLRenderPipelineState> retval = [data.mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err];
205
SDL_assert(err == nil);
Dec 8, 2017
Dec 8, 2017
206
#if !__has_feature(objc_arc)
207
208
209
210
[mtlpipedesc release]; // !!! FIXME: can these be reused for each creation, or does the pipeline obtain it?
[mtlvertfn release];
[mtlfragfn release];
[label release];
Dec 8, 2017
Dec 8, 2017
211
#endif
212
213
214
215
return retval;
}
static void
Dec 8, 2017
Dec 8, 2017
216
MakePipelineStates(METAL_RenderData *data, NSMutableArray *states,
217
218
NSString *label, NSString *vertfn, NSString *fragfn)
{
Dec 8, 2017
Dec 8, 2017
219
220
221
222
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=none)"], vertfn, fragfn, SDL_BLENDMODE_NONE)];
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=blend)"], vertfn, fragfn, SDL_BLENDMODE_BLEND)];
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=add)"], vertfn, fragfn, SDL_BLENDMODE_ADD)];
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD)];
223
224
225
}
static inline id<MTLRenderPipelineState>
Dec 8, 2017
Dec 8, 2017
226
ChoosePipelineState(NSMutableArray *states, const SDL_BlendMode blendmode)
227
228
{
switch (blendmode) {
Dec 8, 2017
Dec 8, 2017
229
230
231
232
case SDL_BLENDMODE_BLEND: return (id<MTLRenderPipelineState>)states[1];
case SDL_BLENDMODE_ADD: return (id<MTLRenderPipelineState>)states[2];
case SDL_BLENDMODE_MOD: return (id<MTLRenderPipelineState>)states[3];
default: return (id<MTLRenderPipelineState>)states[0];
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
}
return nil;
}
static SDL_Renderer *
METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
{
SDL_Renderer *renderer = NULL;
METAL_RenderData *data = NULL;
SDL_SysWMinfo syswm;
SDL_VERSION(&syswm.version);
if (!SDL_GetWindowWMInfo(window, &syswm)) {
return NULL;
}
if (IsMetalAvailable(&syswm) == -1) {
return NULL;
}
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
if (!renderer) {
SDL_OutOfMemory();
return NULL;
}
Dec 8, 2017
Dec 8, 2017
259
data = [[METAL_RenderData alloc] init];
Dec 8, 2017
Dec 8, 2017
260
data.beginScene = YES;
Dec 8, 2017
Dec 8, 2017
261
262
263
264
#if __has_feature(objc_arc)
renderer->driverdata = (void*)CFBridgingRetain(data);
#else
265
renderer->driverdata = data;
Dec 8, 2017
Dec 8, 2017
266
#endif
267
268
renderer->window = window;
Dec 8, 2017
Dec 8, 2017
269
270
271
#ifdef __MACOSX__
id<MTLDevice> mtldevice = MTLCreateSystemDefaultDevice(); // !!! FIXME: MTLCopyAllDevices() can find other GPUs...
if (mtldevice == nil) {
272
SDL_free(renderer);
Dec 8, 2017
Dec 8, 2017
273
274
275
#if !__has_feature(objc_arc)
[data release];
#endif
276
277
278
279
280
281
282
283
SDL_SetError("Failed to obtain Metal device");
return NULL;
}
// !!! FIXME: error checking on all of this.
NSView *nsview = [syswm.info.cocoa.window contentView];
Dec 8, 2017
Dec 8, 2017
284
285
// CAMetalLayer is available in QuartzCore starting at OSX 10.11
CAMetalLayer *layer = [NSClassFromString( @"CAMetalLayer" ) layer];
Dec 8, 2017
Dec 8, 2017
287
layer.device = mtldevice;
288
289
290
291
292
293
294
295
296
//layer.pixelFormat = MTLPixelFormatBGRA8Unorm; // !!! FIXME: MTLPixelFormatBGRA8Unorm_sRGB ?
layer.framebufferOnly = YES;
//layer.drawableSize = (CGSize) [nsview convertRectToBacking:[nsview bounds]].size;
//layer.colorspace = nil;
[nsview setWantsLayer:YES];
[nsview setLayer:layer];
[layer retain];
Dec 8, 2017
Dec 8, 2017
297
#else
Dec 8, 2017
Dec 8, 2017
298
299
UIView *view = UIKit_Mtl_AddMetalView(window);
CAMetalLayer *layer = (CAMetalLayer *)[view layer];
Dec 8, 2017
Dec 8, 2017
300
301
#endif
Dec 8, 2017
Dec 8, 2017
302
303
304
305
data.mtldevice = layer.device;
data.mtllayer = layer;
data.mtlcmdqueue = [data.mtldevice newCommandQueue];
data.mtlcmdqueue.label = @"SDL Metal Renderer";
Dec 9, 2017
Dec 9, 2017
306
data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
Dec 8, 2017
Dec 8, 2017
308
309
310
311
312
313
314
315
316
317
318
319
320
NSError *err = nil;
// The compiled .metallib is embedded in a static array in a header file
// but the original shader source code is in SDL_shaders_metal.metal.
dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
data.mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
SDL_assert(err == nil);
#if !__has_feature(objc_arc)
dispatch_release(mtllibdata);
#endif
data.mtllibrary.label = @"SDL Metal renderer shader library";
data.mtlpipelineprims = [[NSMutableArray alloc] init];
Dec 9, 2017
Dec 9, 2017
321
MakePipelineStates(data, data.mtlpipelineprims, @"SDL primitives pipeline", @"SDL_Solid_vertex", @"SDL_Solid_fragment");
Dec 9, 2017
Dec 9, 2017
322
323
324
325
data.mtlpipelinecopynearest = [[NSMutableArray alloc] init];
MakePipelineStates(data, data.mtlpipelinecopynearest, @"SDL texture pipeline (nearest)", @"SDL_Copy_vertex", @"SDL_Copy_fragment_nearest");
data.mtlpipelinecopylinear = [[NSMutableArray alloc] init];
MakePipelineStates(data, data.mtlpipelinecopylinear, @"SDL texture pipeline (linear)", @"SDL_Copy_vertex", @"SDL_Copy_fragment_linear");
Dec 31, 2017
Dec 31, 2017
327
static const float clearverts[] = { 0, 0, 0, 3, 3, 0 };
Dec 8, 2017
Dec 8, 2017
328
329
data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined];
data.mtlbufclearverts.label = @"SDL_RenderClear vertices";
Dec 8, 2017
Dec 8, 2017
331
// !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
renderer->WindowEvent = METAL_WindowEvent;
renderer->GetOutputSize = METAL_GetOutputSize;
renderer->CreateTexture = METAL_CreateTexture;
renderer->UpdateTexture = METAL_UpdateTexture;
renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
renderer->LockTexture = METAL_LockTexture;
renderer->UnlockTexture = METAL_UnlockTexture;
renderer->SetRenderTarget = METAL_SetRenderTarget;
renderer->UpdateViewport = METAL_UpdateViewport;
renderer->UpdateClipRect = METAL_UpdateClipRect;
renderer->RenderClear = METAL_RenderClear;
renderer->RenderDrawPoints = METAL_RenderDrawPoints;
renderer->RenderDrawLines = METAL_RenderDrawLines;
renderer->RenderFillRects = METAL_RenderFillRects;
renderer->RenderCopy = METAL_RenderCopy;
renderer->RenderCopyEx = METAL_RenderCopyEx;
renderer->RenderReadPixels = METAL_RenderReadPixels;
renderer->RenderPresent = METAL_RenderPresent;
renderer->DestroyTexture = METAL_DestroyTexture;
renderer->DestroyRenderer = METAL_DestroyRenderer;
Dec 8, 2017
Dec 8, 2017
353
354
renderer->GetMetalLayer = METAL_GetMetalLayer;
renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder;
355
356
357
358
359
360
361
renderer->info = METAL_RenderDriver.info;
renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
// !!! FIXME: how do you control this in Metal?
renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
Dec 8, 2017
Dec 8, 2017
362
363
return renderer;
}
Dec 8, 2017
Dec 8, 2017
365
366
367
static void METAL_ActivateRenderer(SDL_Renderer * renderer)
{
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
Dec 8, 2017
Dec 8, 2017
369
370
371
372
373
374
375
376
if (data.beginScene) {
data.beginScene = NO;
data.mtlbackbuffer = [data.mtllayer nextDrawable];
SDL_assert(data.mtlbackbuffer);
data.mtlpassdesc.colorAttachments[0].texture = data.mtlbackbuffer.texture;
data.mtlpassdesc.colorAttachments[0].loadAction = MTLLoadActionDontCare;
data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
Dec 9, 2017
Dec 9, 2017
377
data.mtlcmdencoder.label = @"SDL metal renderer start of frame";
Dec 8, 2017
Dec 8, 2017
378
379
380
381
382
// Set up our current renderer state for the next frame...
METAL_UpdateViewport(renderer);
METAL_UpdateClipRect(renderer);
}
383
384
385
386
387
388
389
390
391
392
393
394
395
396
}
static void
METAL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
{
if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
event->event == SDL_WINDOWEVENT_SHOWN ||
event->event == SDL_WINDOWEVENT_HIDDEN) {
// !!! FIXME: write me
}
}
static int
METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
Dec 8, 2017
Dec 8, 2017
397
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
398
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
399
400
401
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
*w = (int) data.mtlbackbuffer.texture.width;
*h = (int) data.mtlbackbuffer.texture.height;
Dec 8, 2017
Dec 8, 2017
403
}}
404
405
406
static int
METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
Dec 8, 2017
Dec 8, 2017
407
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
408
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
409
410
411
412
413
414
415
416
417
418
MTLPixelFormat mtlpixfmt;
switch (texture->format) {
case SDL_PIXELFORMAT_ABGR8888: mtlpixfmt = MTLPixelFormatRGBA8Unorm; break;
case SDL_PIXELFORMAT_ARGB8888: mtlpixfmt = MTLPixelFormatBGRA8Unorm; break;
default: return SDL_SetError("Texture format %s not supported by Metal", SDL_GetPixelFormatName(texture->format));
}
MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mtlpixfmt
width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
Dec 9, 2017
Dec 9, 2017
419
420
421
422
423
424
425
426
427
if (texture->access == SDL_TEXTUREACCESS_TARGET) {
mtltexdesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
} else {
mtltexdesc.usage = MTLTextureUsageShaderRead;
}
//mtltexdesc.resourceOptions = MTLResourceCPUCacheModeDefaultCache | MTLResourceStorageModeManaged;
//mtltexdesc.storageMode = MTLStorageModeManaged;
Dec 8, 2017
Dec 8, 2017
428
id<MTLTexture> mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
429
430
431
432
if (mtltexture == nil) {
return SDL_SetError("Texture allocation failed");
}
Dec 9, 2017
Dec 9, 2017
433
434
435
436
437
438
439
440
441
442
METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
texturedata.mtlpipeline = data.mtlpipelinecopynearest;
} else {
texturedata.mtlpipeline = data.mtlpipelinecopylinear;
}
texturedata.mtltexture = mtltexture;
texture->driverdata = (void*)CFBridgingRetain(texturedata);
443
444
return 0;
Dec 8, 2017
Dec 8, 2017
445
}}
446
447
448
449
static int
METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
Dec 8, 2017
Dec 8, 2017
450
{ @autoreleasepool {
451
452
453
454
// !!! FIXME: this is a synchronous call; it doesn't return until data is uploaded in some form.
// !!! FIXME: Maybe move this off to a thread that marks the texture as uploaded and only stall the main thread if we try to
// !!! FIXME: use this texture before the marking is done? Is it worth it? Or will we basically always be uploading a bunch of
// !!! FIXME: stuff way ahead of time and/or using it immediately after upload?
Dec 9, 2017
Dec 9, 2017
455
id<MTLTexture> mtltexture = ((__bridge METAL_TextureData *)texture->driverdata).mtltexture;
456
457
[mtltexture replaceRegion:MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h) mipmapLevel:0 withBytes:pixels bytesPerRow:pitch];
return 0;
Dec 8, 2017
Dec 8, 2017
458
}}
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
static int
METAL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect,
const Uint8 *Yplane, int Ypitch,
const Uint8 *Uplane, int Upitch,
const Uint8 *Vplane, int Vpitch)
{
return SDL_Unsupported(); // !!! FIXME
}
static int
METAL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, void **pixels, int *pitch)
{
return SDL_Unsupported(); // !!! FIXME: write me
}
static void
METAL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
// !!! FIXME: write me
}
static int
METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
Dec 8, 2017
Dec 8, 2017
485
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
486
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
487
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
Dec 9, 2017
Dec 9, 2017
488
489
490
491
492
493
// commit the current command buffer, so that any work on a render target
// will be available to the next one we're about to queue up.
[data.mtlcmdencoder endEncoding];
[data.mtlcmdbuffer commit];
Dec 9, 2017
Dec 9, 2017
494
id<MTLTexture> mtltexture = texture ? ((__bridge METAL_TextureData *)texture->driverdata).mtltexture : data.mtlbackbuffer.texture;
Dec 8, 2017
Dec 8, 2017
495
data.mtlpassdesc.colorAttachments[0].texture = mtltexture;
Dec 9, 2017
Dec 9, 2017
496
497
498
499
500
501
502
503
// !!! FIXME: this can be MTLLoadActionDontCare for textures (not the backbuffer) if SDL doesn't guarantee the texture contents should survive.
data.mtlpassdesc.colorAttachments[0].loadAction = MTLLoadActionLoad;
data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
data.mtlcmdencoder.label = texture ? @"SDL metal renderer render texture" : @"SDL metal renderer backbuffer";
// The higher level will reset the viewport and scissor after this call returns.
Dec 8, 2017
Dec 8, 2017
505
}}
Dec 31, 2017
Dec 31, 2017
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
static int
METAL_SetOrthographicProjection(SDL_Renderer *renderer, int w, int h)
{ @autoreleasepool {
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
float projection[4][4];
if (!w || !h) {
return 0;
}
/* Prepare an orthographic projection */
projection[0][0] = 2.0f / w;
projection[0][1] = 0.0f;
projection[0][2] = 0.0f;
projection[0][3] = 0.0f;
projection[1][0] = 0.0f;
projection[1][1] = -2.0f / h;
projection[1][2] = 0.0f;
projection[1][3] = 0.0f;
projection[2][0] = 0.0f;
projection[2][1] = 0.0f;
projection[2][2] = 0.0f;
projection[2][3] = 0.0f;
projection[3][0] = -1.0f;
projection[3][1] = 1.0f;
projection[3][2] = 0.0f;
projection[3][3] = 1.0f;
// !!! FIXME: This should be in a buffer...
[data.mtlcmdencoder setVertexBytes:projection length:sizeof(float)*16 atIndex:2];
return 0;
}}
540
541
static int
METAL_UpdateViewport(SDL_Renderer * renderer)
Dec 8, 2017
Dec 8, 2017
542
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
543
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
544
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
Dec 8, 2017
Dec 8, 2017
545
546
547
548
549
550
551
552
MTLViewport viewport;
viewport.originX = renderer->viewport.x;
viewport.originY = renderer->viewport.y;
viewport.width = renderer->viewport.w;
viewport.height = renderer->viewport.h;
viewport.znear = 0.0;
viewport.zfar = 1.0;
[data.mtlcmdencoder setViewport:viewport];
Dec 31, 2017
Dec 31, 2017
553
METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
Dec 8, 2017
Dec 8, 2017
555
}}
556
557
558
static int
METAL_UpdateClipRect(SDL_Renderer * renderer)
Dec 8, 2017
Dec 8, 2017
559
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
560
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
561
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
Dec 8, 2017
Dec 8, 2017
562
MTLScissorRect mtlrect;
Dec 8, 2017
Dec 8, 2017
563
// !!! FIXME: should this care about the viewport?
Dec 8, 2017
Dec 8, 2017
564
565
566
567
568
569
570
571
572
573
574
575
576
577
if (renderer->clipping_enabled) {
const SDL_Rect *rect = &renderer->clip_rect;
mtlrect.x = renderer->viewport.x + rect->x;
mtlrect.y = renderer->viewport.x + rect->y;
mtlrect.width = rect->w;
mtlrect.height = rect->h;
} else {
mtlrect.x = renderer->viewport.x;
mtlrect.y = renderer->viewport.y;
mtlrect.width = renderer->viewport.w;
mtlrect.height = renderer->viewport.h;
}
if (mtlrect.width > 0 && mtlrect.height > 0) {
[data.mtlcmdencoder setScissorRect:mtlrect];
578
579
}
return 0;
Dec 8, 2017
Dec 8, 2017
580
}}
581
582
583
static int
METAL_RenderClear(SDL_Renderer * renderer)
Dec 8, 2017
Dec 8, 2017
584
{ @autoreleasepool {
585
// We could dump the command buffer and force a clear on a new one, but this will respect the scissor state.
Dec 8, 2017
Dec 8, 2017
586
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
587
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
588
589
590
591
592
593
// !!! FIXME: render color should live in a dedicated uniform buffer.
const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
MTLViewport viewport; // RenderClear ignores the viewport state, though, so reset that.
viewport.originX = viewport.originY = 0.0;
Dec 9, 2017
Dec 9, 2017
594
595
viewport.width = data.mtlpassdesc.colorAttachments[0].texture.width;
viewport.height = data.mtlpassdesc.colorAttachments[0].texture.height;
596
597
598
viewport.znear = 0.0;
viewport.zfar = 1.0;
Dec 30, 2017
Dec 30, 2017
599
// Draw a simple filled fullscreen triangle now.
Dec 31, 2017
Dec 31, 2017
600
METAL_SetOrthographicProjection(renderer, 1, 1);
Dec 8, 2017
Dec 8, 2017
601
602
603
604
[data.mtlcmdencoder setViewport:viewport];
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
[data.mtlcmdencoder setVertexBuffer:data.mtlbufclearverts offset:0 atIndex:0];
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
Dec 30, 2017
Dec 30, 2017
605
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
606
607
608
609
610
611
612
613
// reset the viewport for the rest of our usual drawing work...
viewport.originX = renderer->viewport.x;
viewport.originY = renderer->viewport.y;
viewport.width = renderer->viewport.w;
viewport.height = renderer->viewport.h;
viewport.znear = 0.0;
viewport.zfar = 1.0;
Dec 8, 2017
Dec 8, 2017
614
[data.mtlcmdencoder setViewport:viewport];
Dec 31, 2017
Dec 31, 2017
615
METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
616
617
return 0;
Dec 8, 2017
Dec 8, 2017
618
}}
Dec 10, 2017
Dec 10, 2017
620
621
622
623
624
625
626
627
// normalize a value from 0.0f to len into 0.0f to 1.0f.
static inline float
normtex(const float _val, const float len)
{
const float val = (_val < 0.0f) ? 0.0f : (_val > len) ? len : _val;
return ((val + 0.5f) / len);
}
628
629
630
static int
DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
const MTLPrimitiveType primtype)
Dec 8, 2017
Dec 8, 2017
631
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
632
633
METAL_ActivateRenderer(renderer);
Dec 31, 2017
Dec 31, 2017
634
const size_t vertlen = sizeof(SDL_FPoint) * count;
Dec 8, 2017
Dec 8, 2017
635
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
636
637
638
639
// !!! FIXME: render color should live in a dedicated uniform buffer.
const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
Dec 8, 2017
Dec 8, 2017
640
641
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
Dec 31, 2017
Dec 31, 2017
642
[data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
Dec 8, 2017
Dec 8, 2017
643
[data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
Dec 8, 2017
Dec 8, 2017
645
}}
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
static int
METAL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points, int count)
{
return DrawVerts(renderer, points, count, MTLPrimitiveTypePoint);
}
static int
METAL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points, int count)
{
return DrawVerts(renderer, points, count, MTLPrimitiveTypeLineStrip);
}
static int
METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
Dec 8, 2017
Dec 8, 2017
661
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
662
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
663
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
664
665
666
667
// !!! FIXME: render color should live in a dedicated uniform buffer.
const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
Dec 8, 2017
Dec 8, 2017
668
669
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
670
671
672
673
674
for (int i = 0; i < count; i++, rects++) {
if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue;
const float verts[] = {
Dec 31, 2017
Dec 31, 2017
675
676
677
678
rects->x, rects->y + rects->h,
rects->x, rects->y,
rects->x + rects->w, rects->y + rects->h,
rects->x + rects->w, rects->y,
Dec 8, 2017
Dec 8, 2017
681
[data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
Dec 30, 2017
Dec 30, 2017
682
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
683
684
685
}
return 0;
Dec 8, 2017
Dec 8, 2017
686
}}
687
688
689
690
static int
METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect)
Dec 8, 2017
Dec 8, 2017
691
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
692
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
693
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
Dec 9, 2017
Dec 9, 2017
694
695
696
METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
const float texw = (float) texturedata.mtltexture.width;
const float texh = (float) texturedata.mtltexture.height;
697
698
const float xy[] = {
Dec 31, 2017
Dec 31, 2017
699
700
701
702
dstrect->x, dstrect->y + dstrect->h,
dstrect->x, dstrect->y,
dstrect->x + dstrect->w, dstrect->y + dstrect->h,
dstrect->x + dstrect->w, dstrect->y
703
704
705
};
const float uv[] = {
Dec 10, 2017
Dec 10, 2017
706
707
normtex(srcrect->x, texw), normtex(srcrect->y + srcrect->h, texh),
normtex(srcrect->x, texw), normtex(srcrect->y, texh),
Dec 30, 2017
Dec 30, 2017
708
709
normtex(srcrect->x + srcrect->w, texw), normtex(srcrect->y + srcrect->h, texh),
normtex(srcrect->x + srcrect->w, texw), normtex(srcrect->y, texh)
710
711
712
713
714
715
716
717
718
719
};
float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
if (texture->modMode) {
color[0] = ((float)texture->r) / 255.0f;
color[1] = ((float)texture->g) / 255.0f;
color[2] = ((float)texture->b) / 255.0f;
color[3] = ((float)texture->a) / 255.0f;
}
Dec 9, 2017
Dec 9, 2017
720
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(texturedata.mtlpipeline, texture->blendMode)];
Dec 8, 2017
Dec 8, 2017
721
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
Dec 9, 2017
Dec 9, 2017
722
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
Dec 8, 2017
Dec 8, 2017
723
724
[data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
[data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
Dec 30, 2017
Dec 30, 2017
725
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
726
727
return 0;
Dec 8, 2017
Dec 8, 2017
728
}}
729
730
731
732
733
734
735
736
737
738
739
740
static int
METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect,
const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
return SDL_Unsupported(); // !!! FIXME
}
static int
METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 pixel_format, void * pixels, int pitch)
Dec 8, 2017
Dec 8, 2017
741
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
742
METAL_ActivateRenderer(renderer);
Dec 9, 2017
Dec 9, 2017
743
// !!! FIXME: this probably needs to commit the current command buffer, and probably waitUntilCompleted
Dec 8, 2017
Dec 8, 2017
744
745
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
id<MTLTexture> mtltexture = colorAttachment.texture;
MTLRegion mtlregion;
mtlregion.origin.x = rect->x;
mtlregion.origin.y = rect->y;
mtlregion.origin.z = 0;
mtlregion.size.width = rect->w;
mtlregion.size.height = rect->w;
mtlregion.size.depth = 1;
// we only do BGRA8 or RGBA8 at the moment, so 4 will do.
const int temp_pitch = rect->w * 4;
void *temp_pixels = SDL_malloc(temp_pitch * rect->h);
if (!temp_pixels) {
return SDL_OutOfMemory();
}
[mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
const Uint32 temp_format = (mtltexture.pixelFormat == MTLPixelFormatBGRA8Unorm) ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_ABGR8888;
const int status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
SDL_free(temp_pixels);
return status;
Dec 8, 2017
Dec 8, 2017
769
}}
770
771
772
static void
METAL_RenderPresent(SDL_Renderer * renderer)
Dec 8, 2017
Dec 8, 2017
773
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
774
METAL_ActivateRenderer(renderer);
Dec 8, 2017
Dec 8, 2017
775
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
Dec 8, 2017
Dec 8, 2017
777
[data.mtlcmdencoder endEncoding];
Dec 8, 2017
Dec 8, 2017
778
[data.mtlcmdbuffer presentDrawable:data.mtlbackbuffer];
Dec 8, 2017
Dec 8, 2017
779
[data.mtlcmdbuffer commit];
Dec 8, 2017
Dec 8, 2017
780
781
782
data.mtlcmdencoder = nil;
data.mtlcmdbuffer = nil;
data.mtlbackbuffer = nil;
Dec 8, 2017
Dec 8, 2017
783
data.beginScene = YES;
Dec 8, 2017
Dec 8, 2017
784
}}
785
786
787
static void
METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
Dec 8, 2017
Dec 8, 2017
788
{ @autoreleasepool {
Dec 9, 2017
Dec 9, 2017
789
METAL_TextureData *texturedata = CFBridgingRelease(texture->driverdata);
Dec 9, 2017
Dec 9, 2017
790
#if __has_feature(objc_arc)
Dec 9, 2017
Dec 9, 2017
791
texturedata = nil;
Dec 9, 2017
Dec 9, 2017
792
#else
Dec 9, 2017
Dec 9, 2017
793
794
[texturedata.mtltexture release];
[texturedata release];
Dec 8, 2017
Dec 8, 2017
795
#endif
796
texture->driverdata = NULL;
Dec 8, 2017
Dec 8, 2017
797
}}
798
799
800
static void
METAL_DestroyRenderer(SDL_Renderer * renderer)
Dec 8, 2017
Dec 8, 2017
801
{ @autoreleasepool {
Dec 8, 2017
Dec 8, 2017
802
803
if (renderer->driverdata) {
METAL_RenderData *data = CFBridgingRelease(renderer->driverdata);
Dec 8, 2017
Dec 8, 2017
805
806
807
if (data.mtlcmdencoder != nil) {
[data.mtlcmdencoder endEncoding];
}
Dec 8, 2017
Dec 8, 2017
808
809
810
811
812
#if !__has_feature(objc_arc)
[data.mtlbackbuffer release];
[data.mtlcmdencoder release];
[data.mtlcmdbuffer release];
Dec 8, 2017
Dec 8, 2017
813
[data.mtlcmdqueue release];
Dec 8, 2017
Dec 8, 2017
814
for (int i = 0; i < 4; i++) {
Dec 8, 2017
Dec 8, 2017
815
[data.mtlpipelineprims[i] release];
Dec 11, 2017
Dec 11, 2017
816
817
[data.mtlpipelinecopynearest[i] release];
[data.mtlpipelinecopylinear[i] release];
Dec 8, 2017
Dec 8, 2017
819
[data.mtlpipelineprims release];
Dec 11, 2017
Dec 11, 2017
820
821
[data.mtlpipelinecopynearest release];
[data.mtlpipelinecopylinear release];
Dec 8, 2017
Dec 8, 2017
822
823
824
825
826
827
[data.mtlbufclearverts release];
[data.mtllibrary release];
[data.mtldevice release];
[data.mtlpassdesc release];
[data.mtllayer release];
#endif
Dec 8, 2017
Dec 8, 2017
829
830
SDL_free(renderer);
Dec 8, 2017
Dec 8, 2017
831
}}
Dec 8, 2017
Dec 8, 2017
833
834
835
836
837
838
839
840
841
842
843
844
845
void *METAL_GetMetalLayer(SDL_Renderer * renderer)
{ @autoreleasepool {
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
return (__bridge void*)data.mtllayer;
}}
void *METAL_GetMetalCommandEncoder(SDL_Renderer * renderer)
{ @autoreleasepool {
METAL_ActivateRenderer(renderer);
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
return (__bridge void*)data.mtlcmdencoder;
}}
846
847
848
#endif /* SDL_VIDEO_RENDER_METAL && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */