21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_RENDER_METAL && !SDL_RENDER_DISABLED
28 #include "../SDL_sysrender.h"
30 #include <Availability.h>
31 #import <Metal/Metal.h>
32 #import <QuartzCore/CAMetalLayer.h>
35 #import <AppKit/NSView.h>
40 #include "SDL_shaders_metal_osx.h"
41 #elif defined(__TVOS__)
42 #if TARGET_OS_SIMULATOR
43 #include "SDL_shaders_metal_tvsimulator.h"
45 #include "SDL_shaders_metal_tvos.h"
48 #if TARGET_OS_SIMULATOR
49 #include "SDL_shaders_metal_iphonesimulator.h"
51 #include "SDL_shaders_metal_ios.h"
62 #if defined(__MACOSX__) || TARGET_OS_SIMULATOR
63 #define CONSTANT_ALIGN(x) (256)
65 #define CONSTANT_ALIGN(x) (x < 4 ? 4 : x)
68 #define DEVICE_ALIGN(x) (x < 4 ? 4 : x)
70 #define ALIGN_CONSTANTS(align, size) ((size + CONSTANT_ALIGN(align) - 1) & (~(CONSTANT_ALIGN(align) - 1)))
72 static const size_t CONSTANTS_OFFSET_INVALID = 0xFFFFFFFF;
73 static const size_t CONSTANTS_OFFSET_IDENTITY = 0;
74 static const size_t CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_IDENTITY +
sizeof(
float) * 16);
75 static const size_t CONSTANTS_OFFSET_DECODE_JPEG = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM +
sizeof(
float) * 16);
76 static const size_t CONSTANTS_OFFSET_DECODE_BT601 = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_JPEG +
sizeof(
float) * 4 * 4);
77 static const size_t CONSTANTS_OFFSET_DECODE_BT709 = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT601 +
sizeof(
float) * 4 * 4);
78 static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT709 + sizeof(float) * 4 * 4;
80 typedef enum SDL_MetalVertexFunction
82 SDL_METAL_VERTEX_SOLID,
83 SDL_METAL_VERTEX_COPY,
84 } SDL_MetalVertexFunction;
86 typedef enum SDL_MetalFragmentFunction
88 SDL_METAL_FRAGMENT_SOLID = 0,
89 SDL_METAL_FRAGMENT_COPY,
90 SDL_METAL_FRAGMENT_YUV,
91 SDL_METAL_FRAGMENT_NV12,
92 SDL_METAL_FRAGMENT_NV21,
93 SDL_METAL_FRAGMENT_COUNT,
94 } SDL_MetalFragmentFunction;
96 typedef struct METAL_PipelineState
100 } METAL_PipelineState;
102 typedef struct METAL_PipelineCache
104 METAL_PipelineState *states;
106 SDL_MetalVertexFunction vertexFunction;
107 SDL_MetalFragmentFunction fragmentFunction;
108 MTLPixelFormat renderTargetFormat;
110 } METAL_PipelineCache;
118 typedef struct METAL_ShaderPipelines
120 MTLPixelFormat renderTargetFormat;
121 METAL_PipelineCache caches[SDL_METAL_FRAGMENT_COUNT];
122 } METAL_ShaderPipelines;
124 @interface METAL_RenderData : NSObject
134 @property (nonatomic, retain)
id<MTLBuffer> mtlbufquadindices;
137 @property (nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
138 @property (nonatomic, assign) METAL_ShaderPipelines *activepipelines;
139 @property (nonatomic, assign) METAL_ShaderPipelines *allpipelines;
140 @property (nonatomic, assign)
int pipelinescount;
143 @implementation METAL_RenderData
144 #if !__has_feature(objc_arc)
147 [_mtldevice release];
148 [_mtlcmdqueue release];
149 [_mtlcmdbuffer release];
150 [_mtlcmdencoder release];
151 [_mtllibrary release];
152 [_mtlbackbuffer release];
153 [_mtlsamplernearest release];
154 [_mtlsamplerlinear release];
155 [_mtlbufconstants release];
156 [_mtlbufquadindices release];
158 [_mtlpassdesc release];
164 @interface METAL_TextureData : NSObject
168 @property (nonatomic, assign) SDL_MetalFragmentFunction fragmentFunction;
169 @property (nonatomic, assign) BOOL yuv;
170 @property (nonatomic, assign) BOOL nv12;
171 @property (nonatomic, assign)
size_t conversionBufferOffset;
172 @property (nonatomic, assign) BOOL hasdata;
175 @property (nonatomic, assign)
SDL_Rect lockedrect;
178 @implementation METAL_TextureData
179 #if !__has_feature(objc_arc)
182 [_mtltexture release];
183 [_mtltexture_uv release];
184 [_mtlsampler release];
185 [_lockedbuffer release];
195 return SDL_SetError(
"Metal render target only supports Cocoa and UIKit video targets at the moment.");
199 #if (defined(__MACOSX__) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101100))
200 if (MTLCreateSystemDefaultDevice ==
NULL) {
201 return SDL_SetError(
"Metal framework not available on this system");
208 static const MTLBlendOperation invalidBlendOperation = (MTLBlendOperation)0xFFFFFFFF;
209 static const MTLBlendFactor invalidBlendFactor = (MTLBlendFactor)0xFFFFFFFF;
211 static MTLBlendOperation
220 default:
return invalidBlendOperation;
224 static MTLBlendFactor
238 default:
return invalidBlendFactor;
243 GetVertexFunctionName(SDL_MetalVertexFunction
function)
246 case SDL_METAL_VERTEX_SOLID:
return @"SDL_Solid_vertex";
247 case SDL_METAL_VERTEX_COPY:
return @"SDL_Copy_vertex";
253 GetFragmentFunctionName(SDL_MetalFragmentFunction
function)
256 case SDL_METAL_FRAGMENT_SOLID:
return @"SDL_Solid_fragment";
257 case SDL_METAL_FRAGMENT_COPY:
return @"SDL_Copy_fragment";
258 case SDL_METAL_FRAGMENT_YUV:
return @"SDL_YUV_fragment";
259 case SDL_METAL_FRAGMENT_NV12:
return @"SDL_NV12_fragment";
260 case SDL_METAL_FRAGMENT_NV21:
return @"SDL_NV21_fragment";
266 MakePipelineState(METAL_RenderData *
data, METAL_PipelineCache *cache,
269 id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:GetVertexFunctionName(cache->vertexFunction)];
270 id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:GetFragmentFunctionName(cache->fragmentFunction)];
274 MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
275 mtlpipedesc.vertexFunction = mtlvertfn;
276 mtlpipedesc.fragmentFunction = mtlfragfn;
278 MTLVertexDescriptor *vertdesc = [MTLVertexDescriptor vertexDescriptor];
280 switch (cache->vertexFunction) {
281 case SDL_METAL_VERTEX_SOLID:
283 vertdesc.layouts[0].stride =
sizeof(float) * 2;
284 vertdesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
286 vertdesc.attributes[0].format = MTLVertexFormatFloat2;
287 vertdesc.attributes[0].offset = 0;
288 vertdesc.attributes[0].bufferIndex = 0;
290 case SDL_METAL_VERTEX_COPY:
292 vertdesc.layouts[0].stride =
sizeof(float) * 4;
293 vertdesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
295 vertdesc.attributes[0].format = MTLVertexFormatFloat2;
296 vertdesc.attributes[0].offset = 0;
297 vertdesc.attributes[0].bufferIndex = 0;
299 vertdesc.attributes[1].format = MTLVertexFormatFloat2;
300 vertdesc.attributes[1].offset =
sizeof(float) * 2;
301 vertdesc.attributes[1].bufferIndex = 0;
305 mtlpipedesc.vertexDescriptor = vertdesc;
307 MTLRenderPipelineColorAttachmentDescriptor *rtdesc = mtlpipedesc.colorAttachments[0];
308 rtdesc.pixelFormat = cache->renderTargetFormat;
311 rtdesc.blendingEnabled = YES;
319 rtdesc.blendingEnabled = NO;
322 mtlpipedesc.label = [@(cache->label) stringByAppendingString:blendlabel];
328 METAL_PipelineState pipeline;
329 pipeline.blendMode = blendmode;
330 pipeline.pipe = (
void *)CFBridgingRetain(
state);
332 METAL_PipelineState *states =
SDL_realloc(cache->states, (cache->count + 1) *
sizeof(pipeline));
334 #if !__has_feature(objc_arc)
335 [mtlpipedesc release];
342 states[cache->count++] = pipeline;
343 cache->states = states;
346 CFBridgingRelease(pipeline.pipe);
353 MakePipelineCache(METAL_RenderData *
data, METAL_PipelineCache *cache,
const char *
label,
354 MTLPixelFormat rtformat, SDL_MetalVertexFunction vertfn, SDL_MetalFragmentFunction fragfn)
358 cache->vertexFunction = vertfn;
359 cache->fragmentFunction = fragfn;
360 cache->renderTargetFormat = rtformat;
361 cache->label =
label;
373 DestroyPipelineCache(METAL_PipelineCache *cache)
376 for (
int i = 0;
i < cache->count;
i++) {
377 CFBridgingRelease(cache->states[
i].pipe);
385 MakeShaderPipelines(METAL_RenderData *
data, METAL_ShaderPipelines *
pipelines, MTLPixelFormat rtformat)
389 pipelines->renderTargetFormat = rtformat;
391 MakePipelineCache(
data, &
pipelines->caches[SDL_METAL_FRAGMENT_SOLID],
"SDL primitives pipeline", rtformat, SDL_METAL_VERTEX_SOLID, SDL_METAL_FRAGMENT_SOLID);
392 MakePipelineCache(
data, &
pipelines->caches[SDL_METAL_FRAGMENT_COPY],
"SDL copy pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY);
393 MakePipelineCache(
data, &
pipelines->caches[SDL_METAL_FRAGMENT_YUV],
"SDL YUV pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_YUV);
394 MakePipelineCache(
data, &
pipelines->caches[SDL_METAL_FRAGMENT_NV12],
"SDL NV12 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV12);
395 MakePipelineCache(
data, &
pipelines->caches[SDL_METAL_FRAGMENT_NV21],
"SDL NV21 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV21);
398 static METAL_ShaderPipelines *
399 ChooseShaderPipelines(METAL_RenderData *
data, MTLPixelFormat rtformat)
401 METAL_ShaderPipelines *allpipelines =
data.allpipelines;
405 if (allpipelines[
i].renderTargetFormat == rtformat) {
406 return &allpipelines[i];
410 allpipelines =
SDL_realloc(allpipelines, (
count + 1) *
sizeof(METAL_ShaderPipelines));
412 if (allpipelines ==
NULL) {
417 MakeShaderPipelines(
data, &allpipelines[
count], rtformat);
419 data.allpipelines = allpipelines;
422 return &
data.allpipelines[count];
426 DestroyAllPipelines(METAL_ShaderPipelines *allpipelines,
int count)
428 if (allpipelines !=
NULL) {
430 for (
int cache = 0; cache < SDL_METAL_FRAGMENT_COUNT; cache++) {
431 DestroyPipelineCache(&allpipelines[
i].caches[cache]);
440 ChoosePipelineState(METAL_RenderData *
data, METAL_ShaderPipelines *
pipelines, SDL_MetalFragmentFunction fragfn,
SDL_BlendMode blendmode)
442 METAL_PipelineCache *cache = &
pipelines->caches[fragfn];
444 for (
int i = 0;
i < cache->count;
i++) {
445 if (cache->states[
i].blendMode == blendmode) {
446 return (__bridge id<MTLRenderPipelineState>)cache->states[i].pipe;
450 return MakePipelineState(
data, cache, [NSString stringWithFormat:
@" (blend=custom 0x%x)", blendmode], blendmode);
460 if (
data.mtlcmdencoder == nil) {
465 mtltexture = texdata.mtltexture;
467 if (
data.mtlbackbuffer == nil) {
470 data.mtlbackbuffer = [data.mtllayer nextDrawable];
471 if (load == MTLLoadActionLoad) {
472 load = MTLLoadActionDontCare;
475 mtltexture =
data.mtlbackbuffer.texture;
480 if (load == MTLLoadActionClear) {
482 data.mtlpassdesc.colorAttachments[0].clearColor = *clear_color;
485 data.mtlpassdesc.colorAttachments[0].loadAction = load;
486 data.mtlpassdesc.colorAttachments[0].texture = mtltexture;
488 data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
489 data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
491 if (
data.mtlbackbuffer != nil && mtltexture ==
data.mtlbackbuffer.texture) {
492 data.mtlcmdencoder.label =
@"SDL metal renderer backbuffer";
494 data.mtlcmdencoder.label =
@"SDL metal renderer render target";
499 if (vertex_buffer != nil) {
500 [data.mtlcmdencoder setVertexBuffer:vertex_buffer offset:0 atIndex:0];
501 [data.mtlcmdencoder setFragmentBuffer:vertex_buffer offset:0 atIndex:0];
504 data.activepipelines = ChooseShaderPipelines(
data, mtltexture.pixelFormat);
509 [data.mtlcmdbuffer enqueue];
527 *
w = (
int)
data.mtllayer.drawableSize.width;
530 *
h = (
int)
data.mtllayer.drawableSize.height;
545 if (GetBlendFactor(srcColorFactor) == invalidBlendFactor ||
546 GetBlendFactor(srcAlphaFactor) == invalidBlendFactor ||
547 GetBlendOperation(colorOperation) == invalidBlendOperation ||
548 GetBlendFactor(dstColorFactor) == invalidBlendFactor ||
549 GetBlendFactor(dstAlphaFactor) == invalidBlendFactor ||
550 GetBlendOperation(alphaOperation) == invalidBlendOperation) {
560 MTLPixelFormat pixfmt;
564 pixfmt = MTLPixelFormatRGBA8Unorm;
567 pixfmt = MTLPixelFormatBGRA8Unorm;
573 pixfmt = MTLPixelFormatR8Unorm;
579 MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
580 width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
583 if ([mtltexdesc respondsToSelector:
@selector(
usage)]) {
585 mtltexdesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
587 mtltexdesc.usage = MTLTextureUsageShaderRead;
591 id<MTLTexture> mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
592 if (mtltexture == nil) {
602 mtltexdesc.pixelFormat = MTLPixelFormatR8Unorm;
603 mtltexdesc.width = (
texture->w + 1) / 2;
604 mtltexdesc.height = (
texture->h + 1) / 2;
605 mtltexdesc.textureType = MTLTextureType2DArray;
606 mtltexdesc.arrayLength = 2;
608 mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
609 mtltexdesc.width = (
texture->w + 1) / 2;
610 mtltexdesc.height = (
texture->h + 1) / 2;
614 mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
615 if (mtltexture_uv == nil) {
616 #if !__has_feature(objc_arc)
617 [mtltexture release];
623 METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
625 texturedata.mtlsampler =
data.mtlsamplernearest;
627 texturedata.mtlsampler =
data.mtlsamplerlinear;
629 texturedata.mtltexture = mtltexture;
630 texturedata.mtltexture_uv = mtltexture_uv;
632 texturedata.yuv = yuv;
633 texturedata.nv12 = nv12;
636 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_YUV;
638 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12;
640 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21;
642 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
652 default:
offset = 0;
break;
654 texturedata.conversionBufferOffset =
offset;
657 texture->driverdata = (
void*)CFBridgingRetain(texturedata);
659 #if !__has_feature(objc_arc)
660 [texturedata release];
661 [mtltexture release];
662 [mtltexture_uv release];
670 const void *
pixels,
int pitch)
672 [texture replaceRegion:MTLRegionMake2D(rect.x, rect.y, rect.w, rect.h)
680 static MTLStorageMode
684 if ([resource respondsToSelector:
@selector(storageMode)]) {
685 return resource.storageMode;
687 return MTLStorageModeShared;
693 const void *
pixels,
int pitch)
697 MTLTextureDescriptor *desc;
702 if (!texturedata.hasdata && METAL_GetStorageMode(
texture) != MTLStorageModePrivate) {
707 desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:texture.pixelFormat
719 id<MTLTexture> stagingtex = [data.mtldevice newTextureWithDescriptor:desc];
720 if (stagingtex == nil) {
724 #if !__has_feature(objc_arc)
725 [stagingtex autorelease];
728 METAL_UploadTextureData(stagingtex, stagingrect, 0,
pixels, pitch);
730 if (
data.mtlcmdencoder != nil) {
731 [data.mtlcmdencoder endEncoding];
732 data.mtlcmdencoder = nil;
735 if (
data.mtlcmdbuffer == nil) {
736 data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
741 [blitcmd copyFromTexture:stagingtex
744 sourceOrigin:MTLOriginMake(0, 0, 0)
745 sourceSize:MTLSizeMake(rect.w, rect.h, 1)
747 destinationSlice:slice
749 destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
751 [blitcmd endEncoding];
755 [data.mtlcmdbuffer commit];
756 data.mtlcmdbuffer = nil;
765 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)
texture->driverdata;
767 if (METAL_UpdateTextureInternal(
renderer, texturedata, texturedata.mtltexture, *
rect, 0,
pixels, pitch) < 0) {
771 if (texturedata.yuv) {
774 int UVpitch = (pitch + 1) / 2;
779 if (METAL_UpdateTextureInternal(
renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice,
pixels, UVpitch) < 0) {
785 if (METAL_UpdateTextureInternal(
renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice,
pixels, UVpitch) < 0) {
790 if (texturedata.nv12) {
792 int UVpitch = 2 * ((pitch + 1) / 2);
796 if (METAL_UpdateTextureInternal(
renderer, texturedata, texturedata.mtltexture_uv, UVrect, 0,
pixels, UVpitch) < 0) {
801 texturedata.hasdata = YES;
809 const Uint8 *Yplane,
int Ypitch,
810 const Uint8 *Uplane,
int Upitch,
811 const Uint8 *Vplane,
int Vpitch)
813 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)
texture->driverdata;
814 const int Uslice = 0;
815 const int Vslice = 1;
823 if (METAL_UpdateTextureInternal(
renderer, texturedata, texturedata.mtltexture, *
rect, 0, Yplane, Ypitch) < 0) {
826 if (METAL_UpdateTextureInternal(
renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice, Uplane, Upitch)) {
829 if (METAL_UpdateTextureInternal(
renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice, Vplane, Vpitch)) {
833 texturedata.hasdata = YES;
843 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)
texture->driverdata;
848 return SDL_SetError(
"Invalid rectangle dimensions for LockTexture.");
853 if (texturedata.yuv || texturedata.nv12) {
854 buffersize = ((*pitch) *
rect->
h) + (2 * (*pitch + 1) / 2) * ((
rect->
h + 1) / 2);
856 buffersize = (*pitch) *
rect->
h;
859 lockedbuffer = [data.mtldevice newBufferWithLength:buffersize options:MTLResourceStorageModeShared];
860 if (lockedbuffer == nil) {
864 texturedata.lockedrect = *
rect;
865 texturedata.lockedbuffer = lockedbuffer;
866 *
pixels = [lockedbuffer contents];
869 #if !__has_feature(objc_arc)
870 [lockedbuffer release];
880 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)
texture->driverdata;
885 if (texturedata.lockedbuffer == nil) {
889 if (
data.mtlcmdencoder != nil) {
890 [data.mtlcmdencoder endEncoding];
891 data.mtlcmdencoder = nil;
894 if (
data.mtlcmdbuffer == nil) {
895 data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
900 [blitcmd copyFromBuffer:texturedata.lockedbuffer
902 sourceBytesPerRow:pitch
903 sourceBytesPerImage:0
904 sourceSize:MTLSizeMake(rect.w, rect.h, 1)
905 toTexture:texturedata.mtltexture
908 destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
910 if (texturedata.yuv) {
913 int UVpitch = (pitch + 1) / 2;
915 [blitcmd copyFromBuffer:texturedata.lockedbuffer
916 sourceOffset:rect.h * pitch
917 sourceBytesPerRow:UVpitch
918 sourceBytesPerImage:UVpitch * UVrect.h
919 sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
920 toTexture:texturedata.mtltexture_uv
921 destinationSlice:Uslice
923 destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
925 [blitcmd copyFromBuffer:texturedata.lockedbuffer
926 sourceOffset:(rect.h * pitch) + UVrect.h * UVpitch
927 sourceBytesPerRow:UVpitch
928 sourceBytesPerImage:UVpitch * UVrect.h
929 sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
930 toTexture:texturedata.mtltexture_uv
931 destinationSlice:Vslice
933 destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
936 if (texturedata.nv12) {
937 int UVpitch = 2 * ((pitch + 1) / 2);
939 [blitcmd copyFromBuffer:texturedata.lockedbuffer
940 sourceOffset:rect.h * pitch
941 sourceBytesPerRow:UVpitch
942 sourceBytesPerImage:0
943 sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
944 toTexture:texturedata.mtltexture_uv
947 destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
950 [blitcmd endEncoding];
952 [data.mtlcmdbuffer commit];
953 data.mtlcmdbuffer = nil;
955 texturedata.lockedbuffer = nil;
956 texturedata.hasdata = YES;
963 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)
texture->driverdata;
966 texturedata.mtlsampler =
data.mtlsamplernearest;
968 texturedata.mtlsampler =
data.mtlsamplerlinear;
980 [data.mtlcmdencoder endEncoding];
981 [data.mtlcmdbuffer commit];
983 data.mtlcmdencoder = nil;
984 data.mtlcmdbuffer = nil;
996 normtex(
const float _val,
const float len)
1004 float projection[4][4];
1007 const size_t matrixlen =
sizeof (projection);
1015 projection[0][0] = 2.0f /
w;
1016 projection[1][1] = -2.0
f /
h;
1017 projection[3][0] = -1.0
f;
1018 projection[3][1] = 1.0f;
1019 projection[3][3] = 1.0f;
1029 const size_t vertlen =
sizeof (float) * 4;
1044 const size_t vertlen = (
sizeof (float) * 2) *
count;
1059 const size_t vertlen = (
sizeof (float) * 2) *
count;
1076 verts += (
count * 2) - 2;
1078 const float xstart =
points[0].x;
1079 const float ystart =
points[0].y;
1080 const float xend =
points[1].x;
1081 const float yend =
points[1].y;
1083 if (ystart == yend) {
1084 verts[0] += (xend > xstart) ? 1.0
f : -1.0f;
1085 }
else if (xstart == xend) {
1086 verts[1] += (yend > ystart) ? 1.0
f : -1.0f;
1095 const size_t vertlen = (
sizeof (float) * 8) *
count;
1109 if ((
rects->w <= 0.0f) || (
rects->h <= 0.0f)) {
1134 const float texw = (float)
texture->w;
1135 const float texh = (
float)
texture->h;
1137 const size_t vertlen = (
sizeof (float) * 16);
1146 *(verts++) = dstrect->
x;
1147 *(verts++) = dstrect->
y + dstrect->
h;
1148 *(verts++) = normtex(srcrect->
x, texw);
1149 *(verts++) = normtex(srcrect->
y + srcrect->
h, texh);
1151 *(verts++) = dstrect->
x;
1152 *(verts++) = dstrect->
y;
1153 *(verts++) = normtex(srcrect->
x, texw);
1154 *(verts++) = normtex(srcrect->
y, texh);
1156 *(verts++) = dstrect->
x + dstrect->
w;
1157 *(verts++) = dstrect->
y + dstrect->
h;
1158 *(verts++) = normtex(srcrect->
x + srcrect->
w, texw);
1159 *(verts++) = normtex(srcrect->
y + srcrect->
h, texh);
1161 *(verts++) = dstrect->
x + dstrect->
w;
1162 *(verts++) = dstrect->
y;
1163 *(verts++) = normtex(srcrect->
x + srcrect->
w, texw);
1164 *(verts++) = normtex(srcrect->
y, texh);
1174 const float texw = (float)
texture->
w;
1175 const float texh = (
float)
texture->h;
1176 const float rads = (float)(M_PI * (
float)
angle / 180.0f);
1177 const float c = cosf(rads),
s = sinf(rads);
1178 float minu, maxu, minv, maxv;
1179 const size_t vertlen = (
sizeof (float) * 32);
1189 SDL_memset(verts,
'\0',
sizeof (*verts) * 16);
1190 verts[10] = verts[15] = 1.0f;
1198 verts[12] = dstrect->
x + center->
x;
1199 verts[13] = dstrect->
y + center->
y;
1207 minu = normtex(srcquad->
x, texw);
1208 maxu = normtex(srcquad->
x + srcquad->
w, texw);
1209 minv = normtex(srcquad->
y, texh);
1210 maxv = normtex(srcquad->
y + srcquad->
h, texh);
1224 *(verts++) = -center->
x;
1225 *(verts++) = dstrect->
h - center->
y;
1229 *(verts++) = -center->
x;
1230 *(verts++) = -center->
y;
1234 *(verts++) = dstrect->
w - center->
x;
1235 *(verts++) = dstrect->
h - center->
y;
1239 *(verts++) = dstrect->
w - center->
x;
1240 *(verts++) = -center->
y;
1250 #if __has_feature(objc_arc)
1257 size_t constants_offset;
1264 size_t projection_offset;
1266 size_t color_offset;
1267 } METAL_DrawStateCache;
1271 const size_t constants_offset,
id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
1278 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionLoad,
NULL, statecache->vertex_buffer);
1280 if (statecache->viewport_dirty) {
1282 viewport.originX = statecache->viewport.
x;
1283 viewport.originY = statecache->viewport.
y;
1284 viewport.width = statecache->viewport.
w;
1285 viewport.height = statecache->viewport.
h;
1288 [data.mtlcmdencoder setViewport:viewport];
1289 [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:statecache->projection_offset atIndex:2];
1293 if (statecache->cliprect_dirty) {
1294 MTLScissorRect mtlrect;
1295 if (statecache->cliprect_enabled) {
1297 mtlrect.
x = statecache->viewport.x +
rect->
x;
1298 mtlrect.
y = statecache->viewport.y +
rect->
y;
1299 mtlrect.width =
rect->
w;
1300 mtlrect.height =
rect->
h;
1302 mtlrect.x = statecache->viewport.x;
1303 mtlrect.y = statecache->viewport.y;
1304 mtlrect.width = statecache->viewport.w;
1305 mtlrect.height = statecache->viewport.h;
1307 if (mtlrect.width > 0 && mtlrect.height > 0) {
1308 [data.mtlcmdencoder setScissorRect:mtlrect];
1313 if (statecache->color_dirty) {
1314 [data.mtlcmdencoder setFragmentBufferOffset:statecache->color_offset atIndex:0];
1318 newpipeline = ChoosePipelineState(
data,
data.activepipelines,
shader, blend);
1319 if (newpipeline != statecache->pipeline) {
1320 [data.mtlcmdencoder setRenderPipelineState:newpipeline];
1321 statecache->pipeline = newpipeline;
1324 if (constants_offset != statecache->constants_offset) {
1325 if (constants_offset != CONSTANTS_OFFSET_INVALID) {
1326 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:constants_offset atIndex:3];
1328 statecache->constants_offset = constants_offset;
1331 [data.mtlcmdencoder setVertexBufferOffset:first atIndex:0];
1336 id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
1340 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)
texture->driverdata;
1342 SetDrawState(
renderer, cmd, texturedata.fragmentFunction, constants_offset, mtlbufvertex, statecache);
1344 if (
texture != statecache->texture) {
1345 METAL_TextureData *oldtexturedata =
NULL;
1346 if (statecache->texture) {
1347 oldtexturedata = (__bridge METAL_TextureData *) statecache->texture->driverdata;
1349 if (!oldtexturedata || (texturedata.mtlsampler != oldtexturedata.mtlsampler)) {
1350 [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
1353 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
1354 if (texturedata.yuv || texturedata.nv12) {
1355 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
1356 [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
1358 statecache->texture =
texture;
1364 { @autoreleasepool {
1366 METAL_DrawStateCache statecache;
1371 statecache.pipeline = nil;
1372 statecache.vertex_buffer = nil;
1373 statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
1374 statecache.texture =
NULL;
1376 statecache.cliprect_dirty =
SDL_TRUE;
1377 statecache.viewport_dirty =
SDL_TRUE;
1378 statecache.projection_offset = 0;
1379 statecache.color_offset = 0;
1390 mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
1391 #if !__has_feature(objc_arc)
1392 [mtlbufvertex autorelease];
1394 mtlbufvertex.label =
@"SDL vertex data";
1395 SDL_memcpy([mtlbufvertex contents], vertices, vertsize);
1397 statecache.vertex_buffer = mtlbufvertex;
1401 [data.mtlcmdencoder endEncoding];
1402 [data.mtlcmdbuffer commit];
1403 data.mtlcmdencoder = nil;
1404 data.mtlcmdbuffer = nil;
1410 statecache.projection_offset = cmd->
data.
viewport.first;
1411 statecache.viewport_dirty =
SDL_TRUE;
1412 statecache.cliprect_dirty =
SDL_TRUE;
1418 statecache.cliprect_enabled = cmd->
data.
cliprect.enabled;
1419 statecache.cliprect_dirty =
SDL_TRUE;
1424 statecache.color_offset = cmd->
data.
color.first;
1433 if (
data.mtlcmdencoder != nil) {
1434 [data.mtlcmdencoder endEncoding];
1437 [data.mtlcmdbuffer commit];
1438 data.mtlcmdencoder = nil;
1439 data.mtlcmdbuffer = nil;
1443 statecache.pipeline = nil;
1444 statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
1445 statecache.texture =
NULL;
1447 statecache.cliprect_dirty =
SDL_TRUE;
1448 statecache.viewport_dirty =
SDL_TRUE;
1454 MTLClearColor
color = MTLClearColorMake(
r / 255.0
f,
g / 255.0
f,
b / 255.0
f,
a / 255.0
f);
1457 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionClear, &
color, mtlbufvertex);
1465 SetDrawState(
renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, mtlbufvertex, &statecache);
1466 [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
1472 const size_t maxcount = UINT16_MAX / 4;
1473 SetDrawState(
renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
1475 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1479 for (
size_t i = 0;
i <
count;
i += maxcount) {
1482 [data.mtlcmdencoder setVertexBufferOffset:cmd->data.draw.first + i*sizeof(float)*8 atIndex:0];
1483 [data.mtlcmdencoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
1484 indexCount:SDL_min(maxcount, count - i) * 6
1485 indexType:MTLIndexTypeUInt16
1486 indexBuffer:data.mtlbufquadindices
1487 indexBufferOffset:0];
1494 SetCopyState(
renderer, cmd, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
1495 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1500 SetCopyState(
renderer, cmd, CONSTANTS_OFFSET_INVALID, mtlbufvertex, &statecache);
1501 [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.count atIndex:3];
1502 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1518 { @autoreleasepool {
1520 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionLoad,
NULL, nil);
1522 [data.mtlcmdencoder endEncoding];
1530 if (METAL_GetStorageMode(mtltexture) == MTLStorageModeManaged) {
1532 [blit synchronizeResource:mtltexture];
1539 [data.mtlcmdbuffer commit];
1540 [data.mtlcmdbuffer waitUntilCompleted];
1541 data.mtlcmdencoder = nil;
1542 data.mtlcmdbuffer = nil;
1547 const int temp_pitch =
rect->
w * 4;
1553 [mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
1563 { @autoreleasepool {
1567 if (
data.mtlcmdencoder == nil) {
1569 if (
data.mtlbackbuffer == nil) {
1570 MTLClearColor
color = MTLClearColorMake(0.0
f, 0.0
f, 0.0
f, 1.0
f);
1571 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionClear, &
color, nil);
1573 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionLoad,
NULL, nil);
1577 [data.mtlcmdencoder endEncoding];
1578 [data.mtlcmdbuffer presentDrawable:data.mtlbackbuffer];
1579 [data.mtlcmdbuffer commit];
1581 data.mtlcmdencoder = nil;
1582 data.mtlcmdbuffer = nil;
1583 data.mtlbackbuffer = nil;
1588 { @autoreleasepool {
1589 CFBridgingRelease(
texture->driverdata);
1595 { @autoreleasepool {
1599 if (
data.mtlcmdencoder != nil) {
1600 [data.mtlcmdencoder endEncoding];
1603 DestroyAllPipelines(
data.allpipelines,
data.pipelinescount);
1613 { @autoreleasepool {
1615 return (__bridge
void*)
data.mtllayer;
1620 { @autoreleasepool {
1621 METAL_ActivateRenderCommandEncoder(
renderer, MTLLoadActionLoad,
NULL, nil);
1623 return (__bridge
void*)
data.mtlcmdencoder;
1628 { @autoreleasepool {
1643 if (IsMetalAvailable(&syswm) == -1) {
1658 if (changed_window) {
1665 mtldevice = MTLCreateSystemDefaultDevice();
1667 if (mtldevice == nil) {
1670 if (changed_window) {
1679 #if !__has_feature(objc_arc)
1680 [mtldevice release];
1683 if (changed_window) {
1690 data = [[METAL_RenderData alloc] init];
1693 #if !__has_feature(objc_arc)
1694 [mtldevice release];
1698 if (changed_window) {
1707 data.mtlview = view;
1715 layer.device = mtldevice;
1718 layer.framebufferOnly = NO;
1723 data.mtlcmdqueue = mtlcmdqueue;
1724 data.mtlcmdqueue.label =
@"SDL Metal Renderer";
1725 data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
1731 dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
1732 id<MTLLibrary> mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
1733 data.mtllibrary = mtllibrary;
1735 #if !__has_feature(objc_arc)
1736 dispatch_release(mtllibdata);
1738 data.mtllibrary.label =
@"SDL Metal renderer shader library";
1741 data.pipelinescount = 0;
1743 ChooseShaderPipelines(
data, MTLPixelFormatBGRA8Unorm);
1745 MTLSamplerDescriptor *samplerdesc = [[MTLSamplerDescriptor alloc] init];
1747 samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
1748 samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
1749 id<MTLSamplerState> mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
1750 data.mtlsamplernearest = mtlsamplernearest;
1752 samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
1753 samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
1754 id<MTLSamplerState> mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
1755 data.mtlsamplerlinear = mtlsamplerlinear;
1758 float identitytransform[16] = {
1759 1.0f, 0.0f, 0.0f, 0.0f,
1760 0.0f, 1.0f, 0.0f, 0.0f,
1761 0.0f, 0.0f, 1.0f, 0.0f,
1762 0.0f, 0.0f, 0.0f, 1.0f,
1765 float halfpixeltransform[16] = {
1766 1.0f, 0.0f, 0.0f, 0.0f,
1767 0.0f, 1.0f, 0.0f, 0.0f,
1768 0.0f, 0.0f, 1.0f, 0.0f,
1769 0.5f, 0.5f, 0.0f, 1.0f,
1773 float decodetransformJPEG[4*4] = {
1774 0.0, -0.501960814, -0.501960814, 0.0,
1775 1.0000, 0.0000, 1.4020, 0.0,
1776 1.0000, -0.3441, -0.7141, 0.0,
1777 1.0000, 1.7720, 0.0000, 0.0,
1780 float decodetransformBT601[4*4] = {
1781 -0.0627451017, -0.501960814, -0.501960814, 0.0,
1782 1.1644, 0.0000, 1.5960, 0.0,
1783 1.1644, -0.3918, -0.8130, 0.0,
1784 1.1644, 2.0172, 0.0000, 0.0,
1787 float decodetransformBT709[4*4] = {
1788 0.0, -0.501960814, -0.501960814, 0.0,
1789 1.0000, 0.0000, 1.4020, 0.0,
1790 1.0000, -0.3441, -0.7141, 0.0,
1791 1.0000, 1.7720, 0.0000, 0.0,
1794 id<MTLBuffer> mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
1795 #if !__has_feature(objc_arc)
1796 [mtlbufconstantstaging autorelease];
1799 char *constantdata = [mtlbufconstantstaging contents];
1800 SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform,
sizeof(identitytransform));
1801 SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform,
sizeof(halfpixeltransform));
1802 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG,
sizeof(decodetransformJPEG));
1803 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601,
sizeof(decodetransformBT601));
1804 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709,
sizeof(decodetransformBT709));
1806 int quadcount = UINT16_MAX / 4;
1807 size_t indicessize =
sizeof(UInt16) * quadcount * 6;
1808 id<MTLBuffer> mtlbufquadindicesstaging = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModeShared];
1809 #if !__has_feature(objc_arc)
1810 [mtlbufquadindicesstaging autorelease];
1818 UInt16 *indexdata = [mtlbufquadindicesstaging contents];
1819 for (
int i = 0;
i < quadcount;
i++) {
1820 indexdata[i * 6 + 0] =
i * 4 + 0;
1821 indexdata[i * 6 + 1] =
i * 4 + 1;
1822 indexdata[i * 6 + 2] =
i * 4 + 2;
1824 indexdata[i * 6 + 3] =
i * 4 + 2;
1825 indexdata[i * 6 + 4] =
i * 4 + 1;
1826 indexdata[i * 6 + 5] =
i * 4 + 3;
1829 id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
1830 data.mtlbufconstants = mtlbufconstants;
1831 data.mtlbufconstants.label =
@"SDL constant data";
1833 id<MTLBuffer> mtlbufquadindices = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModePrivate];
1834 data.mtlbufquadindices = mtlbufquadindices;
1835 data.mtlbufquadindices.label =
@"SDL quad index buffer";
1840 [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
1841 [blitcmd copyFromBuffer:mtlbufquadindicesstaging sourceOffset:0 toBuffer:mtlbufquadindices destinationOffset:0 size:indicessize];
1843 [blitcmd endEncoding];
1878 #if defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)
1879 if (@available(macOS 10.13, *)) {
1881 if (
data.mtllayer.displaySyncEnabled) {
1891 int maxtexsize = 4096;
1892 #if defined(__MACOSX__)
1894 #elif defined(__TVOS__)
1897 if (@available(tvOS 11.0, *)) {
1898 if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
1904 #ifdef __IPHONE_11_0
1905 #pragma clang diagnostic push
1906 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
1907 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
1910 #pragma clang diagnostic pop
1912 #ifdef __IPHONE_10_0
1913 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
1917 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
1927 #if !__has_feature(objc_arc)
1928 [mtlcmdqueue release];
1929 [mtllibrary release];
1930 [samplerdesc release];
1931 [mtlsamplernearest release];
1932 [mtlsamplerlinear release];
1933 [mtlbufconstants release];
1934 [mtlbufquadindices release];
1936 [mtldevice release];
1943 METAL_CreateRenderer,
#define SDL_assert(condition)
SDL_BlendOperation
The blend operation used when combining source and destination pixel components.
@ SDL_BLENDOPERATION_MAXIMUM
@ SDL_BLENDOPERATION_MINIMUM
@ SDL_BLENDOPERATION_REV_SUBTRACT
@ SDL_BLENDOPERATION_SUBTRACT
SDL_BlendFactor
The normalized factor used to multiply pixel components.
@ SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR
@ SDL_BLENDFACTOR_SRC_COLOR
@ SDL_BLENDFACTOR_SRC_ALPHA
@ SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR
@ SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA
@ SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA
@ SDL_BLENDFACTOR_DST_ALPHA
@ SDL_BLENDFACTOR_DST_COLOR
SDL_BlendMode
The blend mode used in SDL_RenderCopy() and drawing operations.
#define SDL_Metal_CreateView
#define SDL_Metal_DestroyView
#define SDL_GetWindowFlags
#define SDL_GetYUVConversionModeForResolution
#define SDL_GetPixelFormatName
#define SDL_ConvertPixels
#define SDL_GetWindowWMInfo
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
#define SDL_OutOfMemory()
int uint32_t uint32_t uint32_t pixel_format
GLint GLint GLint GLint GLint GLint y
GLuint GLuint GLsizei count
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
GLdouble GLdouble GLdouble r
GLint GLint GLint GLint GLint x
GLboolean GLboolean GLboolean b
GLfixed GLfixed GLint GLint GLfixed points
GLboolean GLboolean GLboolean GLboolean a
GLuint GLsizei const GLchar * label
GLenum GLenum GLuint texture
GLenum GLuint GLint GLint layer
GLfloat GLfloat GLfloat GLfloat h
GLubyte GLubyte GLubyte GLubyte w
GLsizeiptr const void GLenum usage
#define SDL_BYTESPERPIXEL(X)
@ SDL_PIXELFORMAT_ABGR8888
@ SDL_PIXELFORMAT_ARGB8888
SDL_BlendFactor SDL_GetBlendModeDstColorFactor(SDL_BlendMode blendMode)
SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode)
void * SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset)
SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode)
SDL_BlendFactor SDL_GetBlendModeSrcAlphaFactor(SDL_BlendMode blendMode)
SDL_BlendOperation SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode)
SDL_BlendOperation SDL_GetBlendModeColorOperation(SDL_BlendMode blendMode)
@ SDL_RENDERER_ACCELERATED
@ SDL_RENDERER_PRESENTVSYNC
@ SDL_RENDERER_TARGETTEXTURE
SDL_RendererFlip
Flip constants for SDL_RenderCopyEx.
@ SDL_TEXTUREACCESS_TARGET
SDL_ScaleMode
The scaling mode for a texture.
static void SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate)
SDL_YUV_CONVERSION_MODE
The formula used for converting between YUV and RGB.
@ SDL_YUV_CONVERSION_BT601
@ SDL_YUV_CONVERSION_JPEG
@ SDL_YUV_CONVERSION_BT709
SDL_RenderDriver METAL_RenderDriver
@ SDL_RENDERCMD_SETCLIPRECT
@ SDL_RENDERCMD_DRAW_LINES
@ SDL_RENDERCMD_SETVIEWPORT
@ SDL_RENDERCMD_DRAW_POINTS
@ SDL_RENDERCMD_FILL_RECTS
@ SDL_RENDERCMD_SETDRAWCOLOR
int SDL_RecreateWindow(SDL_Window *window, Uint32 flags)
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
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)
EGLSurface EGLNativeWindowType * window
EGLSurface EGLint * rects
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 skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
The structure that defines a point (floating point)
A rectangle, with the origin at the upper left (floating point).
A rectangle, with the origin at the upper left (integer).
struct SDL_RenderCommand::@38::@42 color
struct SDL_RenderCommand * next
struct SDL_RenderCommand::@38::@39 viewport
struct SDL_RenderCommand::@38::@41 draw
SDL_RenderCommandType command
union SDL_RenderCommand::@38 data
struct SDL_RenderCommand::@38::@40 cliprect
int(* QueueCopy)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
int(* LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, 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)
int(* QueueDrawLines)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
void(* SetTextureScaleMode)(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
void(* UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
int(* SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture)
void(* DestroyRenderer)(SDL_Renderer *renderer)
void(* DestroyTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* GetOutputSize)(SDL_Renderer *renderer, int *w, int *h)
SDL_bool(* SupportsBlendMode)(SDL_Renderer *renderer, SDL_BlendMode blendMode)
void(* RenderPresent)(SDL_Renderer *renderer)
int(* RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
int(* QueueDrawPoints)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
int(* QueueFillRects)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count)
void(* WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event)
int(* RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
int(* QueueCopyEx)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_Rect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
int(* CreateTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* QueueSetViewport)(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
void *(* GetMetalLayer)(SDL_Renderer *renderer)
void *(* GetMetalCommandEncoder)(SDL_Renderer *renderer)
int(* QueueSetDrawColor)(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
Window state change event data (event.window.*)
The type used to identify a window.
static SDL_Renderer * renderer
static SDL_BlendMode blendMode
typedef int(__stdcall *FARPROC)()