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;
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;
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);
473 if (IsMetalAvailable(&syswm) == -1) {
484 mtldevice = MTLCreateSystemDefaultDevice();
486 if (mtldevice == nil) {
493 data = [[METAL_RenderData alloc] init];
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;
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;
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];
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];
707 if (
data.mtlcmdencoder == nil) {
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) {
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);
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) {
799 MTLPixelFormat pixfmt;
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;
921 if (texturedata.yuv) {
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
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) {
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;
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)
1011 { @autoreleasepool {
1014 if (
data.mtlcmdencoder) {
1017 [data.mtlcmdencoder endEncoding];
1018 [data.mtlcmdbuffer commit];
1020 data.mtlcmdencoder = nil;
1021 data.mtlcmdbuffer = nil;
1032 { @autoreleasepool {
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 {
1067 if (
data.mtlcmdencoder) {
1075 [data.mtlcmdencoder setViewport:viewport];
1083 { @autoreleasepool {
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 {
1115 if (
data.mtlcmdencoder == nil) {
1116 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionClear);
1123 viewport.width =
data.mtlpassdesc.colorAttachments[0].texture.width;
1124 viewport.height =
data.mtlpassdesc.colorAttachments[0].texture.height;
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];
1144 [data.mtlcmdencoder setViewport:viewport];
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;
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];
1194 { @autoreleasepool {
1195 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionLoad);
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];
1206 if ((
rects->w <= 0.0f) || (
rects->h <= 0.0f))
continue;
1208 const float verts[] = {
1215 [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
1216 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1225 float color[4] = { 1.0f, 1.0f, 1.0f, 1.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);
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);
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);
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];
1353 { @autoreleasepool {
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;
1375 const int temp_pitch =
rect->
w * 4;
1381 [mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
1391 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionLoad);
1398 { @autoreleasepool {
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 {
1418 CFBridgingRelease(
texture->driverdata);
1424 { @autoreleasepool {
1428 if (
data.mtlcmdencoder != nil) {
1429 [data.mtlcmdencoder endEncoding];
1432 DestroyAllPipelines(
data.allpipelines,
data.pipelinescount);
1440 { @autoreleasepool {
1442 return (__bridge
void*)
data.mtllayer;
1447 { @autoreleasepool {
1448 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionLoad);
1450 return (__bridge
void*)
data.mtlcmdencoder;