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);
764 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
766 *w = (int)data.mtllayer.drawableSize.width;
769 *h = (int)data.mtllayer.drawableSize.height;
784 if (GetBlendFactor(srcColorFactor) == invalidBlendFactor ||
785 GetBlendFactor(srcAlphaFactor) == invalidBlendFactor ||
786 GetBlendOperation(colorOperation) == invalidBlendOperation ||
787 GetBlendFactor(dstColorFactor) == invalidBlendFactor ||
788 GetBlendFactor(dstAlphaFactor) == invalidBlendFactor ||
789 GetBlendOperation(alphaOperation) == invalidBlendOperation) {
798 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
799 MTLPixelFormat pixfmt;
801 switch (texture->
format) {
803 pixfmt = MTLPixelFormatRGBA8Unorm;
806 pixfmt = MTLPixelFormatBGRA8Unorm;
812 pixfmt = MTLPixelFormatR8Unorm;
818 MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
819 width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
822 if ([mtltexdesc respondsToSelector:
@selector(
usage)]) {
824 mtltexdesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
826 mtltexdesc.usage = MTLTextureUsageShaderRead;
830 id<MTLTexture> mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
831 if (mtltexture == nil) {
841 mtltexdesc.pixelFormat = MTLPixelFormatR8Unorm;
842 mtltexdesc.width = (texture->
w + 1) / 2;
843 mtltexdesc.height = (texture->
h + 1) / 2;
844 mtltexdesc.textureType = MTLTextureType2DArray;
845 mtltexdesc.arrayLength = 2;
847 mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
848 mtltexdesc.width = (texture->
w + 1) / 2;
849 mtltexdesc.height = (texture->
h + 1) / 2;
853 mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
854 if (mtltexture_uv == nil) {
855 #if !__has_feature(objc_arc) 856 [mtltexture release];
862 METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
864 texturedata.mtlsampler = data.mtlsamplernearest;
866 texturedata.mtlsampler = data.mtlsamplerlinear;
868 texturedata.mtltexture = mtltexture;
869 texturedata.mtltexture_uv = mtltexture_uv;
871 texturedata.yuv = yuv;
872 texturedata.nv12 = nv12;
875 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_YUV;
877 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12;
879 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21;
881 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
891 default: offset = 0;
break;
893 texturedata.conversionBufferOffset =
offset;
896 texture->
driverdata = (
void*)CFBridgingRetain(texturedata);
898 #if !__has_feature(objc_arc) 899 [texturedata release];
900 [mtltexture release];
901 [mtltexture_uv release];
911 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
916 [texturedata.mtltexture replaceRegion:MTLRegionMake2D(rect->
x, rect->
y, rect->
w, rect->
h)
921 if (texturedata.yuv) {
926 pixels = (
const void*)((
const Uint8*)pixels + rect->h * pitch);
927 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
931 bytesPerRow:(pitch + 1) / 2
935 pixels = (
const void*)((
const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2));
936 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
940 bytesPerRow:(pitch + 1) / 2
944 if (texturedata.nv12) {
946 pixels = (
const void*)((
const Uint8*)pixels + rect->h * pitch);
947 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
951 bytesPerRow:2 * ((pitch + 1) / 2)
961 const Uint8 *Yplane,
int Ypitch,
962 const Uint8 *Uplane,
int Upitch,
963 const Uint8 *Vplane,
int Vpitch)
965 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
966 const int Uslice = 0;
967 const int Vslice = 1;
970 if (rect->
w <= 0 || rect->
h <= 0) {
974 [texturedata.mtltexture replaceRegion:MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h)
979 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
986 [texturedata.mtltexture_uv replaceRegion:MTLRegionMake2D(rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2)
998 const SDL_Rect * rect,
void **pixels,
int *pitch)
1011 { @autoreleasepool {
1012 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1014 if (data.mtlcmdencoder) {
1017 [data.mtlcmdencoder endEncoding];
1018 [data.mtlcmdbuffer commit];
1020 data.mtlcmdencoder = nil;
1021 data.mtlcmdbuffer = nil;
1031 METAL_SetOrthographicProjection(
SDL_Renderer *renderer,
int w,
int h)
1032 { @autoreleasepool {
1033 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1034 float projection[4][4];
1041 projection[0][0] = 2.0f /
w;
1042 projection[0][1] = 0.0f;
1043 projection[0][2] = 0.0f;
1044 projection[0][3] = 0.0f;
1045 projection[1][0] = 0.0f;
1046 projection[1][1] = -2.0
f / h;
1047 projection[1][2] = 0.0f;
1048 projection[1][3] = 0.0f;
1049 projection[2][0] = 0.0f;
1050 projection[2][1] = 0.0f;
1051 projection[2][2] = 0.0f;
1052 projection[2][3] = 0.0f;
1053 projection[3][0] = -1.0
f;
1054 projection[3][1] = 1.0f;
1055 projection[3][2] = 0.0f;
1056 projection[3][3] = 1.0f;
1059 [data.mtlcmdencoder setVertexBytes:projection length:sizeof(float)*16 atIndex:2];
1065 { @autoreleasepool {
1066 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1067 if (data.mtlcmdencoder) {
1069 viewport.originX = renderer->
viewport.
x;
1070 viewport.originY = renderer->
viewport.
y;
1073 viewport.znear = 0.0;
1074 viewport.zfar = 1.0;
1075 [data.mtlcmdencoder setViewport:viewport];
1076 METAL_SetOrthographicProjection(renderer, renderer->
viewport.
w, renderer->
viewport.
h);
1083 { @autoreleasepool {
1084 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1085 if (data.mtlcmdencoder) {
1086 MTLScissorRect mtlrect;
1092 mtlrect.width = rect->
w;
1093 mtlrect.height = rect->
h;
1100 if (mtlrect.width > 0 && mtlrect.height > 0) {
1101 [data.mtlcmdencoder setScissorRect:mtlrect];
1109 { @autoreleasepool {
1110 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1115 if (data.mtlcmdencoder == nil) {
1116 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear);
1119 const float color[4] = { ((float)renderer->
r) / 255.0f, ((float)renderer->
g) / 255.0f, ((float)renderer->
b) / 255.0f, ((float)renderer->
a) / 255.0f };
1122 viewport.originX = viewport.originY = 0.0;
1123 viewport.width = data.mtlpassdesc.colorAttachments[0].texture.width;
1124 viewport.height = data.mtlpassdesc.colorAttachments[0].texture.height;
1125 viewport.znear = 0.0;
1126 viewport.zfar = 1.0;
1129 METAL_SetOrthographicProjection(renderer, 1, 1);
1130 [data.mtlcmdencoder setViewport:viewport];
1131 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, SDL_BLENDMODE_NONE)];
1132 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_CLEAR_VERTS atIndex:0];
1133 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
1134 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1135 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
1138 viewport.originX = renderer->
viewport.
x;
1139 viewport.originY = renderer->
viewport.
y;
1142 viewport.znear = 0.0;
1143 viewport.zfar = 1.0;
1144 [data.mtlcmdencoder setViewport:viewport];
1145 METAL_SetOrthographicProjection(renderer, renderer->
viewport.
w, renderer->
viewport.
h);
1153 normtex(
const float _val,
const float len)
1160 const MTLPrimitiveType primtype)
1161 { @autoreleasepool {
1162 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1164 const size_t vertlen = (
sizeof (float) * 2) *
count;
1165 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1168 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 };
1170 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
1171 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1173 [data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
1174 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM atIndex:3];
1175 [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
1183 return DrawVerts(renderer, points, count, MTLPrimitiveTypePoint);
1189 return DrawVerts(renderer, points, count, MTLPrimitiveTypeLineStrip);
1194 { @autoreleasepool {
1195 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1196 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1199 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 };
1201 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
1202 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1203 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
1205 for (
int i = 0;
i <
count;
i++, rects++) {
1206 if ((rects->
w <= 0.0f) || (rects->
h <= 0.0f))
continue;
1208 const float verts[] = {
1209 rects->
x, rects->
y + rects->h,
1211 rects->
x + rects->w, rects->
y + rects->h,
1212 rects->
x + rects->w, rects->
y 1215 [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
1216 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1223 METAL_SetupRenderCopy(METAL_RenderData *data,
SDL_Texture *texture, METAL_TextureData *texturedata)
1225 float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
1227 color[0] = ((float)texture->
r) / 255.0f;
1228 color[1] = ((float)texture->
g) / 255.0f;
1229 color[2] = ((float)texture->
b) / 255.0f;
1230 color[3] = ((float)texture->
a) / 255.0f;
1233 [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, texturedata.fragmentFunction, texture->blendMode)];
1234 [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
1235 [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
1237 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
1239 if (texturedata.yuv || texturedata.nv12) {
1240 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
1241 [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
1248 { @autoreleasepool {
1249 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1250 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1251 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
1252 const float texw = (float) texturedata.mtltexture.width;
1253 const float texh = (
float) texturedata.mtltexture.height;
1255 METAL_SetupRenderCopy(data, texture, texturedata);
1257 const float xy[] = {
1258 dstrect->
x, dstrect->
y + dstrect->h,
1259 dstrect->
x, dstrect->
y,
1260 dstrect->
x + dstrect->w, dstrect->
y + dstrect->h,
1261 dstrect->
x + dstrect->w, dstrect->
y 1264 const float uv[] = {
1265 normtex(srcrect->
x, texw), normtex(srcrect->
y + srcrect->
h, texh),
1266 normtex(srcrect->
x, texw), normtex(srcrect->
y, texh),
1267 normtex(srcrect->
x + srcrect->
w, texw), normtex(srcrect->
y + srcrect->
h, texh),
1268 normtex(srcrect->
x + srcrect->
w, texw), normtex(srcrect->
y, texh)
1271 [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
1272 [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
1273 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
1274 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1283 { @autoreleasepool {
1284 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1285 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1286 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
1287 const float texw = (float) texturedata.mtltexture.width;
1288 const float texh = (
float) texturedata.mtltexture.height;
1290 float minu, maxu, minv, maxv;
1292 METAL_SetupRenderCopy(data, texture, texturedata);
1294 minu = normtex(srcrect->
x, texw);
1295 maxu = normtex(srcrect->
x + srcrect->
w, texw);
1296 minv = normtex(srcrect->
y, texh);
1297 maxv = normtex(srcrect->
y + srcrect->
h, texh);
1310 const float uv[] = {
1317 const float xy[] = {
1318 -center->
x, dstrect->h - center->
y,
1319 -center->
x, -center->
y,
1320 dstrect->w - center->
x, dstrect->h - center->
y,
1321 dstrect->w - center->
x, -center->
y 1325 float rads = (float)(M_PI * (
float) angle / 180.0f);
1326 float c = cosf(rads),
s = sinf(rads);
1329 transform[10] = transform[15] = 1.0f;
1338 transform[12] = dstrect->
x + center->
x;
1339 transform[13] = dstrect->
y + center->
y;
1342 [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
1343 [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
1344 [data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
1345 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1352 Uint32 pixel_format,
void * pixels,
int pitch)
1353 { @autoreleasepool {
1354 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1358 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1362 if (data.mtlcmdencoder) {
1363 [data.mtlcmdencoder endEncoding];
1364 [data.mtlcmdbuffer commit];
1365 [data.mtlcmdbuffer waitUntilCompleted];
1367 data.mtlcmdencoder = nil;
1368 data.mtlcmdbuffer = nil;
1371 id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
1372 MTLRegion mtlregion = MTLRegionMake2D(rect->
x, rect->
y, rect->
w, rect->
h);
1375 const int temp_pitch = rect->
w * 4;
1376 void *temp_pixels =
SDL_malloc(temp_pitch * rect->
h);
1381 [mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
1384 const int status =
SDL_ConvertPixels(rect->
w, rect->
h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
1391 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1398 { @autoreleasepool {
1399 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1401 if (data.mtlcmdencoder != nil) {
1402 [data.mtlcmdencoder endEncoding];
1404 if (data.mtlbackbuffer != nil) {
1405 [data.mtlcmdbuffer presentDrawable:data.mtlbackbuffer];
1407 if (data.mtlcmdbuffer != nil) {
1408 [data.mtlcmdbuffer commit];
1410 data.mtlcmdencoder = nil;
1411 data.mtlcmdbuffer = nil;
1412 data.mtlbackbuffer = nil;
1417 { @autoreleasepool {
1424 { @autoreleasepool {
1426 METAL_RenderData *data = CFBridgingRelease(renderer->
driverdata);
1428 if (data.mtlcmdencoder != nil) {
1429 [data.mtlcmdencoder endEncoding];
1432 DestroyAllPipelines(data.allpipelines, data.pipelinescount);
1440 { @autoreleasepool {
1441 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1442 return (__bridge
void*)data.mtllayer;
1447 { @autoreleasepool {
1448 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
1449 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1450 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
GLfloat GLfloat GLfloat GLfloat h
SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode)
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d ®2 endm macro vzip8 reg2 vzip d d ®2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld [DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp local skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
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