21 #include "../../SDL_internal.h" 23 #if SDL_VIDEO_RENDER_METAL && !SDL_RENDER_DISABLED 29 #include "../SDL_sysrender.h" 32 #include "../../video/cocoa/SDL_cocoametalview.h" 34 #include "../../video/uikit/SDL_uikitmetalview.h" 36 #include <Availability.h> 37 #import <Metal/Metal.h> 38 #import <QuartzCore/CAMetalLayer.h> 60 const Uint8 *Yplane,
int Ypitch,
61 const Uint8 *Uplane,
int Upitch,
62 const Uint8 *Vplane,
int Vpitch);
109 #define CONSTANT_ALIGN 256 111 #define CONSTANT_ALIGN 4 114 #define ALIGN_CONSTANTS(size) ((size + CONSTANT_ALIGN - 1) & (~(CONSTANT_ALIGN - 1))) 116 static const size_t CONSTANTS_OFFSET_IDENTITY = 0;
117 static const size_t CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM = ALIGN_CONSTANTS(CONSTANTS_OFFSET_IDENTITY +
sizeof(
float) * 16);
118 static const size_t CONSTANTS_OFFSET_DECODE_JPEG = ALIGN_CONSTANTS(CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM +
sizeof(
float) * 16);
119 static const size_t CONSTANTS_OFFSET_DECODE_BT601 = ALIGN_CONSTANTS(CONSTANTS_OFFSET_DECODE_JPEG +
sizeof(
float) * 4 * 4);
120 static const size_t CONSTANTS_OFFSET_DECODE_BT709 = ALIGN_CONSTANTS(CONSTANTS_OFFSET_DECODE_BT601 +
sizeof(
float) * 4 * 4);
121 static const size_t CONSTANTS_OFFSET_CLEAR_VERTS = ALIGN_CONSTANTS(CONSTANTS_OFFSET_DECODE_BT709 +
sizeof(
float) * 4 * 4);
122 static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_CLEAR_VERTS + sizeof(float) * 6;
124 typedef enum SDL_MetalVertexFunction
126 SDL_METAL_VERTEX_SOLID,
127 SDL_METAL_VERTEX_COPY,
128 } SDL_MetalVertexFunction;
130 typedef enum SDL_MetalFragmentFunction
132 SDL_METAL_FRAGMENT_SOLID = 0,
133 SDL_METAL_FRAGMENT_COPY,
134 SDL_METAL_FRAGMENT_YUV,
135 SDL_METAL_FRAGMENT_NV12,
136 SDL_METAL_FRAGMENT_NV21,
137 SDL_METAL_FRAGMENT_COUNT,
138 } SDL_MetalFragmentFunction;
140 typedef struct METAL_PipelineState
144 } METAL_PipelineState;
146 typedef struct METAL_PipelineCache
148 METAL_PipelineState *states;
150 SDL_MetalVertexFunction vertexFunction;
151 SDL_MetalFragmentFunction fragmentFunction;
152 MTLPixelFormat renderTargetFormat;
154 } METAL_PipelineCache;
162 typedef struct METAL_ShaderPipelines
164 MTLPixelFormat renderTargetFormat;
165 METAL_PipelineCache caches[SDL_METAL_FRAGMENT_COUNT];
166 } METAL_ShaderPipelines;
168 @interface METAL_RenderData : NSObject
178 @property (nonatomic, retain) CAMetalLayer *mtllayer;
179 @property (nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
180 @property (nonatomic, assign) METAL_ShaderPipelines *activepipelines;
181 @property (nonatomic, assign) METAL_ShaderPipelines *allpipelines;
182 @property (nonatomic, assign)
int pipelinescount;
185 @implementation METAL_RenderData
186 #if !__has_feature(objc_arc) 189 [_mtldevice release];
190 [_mtlcmdqueue release];
191 [_mtlcmdbuffer release];
192 [_mtlcmdencoder release];
193 [_mtllibrary release];
194 [_mtlbackbuffer release];
195 [_mtlsamplernearest release];
196 [_mtlsamplerlinear release];
197 [_mtlbufconstants release];
199 [_mtlpassdesc release];
205 @interface METAL_TextureData : NSObject
209 @property (nonatomic, assign) SDL_MetalFragmentFunction fragmentFunction;
210 @property (nonatomic, assign) BOOL yuv;
211 @property (nonatomic, assign) BOOL nv12;
212 @property (nonatomic, assign)
size_t conversionBufferOffset;
215 @implementation METAL_TextureData
216 #if !__has_feature(objc_arc) 219 [_mtltexture release];
220 [_mtltexture_uv release];
221 [_mtlsampler release];
231 return SDL_SetError(
"Metal render target only supports Cocoa and UIKit video targets at the moment.");
235 #if (defined(__MACOSX__) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101100)) 236 if (MTLCreateSystemDefaultDevice ==
NULL) {
237 return SDL_SetError(
"Metal framework not available on this system");
244 static const MTLBlendOperation invalidBlendOperation = (MTLBlendOperation)0xFFFFFFFF;
245 static const MTLBlendFactor invalidBlendFactor = (MTLBlendFactor)0xFFFFFFFF;
247 static MTLBlendOperation
256 default:
return invalidBlendOperation;
260 static MTLBlendFactor
274 default:
return invalidBlendFactor;
279 GetVertexFunctionName(SDL_MetalVertexFunction
function)
282 case SDL_METAL_VERTEX_SOLID:
return @"SDL_Solid_vertex";
283 case SDL_METAL_VERTEX_COPY:
return @"SDL_Copy_vertex";
289 GetFragmentFunctionName(SDL_MetalFragmentFunction
function)
292 case SDL_METAL_FRAGMENT_SOLID:
return @"SDL_Solid_fragment";
293 case SDL_METAL_FRAGMENT_COPY:
return @"SDL_Copy_fragment";
294 case SDL_METAL_FRAGMENT_YUV:
return @"SDL_YUV_fragment";
295 case SDL_METAL_FRAGMENT_NV12:
return @"SDL_NV12_fragment";
296 case SDL_METAL_FRAGMENT_NV21:
return @"SDL_NV21_fragment";
302 MakePipelineState(METAL_RenderData *
data, METAL_PipelineCache *cache,
305 id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:GetVertexFunctionName(cache->vertexFunction)];
306 id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:GetFragmentFunctionName(cache->fragmentFunction)];
310 MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
311 mtlpipedesc.vertexFunction = mtlvertfn;
312 mtlpipedesc.fragmentFunction = mtlfragfn;
314 MTLRenderPipelineColorAttachmentDescriptor *rtdesc = mtlpipedesc.colorAttachments[0];
316 rtdesc.pixelFormat = cache->renderTargetFormat;
319 rtdesc.blendingEnabled = YES;
327 rtdesc.blendingEnabled = NO;
330 mtlpipedesc.label = [@(cache->label) stringByAppendingString:blendlabel];
336 METAL_PipelineState pipeline;
337 pipeline.blendMode = blendmode;
338 pipeline.pipe = (
void *)CFBridgingRetain(state);
340 METAL_PipelineState *states =
SDL_realloc(cache->states, (cache->count + 1) *
sizeof(pipeline));
342 #if !__has_feature(objc_arc) 343 [mtlpipedesc release];
350 states[cache->count++] = pipeline;
351 cache->states = states;
354 CFBridgingRelease(pipeline.pipe);
361 MakePipelineCache(METAL_RenderData *data, METAL_PipelineCache *cache,
const char *
label,
362 MTLPixelFormat rtformat, SDL_MetalVertexFunction vertfn, SDL_MetalFragmentFunction fragfn)
366 cache->vertexFunction = vertfn;
367 cache->fragmentFunction = fragfn;
368 cache->renderTargetFormat = rtformat;
369 cache->label =
label;
380 DestroyPipelineCache(METAL_PipelineCache *cache)
383 for (
int i = 0;
i < cache->count;
i++) {
384 CFBridgingRelease(cache->states[
i].pipe);
392 MakeShaderPipelines(METAL_RenderData *data, METAL_ShaderPipelines *
pipelines, MTLPixelFormat rtformat)
396 pipelines->renderTargetFormat = rtformat;
398 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_SOLID],
"SDL primitives pipeline", rtformat, SDL_METAL_VERTEX_SOLID, SDL_METAL_FRAGMENT_SOLID);
399 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_COPY],
"SDL copy pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY);
400 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_YUV],
"SDL YUV pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_YUV);
401 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_NV12],
"SDL NV12 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV12);
402 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_NV21],
"SDL NV21 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV21);
405 static METAL_ShaderPipelines *
406 ChooseShaderPipelines(METAL_RenderData *data, MTLPixelFormat rtformat)
408 METAL_ShaderPipelines *allpipelines = data.allpipelines;
409 int count = data.pipelinescount;
412 if (allpipelines[
i].renderTargetFormat == rtformat) {
413 return &allpipelines[i];
417 allpipelines =
SDL_realloc(allpipelines, (count + 1) *
sizeof(METAL_ShaderPipelines));
419 if (allpipelines ==
NULL) {
424 MakeShaderPipelines(data, &allpipelines[count], rtformat);
426 data.allpipelines = allpipelines;
427 data.pipelinescount = count + 1;
429 return &data.allpipelines[count];
433 DestroyAllPipelines(METAL_ShaderPipelines *allpipelines,
int count)
435 if (allpipelines !=
NULL) {
437 for (
int cache = 0; cache < SDL_METAL_FRAGMENT_COUNT; cache++) {
438 DestroyPipelineCache(&allpipelines[
i].caches[cache]);
447 ChoosePipelineState(METAL_RenderData *data, METAL_ShaderPipelines *
pipelines, SDL_MetalFragmentFunction fragfn,
SDL_BlendMode blendmode)
449 METAL_PipelineCache *cache = &pipelines->caches[fragfn];
451 for (
int i = 0;
i < cache->count;
i++) {
452 if (cache->states[
i].blendMode == blendmode) {
453 return (__bridge id<MTLRenderPipelineState>)cache->states[i].pipe;
457 return MakePipelineState(data, cache, [NSString stringWithFormat:
@" (blend=custom 0x%x)", blendmode], blendmode);
464 METAL_RenderData *data =
NULL;
473 if (IsMetalAvailable(&syswm) == -1) {
484 mtldevice = MTLCreateSystemDefaultDevice();
486 if (mtldevice == nil) {
493 data = [[METAL_RenderData alloc] init];
495 renderer->
driverdata = (
void*)CFBridgingRetain(data);
499 NSView *view = Cocoa_Mtl_AddMetalView(window);
500 CAMetalLayer *
layer = (CAMetalLayer *)[view layer];
502 layer.device = mtldevice;
507 UIView *view = UIKit_Mtl_AddMetalView(window);
508 CAMetalLayer *layer = (CAMetalLayer *)[view layer];
512 layer.framebufferOnly = NO;
514 data.mtldevice = layer.device;
515 data.mtllayer =
layer;
517 data.mtlcmdqueue = mtlcmdqueue;
518 data.mtlcmdqueue.label =
@"SDL Metal Renderer";
519 data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
526 id<MTLLibrary> mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
527 data.mtllibrary = mtllibrary;
529 #if !__has_feature(objc_arc) 530 dispatch_release(mtllibdata);
532 data.mtllibrary.label =
@"SDL Metal renderer shader library";
535 data.pipelinescount = 0;
536 data.allpipelines =
NULL;
537 ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
539 MTLSamplerDescriptor *samplerdesc = [[MTLSamplerDescriptor alloc] init];
541 samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
542 samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
543 id<MTLSamplerState> mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
544 data.mtlsamplernearest = mtlsamplernearest;
546 samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
547 samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
548 id<MTLSamplerState> mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
549 data.mtlsamplerlinear = mtlsamplerlinear;
552 float identitytransform[16] = {
553 1.0f, 0.0f, 0.0f, 0.0f,
554 0.0f, 1.0f, 0.0f, 0.0f,
555 0.0f, 0.0f, 1.0f, 0.0f,
556 0.0f, 0.0f, 0.0f, 1.0f,
559 float halfpixeltransform[16] = {
560 1.0f, 0.0f, 0.0f, 0.0f,
561 0.0f, 1.0f, 0.0f, 0.0f,
562 0.0f, 0.0f, 1.0f, 0.0f,
563 0.5f, 0.5f, 0.0f, 1.0f,
567 float decodetransformJPEG[4*4] = {
568 0.0, -0.501960814, -0.501960814, 0.0,
569 1.0000, 0.0000, 1.4020, 0.0,
570 1.0000, -0.3441, -0.7141, 0.0,
571 1.0000, 1.7720, 0.0000, 0.0,
574 float decodetransformBT601[4*4] = {
575 -0.0627451017, -0.501960814, -0.501960814, 0.0,
576 1.1644, 0.0000, 1.5960, 0.0,
577 1.1644, -0.3918, -0.8130, 0.0,
578 1.1644, 2.0172, 0.0000, 0.0,
581 float decodetransformBT709[4*4] = {
582 0.0, -0.501960814, -0.501960814, 0.0,
583 1.0000, 0.0000, 1.4020, 0.0,
584 1.0000, -0.3441, -0.7141, 0.0,
585 1.0000, 1.7720, 0.0000, 0.0,
588 float clearverts[6] = {0.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.0f};
590 id<MTLBuffer> mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
591 mtlbufconstantstaging.label =
@"SDL constant staging data";
593 id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
594 data.mtlbufconstants = mtlbufconstants;
595 data.mtlbufconstants.label =
@"SDL constant data";
597 char *constantdata = [mtlbufconstantstaging contents];
598 SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform,
sizeof(identitytransform));
599 SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform,
sizeof(halfpixeltransform));
600 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG,
sizeof(decodetransformJPEG));
601 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601,
sizeof(decodetransformBT601));
602 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709,
sizeof(decodetransformBT709));
603 SDL_memcpy(constantdata + CONSTANTS_OFFSET_CLEAR_VERTS, clearverts,
sizeof(clearverts));
608 [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:data.mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
610 [blitcmd endEncoding];
639 renderer->
info = METAL_RenderDriver.
info;
642 #if defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13) 652 int maxtexsize = 4096;
653 #if defined(__MACOSX__) 655 #elif defined(__TVOS__) 659 if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
666 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
671 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
675 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
685 #if !__has_feature(objc_arc) 686 [mtlcmdqueue release];
687 [mtllibrary release];
688 [samplerdesc release];
689 [mtlsamplernearest release];
690 [mtlsamplerlinear release];
691 [mtlbufconstants release];
701 METAL_ActivateRenderCommandEncoder(
SDL_Renderer * renderer, MTLLoadAction load)
703 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
707 if (data.mtlcmdencoder == nil) {
711 METAL_TextureData *texdata = (__bridge METAL_TextureData *)renderer->
target->
driverdata;
712 mtltexture = texdata.mtltexture;
714 if (data.mtlbackbuffer == nil) {
717 data.mtlbackbuffer = [data.mtllayer nextDrawable];
718 if (load == MTLLoadActionLoad) {
719 load = MTLLoadActionDontCare;
722 mtltexture = data.mtlbackbuffer.texture;
727 if (load == MTLLoadActionClear) {
728 MTLClearColor
color = MTLClearColorMake(renderer->
r/255.0, renderer->
g/255.0, renderer->
b/255.0, renderer->
a/255.0);
729 data.mtlpassdesc.colorAttachments[0].clearColor =
color;
732 data.mtlpassdesc.colorAttachments[0].loadAction = load;
733 data.mtlpassdesc.colorAttachments[0].texture = mtltexture;
735 data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
736 data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
738 if (data.mtlbackbuffer != nil && mtltexture == data.mtlbackbuffer.texture) {
739 data.mtlcmdencoder.label =
@"SDL metal renderer backbuffer";
741 data.mtlcmdencoder.label =
@"SDL metal renderer render target";
744 data.activepipelines = ChooseShaderPipelines(data, mtltexture.pixelFormat);
747 METAL_UpdateViewport(renderer);
748 METAL_UpdateClipRect(renderer);
765 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
767 *w = (int)data.mtllayer.drawableSize.width;
770 *h = (int)data.mtllayer.drawableSize.height;
785 if (GetBlendFactor(srcColorFactor) == invalidBlendFactor ||
786 GetBlendFactor(srcAlphaFactor) == invalidBlendFactor ||
787 GetBlendOperation(colorOperation) == invalidBlendOperation ||
788 GetBlendFactor(dstColorFactor) == invalidBlendFactor ||
789 GetBlendFactor(dstAlphaFactor) == invalidBlendFactor ||
790 GetBlendOperation(alphaOperation) == invalidBlendOperation) {
799 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
800 MTLPixelFormat pixfmt;
802 switch (texture->
format) {
804 pixfmt = MTLPixelFormatRGBA8Unorm;
807 pixfmt = MTLPixelFormatBGRA8Unorm;
813 pixfmt = MTLPixelFormatR8Unorm;
819 MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
820 width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
823 if ([mtltexdesc respondsToSelector:
@selector(
usage)]) {
825 mtltexdesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
827 mtltexdesc.usage = MTLTextureUsageShaderRead;
831 id<MTLTexture> mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
832 if (mtltexture == nil) {
842 mtltexdesc.pixelFormat = MTLPixelFormatR8Unorm;
843 mtltexdesc.width = (texture->
w + 1) / 2;
844 mtltexdesc.height = (texture->
h + 1) / 2;
845 mtltexdesc.textureType = MTLTextureType2DArray;
846 mtltexdesc.arrayLength = 2;
847 mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
849 mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
850 mtltexdesc.width = (texture->
w + 1) / 2;
851 mtltexdesc.height = (texture->
h + 1) / 2;
852 mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
855 METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
857 if (!hint || *hint ==
'0' ||
SDL_strcasecmp(hint,
"nearest") == 0) {
858 texturedata.mtlsampler = data.mtlsamplernearest;
860 texturedata.mtlsampler = data.mtlsamplerlinear;
862 texturedata.mtltexture = mtltexture;
863 texturedata.mtltexture_uv = mtltexture_uv;
865 texturedata.yuv = yuv;
866 texturedata.nv12 = nv12;
869 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_YUV;
871 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12;
873 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21;
875 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
885 default: offset = 0;
break;
887 texturedata.conversionBufferOffset =
offset;
890 texture->
driverdata = (
void*)CFBridgingRetain(texturedata);
892 #if !__has_feature(objc_arc) 893 [texturedata release];
894 [mtltexture release];
895 [mtltexture_uv release];
905 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
910 [texturedata.mtltexture replaceRegion:MTLRegionMake2D(rect->
x, rect->
y, rect->
w, rect->
h)
915 if (texturedata.yuv) {
920 pixels = (
const void*)((
const Uint8*)pixels + rect->h * pitch);
921 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
925 bytesPerRow:(pitch + 1) / 2
929 pixels = (
const void*)((
const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2));
930 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
934 bytesPerRow:(pitch + 1) / 2
938 if (texturedata.nv12) {
940 pixels = (
const void*)((
const Uint8*)pixels + rect->h * pitch);
941 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
945 bytesPerRow:2 * ((pitch + 1) / 2)
955 const Uint8 *Yplane,
int Ypitch,
956 const Uint8 *Uplane,
int Upitch,
957 const Uint8 *Vplane,
int Vpitch)
959 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
964 if (rect->
w <= 0 || rect->
h <= 0) {
968 [texturedata.mtltexture replaceRegion:MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h)
973 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
980 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
992 const SDL_Rect * rect,
void **pixels,
int *pitch)
1005 { @autoreleasepool {
1006 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1008 if (data.mtlcmdencoder) {
1011 [data.mtlcmdencoder endEncoding];
1012 [data.mtlcmdbuffer commit];
1014 data.mtlcmdencoder = nil;
1015 data.mtlcmdbuffer = nil;
1025 METAL_SetOrthographicProjection(
SDL_Renderer *renderer,
int w,
int h)
1026 { @autoreleasepool {
1027 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1028 float projection[4][4];
1035 projection[0][0] = 2.0f /
w;
1036 projection[0][1] = 0.0f;
1037 projection[0][2] = 0.0f;
1038 projection[0][3] = 0.0f;
1039 projection[1][0] = 0.0f;
1040 projection[1][1] = -2.0
f / h;
1041 projection[1][2] = 0.0f;
1042 projection[1][3] = 0.0f;
1043 projection[2][0] = 0.0f;
1044 projection[2][1] = 0.0f;
1045 projection[2][2] = 0.0f;
1046 projection[2][3] = 0.0f;
1047 projection[3][0] = -1.0
f;
1048 projection[3][1] = 1.0f;
1049 projection[3][2] = 0.0f;
1050 projection[3][3] = 1.0f;
1053 [data.mtlcmdencoder setVertexBytes:projection length:sizeof(float)*16 atIndex:2];
1059 { @autoreleasepool {
1060 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1061 if (data.mtlcmdencoder) {
1063 viewport.originX = renderer->
viewport.
x;
1064 viewport.originY = renderer->
viewport.
y;
1067 viewport.znear = 0.0;
1068 viewport.zfar = 1.0;
1069 [data.mtlcmdencoder setViewport:viewport];
1070 METAL_SetOrthographicProjection(renderer, renderer->
viewport.
w, renderer->
viewport.
h);
1077 { @autoreleasepool {
1078 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1079 if (data.mtlcmdencoder) {
1080 MTLScissorRect mtlrect;
1086 mtlrect.width = rect->
w;
1087 mtlrect.height = rect->
h;
1094 if (mtlrect.width > 0 && mtlrect.height > 0) {
1095 [data.mtlcmdencoder setScissorRect:mtlrect];
1103 { @autoreleasepool {
1104 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1109 if (data.mtlcmdencoder == nil) {
1110 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear);
1113 const float color[4] = { ((float)renderer->
r) / 255.0f, ((float)renderer->
g) / 255.0f, ((float)renderer->
b) / 255.0f, ((float)renderer->
a) / 255.0f };
1116 viewport.originX = viewport.originY = 0.0;
1117 viewport.width = data.mtlpassdesc.colorAttachments[0].texture.width;
1118 viewport.height = data.mtlpassdesc.colorAttachments[0].texture.height;
1119 viewport.znear = 0.0;
1120 viewport.zfar = 1.0;
1123 METAL_SetOrthographicProjection(renderer, 1, 1);
1124 [data.mtlcmdencoder setViewport:viewport];
1125 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, SDL_BLENDMODE_NONE)];
1126 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_CLEAR_VERTS atIndex:0];
1127 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
1128 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1129 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
1132 viewport.originX = renderer->
viewport.
x;
1133 viewport.originY = renderer->
viewport.
y;
1136 viewport.znear = 0.0;
1137 viewport.zfar = 1.0;
1138 [data.mtlcmdencoder setViewport:viewport];
1139 METAL_SetOrthographicProjection(renderer, renderer->
viewport.
w, renderer->
viewport.
h);
1147 normtex(
const float _val,
const float len)
1154 const MTLPrimitiveType primtype)
1155 { @autoreleasepool {
1156 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1158 const size_t vertlen = (
sizeof (float) * 2) *
count;
1159 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1162 const float color[4] = { ((
float)renderer->
r) / 255.0
f, ((
float)renderer->
g) / 255.0
f, ((
float)renderer->
b) / 255.0
f, ((
float)renderer->
a) / 255.0
f };
1164 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
1165 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1167 [data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
1168 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM atIndex:3];
1169 [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
1177 return DrawVerts(renderer, points, count, MTLPrimitiveTypePoint);
1183 return DrawVerts(renderer, points, count, MTLPrimitiveTypeLineStrip);
1188 { @autoreleasepool {
1189 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1190 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1193 const float color[4] = { ((
float)renderer->
r) / 255.0
f, ((
float)renderer->
g) / 255.0
f, ((
float)renderer->
b) / 255.0
f, ((
float)renderer->
a) / 255.0
f };
1195 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
1196 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1197 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
1199 for (
int i = 0;
i <
count;
i++, rects++) {
1200 if ((rects->
w <= 0.0f) || (rects->
h <= 0.0f))
continue;
1202 const float verts[] = {
1203 rects->
x, rects->
y + rects->h,
1205 rects->
x + rects->w, rects->
y + rects->h,
1206 rects->
x + rects->w, rects->
y 1209 [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
1210 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1217 METAL_SetupRenderCopy(METAL_RenderData *data,
SDL_Texture *texture, METAL_TextureData *texturedata)
1219 float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1221 color[0] = ((float)texture->
r) / 255.0f;
1222 color[1] = ((float)texture->
g) / 255.0f;
1223 color[2] = ((float)texture->
b) / 255.0f;
1224 color[3] = ((float)texture->
a) / 255.0f;
1227 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, texturedata.fragmentFunction, texture->blendMode)];
1228 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1229 [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
1231 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
1233 if (texturedata.yuv || texturedata.nv12) {
1234 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
1235 [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
1242 { @autoreleasepool {
1243 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1244 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1245 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
1246 const float texw = (float) texturedata.mtltexture.width;
1247 const float texh = (
float) texturedata.mtltexture.height;
1249 METAL_SetupRenderCopy(data, texture, texturedata);
1251 const float xy[] = {
1252 dstrect->
x, dstrect->
y + dstrect->h,
1253 dstrect->
x, dstrect->
y,
1254 dstrect->
x + dstrect->w, dstrect->
y + dstrect->h,
1255 dstrect->
x + dstrect->w, dstrect->
y 1258 const float uv[] = {
1259 normtex(srcrect->
x, texw), normtex(srcrect->
y + srcrect->
h, texh),
1260 normtex(srcrect->
x, texw), normtex(srcrect->
y, texh),
1261 normtex(srcrect->
x + srcrect->
w, texw), normtex(srcrect->
y + srcrect->
h, texh),
1262 normtex(srcrect->
x + srcrect->
w, texw), normtex(srcrect->
y, texh)
1265 [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
1266 [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
1267 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
1268 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1277 { @autoreleasepool {
1278 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1279 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1280 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
1281 const float texw = (float) texturedata.mtltexture.width;
1282 const float texh = (
float) texturedata.mtltexture.height;
1284 float minu, maxu, minv, maxv;
1286 METAL_SetupRenderCopy(data, texture, texturedata);
1288 minu = normtex(srcrect->
x, texw);
1289 maxu = normtex(srcrect->
x + srcrect->
w, texw);
1290 minv = normtex(srcrect->
y, texh);
1291 maxv = normtex(srcrect->
y + srcrect->
h, texh);
1304 const float uv[] = {
1311 const float xy[] = {
1312 -center->
x, dstrect->h - center->
y,
1313 -center->
x, -center->
y,
1314 dstrect->w - center->
x, dstrect->h - center->
y,
1315 dstrect->w - center->
x, -center->
y 1319 float rads = (float)(M_PI * (
float) angle / 180.0f);
1320 float c = cosf(rads),
s = sinf(rads);
1323 transform[10] = transform[15] = 1.0f;
1332 transform[12] = dstrect->
x + center->
x;
1333 transform[13] = dstrect->
y + center->
y;
1336 [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
1337 [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
1338 [data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
1339 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1346 Uint32 pixel_format,
void * pixels,
int pitch)
1347 { @autoreleasepool {
1348 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1351 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1352 id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
1353 MTLRegion mtlregion = MTLRegionMake2D(rect->
x, rect->
y, rect->
w, rect->
h);
1356 const int temp_pitch = rect->
w * 4;
1357 void *temp_pixels =
SDL_malloc(temp_pitch * rect->
h);
1362 [mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
1365 const int status =
SDL_ConvertPixels(rect->
w, rect->
h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
1372 { @autoreleasepool {
1373 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1375 if (data.mtlcmdencoder != nil) {
1376 [data.mtlcmdencoder endEncoding];
1378 if (data.mtlbackbuffer != nil) {
1379 [data.mtlcmdbuffer presentDrawable:data.mtlbackbuffer];
1381 if (data.mtlcmdbuffer != nil) {
1382 [data.mtlcmdbuffer commit];
1384 data.mtlcmdencoder = nil;
1385 data.mtlcmdbuffer = nil;
1386 data.mtlbackbuffer = nil;
1391 { @autoreleasepool {
1398 { @autoreleasepool {
1400 METAL_RenderData *data = CFBridgingRelease(renderer->
driverdata);
1402 if (data.mtlcmdencoder != nil) {
1403 [data.mtlcmdencoder endEncoding];
1406 DestroyAllPipelines(data.allpipelines, data.pipelinescount);
1414 { @autoreleasepool {
1415 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1416 return (__bridge
void*)data.mtllayer;
1421 { @autoreleasepool {
1422 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1423 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1424 return (__bridge
void*)data.mtlcmdencoder;
SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode)
SDL_BlendFactor
The normalized factor used to multiply pixel components.
int(* RenderDrawLines)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
int(* RenderDrawPoints)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
int(* LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
int(* RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
SDL_YUV_CONVERSION_MODE
The formula used for converting between YUV and RGB.
GLint GLint GLint GLint GLint x
SDL_BlendMode
The blend mode used in SDL_RenderCopy() and drawing operations.
SDL_bool(* SupportsBlendMode)(SDL_Renderer *renderer, SDL_BlendMode blendMode)
GLuint GLuint GLsizei count
#define SDL_HINT_RENDER_SCALE_QUALITY
A variable controlling the scaling quality.
GLfloat GLfloat GLfloat GLfloat h
SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode)
SDL_BlendOperation SDL_GetBlendModeColorOperation(SDL_BlendMode blendMode)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
int(* RenderFillRects)(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
GLenum GLuint GLint GLint layer
SDL_BlendOperation
The blend operation used when combining source and destination pixel components.
int(* RenderClear)(SDL_Renderer *renderer)
void(* DestroyRenderer)(SDL_Renderer *renderer)
GLfixed GLfixed GLint GLint GLfixed points
int(* GetOutputSize)(SDL_Renderer *renderer, int *w, int *h)
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
static SDL_BlendMode blendMode
int(* UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
int(* 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)
SDL_RenderDriver METAL_RenderDriver
GLsizeiptr const void GLenum usage
GLenum GLenum GLuint texture
SDL_BlendOperation SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode)
GLuint GLsizei const GLchar * label
static SDL_Renderer * renderer
GLubyte GLubyte GLubyte GLubyte w
void *(* GetMetalLayer)(SDL_Renderer *renderer)
void(* UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
GLint GLint GLint GLint GLint GLint y
int(* SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* UpdateViewport)(SDL_Renderer *renderer)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
SDL_RendererFlip
Flip constants for SDL_RenderCopyEx.
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
int(* RenderCopy)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
Window state change event data (event.window.*)
#define SDL_assert(condition)
#define SDL_GetWindowWMInfo
#define SDL_OutOfMemory()
SDL_BlendFactor SDL_GetBlendModeSrcAlphaFactor(SDL_BlendMode blendMode)
int(* RenderCopyEx)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
EGLSurface EGLNativeWindowType * window
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
The type used to identify a window.
GLuint GLenum GLenum transform
SDL_BlendFactor SDL_GetBlendModeDstColorFactor(SDL_BlendMode blendMode)
void(* WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event)
#define SDL_ConvertPixels
void(* DestroyTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* CreateTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
void(* RenderPresent)(SDL_Renderer *renderer)
EGLSurface EGLint * rects
#define SDL_GetYUVConversionModeForResolution
int(* UpdateClipRect)(SDL_Renderer *renderer)
#define SDL_Unsupported()
SDL_bool clipping_enabled
A rectangle, with the origin at the upper left.
void *(* GetMetalCommandEncoder)(SDL_Renderer *renderer)
#define SDL_GetPixelFormatName