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> 51 #define CONSTANT_ALIGN 256 53 #define CONSTANT_ALIGN 4 56 #define ALIGN_CONSTANTS(size) ((size + CONSTANT_ALIGN - 1) & (~(CONSTANT_ALIGN - 1))) 58 static const size_t CONSTANTS_OFFSET_INVALID = 0xFFFFFFFF;
59 static const size_t CONSTANTS_OFFSET_IDENTITY = 0;
60 static const size_t CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM = ALIGN_CONSTANTS(CONSTANTS_OFFSET_IDENTITY +
sizeof(
float) * 16);
61 static const size_t CONSTANTS_OFFSET_DECODE_JPEG = ALIGN_CONSTANTS(CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM +
sizeof(
float) * 16);
62 static const size_t CONSTANTS_OFFSET_DECODE_BT601 = ALIGN_CONSTANTS(CONSTANTS_OFFSET_DECODE_JPEG +
sizeof(
float) * 4 * 4);
63 static const size_t CONSTANTS_OFFSET_DECODE_BT709 = ALIGN_CONSTANTS(CONSTANTS_OFFSET_DECODE_BT601 +
sizeof(
float) * 4 * 4);
64 static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT709 + sizeof(float) * 4 * 4;
66 typedef enum SDL_MetalVertexFunction
68 SDL_METAL_VERTEX_SOLID,
69 SDL_METAL_VERTEX_COPY,
70 } SDL_MetalVertexFunction;
72 typedef enum SDL_MetalFragmentFunction
74 SDL_METAL_FRAGMENT_SOLID = 0,
75 SDL_METAL_FRAGMENT_COPY,
76 SDL_METAL_FRAGMENT_YUV,
77 SDL_METAL_FRAGMENT_NV12,
78 SDL_METAL_FRAGMENT_NV21,
79 SDL_METAL_FRAGMENT_COUNT,
80 } SDL_MetalFragmentFunction;
82 typedef struct METAL_PipelineState
86 } METAL_PipelineState;
88 typedef struct METAL_PipelineCache
90 METAL_PipelineState *states;
92 SDL_MetalVertexFunction vertexFunction;
93 SDL_MetalFragmentFunction fragmentFunction;
94 MTLPixelFormat renderTargetFormat;
96 } METAL_PipelineCache;
104 typedef struct METAL_ShaderPipelines
106 MTLPixelFormat renderTargetFormat;
107 METAL_PipelineCache caches[SDL_METAL_FRAGMENT_COUNT];
108 } METAL_ShaderPipelines;
110 @interface METAL_RenderData : NSObject
120 @property (nonatomic, retain)
id<MTLBuffer> mtlbufquadindices;
121 @property (nonatomic, retain) CAMetalLayer *mtllayer;
122 @property (nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
123 @property (nonatomic, assign) METAL_ShaderPipelines *activepipelines;
124 @property (nonatomic, assign) METAL_ShaderPipelines *allpipelines;
125 @property (nonatomic, assign)
int pipelinescount;
128 @implementation METAL_RenderData
129 #if !__has_feature(objc_arc) 132 [_mtldevice release];
133 [_mtlcmdqueue release];
134 [_mtlcmdbuffer release];
135 [_mtlcmdencoder release];
136 [_mtllibrary release];
137 [_mtlbackbuffer release];
138 [_mtlsamplernearest release];
139 [_mtlsamplerlinear release];
140 [_mtlbufconstants release];
141 [_mtlbufquadindices release];
143 [_mtlpassdesc release];
149 @interface METAL_TextureData : NSObject
153 @property (nonatomic, assign) SDL_MetalFragmentFunction fragmentFunction;
154 @property (nonatomic, assign) BOOL yuv;
155 @property (nonatomic, assign) BOOL nv12;
156 @property (nonatomic, assign)
size_t conversionBufferOffset;
157 @property (nonatomic, assign) BOOL hasdata;
160 @property (nonatomic, assign)
SDL_Rect lockedrect;
163 @implementation METAL_TextureData
164 #if !__has_feature(objc_arc) 167 [_mtltexture release];
168 [_mtltexture_uv release];
169 [_mtlsampler release];
179 return SDL_SetError(
"Metal render target only supports Cocoa and UIKit video targets at the moment.");
183 #if (defined(__MACOSX__) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101100)) 184 if (MTLCreateSystemDefaultDevice ==
NULL) {
185 return SDL_SetError(
"Metal framework not available on this system");
192 static const MTLBlendOperation invalidBlendOperation = (MTLBlendOperation)0xFFFFFFFF;
193 static const MTLBlendFactor invalidBlendFactor = (MTLBlendFactor)0xFFFFFFFF;
195 static MTLBlendOperation
204 default:
return invalidBlendOperation;
208 static MTLBlendFactor
222 default:
return invalidBlendFactor;
227 GetVertexFunctionName(SDL_MetalVertexFunction
function)
230 case SDL_METAL_VERTEX_SOLID:
return @"SDL_Solid_vertex";
231 case SDL_METAL_VERTEX_COPY:
return @"SDL_Copy_vertex";
237 GetFragmentFunctionName(SDL_MetalFragmentFunction
function)
240 case SDL_METAL_FRAGMENT_SOLID:
return @"SDL_Solid_fragment";
241 case SDL_METAL_FRAGMENT_COPY:
return @"SDL_Copy_fragment";
242 case SDL_METAL_FRAGMENT_YUV:
return @"SDL_YUV_fragment";
243 case SDL_METAL_FRAGMENT_NV12:
return @"SDL_NV12_fragment";
244 case SDL_METAL_FRAGMENT_NV21:
return @"SDL_NV21_fragment";
250 MakePipelineState(METAL_RenderData *
data, METAL_PipelineCache *cache,
253 id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:GetVertexFunctionName(cache->vertexFunction)];
254 id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:GetFragmentFunctionName(cache->fragmentFunction)];
258 MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
259 mtlpipedesc.vertexFunction = mtlvertfn;
260 mtlpipedesc.fragmentFunction = mtlfragfn;
262 MTLRenderPipelineColorAttachmentDescriptor *rtdesc = mtlpipedesc.colorAttachments[0];
264 rtdesc.pixelFormat = cache->renderTargetFormat;
267 rtdesc.blendingEnabled = YES;
275 rtdesc.blendingEnabled = NO;
278 mtlpipedesc.label = [@(cache->label) stringByAppendingString:blendlabel];
284 METAL_PipelineState pipeline;
285 pipeline.blendMode = blendmode;
286 pipeline.pipe = (
void *)CFBridgingRetain(state);
288 METAL_PipelineState *states =
SDL_realloc(cache->states, (cache->count + 1) *
sizeof(pipeline));
290 #if !__has_feature(objc_arc) 291 [mtlpipedesc release];
298 states[cache->count++] = pipeline;
299 cache->states = states;
302 CFBridgingRelease(pipeline.pipe);
309 MakePipelineCache(METAL_RenderData *data, METAL_PipelineCache *cache,
const char *
label,
310 MTLPixelFormat rtformat, SDL_MetalVertexFunction vertfn, SDL_MetalFragmentFunction fragfn)
314 cache->vertexFunction = vertfn;
315 cache->fragmentFunction = fragfn;
316 cache->renderTargetFormat = rtformat;
317 cache->label =
label;
328 DestroyPipelineCache(METAL_PipelineCache *cache)
331 for (
int i = 0;
i < cache->count;
i++) {
332 CFBridgingRelease(cache->states[
i].pipe);
340 MakeShaderPipelines(METAL_RenderData *data, METAL_ShaderPipelines *
pipelines, MTLPixelFormat rtformat)
344 pipelines->renderTargetFormat = rtformat;
346 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_SOLID],
"SDL primitives pipeline", rtformat, SDL_METAL_VERTEX_SOLID, SDL_METAL_FRAGMENT_SOLID);
347 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_COPY],
"SDL copy pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY);
348 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_YUV],
"SDL YUV pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_YUV);
349 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_NV12],
"SDL NV12 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV12);
350 MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_NV21],
"SDL NV21 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV21);
353 static METAL_ShaderPipelines *
354 ChooseShaderPipelines(METAL_RenderData *data, MTLPixelFormat rtformat)
356 METAL_ShaderPipelines *allpipelines = data.allpipelines;
357 int count = data.pipelinescount;
360 if (allpipelines[
i].renderTargetFormat == rtformat) {
361 return &allpipelines[i];
365 allpipelines =
SDL_realloc(allpipelines, (count + 1) *
sizeof(METAL_ShaderPipelines));
367 if (allpipelines ==
NULL) {
372 MakeShaderPipelines(data, &allpipelines[count], rtformat);
374 data.allpipelines = allpipelines;
375 data.pipelinescount = count + 1;
377 return &data.allpipelines[count];
381 DestroyAllPipelines(METAL_ShaderPipelines *allpipelines,
int count)
383 if (allpipelines !=
NULL) {
385 for (
int cache = 0; cache < SDL_METAL_FRAGMENT_COUNT; cache++) {
386 DestroyPipelineCache(&allpipelines[
i].caches[cache]);
395 ChoosePipelineState(METAL_RenderData *data, METAL_ShaderPipelines *
pipelines, SDL_MetalFragmentFunction fragfn,
SDL_BlendMode blendmode)
397 METAL_PipelineCache *cache = &pipelines->caches[fragfn];
399 for (
int i = 0;
i < cache->count;
i++) {
400 if (cache->states[
i].blendMode == blendmode) {
401 return (__bridge id<MTLRenderPipelineState>)cache->states[i].pipe;
405 return MakePipelineState(data, cache, [NSString stringWithFormat:
@" (blend=custom 0x%x)", blendmode], blendmode);
409 METAL_ActivateRenderCommandEncoder(
SDL_Renderer *
renderer, MTLLoadAction load, MTLClearColor *clear_color)
411 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
415 if (data.mtlcmdencoder == nil) {
419 METAL_TextureData *texdata = (__bridge METAL_TextureData *)renderer->
target->
driverdata;
420 mtltexture = texdata.mtltexture;
422 if (data.mtlbackbuffer == nil) {
425 data.mtlbackbuffer = [data.mtllayer nextDrawable];
426 if (load == MTLLoadActionLoad) {
427 load = MTLLoadActionDontCare;
430 mtltexture = data.mtlbackbuffer.texture;
435 if (load == MTLLoadActionClear) {
437 data.mtlpassdesc.colorAttachments[0].clearColor = *clear_color;
440 data.mtlpassdesc.colorAttachments[0].loadAction = load;
441 data.mtlpassdesc.colorAttachments[0].texture = mtltexture;
443 data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
444 data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
446 if (data.mtlbackbuffer != nil && mtltexture == data.mtlbackbuffer.texture) {
447 data.mtlcmdencoder.label =
@"SDL metal renderer backbuffer";
449 data.mtlcmdencoder.label =
@"SDL metal renderer render target";
452 data.activepipelines = ChooseShaderPipelines(data, mtltexture.pixelFormat);
457 [data.mtlcmdbuffer enqueue];
473 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
475 *w = (int)data.mtllayer.drawableSize.width;
478 *h = (int)data.mtllayer.drawableSize.height;
493 if (GetBlendFactor(srcColorFactor) == invalidBlendFactor ||
494 GetBlendFactor(srcAlphaFactor) == invalidBlendFactor ||
495 GetBlendOperation(colorOperation) == invalidBlendOperation ||
496 GetBlendFactor(dstColorFactor) == invalidBlendFactor ||
497 GetBlendFactor(dstAlphaFactor) == invalidBlendFactor ||
498 GetBlendOperation(alphaOperation) == invalidBlendOperation) {
507 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
508 MTLPixelFormat pixfmt;
510 switch (texture->
format) {
512 pixfmt = MTLPixelFormatRGBA8Unorm;
515 pixfmt = MTLPixelFormatBGRA8Unorm;
521 pixfmt = MTLPixelFormatR8Unorm;
527 MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
528 width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
531 if ([mtltexdesc respondsToSelector:
@selector(
usage)]) {
533 mtltexdesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
535 mtltexdesc.usage = MTLTextureUsageShaderRead;
539 id<MTLTexture> mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
540 if (mtltexture == nil) {
550 mtltexdesc.pixelFormat = MTLPixelFormatR8Unorm;
551 mtltexdesc.width = (texture->
w + 1) / 2;
552 mtltexdesc.height = (texture->
h + 1) / 2;
553 mtltexdesc.textureType = MTLTextureType2DArray;
554 mtltexdesc.arrayLength = 2;
556 mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
557 mtltexdesc.width = (texture->
w + 1) / 2;
558 mtltexdesc.height = (texture->
h + 1) / 2;
562 mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
563 if (mtltexture_uv == nil) {
564 #if !__has_feature(objc_arc) 565 [mtltexture release];
571 METAL_TextureData *texturedata = [[METAL_TextureData alloc] init];
573 texturedata.mtlsampler = data.mtlsamplernearest;
575 texturedata.mtlsampler = data.mtlsamplerlinear;
577 texturedata.mtltexture = mtltexture;
578 texturedata.mtltexture_uv = mtltexture_uv;
580 texturedata.yuv = yuv;
581 texturedata.nv12 = nv12;
584 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_YUV;
586 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12;
588 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21;
590 texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
600 default: offset = 0;
break;
602 texturedata.conversionBufferOffset =
offset;
605 texture->
driverdata = (
void*)CFBridgingRetain(texturedata);
607 #if !__has_feature(objc_arc) 608 [texturedata release];
609 [mtltexture release];
610 [mtltexture_uv release];
618 const void *
pixels,
int pitch)
620 [texture replaceRegion:MTLRegionMake2D(rect.x, rect.y, rect.w, rect.h)
628 static MTLStorageMode
632 if ([resource respondsToSelector:
@selector(storageMode)]) {
633 return resource.storageMode;
635 return MTLStorageModeShared;
639 METAL_UpdateTextureInternal(
SDL_Renderer * renderer, METAL_TextureData *texturedata,
641 const void *
pixels,
int pitch)
643 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
644 SDL_Rect stagingrect = {0, 0, rect.
w, rect.
h};
645 MTLTextureDescriptor *desc;
650 if (!texturedata.hasdata && METAL_GetStorageMode(texture) != MTLStorageModePrivate) {
651 METAL_UploadTextureData(texture,
rect, slice,
pixels, pitch);
655 desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:texture.pixelFormat
667 id<MTLTexture> stagingtex = [data.mtldevice newTextureWithDescriptor:desc];
668 if (stagingtex == nil) {
672 #if !__has_feature(objc_arc) 673 [stagingtex autorelease];
676 METAL_UploadTextureData(stagingtex, stagingrect, 0,
pixels, pitch);
678 if (data.mtlcmdencoder != nil) {
679 [data.mtlcmdencoder endEncoding];
680 data.mtlcmdencoder = nil;
683 if (data.mtlcmdbuffer == nil) {
684 data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
689 [blitcmd copyFromTexture:stagingtex
692 sourceOrigin:MTLOriginMake(0, 0, 0)
693 sourceSize:MTLSizeMake(rect.w, rect.h, 1)
695 destinationSlice:slice
697 destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
699 [blitcmd endEncoding];
703 [data.mtlcmdbuffer commit];
704 data.mtlcmdbuffer = nil;
713 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
715 if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, pixels, pitch) < 0) {
719 if (texturedata.yuv) {
722 int UVpitch = (pitch + 1) / 2;
723 SDL_Rect UVrect = {rect->
x / 2, rect->
y / 2, (rect->
w + 1) / 2, (rect->h + 1) / 2};
726 pixels = (
const void*)((
const Uint8*)pixels + rect->h * pitch);
727 if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice, pixels, UVpitch) < 0) {
732 pixels = (
const void*)((
const Uint8*)pixels + UVrect.h * UVpitch);
733 if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice, pixels, UVpitch) < 0) {
738 if (texturedata.nv12) {
739 SDL_Rect UVrect = {rect->
x / 2, rect->
y / 2, (rect->
w + 1) / 2, (rect->h + 1) / 2};
740 int UVpitch = 2 * ((pitch + 1) / 2);
743 pixels = (
const void*)((
const Uint8*)pixels + rect->h * pitch);
744 if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, 0, pixels, UVpitch) < 0) {
749 texturedata.hasdata = YES;
757 const Uint8 *Yplane,
int Ypitch,
758 const Uint8 *Uplane,
int Upitch,
759 const Uint8 *Vplane,
int Vpitch)
761 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
762 const int Uslice = 0;
763 const int Vslice = 1;
764 SDL_Rect UVrect = {rect->
x / 2, rect->
y / 2, (rect->
w + 1) / 2, (rect->
h + 1) / 2};
767 if (rect->
w <= 0 || rect->
h <= 0) {
771 if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch) < 0) {
774 if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice, Uplane, Upitch)) {
777 if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice, Vplane, Vpitch)) {
781 texturedata.hasdata = YES;
788 const SDL_Rect * rect,
void **pixels,
int *pitch)
790 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
791 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
794 if (rect->
w <= 0 || rect->
h <= 0) {
795 return SDL_SetError(
"Invalid rectangle dimensions for LockTexture.");
800 if (texturedata.yuv || texturedata.nv12) {
801 buffersize = ((*pitch) * rect->
h) + (2 * (*pitch + 1) / 2) * ((rect->
h + 1) / 2);
803 buffersize = (*pitch) * rect->
h;
806 texturedata.lockedrect = *
rect;
807 texturedata.lockedbuffer = [data.mtldevice newBufferWithLength:buffersize options:MTLResourceStorageModeShared];
808 if (texturedata.lockedbuffer == nil) {
812 *pixels = [texturedata.lockedbuffer contents];
820 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
821 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
822 SDL_Rect rect = texturedata.lockedrect;
824 SDL_Rect UVrect = {rect.
x / 2, rect.
y / 2, (rect.
w + 1) / 2, (rect.h + 1) / 2};
826 if (texturedata.lockedbuffer == nil) {
830 if (data.mtlcmdencoder != nil) {
831 [data.mtlcmdencoder endEncoding];
832 data.mtlcmdencoder = nil;
835 if (data.mtlcmdbuffer == nil) {
836 data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
841 [blitcmd copyFromBuffer:texturedata.lockedbuffer
843 sourceBytesPerRow:pitch
844 sourceBytesPerImage:0
845 sourceSize:MTLSizeMake(rect.w, rect.h, 1)
846 toTexture:texturedata.mtltexture
849 destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
851 if (texturedata.yuv) {
854 int UVpitch = (pitch + 1) / 2;
856 [blitcmd copyFromBuffer:texturedata.lockedbuffer
857 sourceOffset:rect.h * pitch
858 sourceBytesPerRow:UVpitch
859 sourceBytesPerImage:UVpitch * UVrect.h
860 sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
861 toTexture:texturedata.mtltexture_uv
862 destinationSlice:Uslice
864 destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
866 [blitcmd copyFromBuffer:texturedata.lockedbuffer
867 sourceOffset:(rect.h * pitch) + UVrect.h * UVpitch
868 sourceBytesPerRow:UVpitch
869 sourceBytesPerImage:UVpitch * UVrect.h
870 sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
871 toTexture:texturedata.mtltexture_uv
872 destinationSlice:Vslice
874 destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
877 if (texturedata.nv12) {
878 int UVpitch = 2 * ((pitch + 1) / 2);
880 [blitcmd copyFromBuffer:texturedata.lockedbuffer
881 sourceOffset:rect.h * pitch
882 sourceBytesPerRow:UVpitch
883 sourceBytesPerImage:0
884 sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
885 toTexture:texturedata.mtltexture_uv
888 destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
891 [blitcmd endEncoding];
893 [data.mtlcmdbuffer commit];
894 data.mtlcmdbuffer = nil;
896 #if !__has_feature(objc_arc) 897 [texturedata.lockedbuffer release];
900 texturedata.lockedbuffer = nil;
901 texturedata.hasdata = YES;
907 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
909 if (data.mtlcmdencoder) {
912 [data.mtlcmdencoder endEncoding];
913 [data.mtlcmdbuffer commit];
915 data.mtlcmdencoder = nil;
916 data.mtlcmdbuffer = nil;
928 normtex(
const float _val,
const float len)
936 float projection[4][4];
939 const size_t matrixlen =
sizeof (projection);
947 projection[0][0] = 2.0f /
w;
948 projection[1][1] = -2.0
f / h;
949 projection[3][0] = -1.0
f;
950 projection[3][1] = 1.0f;
951 projection[3][3] = 1.0f;
961 const size_t vertlen =
sizeof (float) * 4;
966 *(verts++) = ((float)cmd->data.
color.
r) / 255.0
f;
967 *(verts++) = ((float)cmd->data.
color.
g) / 255.0
f;
968 *(verts++) = ((float)cmd->data.
color.
b) / 255.0
f;
969 *(verts++) = ((float)cmd->data.
color.
a) / 255.0
f;
976 const size_t vertlen = (
sizeof (float) * 2) *
count;
989 const size_t vertlen = (
sizeof (float) * 8) *
count;
1002 for (
int i = 0;
i <
count;
i++, rects++) {
1003 if ((rects->
w <= 0.0f) || (rects->
h <= 0.0f)) {
1006 *(verts++) = rects->
x;
1007 *(verts++) = rects->
y + rects->h;
1008 *(verts++) = rects->
x;
1009 *(verts++) = rects->
y;
1010 *(verts++) = rects->
x + rects->w;
1011 *(verts++) = rects->
y + rects->h;
1012 *(verts++) = rects->
x + rects->w;
1013 *(verts++) = rects->
y;
1028 const float texw = (float) texture->
w;
1029 const float texh = (
float) texture->
h;
1031 const size_t vertlen = (
sizeof (float) * 16);
1039 *(verts++) = dstrect->
x;
1040 *(verts++) = dstrect->
y + dstrect->h;
1041 *(verts++) = dstrect->
x;
1042 *(verts++) = dstrect->
y;
1043 *(verts++) = dstrect->
x + dstrect->w;
1044 *(verts++) = dstrect->
y + dstrect->h;
1045 *(verts++) = dstrect->
x + dstrect->w;
1046 *(verts++) = dstrect->
y;
1048 *(verts++) = normtex(srcrect->
x, texw);
1049 *(verts++) = normtex(srcrect->
y + srcrect->h, texh);
1050 *(verts++) = normtex(srcrect->
x, texw);
1051 *(verts++) = normtex(srcrect->
y, texh);
1052 *(verts++) = normtex(srcrect->
x + srcrect->w, texw);
1053 *(verts++) = normtex(srcrect->
y + srcrect->h, texh);
1054 *(verts++) = normtex(srcrect->
x + srcrect->w, texw);
1055 *(verts++) = normtex(srcrect->
y, texh);
1065 const float texw = (float) texture->
w;
1066 const float texh = (
float) texture->
h;
1067 const float rads = (float)(M_PI * (
float) angle / 180.0f);
1068 const float c = cosf(rads),
s = sinf(rads);
1069 float minu, maxu, minv, maxv;
1070 const size_t vertlen = (
sizeof (float) * 32);
1080 SDL_memset(verts,
'\0',
sizeof (*verts) * 16);
1081 verts[10] = verts[15] = 1.0f;
1089 verts[12] = dstrect->
x + center->
x;
1090 verts[13] = dstrect->
y + center->
y;
1098 minu = normtex(srcquad->
x, texw);
1099 maxu = normtex(srcquad->
x + srcquad->
w, texw);
1100 minv = normtex(srcquad->
y, texh);
1101 maxv = normtex(srcquad->
y + srcquad->
h, texh);
1115 *(verts++) = -center->
x;
1116 *(verts++) = dstrect->h - center->
y;
1117 *(verts++) = -center->
x;
1118 *(verts++) = -center->
y;
1119 *(verts++) = dstrect->w - center->
x;
1120 *(verts++) = dstrect->h - center->
y;
1121 *(verts++) = dstrect->w - center->
x;
1122 *(verts++) = -center->
y;
1140 #if __has_feature(objc_arc) 1145 size_t constants_offset;
1152 size_t projection_offset;
1154 size_t color_offset;
1155 } METAL_DrawStateCache;
1159 const size_t constants_offset,
id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
1161 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1166 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad,
NULL);
1168 if (statecache->viewport_dirty) {
1170 viewport.originX = statecache->viewport.
x;
1171 viewport.originY = statecache->viewport.y;
1172 viewport.width = statecache->viewport.w;
1173 viewport.height = statecache->viewport.h;
1174 viewport.znear = 0.0;
1175 viewport.zfar = 1.0;
1176 [data.mtlcmdencoder setViewport:viewport];
1177 [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:statecache->projection_offset atIndex:2];
1181 if (statecache->cliprect_dirty) {
1182 MTLScissorRect mtlrect;
1183 if (statecache->cliprect_enabled) {
1184 const SDL_Rect *rect = &statecache->cliprect;
1185 mtlrect.
x = statecache->viewport.x + rect->
x;
1186 mtlrect.
y = statecache->viewport.y + rect->
y;
1187 mtlrect.width = rect->
w;
1188 mtlrect.height = rect->
h;
1190 mtlrect.x = statecache->viewport.x;
1191 mtlrect.y = statecache->viewport.y;
1192 mtlrect.width = statecache->viewport.w;
1193 mtlrect.height = statecache->viewport.h;
1195 if (mtlrect.width > 0 && mtlrect.height > 0) {
1196 [data.mtlcmdencoder setScissorRect:mtlrect];
1201 if (statecache->color_dirty) {
1202 [data.mtlcmdencoder setFragmentBuffer:mtlbufvertex offset:statecache->color_offset atIndex:0];
1206 newpipeline = ChoosePipelineState(data, data.activepipelines, shader, blend);
1207 if (newpipeline != statecache->pipeline) {
1208 [data.mtlcmdencoder setRenderPipelineState:newpipeline];
1209 statecache->pipeline = newpipeline;
1212 if (constants_offset != statecache->constants_offset) {
1213 if (constants_offset != CONSTANTS_OFFSET_INVALID) {
1214 [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:constants_offset atIndex:3];
1216 statecache->constants_offset = constants_offset;
1219 [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:first atIndex:0];
1224 id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
1226 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1228 METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->
driverdata;
1230 SetDrawState(renderer, cmd, texturedata.fragmentFunction, constants_offset, mtlbufvertex, statecache);
1232 [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.first+(8*sizeof (float)) atIndex:1];
1234 if (texture != statecache->texture) {
1235 METAL_TextureData *oldtexturedata =
NULL;
1236 if (statecache->texture) {
1237 oldtexturedata = (__bridge METAL_TextureData *) statecache->texture->driverdata;
1239 if (!oldtexturedata || (texturedata.mtlsampler != oldtexturedata.mtlsampler)) {
1240 [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
1243 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
1244 if (texturedata.yuv || texturedata.nv12) {
1245 [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
1246 [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
1248 statecache->texture =
texture;
1254 { @autoreleasepool {
1255 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1256 METAL_DrawStateCache statecache;
1259 statecache.pipeline = nil;
1260 statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
1261 statecache.texture =
NULL;
1263 statecache.cliprect_dirty =
SDL_TRUE;
1264 statecache.viewport_dirty =
SDL_TRUE;
1265 statecache.projection_offset = 0;
1266 statecache.color_offset = 0;
1277 mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
1278 #if !__has_feature(objc_arc) 1279 [mtlbufvertex autorelease];
1281 mtlbufvertex.label =
@"SDL vertex data";
1282 SDL_memcpy([mtlbufvertex contents], vertices, vertsize);
1286 [data.mtlcmdencoder endEncoding];
1287 [data.mtlcmdbuffer commit];
1288 data.mtlcmdencoder = nil;
1289 data.mtlcmdbuffer = nil;
1295 statecache.projection_offset = cmd->
data.
viewport.first;
1296 statecache.viewport_dirty =
SDL_TRUE;
1302 statecache.cliprect_enabled = cmd->
data.
cliprect.enabled;
1303 statecache.cliprect_dirty =
SDL_TRUE;
1308 statecache.color_offset = cmd->
data.
color.first;
1317 if (data.mtlcmdencoder != nil) {
1318 [data.mtlcmdencoder endEncoding];
1321 [data.mtlcmdbuffer commit];
1322 data.mtlcmdencoder = nil;
1323 data.mtlcmdbuffer = nil;
1327 statecache.pipeline = nil;
1328 statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
1329 statecache.texture =
NULL;
1331 statecache.cliprect_dirty =
SDL_TRUE;
1332 statecache.viewport_dirty =
SDL_TRUE;
1338 MTLClearColor
color = MTLClearColorMake(r / 255.0
f, g / 255.0
f, b / 255.0
f, a / 255.0
f);
1341 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color);
1347 const size_t count = cmd->
data.
draw.count;
1349 SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, mtlbufvertex, &statecache);
1350 [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
1355 const size_t count = cmd->
data.
draw.count;
1356 const size_t maxcount = UINT16_MAX / 4;
1357 SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
1360 for (
size_t i = 0;
i <
count;
i += maxcount) {
1363 [data.mtlcmdencoder setVertexBufferOffset:cmd->data.draw.first + i*sizeof(float)*8 atIndex:0];
1364 [data.mtlcmdencoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
1365 indexCount:SDL_min(maxcount, count - i) * 6
1366 indexType:MTLIndexTypeUInt16
1367 indexBuffer:data.mtlbufquadindices
1368 indexBufferOffset:0];
1374 SetCopyState(renderer, cmd, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
1375 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1380 SetCopyState(renderer, cmd, CONSTANTS_OFFSET_INVALID, mtlbufvertex, &statecache);
1381 [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.count atIndex:3];
1382 [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
1397 Uint32 pixel_format,
void * pixels,
int pitch)
1398 { @autoreleasepool {
1399 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1400 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad,
NULL);
1402 [data.mtlcmdencoder endEncoding];
1403 id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
1410 if (METAL_GetStorageMode(mtltexture) == MTLStorageModeManaged) {
1412 [blit synchronizeResource:mtltexture];
1419 [data.mtlcmdbuffer commit];
1420 [data.mtlcmdbuffer waitUntilCompleted];
1421 data.mtlcmdencoder = nil;
1422 data.mtlcmdbuffer = nil;
1424 MTLRegion mtlregion = MTLRegionMake2D(rect->
x, rect->
y, rect->
w, rect->
h);
1427 const int temp_pitch = rect->
w * 4;
1428 void *temp_pixels =
SDL_malloc(temp_pitch * rect->
h);
1433 [mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
1436 const int status =
SDL_ConvertPixels(rect->
w, rect->
h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
1443 { @autoreleasepool {
1444 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1446 if (data.mtlcmdencoder != nil) {
1447 [data.mtlcmdencoder endEncoding];
1449 if (data.mtlbackbuffer != nil) {
1450 [data.mtlcmdbuffer presentDrawable:data.mtlbackbuffer];
1452 if (data.mtlcmdbuffer != nil) {
1453 [data.mtlcmdbuffer commit];
1455 data.mtlcmdencoder = nil;
1456 data.mtlcmdbuffer = nil;
1457 data.mtlbackbuffer = nil;
1462 { @autoreleasepool {
1469 { @autoreleasepool {
1471 METAL_RenderData *data = CFBridgingRelease(renderer->
driverdata);
1473 if (data.mtlcmdencoder != nil) {
1474 [data.mtlcmdencoder endEncoding];
1477 DestroyAllPipelines(data.allpipelines, data.pipelinescount);
1485 { @autoreleasepool {
1486 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1487 return (__bridge
void*)data.mtllayer;
1492 { @autoreleasepool {
1493 METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad,
NULL);
1494 METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->
driverdata;
1495 return (__bridge
void*)data.mtlcmdencoder;
1500 { @autoreleasepool {
1502 METAL_RenderData *data =
NULL;
1511 if (IsMetalAvailable(&syswm) == -1) {
1522 mtldevice = MTLCreateSystemDefaultDevice();
1524 if (mtldevice == nil) {
1531 data = [[METAL_RenderData alloc] init];
1533 renderer->
driverdata = (
void*)CFBridgingRetain(data);
1537 NSView *view = Cocoa_Mtl_AddMetalView(window);
1538 CAMetalLayer *
layer = (CAMetalLayer *)[view layer];
1540 layer.device = mtldevice;
1545 UIView *view = UIKit_Mtl_AddMetalView(window);
1546 CAMetalLayer *layer = (CAMetalLayer *)[view layer];
1550 layer.framebufferOnly = NO;
1552 data.mtldevice = layer.device;
1553 data.mtllayer =
layer;
1555 data.mtlcmdqueue = mtlcmdqueue;
1556 data.mtlcmdqueue.label =
@"SDL Metal Renderer";
1557 data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
1564 id<MTLLibrary> mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
1565 data.mtllibrary = mtllibrary;
1567 #if !__has_feature(objc_arc) 1568 dispatch_release(mtllibdata);
1570 data.mtllibrary.label =
@"SDL Metal renderer shader library";
1573 data.pipelinescount = 0;
1574 data.allpipelines =
NULL;
1575 ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
1577 MTLSamplerDescriptor *samplerdesc = [[MTLSamplerDescriptor alloc] init];
1579 samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
1580 samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
1581 id<MTLSamplerState> mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
1582 data.mtlsamplernearest = mtlsamplernearest;
1584 samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
1585 samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
1586 id<MTLSamplerState> mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
1587 data.mtlsamplerlinear = mtlsamplerlinear;
1590 float identitytransform[16] = {
1591 1.0f, 0.0f, 0.0f, 0.0f,
1592 0.0f, 1.0f, 0.0f, 0.0f,
1593 0.0f, 0.0f, 1.0f, 0.0f,
1594 0.0f, 0.0f, 0.0f, 1.0f,
1597 float halfpixeltransform[16] = {
1598 1.0f, 0.0f, 0.0f, 0.0f,
1599 0.0f, 1.0f, 0.0f, 0.0f,
1600 0.0f, 0.0f, 1.0f, 0.0f,
1601 0.5f, 0.5f, 0.0f, 1.0f,
1605 float decodetransformJPEG[4*4] = {
1606 0.0, -0.501960814, -0.501960814, 0.0,
1607 1.0000, 0.0000, 1.4020, 0.0,
1608 1.0000, -0.3441, -0.7141, 0.0,
1609 1.0000, 1.7720, 0.0000, 0.0,
1612 float decodetransformBT601[4*4] = {
1613 -0.0627451017, -0.501960814, -0.501960814, 0.0,
1614 1.1644, 0.0000, 1.5960, 0.0,
1615 1.1644, -0.3918, -0.8130, 0.0,
1616 1.1644, 2.0172, 0.0000, 0.0,
1619 float decodetransformBT709[4*4] = {
1620 0.0, -0.501960814, -0.501960814, 0.0,
1621 1.0000, 0.0000, 1.4020, 0.0,
1622 1.0000, -0.3441, -0.7141, 0.0,
1623 1.0000, 1.7720, 0.0000, 0.0,
1626 id<MTLBuffer> mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
1627 #if !__has_feature(objc_arc) 1628 [mtlbufconstantstaging autorelease];
1631 char *constantdata = [mtlbufconstantstaging contents];
1632 SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform,
sizeof(identitytransform));
1633 SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform,
sizeof(halfpixeltransform));
1634 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG,
sizeof(decodetransformJPEG));
1635 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601,
sizeof(decodetransformBT601));
1636 SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709,
sizeof(decodetransformBT709));
1638 int quadcount = UINT16_MAX / 4;
1639 size_t indicessize =
sizeof(UInt16) * quadcount * 6;
1640 id<MTLBuffer> mtlbufquadindicesstaging = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModeShared];
1641 #if !__has_feature(objc_arc) 1642 [mtlbufquadindicesstaging autorelease];
1650 UInt16 *indexdata = [mtlbufquadindicesstaging contents];
1651 for (
int i = 0;
i < quadcount;
i++) {
1652 indexdata[i * 6 + 0] =
i * 4 + 0;
1653 indexdata[i * 6 + 1] =
i * 4 + 1;
1654 indexdata[i * 6 + 2] =
i * 4 + 2;
1656 indexdata[i * 6 + 3] =
i * 4 + 2;
1657 indexdata[i * 6 + 4] =
i * 4 + 1;
1658 indexdata[i * 6 + 5] =
i * 4 + 3;
1661 id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
1662 data.mtlbufconstants = mtlbufconstants;
1663 data.mtlbufconstants.label =
@"SDL constant data";
1665 id<MTLBuffer> mtlbufquadindices = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModePrivate];
1666 data.mtlbufquadindices = mtlbufquadindices;
1667 data.mtlbufquadindices.label =
@"SDL quad index buffer";
1672 [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
1673 [blitcmd copyFromBuffer:mtlbufquadindicesstaging sourceOffset:0 toBuffer:mtlbufquadindices destinationOffset:0 size:indicessize];
1675 [blitcmd endEncoding];
1709 #if defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13) 1712 if (data.mtllayer.displaySyncEnabled) {
1722 int maxtexsize = 4096;
1723 #if defined(__MACOSX__) 1725 #elif defined(__TVOS__) 1729 if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
1735 #ifdef __IPHONE_11_0 1736 #pragma clang diagnostic push 1737 #pragma clang diagnostic ignored "-Wunguarded-availability-new" 1738 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
1741 #pragma clang diagnostic pop 1743 #ifdef __IPHONE_10_0 1744 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
1748 if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
1758 #if !__has_feature(objc_arc) 1759 [mtlcmdqueue release];
1760 [mtllibrary release];
1761 [samplerdesc release];
1762 [mtlsamplernearest release];
1763 [mtlsamplerlinear release];
1764 [mtlbufconstants release];
1765 [mtlbufquadindices release];
1768 [mtldevice release];
1775 METAL_CreateRenderer,
SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode)
SDL_BlendFactor
The normalized factor used to multiply pixel components.
GLdouble GLdouble GLdouble r
int(* LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
struct SDL_RenderCommand::@30::@31 viewport
static void SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate)
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
struct SDL_RenderCommand::@30::@32 cliprect
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
void * SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset)
struct SDL_RenderCommand::@30::@34 color
GLfloat GLfloat GLfloat GLfloat h
int(* QueueSetDrawColor)(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode)
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)
SDL_BlendOperation SDL_GetBlendModeColorOperation(SDL_BlendMode blendMode)
SDL_RendererFlip
Flip constants for SDL_RenderCopyEx.
#define SDL_BYTESPERPIXEL(X)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
GLenum GLuint GLint GLint layer
SDL_BlendOperation
The blend operation used when combining source and destination pixel components.
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)
int(* QueueCopy)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
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
struct SDL_RenderCommand::@30::@33 draw
static SDL_Renderer * renderer
int(* QueueSetViewport)(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
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)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
int(* QueueDrawLines)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
int(* RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
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)
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(* QueueDrawPoints)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
EGLSurface EGLNativeWindowType * window
SDL_RenderCommandType command
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.
union SDL_RenderCommand::@30 data
SDL_BlendFactor SDL_GetBlendModeDstColorFactor(SDL_BlendMode blendMode)
int(* QueueFillRects)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count)
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
struct SDL_RenderCommand * next
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean GLboolean b
A rectangle, with the origin at the upper left (floating point).
The structure that defines a point (floating point)
A rectangle, with the origin at the upper left (integer).
void *(* GetMetalCommandEncoder)(SDL_Renderer *renderer)
#define SDL_GetPixelFormatName