|
@@ -120,46 +120,47 @@ typedef struct METAL_ShaderPipelines
|
|
|
} METAL_ShaderPipelines;
|
|
|
|
|
|
@interface METAL_RenderData : NSObject
|
|
|
-@property(nonatomic, retain) id<MTLDevice> mtldevice;
|
|
|
-@property(nonatomic, retain) id<MTLCommandQueue> mtlcmdqueue;
|
|
|
-@property(nonatomic, retain) id<MTLCommandBuffer> mtlcmdbuffer;
|
|
|
-@property(nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
|
|
|
-@property(nonatomic, retain) id<MTLLibrary> mtllibrary;
|
|
|
-@property(nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
|
|
|
-@property(nonatomic, retain) id<MTLSamplerState> mtlsamplernearest;
|
|
|
-@property(nonatomic, retain) id<MTLSamplerState> mtlsamplerlinear;
|
|
|
-@property(nonatomic, retain) id<MTLBuffer> mtlbufconstants;
|
|
|
-@property(nonatomic, retain) id<MTLBuffer> mtlbufquadindices;
|
|
|
-@property(nonatomic, assign) SDL_MetalView mtlview;
|
|
|
-@property(nonatomic, retain) CAMetalLayer *mtllayer;
|
|
|
-@property(nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
|
|
|
-@property(nonatomic, assign) METAL_ShaderPipelines *activepipelines;
|
|
|
-@property(nonatomic, assign) METAL_ShaderPipelines *allpipelines;
|
|
|
-@property(nonatomic, assign) int pipelinescount;
|
|
|
+ @property (nonatomic, retain) id<MTLDevice> mtldevice;
|
|
|
+ @property (nonatomic, retain) id<MTLCommandQueue> mtlcmdqueue;
|
|
|
+ @property (nonatomic, retain) id<MTLCommandBuffer> mtlcmdbuffer;
|
|
|
+ @property (nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
|
|
|
+ @property (nonatomic, retain) id<MTLLibrary> mtllibrary;
|
|
|
+ @property (nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
|
|
|
+ @property (nonatomic, retain) id<MTLSamplerState> mtlsamplernearest;
|
|
|
+ @property (nonatomic, retain) id<MTLSamplerState> mtlsamplerlinear;
|
|
|
+ @property (nonatomic, retain) id<MTLBuffer> mtlbufconstants;
|
|
|
+ @property (nonatomic, retain) id<MTLBuffer> mtlbufquadindices;
|
|
|
+ @property (nonatomic, assign) SDL_MetalView mtlview;
|
|
|
+ @property (nonatomic, retain) CAMetalLayer *mtllayer;
|
|
|
+ @property (nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
|
|
|
+ @property (nonatomic, assign) METAL_ShaderPipelines *activepipelines;
|
|
|
+ @property (nonatomic, assign) METAL_ShaderPipelines *allpipelines;
|
|
|
+ @property (nonatomic, assign) int pipelinescount;
|
|
|
@end
|
|
|
|
|
|
@implementation METAL_RenderData
|
|
|
@end
|
|
|
|
|
|
@interface METAL_TextureData : NSObject
|
|
|
-@property(nonatomic, retain) id<MTLTexture> mtltexture;
|
|
|
-@property(nonatomic, retain) id<MTLTexture> mtltexture_uv;
|
|
|
-@property(nonatomic, retain) id<MTLSamplerState> mtlsampler;
|
|
|
-@property(nonatomic, assign) SDL_MetalFragmentFunction fragmentFunction;
|
|
|
+ @property (nonatomic, retain) id<MTLTexture> mtltexture;
|
|
|
+ @property (nonatomic, retain) id<MTLTexture> mtltexture_uv;
|
|
|
+ @property (nonatomic, retain) id<MTLSamplerState> mtlsampler;
|
|
|
+ @property (nonatomic, assign) SDL_MetalFragmentFunction fragmentFunction;
|
|
|
#if SDL_HAVE_YUV
|
|
|
-@property(nonatomic, assign) BOOL yuv;
|
|
|
-@property(nonatomic, assign) BOOL nv12;
|
|
|
-@property(nonatomic, assign) size_t conversionBufferOffset;
|
|
|
+ @property (nonatomic, assign) BOOL yuv;
|
|
|
+ @property (nonatomic, assign) BOOL nv12;
|
|
|
+ @property (nonatomic, assign) size_t conversionBufferOffset;
|
|
|
#endif
|
|
|
-@property(nonatomic, assign) BOOL hasdata;
|
|
|
-@property(nonatomic, retain) id<MTLBuffer> lockedbuffer;
|
|
|
-@property(nonatomic, assign) SDL_Rect lockedrect;
|
|
|
+ @property (nonatomic, assign) BOOL hasdata;
|
|
|
+ @property (nonatomic, retain) id<MTLBuffer> lockedbuffer;
|
|
|
+ @property (nonatomic, assign) SDL_Rect lockedrect;
|
|
|
@end
|
|
|
|
|
|
@implementation METAL_TextureData
|
|
|
@end
|
|
|
|
|
|
-static int IsMetalAvailable(const SDL_SysWMinfo *syswm)
|
|
|
+static int
|
|
|
+IsMetalAvailable(const SDL_SysWMinfo *syswm)
|
|
|
{
|
|
|
if (syswm->subsystem != SDL_SYSWM_COCOA && syswm->subsystem != SDL_SYSWM_UIKIT) {
|
|
|
return SDL_SetError("Metal render target only supports Cocoa and UIKit video targets at the moment.");
|
|
@@ -178,84 +179,63 @@ static int IsMetalAvailable(const SDL_SysWMinfo *syswm)
|
|
|
static const MTLBlendOperation invalidBlendOperation = (MTLBlendOperation)0xFFFFFFFF;
|
|
|
static const MTLBlendFactor invalidBlendFactor = (MTLBlendFactor)0xFFFFFFFF;
|
|
|
|
|
|
-static MTLBlendOperation GetBlendOperation(SDL_BlendOperation operation)
|
|
|
+static MTLBlendOperation
|
|
|
+GetBlendOperation(SDL_BlendOperation operation)
|
|
|
{
|
|
|
switch (operation) {
|
|
|
- case SDL_BLENDOPERATION_ADD:
|
|
|
- return MTLBlendOperationAdd;
|
|
|
- case SDL_BLENDOPERATION_SUBTRACT:
|
|
|
- return MTLBlendOperationSubtract;
|
|
|
- case SDL_BLENDOPERATION_REV_SUBTRACT:
|
|
|
- return MTLBlendOperationReverseSubtract;
|
|
|
- case SDL_BLENDOPERATION_MINIMUM:
|
|
|
- return MTLBlendOperationMin;
|
|
|
- case SDL_BLENDOPERATION_MAXIMUM:
|
|
|
- return MTLBlendOperationMax;
|
|
|
- default:
|
|
|
- return invalidBlendOperation;
|
|
|
+ case SDL_BLENDOPERATION_ADD: return MTLBlendOperationAdd;
|
|
|
+ case SDL_BLENDOPERATION_SUBTRACT: return MTLBlendOperationSubtract;
|
|
|
+ case SDL_BLENDOPERATION_REV_SUBTRACT: return MTLBlendOperationReverseSubtract;
|
|
|
+ case SDL_BLENDOPERATION_MINIMUM: return MTLBlendOperationMin;
|
|
|
+ case SDL_BLENDOPERATION_MAXIMUM: return MTLBlendOperationMax;
|
|
|
+ default: return invalidBlendOperation;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static MTLBlendFactor GetBlendFactor(SDL_BlendFactor factor)
|
|
|
+static MTLBlendFactor
|
|
|
+GetBlendFactor(SDL_BlendFactor factor)
|
|
|
{
|
|
|
switch (factor) {
|
|
|
- case SDL_BLENDFACTOR_ZERO:
|
|
|
- return MTLBlendFactorZero;
|
|
|
- case SDL_BLENDFACTOR_ONE:
|
|
|
- return MTLBlendFactorOne;
|
|
|
- case SDL_BLENDFACTOR_SRC_COLOR:
|
|
|
- return MTLBlendFactorSourceColor;
|
|
|
- case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
|
|
|
- return MTLBlendFactorOneMinusSourceColor;
|
|
|
- case SDL_BLENDFACTOR_SRC_ALPHA:
|
|
|
- return MTLBlendFactorSourceAlpha;
|
|
|
- case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
|
|
|
- return MTLBlendFactorOneMinusSourceAlpha;
|
|
|
- case SDL_BLENDFACTOR_DST_COLOR:
|
|
|
- return MTLBlendFactorDestinationColor;
|
|
|
- case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
|
|
|
- return MTLBlendFactorOneMinusDestinationColor;
|
|
|
- case SDL_BLENDFACTOR_DST_ALPHA:
|
|
|
- return MTLBlendFactorDestinationAlpha;
|
|
|
- case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
|
|
|
- return MTLBlendFactorOneMinusDestinationAlpha;
|
|
|
- default:
|
|
|
- return invalidBlendFactor;
|
|
|
+ case SDL_BLENDFACTOR_ZERO: return MTLBlendFactorZero;
|
|
|
+ case SDL_BLENDFACTOR_ONE: return MTLBlendFactorOne;
|
|
|
+ case SDL_BLENDFACTOR_SRC_COLOR: return MTLBlendFactorSourceColor;
|
|
|
+ case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return MTLBlendFactorOneMinusSourceColor;
|
|
|
+ case SDL_BLENDFACTOR_SRC_ALPHA: return MTLBlendFactorSourceAlpha;
|
|
|
+ case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return MTLBlendFactorOneMinusSourceAlpha;
|
|
|
+ case SDL_BLENDFACTOR_DST_COLOR: return MTLBlendFactorDestinationColor;
|
|
|
+ case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR: return MTLBlendFactorOneMinusDestinationColor;
|
|
|
+ case SDL_BLENDFACTOR_DST_ALPHA: return MTLBlendFactorDestinationAlpha;
|
|
|
+ case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return MTLBlendFactorOneMinusDestinationAlpha;
|
|
|
+ default: return invalidBlendFactor;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static NSString *GetVertexFunctionName(SDL_MetalVertexFunction function)
|
|
|
+static NSString *
|
|
|
+GetVertexFunctionName(SDL_MetalVertexFunction function)
|
|
|
{
|
|
|
switch (function) {
|
|
|
- case SDL_METAL_VERTEX_SOLID:
|
|
|
- return @"SDL_Solid_vertex";
|
|
|
- case SDL_METAL_VERTEX_COPY:
|
|
|
- return @"SDL_Copy_vertex";
|
|
|
- default:
|
|
|
- return nil;
|
|
|
+ case SDL_METAL_VERTEX_SOLID: return @"SDL_Solid_vertex";
|
|
|
+ case SDL_METAL_VERTEX_COPY: return @"SDL_Copy_vertex";
|
|
|
+ default: return nil;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static NSString *GetFragmentFunctionName(SDL_MetalFragmentFunction function)
|
|
|
+static NSString *
|
|
|
+GetFragmentFunctionName(SDL_MetalFragmentFunction function)
|
|
|
{
|
|
|
switch (function) {
|
|
|
- case SDL_METAL_FRAGMENT_SOLID:
|
|
|
- return @"SDL_Solid_fragment";
|
|
|
- case SDL_METAL_FRAGMENT_COPY:
|
|
|
- return @"SDL_Copy_fragment";
|
|
|
- case SDL_METAL_FRAGMENT_YUV:
|
|
|
- return @"SDL_YUV_fragment";
|
|
|
- case SDL_METAL_FRAGMENT_NV12:
|
|
|
- return @"SDL_NV12_fragment";
|
|
|
- case SDL_METAL_FRAGMENT_NV21:
|
|
|
- return @"SDL_NV21_fragment";
|
|
|
- default:
|
|
|
- return nil;
|
|
|
+ case SDL_METAL_FRAGMENT_SOLID: return @"SDL_Solid_fragment";
|
|
|
+ case SDL_METAL_FRAGMENT_COPY: return @"SDL_Copy_fragment";
|
|
|
+ case SDL_METAL_FRAGMENT_YUV: return @"SDL_YUV_fragment";
|
|
|
+ case SDL_METAL_FRAGMENT_NV12: return @"SDL_NV12_fragment";
|
|
|
+ case SDL_METAL_FRAGMENT_NV21: return @"SDL_NV21_fragment";
|
|
|
+ default: return nil;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static id<MTLRenderPipelineState> MakePipelineState(METAL_RenderData *data, METAL_PipelineCache *cache,
|
|
|
- NSString *blendlabel, SDL_BlendMode blendmode)
|
|
|
+static id<MTLRenderPipelineState>
|
|
|
+MakePipelineState(METAL_RenderData *data, METAL_PipelineCache *cache,
|
|
|
+ NSString *blendlabel, SDL_BlendMode blendmode)
|
|
|
{
|
|
|
MTLRenderPipelineDescriptor *mtlpipedesc;
|
|
|
MTLVertexDescriptor *vertdesc;
|
|
@@ -277,37 +257,37 @@ static id<MTLRenderPipelineState> MakePipelineState(METAL_RenderData *data, META
|
|
|
vertdesc = [MTLVertexDescriptor vertexDescriptor];
|
|
|
|
|
|
switch (cache->vertexFunction) {
|
|
|
- case SDL_METAL_VERTEX_SOLID:
|
|
|
- /* position (float2), color (uchar4normalized) */
|
|
|
- vertdesc.layouts[0].stride = sizeof(float) * 2 + sizeof(int);
|
|
|
- vertdesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
|
|
+ case SDL_METAL_VERTEX_SOLID:
|
|
|
+ /* position (float2), color (uchar4normalized) */
|
|
|
+ vertdesc.layouts[0].stride = sizeof(float) * 2 + sizeof (int);
|
|
|
+ vertdesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
|
|
|
|
|
- vertdesc.attributes[0].format = MTLVertexFormatFloat2;
|
|
|
- vertdesc.attributes[0].offset = 0;
|
|
|
- vertdesc.attributes[0].bufferIndex = 0;
|
|
|
+ vertdesc.attributes[0].format = MTLVertexFormatFloat2;
|
|
|
+ vertdesc.attributes[0].offset = 0;
|
|
|
+ vertdesc.attributes[0].bufferIndex = 0;
|
|
|
|
|
|
- vertdesc.attributes[1].format = MTLVertexFormatUChar4Normalized;
|
|
|
- vertdesc.attributes[1].offset = sizeof(float) * 2;
|
|
|
- vertdesc.attributes[1].bufferIndex = 0;
|
|
|
+ vertdesc.attributes[1].format = MTLVertexFormatUChar4Normalized;
|
|
|
+ vertdesc.attributes[1].offset = sizeof (float) * 2;
|
|
|
+ vertdesc.attributes[1].bufferIndex = 0;
|
|
|
|
|
|
- break;
|
|
|
- case SDL_METAL_VERTEX_COPY:
|
|
|
- /* position (float2), color (uchar4normalized), texcoord (float2) */
|
|
|
- vertdesc.layouts[0].stride = sizeof(float) * 2 + sizeof(int) + sizeof(float) * 2;
|
|
|
- vertdesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
|
|
-
|
|
|
- vertdesc.attributes[0].format = MTLVertexFormatFloat2;
|
|
|
- vertdesc.attributes[0].offset = 0;
|
|
|
- vertdesc.attributes[0].bufferIndex = 0;
|
|
|
-
|
|
|
- vertdesc.attributes[1].format = MTLVertexFormatUChar4Normalized;
|
|
|
- vertdesc.attributes[1].offset = sizeof(float) * 2;
|
|
|
- vertdesc.attributes[1].bufferIndex = 0;
|
|
|
-
|
|
|
- vertdesc.attributes[2].format = MTLVertexFormatFloat2;
|
|
|
- vertdesc.attributes[2].offset = sizeof(float) * 2 + sizeof(int);
|
|
|
- vertdesc.attributes[2].bufferIndex = 0;
|
|
|
- break;
|
|
|
+ break;
|
|
|
+ case SDL_METAL_VERTEX_COPY:
|
|
|
+ /* position (float2), color (uchar4normalized), texcoord (float2) */
|
|
|
+ vertdesc.layouts[0].stride = sizeof(float) * 2 + sizeof (int) + sizeof (float) * 2;
|
|
|
+ vertdesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
|
|
+
|
|
|
+ vertdesc.attributes[0].format = MTLVertexFormatFloat2;
|
|
|
+ vertdesc.attributes[0].offset = 0;
|
|
|
+ vertdesc.attributes[0].bufferIndex = 0;
|
|
|
+
|
|
|
+ vertdesc.attributes[1].format = MTLVertexFormatUChar4Normalized;
|
|
|
+ vertdesc.attributes[1].offset = sizeof (float) * 2;
|
|
|
+ vertdesc.attributes[1].bufferIndex = 0;
|
|
|
+
|
|
|
+ vertdesc.attributes[2].format = MTLVertexFormatFloat2;
|
|
|
+ vertdesc.attributes[2].offset = sizeof(float) * 2 + sizeof (int);
|
|
|
+ vertdesc.attributes[2].bufferIndex = 0;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
mtlpipedesc.vertexDescriptor = vertdesc;
|
|
@@ -348,8 +328,9 @@ static id<MTLRenderPipelineState> MakePipelineState(METAL_RenderData *data, META
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void MakePipelineCache(METAL_RenderData *data, METAL_PipelineCache *cache, const char *label,
|
|
|
- MTLPixelFormat rtformat, SDL_MetalVertexFunction vertfn, SDL_MetalFragmentFunction fragfn)
|
|
|
+static void
|
|
|
+MakePipelineCache(METAL_RenderData *data, METAL_PipelineCache *cache, const char *label,
|
|
|
+ MTLPixelFormat rtformat, SDL_MetalVertexFunction vertfn, SDL_MetalFragmentFunction fragfn)
|
|
|
{
|
|
|
SDL_zerop(cache);
|
|
|
|
|
@@ -367,7 +348,8 @@ static void MakePipelineCache(METAL_RenderData *data, METAL_PipelineCache *cache
|
|
|
MakePipelineState(data, cache, @" (blend=mul)", SDL_BLENDMODE_MUL);
|
|
|
}
|
|
|
|
|
|
-static void DestroyPipelineCache(METAL_PipelineCache *cache)
|
|
|
+static void
|
|
|
+DestroyPipelineCache(METAL_PipelineCache *cache)
|
|
|
{
|
|
|
if (cache != NULL) {
|
|
|
for (int i = 0; i < cache->count; i++) {
|
|
@@ -378,7 +360,8 @@ static void DestroyPipelineCache(METAL_PipelineCache *cache)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void MakeShaderPipelines(METAL_RenderData *data, METAL_ShaderPipelines *pipelines, MTLPixelFormat rtformat)
|
|
|
+void
|
|
|
+MakeShaderPipelines(METAL_RenderData *data, METAL_ShaderPipelines *pipelines, MTLPixelFormat rtformat)
|
|
|
{
|
|
|
SDL_zerop(pipelines);
|
|
|
|
|
@@ -391,7 +374,8 @@ void MakeShaderPipelines(METAL_RenderData *data, METAL_ShaderPipelines *pipeline
|
|
|
MakePipelineCache(data, &pipelines->caches[SDL_METAL_FRAGMENT_NV21], "SDL NV21 pipeline", rtformat, SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_NV21);
|
|
|
}
|
|
|
|
|
|
-static METAL_ShaderPipelines *ChooseShaderPipelines(METAL_RenderData *data, MTLPixelFormat rtformat)
|
|
|
+static METAL_ShaderPipelines *
|
|
|
+ChooseShaderPipelines(METAL_RenderData *data, MTLPixelFormat rtformat)
|
|
|
{
|
|
|
METAL_ShaderPipelines *allpipelines = data.allpipelines;
|
|
|
int count = data.pipelinescount;
|
|
@@ -417,7 +401,8 @@ static METAL_ShaderPipelines *ChooseShaderPipelines(METAL_RenderData *data, MTLP
|
|
|
return &data.allpipelines[count];
|
|
|
}
|
|
|
|
|
|
-static void DestroyAllPipelines(METAL_ShaderPipelines *allpipelines, int count)
|
|
|
+static void
|
|
|
+DestroyAllPipelines(METAL_ShaderPipelines *allpipelines, int count)
|
|
|
{
|
|
|
if (allpipelines != NULL) {
|
|
|
for (int i = 0; i < count; i++) {
|
|
@@ -430,7 +415,8 @@ static void DestroyAllPipelines(METAL_ShaderPipelines *allpipelines, int count)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static inline id<MTLRenderPipelineState> ChoosePipelineState(METAL_RenderData *data, METAL_ShaderPipelines *pipelines, SDL_MetalFragmentFunction fragfn, SDL_BlendMode blendmode)
|
|
|
+static inline id<MTLRenderPipelineState>
|
|
|
+ChoosePipelineState(METAL_RenderData *data, METAL_ShaderPipelines *pipelines, SDL_MetalFragmentFunction fragfn, SDL_BlendMode blendmode)
|
|
|
{
|
|
|
METAL_PipelineCache *cache = &pipelines->caches[fragfn];
|
|
|
|
|
@@ -443,9 +429,10 @@ static inline id<MTLRenderPipelineState> ChoosePipelineState(METAL_RenderData *d
|
|
|
return MakePipelineState(data, cache, [NSString stringWithFormat:@" (blend=custom 0x%x)", blendmode], blendmode);
|
|
|
}
|
|
|
|
|
|
-static SDL_bool METAL_ActivateRenderCommandEncoder(SDL_Renderer *renderer, MTLLoadAction load, MTLClearColor *clear_color, id<MTLBuffer> vertex_buffer)
|
|
|
+static SDL_bool
|
|
|
+METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load, MTLClearColor *clear_color, id<MTLBuffer> vertex_buffer)
|
|
|
{
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
|
|
|
/* Our SetRenderTarget just signals that the next render operation should
|
|
|
* set up a new render pass. This is where that work happens. */
|
|
@@ -510,25 +497,26 @@ static SDL_bool METAL_ActivateRenderCommandEncoder(SDL_Renderer *renderer, MTLLo
|
|
|
return SDL_TRUE;
|
|
|
}
|
|
|
|
|
|
-static void METAL_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
|
|
|
+static void
|
|
|
+METAL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
-static int METAL_GetOutputSize(SDL_Renderer *renderer, int *w, int *h)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- if (w) {
|
|
|
- *w = (int)data.mtllayer.drawableSize.width;
|
|
|
- }
|
|
|
- if (h) {
|
|
|
- *h = (int)data.mtllayer.drawableSize.height;
|
|
|
- }
|
|
|
- return 0;
|
|
|
+static int
|
|
|
+METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ if (w) {
|
|
|
+ *w = (int)data.mtllayer.drawableSize.width;
|
|
|
}
|
|
|
-}
|
|
|
+ if (h) {
|
|
|
+ *h = (int)data.mtllayer.drawableSize.height;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
|
|
|
-static SDL_bool METAL_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode)
|
|
|
+static SDL_bool
|
|
|
+METAL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
|
|
|
{
|
|
|
SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
|
|
|
SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
|
|
@@ -548,17 +536,17 @@ static SDL_bool METAL_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode bl
|
|
|
return SDL_TRUE;
|
|
|
}
|
|
|
|
|
|
-static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- MTLPixelFormat pixfmt;
|
|
|
- MTLTextureDescriptor *mtltexdesc;
|
|
|
- id<MTLTexture> mtltexture, mtltexture_uv;
|
|
|
- BOOL yuv, nv12;
|
|
|
- METAL_TextureData *texturedata;
|
|
|
-
|
|
|
- switch (texture->format) {
|
|
|
+static int
|
|
|
+METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ MTLPixelFormat pixfmt;
|
|
|
+ MTLTextureDescriptor *mtltexdesc;
|
|
|
+ id<MTLTexture> mtltexture, mtltexture_uv;
|
|
|
+ BOOL yuv, nv12;
|
|
|
+ METAL_TextureData *texturedata;
|
|
|
+
|
|
|
+ switch (texture->format) {
|
|
|
case SDL_PIXELFORMAT_ABGR8888:
|
|
|
pixfmt = MTLPixelFormatRGBA8Unorm;
|
|
|
break;
|
|
@@ -573,103 +561,93 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
|
|
|
break;
|
|
|
default:
|
|
|
return SDL_SetError("Texture format %s not supported by Metal", SDL_GetPixelFormatName(texture->format));
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
|
|
|
- width:(NSUInteger)texture->w
|
|
|
- height:(NSUInteger)texture->h
|
|
|
- mipmapped:NO];
|
|
|
-
|
|
|
- /* Not available in iOS 8. */
|
|
|
- if ([mtltexdesc respondsToSelector:@selector(usage)]) {
|
|
|
- if (texture->access == SDL_TEXTUREACCESS_TARGET) {
|
|
|
- mtltexdesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
|
|
|
- } else {
|
|
|
- mtltexdesc.usage = MTLTextureUsageShaderRead;
|
|
|
- }
|
|
|
- }
|
|
|
+ mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
|
|
|
+ width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
|
|
|
|
|
|
- mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
|
|
|
- if (mtltexture == nil) {
|
|
|
- return SDL_SetError("Texture allocation failed");
|
|
|
+ /* Not available in iOS 8. */
|
|
|
+ if ([mtltexdesc respondsToSelector:@selector(usage)]) {
|
|
|
+ if (texture->access == SDL_TEXTUREACCESS_TARGET) {
|
|
|
+ mtltexdesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
|
|
|
+ } else {
|
|
|
+ mtltexdesc.usage = MTLTextureUsageShaderRead;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
|
|
|
+ if (mtltexture == nil) {
|
|
|
+ return SDL_SetError("Texture allocation failed");
|
|
|
+ }
|
|
|
|
|
|
- mtltexture_uv = nil;
|
|
|
+ mtltexture_uv = nil;
|
|
|
#if SDL_HAVE_YUV
|
|
|
- yuv = (texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12);
|
|
|
- nv12 = (texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21);
|
|
|
-
|
|
|
- if (yuv) {
|
|
|
- mtltexdesc.pixelFormat = MTLPixelFormatR8Unorm;
|
|
|
- mtltexdesc.width = (texture->w + 1) / 2;
|
|
|
- mtltexdesc.height = (texture->h + 1) / 2;
|
|
|
- mtltexdesc.textureType = MTLTextureType2DArray;
|
|
|
- mtltexdesc.arrayLength = 2;
|
|
|
- } else if (nv12) {
|
|
|
- mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
|
|
|
- mtltexdesc.width = (texture->w + 1) / 2;
|
|
|
- mtltexdesc.height = (texture->h + 1) / 2;
|
|
|
- }
|
|
|
+ yuv = (texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12);
|
|
|
+ nv12 = (texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21);
|
|
|
+
|
|
|
+ if (yuv) {
|
|
|
+ mtltexdesc.pixelFormat = MTLPixelFormatR8Unorm;
|
|
|
+ mtltexdesc.width = (texture->w + 1) / 2;
|
|
|
+ mtltexdesc.height = (texture->h + 1) / 2;
|
|
|
+ mtltexdesc.textureType = MTLTextureType2DArray;
|
|
|
+ mtltexdesc.arrayLength = 2;
|
|
|
+ } else if (nv12) {
|
|
|
+ mtltexdesc.pixelFormat = MTLPixelFormatRG8Unorm;
|
|
|
+ mtltexdesc.width = (texture->w + 1) / 2;
|
|
|
+ mtltexdesc.height = (texture->h + 1) / 2;
|
|
|
+ }
|
|
|
|
|
|
- if (yuv || nv12) {
|
|
|
- mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
|
|
|
- if (mtltexture_uv == nil) {
|
|
|
- return SDL_SetError("Texture allocation failed");
|
|
|
- }
|
|
|
+ if (yuv || nv12) {
|
|
|
+ mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
|
|
|
+ if (mtltexture_uv == nil) {
|
|
|
+ return SDL_SetError("Texture allocation failed");
|
|
|
}
|
|
|
+ }
|
|
|
#endif /* SDL_HAVE_YUV */
|
|
|
- texturedata = [[METAL_TextureData alloc] init];
|
|
|
- if (texture->scaleMode == SDL_ScaleModeNearest) {
|
|
|
- texturedata.mtlsampler = data.mtlsamplernearest;
|
|
|
- } else {
|
|
|
- texturedata.mtlsampler = data.mtlsamplerlinear;
|
|
|
- }
|
|
|
- texturedata.mtltexture = mtltexture;
|
|
|
- texturedata.mtltexture_uv = mtltexture_uv;
|
|
|
+ texturedata = [[METAL_TextureData alloc] init];
|
|
|
+ if (texture->scaleMode == SDL_ScaleModeNearest) {
|
|
|
+ texturedata.mtlsampler = data.mtlsamplernearest;
|
|
|
+ } else {
|
|
|
+ texturedata.mtlsampler = data.mtlsamplerlinear;
|
|
|
+ }
|
|
|
+ texturedata.mtltexture = mtltexture;
|
|
|
+ texturedata.mtltexture_uv = mtltexture_uv;
|
|
|
#if SDL_HAVE_YUV
|
|
|
- texturedata.yuv = yuv;
|
|
|
- texturedata.nv12 = nv12;
|
|
|
-
|
|
|
- if (yuv) {
|
|
|
- texturedata.fragmentFunction = SDL_METAL_FRAGMENT_YUV;
|
|
|
- } else if (texture->format == SDL_PIXELFORMAT_NV12) {
|
|
|
- texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12;
|
|
|
- } else if (texture->format == SDL_PIXELFORMAT_NV21) {
|
|
|
- texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21;
|
|
|
- } else
|
|
|
+ texturedata.yuv = yuv;
|
|
|
+ texturedata.nv12 = nv12;
|
|
|
+
|
|
|
+ if (yuv) {
|
|
|
+ texturedata.fragmentFunction = SDL_METAL_FRAGMENT_YUV;
|
|
|
+ } else if (texture->format == SDL_PIXELFORMAT_NV12) {
|
|
|
+ texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12;
|
|
|
+ } else if (texture->format == SDL_PIXELFORMAT_NV21) {
|
|
|
+ texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21;
|
|
|
+ } else
|
|
|
#endif
|
|
|
- {
|
|
|
- texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
|
|
|
- }
|
|
|
+ {
|
|
|
+ texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
|
|
|
+ }
|
|
|
#if SDL_HAVE_YUV
|
|
|
- if (yuv || nv12) {
|
|
|
- size_t offset = 0;
|
|
|
- SDL_YUV_CONVERSION_MODE mode = SDL_GetYUVConversionModeForResolution(texture->w, texture->h);
|
|
|
- switch (mode) {
|
|
|
- case SDL_YUV_CONVERSION_JPEG:
|
|
|
- offset = CONSTANTS_OFFSET_DECODE_JPEG;
|
|
|
- break;
|
|
|
- case SDL_YUV_CONVERSION_BT601:
|
|
|
- offset = CONSTANTS_OFFSET_DECODE_BT601;
|
|
|
- break;
|
|
|
- case SDL_YUV_CONVERSION_BT709:
|
|
|
- offset = CONSTANTS_OFFSET_DECODE_BT709;
|
|
|
- break;
|
|
|
- default:
|
|
|
- offset = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
- texturedata.conversionBufferOffset = offset;
|
|
|
- }
|
|
|
+ if (yuv || nv12) {
|
|
|
+ size_t offset = 0;
|
|
|
+ SDL_YUV_CONVERSION_MODE mode = SDL_GetYUVConversionModeForResolution(texture->w, texture->h);
|
|
|
+ switch (mode) {
|
|
|
+ case SDL_YUV_CONVERSION_JPEG: offset = CONSTANTS_OFFSET_DECODE_JPEG; break;
|
|
|
+ case SDL_YUV_CONVERSION_BT601: offset = CONSTANTS_OFFSET_DECODE_BT601; break;
|
|
|
+ case SDL_YUV_CONVERSION_BT709: offset = CONSTANTS_OFFSET_DECODE_BT709; break;
|
|
|
+ default: offset = 0; break;
|
|
|
+ }
|
|
|
+ texturedata.conversionBufferOffset = offset;
|
|
|
+ }
|
|
|
#endif
|
|
|
- texture->driverdata = (void *)CFBridgingRetain(texturedata);
|
|
|
+ texture->driverdata = (void*)CFBridgingRetain(texturedata);
|
|
|
|
|
|
- return 0;
|
|
|
- }
|
|
|
-}
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
|
|
|
-static void METAL_UploadTextureData(id<MTLTexture> texture, SDL_Rect rect, int slice,
|
|
|
- const void *pixels, int pitch)
|
|
|
+static void
|
|
|
+METAL_UploadTextureData(id<MTLTexture> texture, SDL_Rect rect, int slice,
|
|
|
+ const void * pixels, int pitch)
|
|
|
{
|
|
|
[texture replaceRegion:MTLRegionMake2D(rect.x, rect.y, rect.w, rect.h)
|
|
|
mipmapLevel:0
|
|
@@ -679,7 +657,8 @@ static void METAL_UploadTextureData(id<MTLTexture> texture, SDL_Rect rect, int s
|
|
|
bytesPerImage:0];
|
|
|
}
|
|
|
|
|
|
-static MTLStorageMode METAL_GetStorageMode(id<MTLResource> resource)
|
|
|
+static MTLStorageMode
|
|
|
+METAL_GetStorageMode(id<MTLResource> resource)
|
|
|
{
|
|
|
/* iOS 8 does not have this method. */
|
|
|
if ([resource respondsToSelector:@selector(storageMode)]) {
|
|
@@ -688,12 +667,13 @@ static MTLStorageMode METAL_GetStorageMode(id<MTLResource> resource)
|
|
|
return MTLStorageModeShared;
|
|
|
}
|
|
|
|
|
|
-static int METAL_UpdateTextureInternal(SDL_Renderer *renderer, METAL_TextureData *texturedata,
|
|
|
- id<MTLTexture> texture, SDL_Rect rect, int slice,
|
|
|
- const void *pixels, int pitch)
|
|
|
+static int
|
|
|
+METAL_UpdateTextureInternal(SDL_Renderer * renderer, METAL_TextureData *texturedata,
|
|
|
+ id<MTLTexture> texture, SDL_Rect rect, int slice,
|
|
|
+ const void * pixels, int pitch)
|
|
|
{
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- SDL_Rect stagingrect = { 0, 0, rect.w, rect.h };
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ SDL_Rect stagingrect = {0, 0, rect.w, rect.h};
|
|
|
MTLTextureDescriptor *desc;
|
|
|
id<MTLTexture> stagingtex;
|
|
|
id<MTLBlitCommandEncoder> blitcmd;
|
|
@@ -756,279 +736,274 @@ static int METAL_UpdateTextureInternal(SDL_Renderer *renderer, METAL_TextureData
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int METAL_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
|
- const SDL_Rect *rect, const void *pixels, int pitch)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
+static int
|
|
|
+METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
|
|
+ const SDL_Rect * rect, const void *pixels, int pitch)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, pixels, pitch) < 0) {
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, pixels, pitch) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+#if SDL_HAVE_YUV
|
|
|
+ if (texturedata.yuv) {
|
|
|
+ int Uslice = texture->format == SDL_PIXELFORMAT_YV12 ? 1 : 0;
|
|
|
+ int Vslice = texture->format == SDL_PIXELFORMAT_YV12 ? 0 : 1;
|
|
|
+ int UVpitch = (pitch + 1) / 2;
|
|
|
+ SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2};
|
|
|
+
|
|
|
+ /* Skip to the correct offset into the next texture */
|
|
|
+ pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice, pixels, UVpitch) < 0) {
|
|
|
return -1;
|
|
|
}
|
|
|
-#if SDL_HAVE_YUV
|
|
|
- if (texturedata.yuv) {
|
|
|
- int Uslice = texture->format == SDL_PIXELFORMAT_YV12 ? 1 : 0;
|
|
|
- int Vslice = texture->format == SDL_PIXELFORMAT_YV12 ? 0 : 1;
|
|
|
- int UVpitch = (pitch + 1) / 2;
|
|
|
- SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
|
|
-
|
|
|
- /* Skip to the correct offset into the next texture */
|
|
|
- pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice, pixels, UVpitch) < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
|
|
|
- /* Skip to the correct offset into the next texture */
|
|
|
- pixels = (const void *)((const Uint8 *)pixels + UVrect.h * UVpitch);
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice, pixels, UVpitch) < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ /* Skip to the correct offset into the next texture */
|
|
|
+ pixels = (const void*)((const Uint8*)pixels + UVrect.h * UVpitch);
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice, pixels, UVpitch) < 0) {
|
|
|
+ return -1;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (texturedata.nv12) {
|
|
|
- SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
|
|
- int UVpitch = 2 * ((pitch + 1) / 2);
|
|
|
+ if (texturedata.nv12) {
|
|
|
+ SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2};
|
|
|
+ int UVpitch = 2 * ((pitch + 1) / 2);
|
|
|
|
|
|
- /* Skip to the correct offset into the next texture */
|
|
|
- pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, 0, pixels, UVpitch) < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ /* Skip to the correct offset into the next texture */
|
|
|
+ pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, 0, pixels, UVpitch) < 0) {
|
|
|
+ return -1;
|
|
|
}
|
|
|
+ }
|
|
|
#endif
|
|
|
- texturedata.hasdata = YES;
|
|
|
+ texturedata.hasdata = YES;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
+
|
|
|
+#if SDL_HAVE_YUV
|
|
|
+static int
|
|
|
+METAL_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)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
+ const int Uslice = 0;
|
|
|
+ const int Vslice = 1;
|
|
|
+ SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2};
|
|
|
|
|
|
+ /* Bail out if we're supposed to update an empty rectangle */
|
|
|
+ if (rect->w <= 0 || rect->h <= 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-#if SDL_HAVE_YUV
|
|
|
-static int METAL_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)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
- const int Uslice = 0;
|
|
|
- const int Vslice = 1;
|
|
|
- SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
|
|
-
|
|
|
- /* Bail out if we're supposed to update an empty rectangle */
|
|
|
- if (rect->w <= 0 || rect->h <= 0) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice, Uplane, Upitch)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice, Vplane, Vpitch)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch) < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Uslice, Uplane, Upitch)) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, Vslice, Vplane, Vpitch)) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ texturedata.hasdata = YES;
|
|
|
|
|
|
- texturedata.hasdata = YES;
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
+
|
|
|
+static int
|
|
|
+METAL_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture,
|
|
|
+ const SDL_Rect * rect,
|
|
|
+ const Uint8 *Yplane, int Ypitch,
|
|
|
+ const Uint8 *UVplane, int UVpitch)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
+ SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2};
|
|
|
|
|
|
+ /* Bail out if we're supposed to update an empty rectangle */
|
|
|
+ if (rect->w <= 0 || rect->h <= 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-static int METAL_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
|
- const SDL_Rect *rect,
|
|
|
- const Uint8 *Yplane, int Ypitch,
|
|
|
- const Uint8 *UVplane, int UVpitch)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
- SDL_Rect UVrect = { rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2 };
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
- /* Bail out if we're supposed to update an empty rectangle */
|
|
|
- if (rect->w <= 0 || rect->h <= 0) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, 0, UVplane, UVpitch) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch) < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ texturedata.hasdata = YES;
|
|
|
|
|
|
- if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture_uv, UVrect, 0, UVplane, UVpitch) < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
+#endif
|
|
|
|
|
|
- texturedata.hasdata = YES;
|
|
|
+static int
|
|
|
+METAL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
|
|
+ const SDL_Rect * rect, void **pixels, int *pitch)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
+ int buffersize = 0;
|
|
|
+ id<MTLBuffer> lockedbuffer = nil;
|
|
|
|
|
|
- return 0;
|
|
|
+ if (rect->w <= 0 || rect->h <= 0) {
|
|
|
+ return SDL_SetError("Invalid rectangle dimensions for LockTexture.");
|
|
|
}
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-static int METAL_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
|
- const SDL_Rect *rect, void **pixels, int *pitch)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
- int buffersize = 0;
|
|
|
- id<MTLBuffer> lockedbuffer = nil;
|
|
|
-
|
|
|
- if (rect->w <= 0 || rect->h <= 0) {
|
|
|
- return SDL_SetError("Invalid rectangle dimensions for LockTexture.");
|
|
|
- }
|
|
|
|
|
|
- *pitch = SDL_BYTESPERPIXEL(texture->format) * rect->w;
|
|
|
+ *pitch = SDL_BYTESPERPIXEL(texture->format) * rect->w;
|
|
|
#if SDL_HAVE_YUV
|
|
|
- if (texturedata.yuv || texturedata.nv12) {
|
|
|
- buffersize = ((*pitch) * rect->h) + (2 * (*pitch + 1) / 2) * ((rect->h + 1) / 2);
|
|
|
- } else
|
|
|
+ if (texturedata.yuv || texturedata.nv12) {
|
|
|
+ buffersize = ((*pitch) * rect->h) + (2 * (*pitch + 1) / 2) * ((rect->h + 1) / 2);
|
|
|
+ } else
|
|
|
#endif
|
|
|
- {
|
|
|
- buffersize = (*pitch) * rect->h;
|
|
|
- }
|
|
|
+ {
|
|
|
+ buffersize = (*pitch) * rect->h;
|
|
|
+ }
|
|
|
|
|
|
- lockedbuffer = [data.mtldevice newBufferWithLength:buffersize options:MTLResourceStorageModeShared];
|
|
|
- if (lockedbuffer == nil) {
|
|
|
- return SDL_OutOfMemory();
|
|
|
- }
|
|
|
+ lockedbuffer = [data.mtldevice newBufferWithLength:buffersize options:MTLResourceStorageModeShared];
|
|
|
+ if (lockedbuffer == nil) {
|
|
|
+ return SDL_OutOfMemory();
|
|
|
+ }
|
|
|
|
|
|
- texturedata.lockedrect = *rect;
|
|
|
- texturedata.lockedbuffer = lockedbuffer;
|
|
|
- *pixels = [lockedbuffer contents];
|
|
|
+ texturedata.lockedrect = *rect;
|
|
|
+ texturedata.lockedbuffer = lockedbuffer;
|
|
|
+ *pixels = [lockedbuffer contents];
|
|
|
|
|
|
- return 0;
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
+
|
|
|
+static void
|
|
|
+METAL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
+ id<MTLBlitCommandEncoder> blitcmd;
|
|
|
+ SDL_Rect rect = texturedata.lockedrect;
|
|
|
+ int pitch = SDL_BYTESPERPIXEL(texture->format) * rect.w;
|
|
|
+ SDL_Rect UVrect = {rect.x / 2, rect.y / 2, (rect.w + 1) / 2, (rect.h + 1) / 2};
|
|
|
+
|
|
|
+ if (texturedata.lockedbuffer == nil) {
|
|
|
+ return;
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-static void METAL_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
- id<MTLBlitCommandEncoder> blitcmd;
|
|
|
- SDL_Rect rect = texturedata.lockedrect;
|
|
|
- int pitch = SDL_BYTESPERPIXEL(texture->format) * rect.w;
|
|
|
- SDL_Rect UVrect = { rect.x / 2, rect.y / 2, (rect.w + 1) / 2, (rect.h + 1) / 2 };
|
|
|
-
|
|
|
- if (texturedata.lockedbuffer == nil) {
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (data.mtlcmdencoder != nil) {
|
|
|
+ [data.mtlcmdencoder endEncoding];
|
|
|
+ data.mtlcmdencoder = nil;
|
|
|
+ }
|
|
|
|
|
|
- if (data.mtlcmdencoder != nil) {
|
|
|
- [data.mtlcmdencoder endEncoding];
|
|
|
- data.mtlcmdencoder = nil;
|
|
|
- }
|
|
|
+ if (data.mtlcmdbuffer == nil) {
|
|
|
+ data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
|
|
|
+ }
|
|
|
|
|
|
- if (data.mtlcmdbuffer == nil) {
|
|
|
- data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
|
|
|
- }
|
|
|
+ blitcmd = [data.mtlcmdbuffer blitCommandEncoder];
|
|
|
+
|
|
|
+ [blitcmd copyFromBuffer:texturedata.lockedbuffer
|
|
|
+ sourceOffset:0
|
|
|
+ sourceBytesPerRow:pitch
|
|
|
+ sourceBytesPerImage:0
|
|
|
+ sourceSize:MTLSizeMake(rect.w, rect.h, 1)
|
|
|
+ toTexture:texturedata.mtltexture
|
|
|
+ destinationSlice:0
|
|
|
+ destinationLevel:0
|
|
|
+ destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
|
|
|
+#if SDL_HAVE_YUV
|
|
|
+ if (texturedata.yuv) {
|
|
|
+ int Uslice = texture->format == SDL_PIXELFORMAT_YV12 ? 1 : 0;
|
|
|
+ int Vslice = texture->format == SDL_PIXELFORMAT_YV12 ? 0 : 1;
|
|
|
+ int UVpitch = (pitch + 1) / 2;
|
|
|
+
|
|
|
+ [blitcmd copyFromBuffer:texturedata.lockedbuffer
|
|
|
+ sourceOffset:rect.h * pitch
|
|
|
+ sourceBytesPerRow:UVpitch
|
|
|
+ sourceBytesPerImage:UVpitch * UVrect.h
|
|
|
+ sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
|
|
|
+ toTexture:texturedata.mtltexture_uv
|
|
|
+ destinationSlice:Uslice
|
|
|
+ destinationLevel:0
|
|
|
+ destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
|
|
|
+
|
|
|
+ [blitcmd copyFromBuffer:texturedata.lockedbuffer
|
|
|
+ sourceOffset:(rect.h * pitch) + UVrect.h * UVpitch
|
|
|
+ sourceBytesPerRow:UVpitch
|
|
|
+ sourceBytesPerImage:UVpitch * UVrect.h
|
|
|
+ sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
|
|
|
+ toTexture:texturedata.mtltexture_uv
|
|
|
+ destinationSlice:Vslice
|
|
|
+ destinationLevel:0
|
|
|
+ destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
|
|
|
+ }
|
|
|
|
|
|
- blitcmd = [data.mtlcmdbuffer blitCommandEncoder];
|
|
|
+ if (texturedata.nv12) {
|
|
|
+ int UVpitch = 2 * ((pitch + 1) / 2);
|
|
|
|
|
|
[blitcmd copyFromBuffer:texturedata.lockedbuffer
|
|
|
- sourceOffset:0
|
|
|
- sourceBytesPerRow:pitch
|
|
|
+ sourceOffset:rect.h * pitch
|
|
|
+ sourceBytesPerRow:UVpitch
|
|
|
sourceBytesPerImage:0
|
|
|
- sourceSize:MTLSizeMake(rect.w, rect.h, 1)
|
|
|
- toTexture:texturedata.mtltexture
|
|
|
+ sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
|
|
|
+ toTexture:texturedata.mtltexture_uv
|
|
|
destinationSlice:0
|
|
|
destinationLevel:0
|
|
|
- destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)];
|
|
|
-#if SDL_HAVE_YUV
|
|
|
- if (texturedata.yuv) {
|
|
|
- int Uslice = texture->format == SDL_PIXELFORMAT_YV12 ? 1 : 0;
|
|
|
- int Vslice = texture->format == SDL_PIXELFORMAT_YV12 ? 0 : 1;
|
|
|
- int UVpitch = (pitch + 1) / 2;
|
|
|
-
|
|
|
- [blitcmd copyFromBuffer:texturedata.lockedbuffer
|
|
|
- sourceOffset:rect.h * pitch
|
|
|
- sourceBytesPerRow:UVpitch
|
|
|
- sourceBytesPerImage:UVpitch * UVrect.h
|
|
|
- sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
|
|
|
- toTexture:texturedata.mtltexture_uv
|
|
|
- destinationSlice:Uslice
|
|
|
- destinationLevel:0
|
|
|
- destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
|
|
|
-
|
|
|
- [blitcmd copyFromBuffer:texturedata.lockedbuffer
|
|
|
- sourceOffset:(rect.h * pitch) + UVrect.h * UVpitch
|
|
|
- sourceBytesPerRow:UVpitch
|
|
|
- sourceBytesPerImage:UVpitch * UVrect.h
|
|
|
- sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
|
|
|
- toTexture:texturedata.mtltexture_uv
|
|
|
- destinationSlice:Vslice
|
|
|
- destinationLevel:0
|
|
|
- destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
|
|
|
- }
|
|
|
-
|
|
|
- if (texturedata.nv12) {
|
|
|
- int UVpitch = 2 * ((pitch + 1) / 2);
|
|
|
-
|
|
|
- [blitcmd copyFromBuffer:texturedata.lockedbuffer
|
|
|
- sourceOffset:rect.h * pitch
|
|
|
- sourceBytesPerRow:UVpitch
|
|
|
- sourceBytesPerImage:0
|
|
|
- sourceSize:MTLSizeMake(UVrect.w, UVrect.h, 1)
|
|
|
- toTexture:texturedata.mtltexture_uv
|
|
|
- destinationSlice:0
|
|
|
- destinationLevel:0
|
|
|
- destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
|
|
|
- }
|
|
|
+ destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)];
|
|
|
+ }
|
|
|
#endif
|
|
|
- [blitcmd endEncoding];
|
|
|
+ [blitcmd endEncoding];
|
|
|
|
|
|
- [data.mtlcmdbuffer commit];
|
|
|
- data.mtlcmdbuffer = nil;
|
|
|
+ [data.mtlcmdbuffer commit];
|
|
|
+ data.mtlcmdbuffer = nil;
|
|
|
|
|
|
- texturedata.lockedbuffer = nil; /* Retained property, so it calls release. */
|
|
|
- texturedata.hasdata = YES;
|
|
|
- }
|
|
|
-}
|
|
|
+ texturedata.lockedbuffer = nil; /* Retained property, so it calls release. */
|
|
|
+ texturedata.hasdata = YES;
|
|
|
+}}
|
|
|
|
|
|
-static void METAL_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
+static void
|
|
|
+METAL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
|
|
|
- if (scaleMode == SDL_ScaleModeNearest) {
|
|
|
- texturedata.mtlsampler = data.mtlsamplernearest;
|
|
|
- } else {
|
|
|
- texturedata.mtlsampler = data.mtlsamplerlinear;
|
|
|
- }
|
|
|
+ if (scaleMode == SDL_ScaleModeNearest) {
|
|
|
+ texturedata.mtlsampler = data.mtlsamplernearest;
|
|
|
+ } else {
|
|
|
+ texturedata.mtlsampler = data.mtlsamplerlinear;
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-static int METAL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
+}}
|
|
|
|
|
|
- if (data.mtlcmdencoder) {
|
|
|
- /* End encoding for the previous render target so we can set up a new
|
|
|
- * render pass for this one. */
|
|
|
- [data.mtlcmdencoder endEncoding];
|
|
|
- [data.mtlcmdbuffer commit];
|
|
|
+static int
|
|
|
+METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
|
|
|
- data.mtlcmdencoder = nil;
|
|
|
- data.mtlcmdbuffer = nil;
|
|
|
- }
|
|
|
+ if (data.mtlcmdencoder) {
|
|
|
+ /* End encoding for the previous render target so we can set up a new
|
|
|
+ * render pass for this one. */
|
|
|
+ [data.mtlcmdencoder endEncoding];
|
|
|
+ [data.mtlcmdbuffer commit];
|
|
|
|
|
|
- /* We don't begin a new render pass right away - we delay it until an actual
|
|
|
- * draw or clear happens. That way we can use hardware clears when possible,
|
|
|
- * which are only available when beginning a new render pass. */
|
|
|
- return 0;
|
|
|
+ data.mtlcmdencoder = nil;
|
|
|
+ data.mtlcmdbuffer = nil;
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-static int METAL_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
|
|
|
+ /* We don't begin a new render pass right away - we delay it until an actual
|
|
|
+ * draw or clear happens. That way we can use hardware clears when possible,
|
|
|
+ * which are only available when beginning a new render pass. */
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
+
|
|
|
+
|
|
|
+static int
|
|
|
+METAL_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
|
|
|
{
|
|
|
- float projection[4][4]; /* Prepare an orthographic projection */
|
|
|
+ float projection[4][4]; /* Prepare an orthographic projection */
|
|
|
const int w = cmd->data.viewport.rect.w;
|
|
|
const int h = cmd->data.viewport.rect.h;
|
|
|
- const size_t matrixlen = sizeof(projection);
|
|
|
- float *matrix = (float *)SDL_AllocateRenderVertices(renderer, matrixlen, CONSTANT_ALIGN(16), &cmd->data.viewport.first);
|
|
|
+ const size_t matrixlen = sizeof (projection);
|
|
|
+ float *matrix = (float *) SDL_AllocateRenderVertices(renderer, matrixlen, CONSTANT_ALIGN(16), &cmd->data.viewport.first);
|
|
|
if (!matrix) {
|
|
|
return -1;
|
|
|
}
|
|
@@ -1046,25 +1021,27 @@ static int METAL_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int METAL_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
|
|
|
+static int
|
|
|
+METAL_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
|
|
|
{
|
|
|
- const size_t vertlen = sizeof(float) * 4;
|
|
|
- float *verts = (float *)SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(16), &cmd->data.color.first);
|
|
|
+ const size_t vertlen = sizeof (float) * 4;
|
|
|
+ float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(16), &cmd->data.color.first);
|
|
|
if (!verts) {
|
|
|
return -1;
|
|
|
}
|
|
|
/*
|
|
|
- * FIXME: not needed anymore, some cleanup to do
|
|
|
+ * FIXME: not needed anymore, some cleanup to do
|
|
|
*
|
|
|
- *(verts++) = ((float)cmd->data.color.r) / 255.0f;
|
|
|
- *(verts++) = ((float)cmd->data.color.g) / 255.0f;
|
|
|
- *(verts++) = ((float)cmd->data.color.b) / 255.0f;
|
|
|
- *(verts++) = ((float)cmd->data.color.a) / 255.0f;
|
|
|
- */
|
|
|
+ *(verts++) = ((float)cmd->data.color.r) / 255.0f;
|
|
|
+ *(verts++) = ((float)cmd->data.color.g) / 255.0f;
|
|
|
+ *(verts++) = ((float)cmd->data.color.b) / 255.0f;
|
|
|
+ *(verts++) = ((float)cmd->data.color.a) / 255.0f;
|
|
|
+ */
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int METAL_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
|
|
|
+static int
|
|
|
+METAL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
|
|
|
{
|
|
|
const SDL_Color color = {
|
|
|
cmd->data.draw.r,
|
|
@@ -1073,8 +1050,8 @@ static int METAL_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
cmd->data.draw.a
|
|
|
};
|
|
|
|
|
|
- const size_t vertlen = (2 * sizeof(float) + sizeof(SDL_Color)) * count;
|
|
|
- float *verts = (float *)SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(8), &cmd->data.draw.first);
|
|
|
+ const size_t vertlen = (2 * sizeof (float) + sizeof (SDL_Color)) * count;
|
|
|
+ float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(8), &cmd->data.draw.first);
|
|
|
if (!verts) {
|
|
|
return -1;
|
|
|
}
|
|
@@ -1088,7 +1065,8 @@ static int METAL_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int METAL_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
|
|
|
+static int
|
|
|
+METAL_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
|
|
|
{
|
|
|
const SDL_Color color = {
|
|
|
cmd->data.draw.r,
|
|
@@ -1099,10 +1077,10 @@ static int METAL_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
size_t vertlen;
|
|
|
float *verts;
|
|
|
|
|
|
- SDL_assert(count >= 2); /* should have been checked at the higher level. */
|
|
|
+ SDL_assert(count >= 2); /* should have been checked at the higher level. */
|
|
|
|
|
|
- vertlen = (2 * sizeof(float) + sizeof(SDL_Color)) * count;
|
|
|
- verts = (float *)SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(8), &cmd->data.draw.first);
|
|
|
+ vertlen = (2 * sizeof (float) + sizeof (SDL_Color)) * count;
|
|
|
+ verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(8), &cmd->data.draw.first);
|
|
|
if (!verts) {
|
|
|
return -1;
|
|
|
}
|
|
@@ -1122,7 +1100,7 @@ static int METAL_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
that are missing a pixel that frames something and not arbitrary
|
|
|
angles. Maybe !!! FIXME for later, though. */
|
|
|
|
|
|
- points -= 2; /* update the last line. */
|
|
|
+ points -= 2; /* update the last line. */
|
|
|
verts -= 2 + 1;
|
|
|
|
|
|
{
|
|
@@ -1131,9 +1109,9 @@ static int METAL_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
const float xend = points[1].x;
|
|
|
const float yend = points[1].y;
|
|
|
|
|
|
- if (ystart == yend) { /* horizontal line */
|
|
|
+ if (ystart == yend) { /* horizontal line */
|
|
|
verts[0] += (xend > xstart) ? 1.0f : -1.0f;
|
|
|
- } else if (xstart == xend) { /* vertical line */
|
|
|
+ } else if (xstart == xend) { /* vertical line */
|
|
|
verts[1] += (yend > ystart) ? 1.0f : -1.0f;
|
|
|
}
|
|
|
}
|
|
@@ -1141,14 +1119,15 @@ static int METAL_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int METAL_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
|
|
|
- const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
|
|
|
- int num_vertices, const void *indices, int num_indices, int size_indices,
|
|
|
- float scale_x, float scale_y)
|
|
|
+static int
|
|
|
+METAL_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
|
|
|
+ const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
|
|
|
+ int num_vertices, const void *indices, int num_indices, int size_indices,
|
|
|
+ float scale_x, float scale_y)
|
|
|
{
|
|
|
int count = indices ? num_indices : num_vertices;
|
|
|
- const size_t vertlen = (2 * sizeof(float) + sizeof(int) + (texture ? 2 : 0) * sizeof(float)) * count;
|
|
|
- float *verts = (float *)SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(8), &cmd->data.draw.first);
|
|
|
+ const size_t vertlen = (2 * sizeof (float) + sizeof (int) + (texture ? 2 : 0) * sizeof (float)) * count;
|
|
|
+ float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, DEVICE_ALIGN(8), &cmd->data.draw.first);
|
|
|
if (!verts) {
|
|
|
return -1;
|
|
|
}
|
|
@@ -1169,15 +1148,15 @@ static int METAL_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, S
|
|
|
j = i;
|
|
|
}
|
|
|
|
|
|
- xy_ = (float *)((char *)xy + j * xy_stride);
|
|
|
+ xy_ = (float *)((char*)xy + j * xy_stride);
|
|
|
|
|
|
*(verts++) = xy_[0] * scale_x;
|
|
|
*(verts++) = xy_[1] * scale_y;
|
|
|
|
|
|
- *((SDL_Color *)verts++) = *(SDL_Color *)((char *)color + j * color_stride);
|
|
|
+ *((SDL_Color *)verts++) = *(SDL_Color *)((char*)color + j * color_stride);
|
|
|
|
|
|
if (texture) {
|
|
|
- float *uv_ = (float *)((char *)uv + j * uv_stride);
|
|
|
+ float *uv_ = (float *)((char*)uv + j * uv_stride);
|
|
|
*(verts++) = uv_[0];
|
|
|
*(verts++) = uv_[1];
|
|
|
}
|
|
@@ -1202,10 +1181,11 @@ typedef struct
|
|
|
size_t color_offset;
|
|
|
} METAL_DrawStateCache;
|
|
|
|
|
|
-static SDL_bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_MetalFragmentFunction shader,
|
|
|
- const size_t constants_offset, id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
|
|
|
+static SDL_bool
|
|
|
+SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_MetalFragmentFunction shader,
|
|
|
+ const size_t constants_offset, id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
|
|
|
{
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
const SDL_BlendMode blend = cmd->data.draw.blend;
|
|
|
size_t first = cmd->data.draw.first;
|
|
|
id<MTLRenderPipelineState> newpipeline;
|
|
@@ -1223,7 +1203,7 @@ static SDL_bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cm
|
|
|
viewport.znear = 0.0;
|
|
|
viewport.zfar = 1.0;
|
|
|
[data.mtlcmdencoder setViewport:viewport];
|
|
|
- [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:statecache->projection_offset atIndex:2]; // projection
|
|
|
+ [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:statecache->projection_offset atIndex:2]; // projection
|
|
|
statecache->viewport_dirty = SDL_FALSE;
|
|
|
}
|
|
|
|
|
@@ -1282,10 +1262,11 @@ static SDL_bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cm
|
|
|
return SDL_TRUE;
|
|
|
}
|
|
|
|
|
|
-static SDL_bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
|
|
|
- id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
|
|
|
+static SDL_bool
|
|
|
+SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
|
|
|
+ id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
|
|
|
{
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
SDL_Texture *texture = cmd->data.draw.texture;
|
|
|
METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
|
|
|
|
|
@@ -1296,7 +1277,7 @@ static SDL_bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cm
|
|
|
if (texture != statecache->texture) {
|
|
|
METAL_TextureData *oldtexturedata = NULL;
|
|
|
if (statecache->texture) {
|
|
|
- oldtexturedata = (__bridge METAL_TextureData *)statecache->texture->driverdata;
|
|
|
+ oldtexturedata = (__bridge METAL_TextureData *) statecache->texture->driverdata;
|
|
|
}
|
|
|
if (!oldtexturedata || (texturedata.mtlsampler != oldtexturedata.mtlsampler)) {
|
|
|
[data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
|
|
@@ -1314,74 +1295,70 @@ static SDL_bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cm
|
|
|
return SDL_TRUE;
|
|
|
}
|
|
|
|
|
|
-static int METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- id<MTLBuffer> mtlbufvertex = nil;
|
|
|
- METAL_DrawStateCache statecache;
|
|
|
- SDL_zero(statecache);
|
|
|
-
|
|
|
- statecache.pipeline = nil;
|
|
|
- statecache.vertex_buffer = nil;
|
|
|
- statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
|
|
|
- statecache.texture = NULL;
|
|
|
- statecache.color_dirty = SDL_TRUE;
|
|
|
- statecache.cliprect_dirty = SDL_TRUE;
|
|
|
- statecache.viewport_dirty = SDL_TRUE;
|
|
|
- statecache.projection_offset = 0;
|
|
|
- statecache.color_offset = 0;
|
|
|
-
|
|
|
- // !!! FIXME: have a ring of pre-made MTLBuffers we cycle through? How expensive is creation?
|
|
|
- if (vertsize > 0) {
|
|
|
- /* We can memcpy to a shared buffer from the CPU and read it from the GPU
|
|
|
- * without any extra copying. It's a bit slower on macOS to read shared
|
|
|
- * data from the GPU than to read managed/private data, but we avoid the
|
|
|
- * cost of copying the data and the code's simpler. Apple's best
|
|
|
- * practices guide recommends this approach for streamed vertex data.
|
|
|
- * TODO: this buffer is also used for constants. Is performance still
|
|
|
- * good for those, or should we have a managed buffer for them? */
|
|
|
- mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
|
|
|
- mtlbufvertex.label = @"SDL vertex data";
|
|
|
- SDL_memcpy([mtlbufvertex contents], vertices, vertsize);
|
|
|
-
|
|
|
- statecache.vertex_buffer = mtlbufvertex;
|
|
|
- }
|
|
|
+static int
|
|
|
+METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ id<MTLBuffer> mtlbufvertex = nil;
|
|
|
+ METAL_DrawStateCache statecache;
|
|
|
+ SDL_zero(statecache);
|
|
|
+
|
|
|
+ statecache.pipeline = nil;
|
|
|
+ statecache.vertex_buffer = nil;
|
|
|
+ statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
|
|
|
+ statecache.texture = NULL;
|
|
|
+ statecache.color_dirty = SDL_TRUE;
|
|
|
+ statecache.cliprect_dirty = SDL_TRUE;
|
|
|
+ statecache.viewport_dirty = SDL_TRUE;
|
|
|
+ statecache.projection_offset = 0;
|
|
|
+ statecache.color_offset = 0;
|
|
|
+
|
|
|
+ // !!! FIXME: have a ring of pre-made MTLBuffers we cycle through? How expensive is creation?
|
|
|
+ if (vertsize > 0) {
|
|
|
+ /* We can memcpy to a shared buffer from the CPU and read it from the GPU
|
|
|
+ * without any extra copying. It's a bit slower on macOS to read shared
|
|
|
+ * data from the GPU than to read managed/private data, but we avoid the
|
|
|
+ * cost of copying the data and the code's simpler. Apple's best
|
|
|
+ * practices guide recommends this approach for streamed vertex data.
|
|
|
+ * TODO: this buffer is also used for constants. Is performance still
|
|
|
+ * good for those, or should we have a managed buffer for them? */
|
|
|
+ mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
|
|
|
+ mtlbufvertex.label = @"SDL vertex data";
|
|
|
+ SDL_memcpy([mtlbufvertex contents], vertices, vertsize);
|
|
|
+
|
|
|
+ statecache.vertex_buffer = mtlbufvertex;
|
|
|
+ }
|
|
|
|
|
|
- // If there's a command buffer here unexpectedly (app requested one?). Commit it so we can start fresh.
|
|
|
- [data.mtlcmdencoder endEncoding];
|
|
|
- [data.mtlcmdbuffer commit];
|
|
|
- data.mtlcmdencoder = nil;
|
|
|
- data.mtlcmdbuffer = nil;
|
|
|
+ // If there's a command buffer here unexpectedly (app requested one?). Commit it so we can start fresh.
|
|
|
+ [data.mtlcmdencoder endEncoding];
|
|
|
+ [data.mtlcmdbuffer commit];
|
|
|
+ data.mtlcmdencoder = nil;
|
|
|
+ data.mtlcmdbuffer = nil;
|
|
|
|
|
|
- while (cmd) {
|
|
|
- switch (cmd->command) {
|
|
|
- case SDL_RENDERCMD_SETVIEWPORT:
|
|
|
- {
|
|
|
- SDL_memcpy(&statecache.viewport, &cmd->data.viewport.rect, sizeof(statecache.viewport));
|
|
|
+ while (cmd) {
|
|
|
+ switch (cmd->command) {
|
|
|
+ case SDL_RENDERCMD_SETVIEWPORT: {
|
|
|
+ SDL_memcpy(&statecache.viewport, &cmd->data.viewport.rect, sizeof (statecache.viewport));
|
|
|
statecache.projection_offset = cmd->data.viewport.first;
|
|
|
statecache.viewport_dirty = SDL_TRUE;
|
|
|
statecache.cliprect_dirty = SDL_TRUE;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- case SDL_RENDERCMD_SETCLIPRECT:
|
|
|
- {
|
|
|
- SDL_memcpy(&statecache.cliprect, &cmd->data.cliprect.rect, sizeof(statecache.cliprect));
|
|
|
+ case SDL_RENDERCMD_SETCLIPRECT: {
|
|
|
+ SDL_memcpy(&statecache.cliprect, &cmd->data.cliprect.rect, sizeof (statecache.cliprect));
|
|
|
statecache.cliprect_enabled = cmd->data.cliprect.enabled;
|
|
|
statecache.cliprect_dirty = SDL_TRUE;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- case SDL_RENDERCMD_SETDRAWCOLOR:
|
|
|
- {
|
|
|
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
|
|
|
statecache.color_offset = cmd->data.color.first;
|
|
|
statecache.color_dirty = SDL_TRUE;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- case SDL_RENDERCMD_CLEAR:
|
|
|
- {
|
|
|
+ case SDL_RENDERCMD_CLEAR: {
|
|
|
/* If we're already encoding a command buffer, dump it without committing it. We'd just
|
|
|
clear all its work anyhow, and starting a new encoder will let us use a hardware clear
|
|
|
operation via MTLLoadActionClear. */
|
|
@@ -1417,8 +1394,7 @@ static int METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
}
|
|
|
|
|
|
case SDL_RENDERCMD_DRAW_POINTS:
|
|
|
- case SDL_RENDERCMD_DRAW_LINES:
|
|
|
- {
|
|
|
+ case SDL_RENDERCMD_DRAW_LINES: {
|
|
|
const size_t count = cmd->data.draw.count;
|
|
|
const MTLPrimitiveType primtype = (cmd->command == SDL_RENDERCMD_DRAW_POINTS) ? MTLPrimitiveTypePoint : MTLPrimitiveTypeLineStrip;
|
|
|
if (SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, mtlbufvertex, &statecache)) {
|
|
@@ -1436,8 +1412,7 @@ static int METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
case SDL_RENDERCMD_COPY_EX: /* unused */
|
|
|
break;
|
|
|
|
|
|
- case SDL_RENDERCMD_GEOMETRY:
|
|
|
- {
|
|
|
+ case SDL_RENDERCMD_GEOMETRY: {
|
|
|
const size_t count = cmd->data.draw.count;
|
|
|
SDL_Texture *texture = cmd->data.draw.texture;
|
|
|
|
|
@@ -1455,30 +1430,29 @@ static int METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
|
|
|
|
|
|
case SDL_RENDERCMD_NO_OP:
|
|
|
break;
|
|
|
- }
|
|
|
- cmd = cmd->next;
|
|
|
}
|
|
|
-
|
|
|
- return 0;
|
|
|
+ cmd = cmd->next;
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-static int METAL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
|
|
|
- Uint32 pixel_format, void *pixels, int pitch)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- id<MTLTexture> mtltexture;
|
|
|
- MTLRegion mtlregion;
|
|
|
- int temp_pitch, status;
|
|
|
- Uint32 temp_format;
|
|
|
- void *temp_pixels;
|
|
|
- if (!METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil)) {
|
|
|
- return SDL_SetError("Failed to activate render command encoder (is your window in the background?");
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
+
|
|
|
+static int
|
|
|
+METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
|
|
+ Uint32 pixel_format, void * pixels, int pitch)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ id<MTLTexture> mtltexture;
|
|
|
+ MTLRegion mtlregion;
|
|
|
+ int temp_pitch, status;
|
|
|
+ Uint32 temp_format;
|
|
|
+ void *temp_pixels;
|
|
|
+ if (!METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil)) {
|
|
|
+ return SDL_SetError("Failed to activate render command encoder (is your window in the background?");
|
|
|
+ }
|
|
|
|
|
|
- [data.mtlcmdencoder endEncoding];
|
|
|
- mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
|
|
|
+ [data.mtlcmdencoder endEncoding];
|
|
|
+ mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
|
|
|
|
|
|
#ifdef __MACOSX__
|
|
|
/* on macOS with managed-storage textures, we need to tell the driver to
|
|
@@ -1492,127 +1466,122 @@ static int METAL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- /* Commit the current command buffer and wait until it's completed, to make
|
|
|
- * sure the GPU has finished rendering to it by the time we read it. */
|
|
|
- [data.mtlcmdbuffer commit];
|
|
|
- [data.mtlcmdbuffer waitUntilCompleted];
|
|
|
- data.mtlcmdencoder = nil;
|
|
|
- data.mtlcmdbuffer = nil;
|
|
|
-
|
|
|
- mtlregion = MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h);
|
|
|
-
|
|
|
- // we only do BGRA8 or RGBA8 at the moment, so 4 will do.
|
|
|
- temp_pitch = rect->w * 4;
|
|
|
- temp_pixels = SDL_malloc(temp_pitch * rect->h);
|
|
|
- if (!temp_pixels) {
|
|
|
- return SDL_OutOfMemory();
|
|
|
- }
|
|
|
+ /* Commit the current command buffer and wait until it's completed, to make
|
|
|
+ * sure the GPU has finished rendering to it by the time we read it. */
|
|
|
+ [data.mtlcmdbuffer commit];
|
|
|
+ [data.mtlcmdbuffer waitUntilCompleted];
|
|
|
+ data.mtlcmdencoder = nil;
|
|
|
+ data.mtlcmdbuffer = nil;
|
|
|
|
|
|
- [mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
|
|
|
+ mtlregion = MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h);
|
|
|
|
|
|
- temp_format = (mtltexture.pixelFormat == MTLPixelFormatBGRA8Unorm) ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_ABGR8888;
|
|
|
- status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
|
|
|
- SDL_free(temp_pixels);
|
|
|
- return status;
|
|
|
+ // we only do BGRA8 or RGBA8 at the moment, so 4 will do.
|
|
|
+ temp_pitch = rect->w * 4;
|
|
|
+ temp_pixels = SDL_malloc(temp_pitch * rect->h);
|
|
|
+ if (!temp_pixels) {
|
|
|
+ return SDL_OutOfMemory();
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-static int METAL_RenderPresent(SDL_Renderer *renderer)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- SDL_bool ready = SDL_TRUE;
|
|
|
+ [mtltexture getBytes:temp_pixels bytesPerRow:temp_pitch fromRegion:mtlregion mipmapLevel:0];
|
|
|
|
|
|
- // If we don't have a command buffer, we can't present, so activate to get one.
|
|
|
- if (data.mtlcmdencoder == nil) {
|
|
|
- // We haven't even gotten a backbuffer yet? Clear it to black. Otherwise, load the existing data.
|
|
|
- if (data.mtlbackbuffer == nil) {
|
|
|
- MTLClearColor color = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
- ready = METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color, nil);
|
|
|
- } else {
|
|
|
- ready = METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);
|
|
|
- }
|
|
|
- }
|
|
|
+ temp_format = (mtltexture.pixelFormat == MTLPixelFormatBGRA8Unorm) ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_ABGR8888;
|
|
|
+ status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
|
|
|
+ SDL_free(temp_pixels);
|
|
|
+ return status;
|
|
|
+}}
|
|
|
|
|
|
- [data.mtlcmdencoder endEncoding];
|
|
|
+static int
|
|
|
+METAL_RenderPresent(SDL_Renderer * renderer)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ SDL_bool ready = SDL_TRUE;
|
|
|
|
|
|
- // If we don't have a drawable to present, don't try to present it.
|
|
|
- // But we'll still try to commit the command buffer in case it was already enqueued.
|
|
|
- if (ready) {
|
|
|
- SDL_assert(data.mtlbackbuffer != nil);
|
|
|
- [data.mtlcmdbuffer presentDrawable:data.mtlbackbuffer];
|
|
|
+ // If we don't have a command buffer, we can't present, so activate to get one.
|
|
|
+ if (data.mtlcmdencoder == nil) {
|
|
|
+ // We haven't even gotten a backbuffer yet? Clear it to black. Otherwise, load the existing data.
|
|
|
+ if (data.mtlbackbuffer == nil) {
|
|
|
+ MTLClearColor color = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+ ready = METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color, nil);
|
|
|
+ } else {
|
|
|
+ ready = METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [data.mtlcmdbuffer commit];
|
|
|
-
|
|
|
- data.mtlcmdencoder = nil;
|
|
|
- data.mtlcmdbuffer = nil;
|
|
|
- data.mtlbackbuffer = nil;
|
|
|
+ [data.mtlcmdencoder endEncoding];
|
|
|
|
|
|
- if (renderer->hidden || !ready) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
+ // If we don't have a drawable to present, don't try to present it.
|
|
|
+ // But we'll still try to commit the command buffer in case it was already enqueued.
|
|
|
+ if (ready) {
|
|
|
+ SDL_assert(data.mtlbackbuffer != nil);
|
|
|
+ [data.mtlcmdbuffer presentDrawable:data.mtlbackbuffer];
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-static void METAL_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- CFBridgingRelease(texture->driverdata);
|
|
|
- texture->driverdata = NULL;
|
|
|
- }
|
|
|
-}
|
|
|
+ [data.mtlcmdbuffer commit];
|
|
|
|
|
|
-static void METAL_DestroyRenderer(SDL_Renderer *renderer)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- if (renderer->driverdata) {
|
|
|
- METAL_RenderData *data = CFBridgingRelease(renderer->driverdata);
|
|
|
+ data.mtlcmdencoder = nil;
|
|
|
+ data.mtlcmdbuffer = nil;
|
|
|
+ data.mtlbackbuffer = nil;
|
|
|
|
|
|
- if (data.mtlcmdencoder != nil) {
|
|
|
- [data.mtlcmdencoder endEncoding];
|
|
|
- }
|
|
|
+ if (renderer->hidden || !ready) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}}
|
|
|
|
|
|
- DestroyAllPipelines(data.allpipelines, data.pipelinescount);
|
|
|
+static void
|
|
|
+METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
|
|
|
+{ @autoreleasepool {
|
|
|
+ CFBridgingRelease(texture->driverdata);
|
|
|
+ texture->driverdata = NULL;
|
|
|
+}}
|
|
|
|
|
|
- /* Release the metal view instead of destroying it,
|
|
|
- in case we want to use it later (recreating the renderer)
|
|
|
- */
|
|
|
- /* SDL_Metal_DestroyView(data.mtlview); */
|
|
|
- CFBridgingRelease(data.mtlview);
|
|
|
- }
|
|
|
+static void
|
|
|
+METAL_DestroyRenderer(SDL_Renderer * renderer)
|
|
|
+{ @autoreleasepool {
|
|
|
+ if (renderer->driverdata) {
|
|
|
+ METAL_RenderData *data = CFBridgingRelease(renderer->driverdata);
|
|
|
|
|
|
- SDL_free(renderer);
|
|
|
- }
|
|
|
-}
|
|
|
+ if (data.mtlcmdencoder != nil) {
|
|
|
+ [data.mtlcmdencoder endEncoding];
|
|
|
+ }
|
|
|
|
|
|
-static void *METAL_GetMetalLayer(SDL_Renderer *renderer)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- return (__bridge void *)data.mtllayer;
|
|
|
- }
|
|
|
-}
|
|
|
+ DestroyAllPipelines(data.allpipelines, data.pipelinescount);
|
|
|
|
|
|
-static void *METAL_GetMetalCommandEncoder(SDL_Renderer *renderer)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- // note that data.mtlcmdencoder can be nil if METAL_ActivateRenderCommandEncoder fails.
|
|
|
- // Before SDL 2.0.18, it might have returned a non-nil encoding that might not have been
|
|
|
- // usable for presentation. Check your return values!
|
|
|
- METAL_RenderData *data;
|
|
|
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);
|
|
|
- data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
- return (__bridge void *)data.mtlcmdencoder;
|
|
|
+ /* Release the metal view instead of destroying it,
|
|
|
+ in case we want to use it later (recreating the renderer)
|
|
|
+ */
|
|
|
+ /* SDL_Metal_DestroyView(data.mtlview); */
|
|
|
+ CFBridgingRelease(data.mtlview);
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-static int METAL_SetVSync(SDL_Renderer *renderer, const int vsync)
|
|
|
+ SDL_free(renderer);
|
|
|
+}}
|
|
|
+
|
|
|
+static void *
|
|
|
+METAL_GetMetalLayer(SDL_Renderer * renderer)
|
|
|
+{ @autoreleasepool {
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ return (__bridge void*)data.mtllayer;
|
|
|
+}}
|
|
|
+
|
|
|
+static void *
|
|
|
+METAL_GetMetalCommandEncoder(SDL_Renderer * renderer)
|
|
|
+{ @autoreleasepool {
|
|
|
+ // note that data.mtlcmdencoder can be nil if METAL_ActivateRenderCommandEncoder fails.
|
|
|
+ // Before SDL 2.0.18, it might have returned a non-nil encoding that might not have been
|
|
|
+ // usable for presentation. Check your return values!
|
|
|
+ METAL_RenderData *data;
|
|
|
+ METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL, nil);
|
|
|
+ data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
+ return (__bridge void*)data.mtlcmdencoder;
|
|
|
+}}
|
|
|
+
|
|
|
+static int
|
|
|
+METAL_SetVSync(SDL_Renderer * renderer, const int vsync)
|
|
|
{
|
|
|
#if (defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)) || TARGET_OS_MACCATALYST
|
|
|
if (@available(macOS 10.13, *)) {
|
|
|
- METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->driverdata;
|
|
|
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
|
|
if (vsync) {
|
|
|
data.mtllayer.displaySyncEnabled = YES;
|
|
|
renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
|
|
@@ -1654,263 +1623,238 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
|
|
|
return nil;
|
|
|
}
|
|
|
|
|
|
-static SDL_Renderer *METAL_CreateRenderer(SDL_Window *window, Uint32 flags)
|
|
|
-{
|
|
|
- @autoreleasepool {
|
|
|
- SDL_Renderer *renderer = NULL;
|
|
|
- METAL_RenderData *data = NULL;
|
|
|
- id<MTLDevice> mtldevice = nil;
|
|
|
- SDL_MetalView view = NULL;
|
|
|
- CAMetalLayer *layer = nil;
|
|
|
- SDL_SysWMinfo syswm;
|
|
|
- NSError *err = nil;
|
|
|
- dispatch_data_t mtllibdata;
|
|
|
- char *constantdata;
|
|
|
- int maxtexsize, quadcount = UINT16_MAX / 4;
|
|
|
- UInt16 *indexdata;
|
|
|
- size_t indicessize = sizeof(UInt16) * quadcount * 6;
|
|
|
- MTLSamplerDescriptor *samplerdesc;
|
|
|
- id<MTLCommandQueue> mtlcmdqueue;
|
|
|
- id<MTLLibrary> mtllibrary;
|
|
|
- id<MTLSamplerState> mtlsamplernearest, mtlsamplerlinear;
|
|
|
- id<MTLBuffer> mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices;
|
|
|
- id<MTLCommandBuffer> cmdbuffer;
|
|
|
- id<MTLBlitCommandEncoder> blitcmd;
|
|
|
-
|
|
|
- /* Note: matrices are column major. */
|
|
|
- float identitytransform[16] = {
|
|
|
- 1.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 1.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 1.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 1.0f,
|
|
|
- };
|
|
|
-
|
|
|
- float halfpixeltransform[16] = {
|
|
|
- 1.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 1.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 0.0f,
|
|
|
- 1.0f,
|
|
|
- 0.0f,
|
|
|
- 0.5f,
|
|
|
- 0.5f,
|
|
|
- 0.0f,
|
|
|
- 1.0f,
|
|
|
- };
|
|
|
-
|
|
|
- /* Metal pads float3s to 16 bytes. */
|
|
|
- float decodetransformJPEG[4 * 4] = {
|
|
|
- 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
|
|
|
- 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
|
|
|
- 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
|
|
|
- 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
|
|
|
- };
|
|
|
-
|
|
|
- float decodetransformBT601[4 * 4] = {
|
|
|
- -0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
|
|
|
- 1.1644, 0.0000, 1.5960, 0.0, /* Rcoeff */
|
|
|
- 1.1644, -0.3918, -0.8130, 0.0, /* Gcoeff */
|
|
|
- 1.1644, 2.0172, 0.0000, 0.0, /* Bcoeff */
|
|
|
- };
|
|
|
-
|
|
|
- float decodetransformBT709[4 * 4] = {
|
|
|
- 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
|
|
|
- 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
|
|
|
- 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
|
|
|
- 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
|
|
|
- };
|
|
|
+static SDL_Renderer *
|
|
|
+METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|
|
+{ @autoreleasepool {
|
|
|
+ SDL_Renderer *renderer = NULL;
|
|
|
+ METAL_RenderData *data = NULL;
|
|
|
+ id<MTLDevice> mtldevice = nil;
|
|
|
+ SDL_MetalView view = NULL;
|
|
|
+ CAMetalLayer *layer = nil;
|
|
|
+ SDL_SysWMinfo syswm;
|
|
|
+ NSError *err = nil;
|
|
|
+ dispatch_data_t mtllibdata;
|
|
|
+ char *constantdata;
|
|
|
+ int maxtexsize, quadcount = UINT16_MAX / 4;
|
|
|
+ UInt16 *indexdata;
|
|
|
+ size_t indicessize = sizeof(UInt16) * quadcount * 6;
|
|
|
+ MTLSamplerDescriptor *samplerdesc;
|
|
|
+ id<MTLCommandQueue> mtlcmdqueue;
|
|
|
+ id<MTLLibrary> mtllibrary;
|
|
|
+ id<MTLSamplerState> mtlsamplernearest, mtlsamplerlinear;
|
|
|
+ id<MTLBuffer> mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices;
|
|
|
+ id<MTLCommandBuffer> cmdbuffer;
|
|
|
+ id<MTLBlitCommandEncoder> blitcmd;
|
|
|
+
|
|
|
+ /* Note: matrices are column major. */
|
|
|
+ float identitytransform[16] = {
|
|
|
+ 1.0f, 0.0f, 0.0f, 0.0f,
|
|
|
+ 0.0f, 1.0f, 0.0f, 0.0f,
|
|
|
+ 0.0f, 0.0f, 1.0f, 0.0f,
|
|
|
+ 0.0f, 0.0f, 0.0f, 1.0f,
|
|
|
+ };
|
|
|
+
|
|
|
+ float halfpixeltransform[16] = {
|
|
|
+ 1.0f, 0.0f, 0.0f, 0.0f,
|
|
|
+ 0.0f, 1.0f, 0.0f, 0.0f,
|
|
|
+ 0.0f, 0.0f, 1.0f, 0.0f,
|
|
|
+ 0.5f, 0.5f, 0.0f, 1.0f,
|
|
|
+ };
|
|
|
+
|
|
|
+ /* Metal pads float3s to 16 bytes. */
|
|
|
+ float decodetransformJPEG[4*4] = {
|
|
|
+ 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
|
|
|
+ 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
|
|
|
+ 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
|
|
|
+ 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
|
|
|
+ };
|
|
|
+
|
|
|
+ float decodetransformBT601[4*4] = {
|
|
|
+ -0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
|
|
|
+ 1.1644, 0.0000, 1.5960, 0.0, /* Rcoeff */
|
|
|
+ 1.1644, -0.3918, -0.8130, 0.0, /* Gcoeff */
|
|
|
+ 1.1644, 2.0172, 0.0000, 0.0, /* Bcoeff */
|
|
|
+ };
|
|
|
+
|
|
|
+ float decodetransformBT709[4*4] = {
|
|
|
+ 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
|
|
|
+ 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
|
|
|
+ 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
|
|
|
+ 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
|
|
|
+ };
|
|
|
|
|
|
SDL_VERSION(&syswm.version);
|
|
|
if (!SDL_GetWindowWMInfo(window, &syswm)) {
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- if (IsMetalAvailable(&syswm) == -1) {
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ if (IsMetalAvailable(&syswm) == -1) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer));
|
|
|
- if (!renderer) {
|
|
|
- SDL_OutOfMemory();
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
|
|
|
+ if (!renderer) {
|
|
|
+ SDL_OutOfMemory();
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- // !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
|
|
|
- mtldevice = MTLCreateSystemDefaultDevice();
|
|
|
+ // !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
|
|
|
+ mtldevice = MTLCreateSystemDefaultDevice();
|
|
|
|
|
|
- if (mtldevice == nil) {
|
|
|
- SDL_free(renderer);
|
|
|
- SDL_SetError("Failed to obtain Metal device");
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ if (mtldevice == nil) {
|
|
|
+ SDL_free(renderer);
|
|
|
+ SDL_SetError("Failed to obtain Metal device");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- view = GetWindowView(window);
|
|
|
- if (view == nil) {
|
|
|
- view = SDL_Metal_CreateView(window);
|
|
|
- }
|
|
|
+ view = GetWindowView(window);
|
|
|
+ if (view == nil) {
|
|
|
+ view = SDL_Metal_CreateView(window);
|
|
|
+ }
|
|
|
|
|
|
- if (view == NULL) {
|
|
|
- SDL_free(renderer);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ if (view == NULL) {
|
|
|
+ SDL_free(renderer);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- // !!! FIXME: error checking on all of this.
|
|
|
- data = [[METAL_RenderData alloc] init];
|
|
|
-
|
|
|
- if (data == nil) {
|
|
|
- /* Release the metal view instead of destroying it,
|
|
|
- in case we want to use it later (recreating the renderer)
|
|
|
- */
|
|
|
- /* SDL_Metal_DestroyView(view); */
|
|
|
- CFBridgingRelease(view);
|
|
|
- SDL_free(renderer);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ // !!! FIXME: error checking on all of this.
|
|
|
+ data = [[METAL_RenderData alloc] init];
|
|
|
|
|
|
- renderer->driverdata = (void *)CFBridgingRetain(data);
|
|
|
- renderer->window = window;
|
|
|
+ if (data == nil) {
|
|
|
+ /* Release the metal view instead of destroying it,
|
|
|
+ in case we want to use it later (recreating the renderer)
|
|
|
+ */
|
|
|
+ /* SDL_Metal_DestroyView(view); */
|
|
|
+ CFBridgingRelease(view);
|
|
|
+ SDL_free(renderer);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
- data.mtlview = view;
|
|
|
+ renderer->driverdata = (void*)CFBridgingRetain(data);
|
|
|
+ renderer->window = window;
|
|
|
+
|
|
|
+ data.mtlview = view;
|
|
|
|
|
|
#ifdef __MACOSX__
|
|
|
layer = (CAMetalLayer *)[(__bridge NSView *)view layer];
|
|
|
#else
|
|
|
- layer = (CAMetalLayer *)[(__bridge UIView *)view layer];
|
|
|
+ layer = (CAMetalLayer *)[(__bridge UIView *)view layer];
|
|
|
#endif
|
|
|
|
|
|
- layer.device = mtldevice;
|
|
|
-
|
|
|
- /* Necessary for RenderReadPixels. */
|
|
|
- layer.framebufferOnly = NO;
|
|
|
-
|
|
|
- data.mtldevice = layer.device;
|
|
|
- data.mtllayer = layer;
|
|
|
- mtlcmdqueue = [data.mtldevice newCommandQueue];
|
|
|
- data.mtlcmdqueue = mtlcmdqueue;
|
|
|
- data.mtlcmdqueue.label = @"SDL Metal Renderer";
|
|
|
- data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
|
|
|
-
|
|
|
- // The compiled .metallib is embedded in a static array in a header file
|
|
|
- // but the original shader source code is in SDL_shaders_metal.metal.
|
|
|
- mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{
|
|
|
- });
|
|
|
- mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
|
|
|
- data.mtllibrary = mtllibrary;
|
|
|
- SDL_assert(err == nil);
|
|
|
- data.mtllibrary.label = @"SDL Metal renderer shader library";
|
|
|
-
|
|
|
- /* Do some shader pipeline state loading up-front rather than on demand. */
|
|
|
- data.pipelinescount = 0;
|
|
|
- data.allpipelines = NULL;
|
|
|
- ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
|
|
|
-
|
|
|
- samplerdesc = [[MTLSamplerDescriptor alloc] init];
|
|
|
-
|
|
|
- samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
|
|
|
- samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
|
|
|
- mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
|
|
|
- data.mtlsamplernearest = mtlsamplernearest;
|
|
|
-
|
|
|
- samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
|
|
|
- samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
|
|
|
- mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
|
|
|
- data.mtlsamplerlinear = mtlsamplerlinear;
|
|
|
-
|
|
|
- mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
|
|
|
-
|
|
|
- constantdata = [mtlbufconstantstaging contents];
|
|
|
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform, sizeof(identitytransform));
|
|
|
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform, sizeof(halfpixeltransform));
|
|
|
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG, sizeof(decodetransformJPEG));
|
|
|
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601, sizeof(decodetransformBT601));
|
|
|
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709, sizeof(decodetransformBT709));
|
|
|
-
|
|
|
- mtlbufquadindicesstaging = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModeShared];
|
|
|
-
|
|
|
- /* Quads in the following vertex order (matches the FillRects vertices):
|
|
|
- * 1---3
|
|
|
- * | \ |
|
|
|
- * 0---2
|
|
|
- */
|
|
|
- indexdata = [mtlbufquadindicesstaging contents];
|
|
|
- for (int i = 0; i < quadcount; i++) {
|
|
|
- indexdata[i * 6 + 0] = i * 4 + 0;
|
|
|
- indexdata[i * 6 + 1] = i * 4 + 1;
|
|
|
- indexdata[i * 6 + 2] = i * 4 + 2;
|
|
|
-
|
|
|
- indexdata[i * 6 + 3] = i * 4 + 2;
|
|
|
- indexdata[i * 6 + 4] = i * 4 + 1;
|
|
|
- indexdata[i * 6 + 5] = i * 4 + 3;
|
|
|
- }
|
|
|
+ layer.device = mtldevice;
|
|
|
+
|
|
|
+ /* Necessary for RenderReadPixels. */
|
|
|
+ layer.framebufferOnly = NO;
|
|
|
+
|
|
|
+ data.mtldevice = layer.device;
|
|
|
+ data.mtllayer = layer;
|
|
|
+ mtlcmdqueue = [data.mtldevice newCommandQueue];
|
|
|
+ data.mtlcmdqueue = mtlcmdqueue;
|
|
|
+ data.mtlcmdqueue.label = @"SDL Metal Renderer";
|
|
|
+ data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
|
|
|
+
|
|
|
+ // The compiled .metallib is embedded in a static array in a header file
|
|
|
+ // but the original shader source code is in SDL_shaders_metal.metal.
|
|
|
+ mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
|
|
|
+ mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
|
|
|
+ data.mtllibrary = mtllibrary;
|
|
|
+ SDL_assert(err == nil);
|
|
|
+ data.mtllibrary.label = @"SDL Metal renderer shader library";
|
|
|
+
|
|
|
+ /* Do some shader pipeline state loading up-front rather than on demand. */
|
|
|
+ data.pipelinescount = 0;
|
|
|
+ data.allpipelines = NULL;
|
|
|
+ ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
|
|
|
+
|
|
|
+ samplerdesc = [[MTLSamplerDescriptor alloc] init];
|
|
|
+
|
|
|
+ samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
|
|
|
+ samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
|
|
|
+ mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
|
|
|
+ data.mtlsamplernearest = mtlsamplernearest;
|
|
|
+
|
|
|
+ samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
|
|
|
+ samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
|
|
|
+ mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
|
|
|
+ data.mtlsamplerlinear = mtlsamplerlinear;
|
|
|
+
|
|
|
+ mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
|
|
|
+
|
|
|
+ constantdata = [mtlbufconstantstaging contents];
|
|
|
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform, sizeof(identitytransform));
|
|
|
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform, sizeof(halfpixeltransform));
|
|
|
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG, sizeof(decodetransformJPEG));
|
|
|
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601, sizeof(decodetransformBT601));
|
|
|
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709, sizeof(decodetransformBT709));
|
|
|
+
|
|
|
+ mtlbufquadindicesstaging = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModeShared];
|
|
|
+
|
|
|
+ /* Quads in the following vertex order (matches the FillRects vertices):
|
|
|
+ * 1---3
|
|
|
+ * | \ |
|
|
|
+ * 0---2
|
|
|
+ */
|
|
|
+ indexdata = [mtlbufquadindicesstaging contents];
|
|
|
+ for (int i = 0; i < quadcount; i++) {
|
|
|
+ indexdata[i * 6 + 0] = i * 4 + 0;
|
|
|
+ indexdata[i * 6 + 1] = i * 4 + 1;
|
|
|
+ indexdata[i * 6 + 2] = i * 4 + 2;
|
|
|
+
|
|
|
+ indexdata[i * 6 + 3] = i * 4 + 2;
|
|
|
+ indexdata[i * 6 + 4] = i * 4 + 1;
|
|
|
+ indexdata[i * 6 + 5] = i * 4 + 3;
|
|
|
+ }
|
|
|
|
|
|
- mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
|
|
|
- data.mtlbufconstants = mtlbufconstants;
|
|
|
- data.mtlbufconstants.label = @"SDL constant data";
|
|
|
+ mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
|
|
|
+ data.mtlbufconstants = mtlbufconstants;
|
|
|
+ data.mtlbufconstants.label = @"SDL constant data";
|
|
|
|
|
|
- mtlbufquadindices = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModePrivate];
|
|
|
- data.mtlbufquadindices = mtlbufquadindices;
|
|
|
- data.mtlbufquadindices.label = @"SDL quad index buffer";
|
|
|
+ mtlbufquadindices = [data.mtldevice newBufferWithLength:indicessize options:MTLResourceStorageModePrivate];
|
|
|
+ data.mtlbufquadindices = mtlbufquadindices;
|
|
|
+ data.mtlbufquadindices.label = @"SDL quad index buffer";
|
|
|
|
|
|
- cmdbuffer = [data.mtlcmdqueue commandBuffer];
|
|
|
- blitcmd = [cmdbuffer blitCommandEncoder];
|
|
|
+ cmdbuffer = [data.mtlcmdqueue commandBuffer];
|
|
|
+ blitcmd = [cmdbuffer blitCommandEncoder];
|
|
|
|
|
|
- [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
|
|
|
- [blitcmd copyFromBuffer:mtlbufquadindicesstaging sourceOffset:0 toBuffer:mtlbufquadindices destinationOffset:0 size:indicessize];
|
|
|
+ [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
|
|
|
+ [blitcmd copyFromBuffer:mtlbufquadindicesstaging sourceOffset:0 toBuffer:mtlbufquadindices destinationOffset:0 size:indicessize];
|
|
|
|
|
|
- [blitcmd endEncoding];
|
|
|
- [cmdbuffer commit];
|
|
|
+ [blitcmd endEncoding];
|
|
|
+ [cmdbuffer commit];
|
|
|
|
|
|
- // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
|
|
|
+ // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
|
|
|
|
|
|
- renderer->WindowEvent = METAL_WindowEvent;
|
|
|
- renderer->GetOutputSize = METAL_GetOutputSize;
|
|
|
- renderer->SupportsBlendMode = METAL_SupportsBlendMode;
|
|
|
- renderer->CreateTexture = METAL_CreateTexture;
|
|
|
- renderer->UpdateTexture = METAL_UpdateTexture;
|
|
|
+ renderer->WindowEvent = METAL_WindowEvent;
|
|
|
+ renderer->GetOutputSize = METAL_GetOutputSize;
|
|
|
+ renderer->SupportsBlendMode = METAL_SupportsBlendMode;
|
|
|
+ renderer->CreateTexture = METAL_CreateTexture;
|
|
|
+ renderer->UpdateTexture = METAL_UpdateTexture;
|
|
|
#if SDL_HAVE_YUV
|
|
|
- renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
|
|
|
- renderer->UpdateTextureNV = METAL_UpdateTextureNV;
|
|
|
+ renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
|
|
|
+ renderer->UpdateTextureNV = METAL_UpdateTextureNV;
|
|
|
#endif
|
|
|
- renderer->LockTexture = METAL_LockTexture;
|
|
|
- renderer->UnlockTexture = METAL_UnlockTexture;
|
|
|
- renderer->SetTextureScaleMode = METAL_SetTextureScaleMode;
|
|
|
- renderer->SetRenderTarget = METAL_SetRenderTarget;
|
|
|
- renderer->QueueSetViewport = METAL_QueueSetViewport;
|
|
|
- renderer->QueueSetDrawColor = METAL_QueueSetDrawColor;
|
|
|
- renderer->QueueDrawPoints = METAL_QueueDrawPoints;
|
|
|
- renderer->QueueDrawLines = METAL_QueueDrawLines;
|
|
|
- renderer->QueueGeometry = METAL_QueueGeometry;
|
|
|
- renderer->RunCommandQueue = METAL_RunCommandQueue;
|
|
|
- renderer->RenderReadPixels = METAL_RenderReadPixels;
|
|
|
- renderer->RenderPresent = METAL_RenderPresent;
|
|
|
- renderer->DestroyTexture = METAL_DestroyTexture;
|
|
|
- renderer->DestroyRenderer = METAL_DestroyRenderer;
|
|
|
- renderer->SetVSync = METAL_SetVSync;
|
|
|
- renderer->GetMetalLayer = METAL_GetMetalLayer;
|
|
|
- renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder;
|
|
|
-
|
|
|
- renderer->info = METAL_RenderDriver.info;
|
|
|
- renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
|
|
|
-
|
|
|
- renderer->always_batch = SDL_TRUE;
|
|
|
+ renderer->LockTexture = METAL_LockTexture;
|
|
|
+ renderer->UnlockTexture = METAL_UnlockTexture;
|
|
|
+ renderer->SetTextureScaleMode = METAL_SetTextureScaleMode;
|
|
|
+ renderer->SetRenderTarget = METAL_SetRenderTarget;
|
|
|
+ renderer->QueueSetViewport = METAL_QueueSetViewport;
|
|
|
+ renderer->QueueSetDrawColor = METAL_QueueSetDrawColor;
|
|
|
+ renderer->QueueDrawPoints = METAL_QueueDrawPoints;
|
|
|
+ renderer->QueueDrawLines = METAL_QueueDrawLines;
|
|
|
+ renderer->QueueGeometry = METAL_QueueGeometry;
|
|
|
+ renderer->RunCommandQueue = METAL_RunCommandQueue;
|
|
|
+ renderer->RenderReadPixels = METAL_RenderReadPixels;
|
|
|
+ renderer->RenderPresent = METAL_RenderPresent;
|
|
|
+ renderer->DestroyTexture = METAL_DestroyTexture;
|
|
|
+ renderer->DestroyRenderer = METAL_DestroyRenderer;
|
|
|
+ renderer->SetVSync = METAL_SetVSync;
|
|
|
+ renderer->GetMetalLayer = METAL_GetMetalLayer;
|
|
|
+ renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder;
|
|
|
+
|
|
|
+ renderer->info = METAL_RenderDriver.info;
|
|
|
+ renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
|
|
|
+
|
|
|
+ renderer->always_batch = SDL_TRUE;
|
|
|
|
|
|
#if (defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)) || TARGET_OS_MACCATALYST
|
|
|
if (@available(macOS 10.13, *)) {
|
|
@@ -1918,47 +1862,51 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window *window, Uint32 flags)
|
|
|
if (data.mtllayer.displaySyncEnabled) {
|
|
|
renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
|
|
|
}
|
|
|
+ } else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
|
|
|
+ }
|
|
|
|
|
|
/* https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
|
|
|
maxtexsize = 4096;
|
|
|
#if defined(__MACOSX__) || TARGET_OS_MACCATALYST
|
|
|
maxtexsize = 16384;
|
|
|
#elif defined(__TVOS__)
|
|
|
- maxtexsize = 8192;
|
|
|
+ maxtexsize = 8192;
|
|
|
#ifdef __TVOS_11_0
|
|
|
- if (@available(tvOS 11.0, *)) {
|
|
|
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
|
|
|
- maxtexsize = 16384;
|
|
|
- }
|
|
|
+ if (@available(tvOS 11.0, *)) {
|
|
|
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
|
|
|
+ maxtexsize = 16384;
|
|
|
}
|
|
|
+ }
|
|
|
#endif
|
|
|
#else
|
|
|
#ifdef __IPHONE_11_0
|
|
|
#pragma clang diagnostic push
|
|
|
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
|
|
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
|
|
|
- maxtexsize = 16384;
|
|
|
- } else
|
|
|
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
|
|
|
+ maxtexsize = 16384;
|
|
|
+ } else
|
|
|
#pragma clang diagnostic pop
|
|
|
#endif
|
|
|
#ifdef __IPHONE_10_0
|
|
|
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
|
|
|
- maxtexsize = 16384;
|
|
|
- } else
|
|
|
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
|
|
|
+ maxtexsize = 16384;
|
|
|
+ } else
|
|
|
#endif
|
|
|
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
|
|
|
- maxtexsize = 8192;
|
|
|
- } else {
|
|
|
- maxtexsize = 4096;
|
|
|
- }
|
|
|
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
|
|
|
+ maxtexsize = 8192;
|
|
|
+ } else {
|
|
|
+ maxtexsize = 4096;
|
|
|
+ }
|
|
|
#endif
|
|
|
|
|
|
- renderer->info.max_texture_width = maxtexsize;
|
|
|
- renderer->info.max_texture_height = maxtexsize;
|
|
|
+ renderer->info.max_texture_width = maxtexsize;
|
|
|
+ renderer->info.max_texture_height = maxtexsize;
|
|
|
|
|
|
- return renderer;
|
|
|
- }
|
|
|
-}
|
|
|
+ return renderer;
|
|
|
+}}
|
|
|
|
|
|
SDL_RenderDriver METAL_RenderDriver = {
|
|
|
METAL_CreateRenderer,
|
|
@@ -1966,14 +1914,15 @@ SDL_RenderDriver METAL_RenderDriver = {
|
|
|
"metal",
|
|
|
(SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
|
|
|
6,
|
|
|
- { SDL_PIXELFORMAT_ARGB8888,
|
|
|
- SDL_PIXELFORMAT_ABGR8888,
|
|
|
- SDL_PIXELFORMAT_YV12,
|
|
|
- SDL_PIXELFORMAT_IYUV,
|
|
|
- SDL_PIXELFORMAT_NV12,
|
|
|
- SDL_PIXELFORMAT_NV21 },
|
|
|
- 0,
|
|
|
- 0,
|
|
|
+ {
|
|
|
+ SDL_PIXELFORMAT_ARGB8888,
|
|
|
+ SDL_PIXELFORMAT_ABGR8888,
|
|
|
+ SDL_PIXELFORMAT_YV12,
|
|
|
+ SDL_PIXELFORMAT_IYUV,
|
|
|
+ SDL_PIXELFORMAT_NV12,
|
|
|
+ SDL_PIXELFORMAT_NV21
|
|
|
+ },
|
|
|
+ 0, 0,
|
|
|
}
|
|
|
};
|
|
|
|