mirror of
https://github.com/Ryujinx/SDL.git
synced 2024-12-23 17:05:36 +00:00
metal: Add support for custom blend modes.
This commit is contained in:
parent
85470a2f95
commit
cf45cf70e5
|
@ -49,6 +49,7 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window * window, Uint32 flags);
|
||||||
static void METAL_WindowEvent(SDL_Renderer * renderer,
|
static void METAL_WindowEvent(SDL_Renderer * renderer,
|
||||||
const SDL_WindowEvent *event);
|
const SDL_WindowEvent *event);
|
||||||
static int METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
|
static int METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
|
||||||
|
static SDL_bool METAL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
|
||||||
static int METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
|
static int METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
|
||||||
static int METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
static int METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
const SDL_Rect * rect, const void *pixels,
|
const SDL_Rect * rect, const void *pixels,
|
||||||
|
@ -104,6 +105,34 @@ SDL_RenderDriver METAL_RenderDriver = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum SDL_MetalVertexFunction
|
||||||
|
{
|
||||||
|
SDL_METAL_VERTEX_SOLID,
|
||||||
|
SDL_METAL_VERTEX_COPY,
|
||||||
|
} SDL_MetalVertexFunction;
|
||||||
|
|
||||||
|
typedef enum SDL_MetalFragmentFunction
|
||||||
|
{
|
||||||
|
SDL_METAL_FRAGMENT_SOLID,
|
||||||
|
SDL_METAL_FRAGMENT_COPY_NEAREST,
|
||||||
|
SDL_METAL_FRAGMENT_COPY_LINEAR,
|
||||||
|
} SDL_MetalFragmentFunction;
|
||||||
|
|
||||||
|
typedef struct METAL_PipelineState
|
||||||
|
{
|
||||||
|
SDL_BlendMode blendMode;
|
||||||
|
void *pipe;
|
||||||
|
} METAL_PipelineState;
|
||||||
|
|
||||||
|
typedef struct METAL_PipelineCache
|
||||||
|
{
|
||||||
|
METAL_PipelineState *states;
|
||||||
|
int count;
|
||||||
|
SDL_MetalVertexFunction vertexFunction;
|
||||||
|
SDL_MetalFragmentFunction fragmentFunction;
|
||||||
|
const char *label;
|
||||||
|
} METAL_PipelineCache;
|
||||||
|
|
||||||
@interface METAL_RenderData : NSObject
|
@interface METAL_RenderData : NSObject
|
||||||
@property (nonatomic, assign) BOOL beginScene;
|
@property (nonatomic, assign) BOOL beginScene;
|
||||||
@property (nonatomic, retain) id<MTLDevice> mtldevice;
|
@property (nonatomic, retain) id<MTLDevice> mtldevice;
|
||||||
|
@ -112,9 +141,9 @@ SDL_RenderDriver METAL_RenderDriver = {
|
||||||
@property (nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
|
@property (nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
|
||||||
@property (nonatomic, retain) id<MTLLibrary> mtllibrary;
|
@property (nonatomic, retain) id<MTLLibrary> mtllibrary;
|
||||||
@property (nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
|
@property (nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
|
||||||
@property (nonatomic, retain) NSMutableArray *mtlpipelineprims;
|
@property (nonatomic) METAL_PipelineCache *mtlpipelineprims;
|
||||||
@property (nonatomic, retain) NSMutableArray *mtlpipelinecopynearest;
|
@property (nonatomic) METAL_PipelineCache *mtlpipelinecopynearest;
|
||||||
@property (nonatomic, retain) NSMutableArray *mtlpipelinecopylinear;
|
@property (nonatomic) METAL_PipelineCache *mtlpipelinecopylinear;
|
||||||
@property (nonatomic, retain) id<MTLBuffer> mtlbufclearverts;
|
@property (nonatomic, retain) id<MTLBuffer> mtlbufclearverts;
|
||||||
@property (nonatomic, retain) id<MTLBuffer> mtlbufidentitytransform;
|
@property (nonatomic, retain) id<MTLBuffer> mtlbufidentitytransform;
|
||||||
@property (nonatomic, retain) CAMetalLayer *mtllayer;
|
@property (nonatomic, retain) CAMetalLayer *mtllayer;
|
||||||
|
@ -126,7 +155,7 @@ SDL_RenderDriver METAL_RenderDriver = {
|
||||||
|
|
||||||
@interface METAL_TextureData : NSObject
|
@interface METAL_TextureData : NSObject
|
||||||
@property (nonatomic, retain) id<MTLTexture> mtltexture;
|
@property (nonatomic, retain) id<MTLTexture> mtltexture;
|
||||||
@property (nonatomic, retain) NSMutableArray *mtlpipeline;
|
@property (nonatomic) METAL_PipelineCache *mtlpipeline;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation METAL_TextureData
|
@implementation METAL_TextureData
|
||||||
|
@ -149,90 +178,170 @@ IsMetalAvailable(const SDL_SysWMinfo *syswm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static id<MTLRenderPipelineState>
|
static const MTLBlendOperation invalidBlendOperation = (MTLBlendOperation)0xFFFFFFFF;
|
||||||
MakePipelineState(METAL_RenderData *data, NSString *label, NSString *vertfn,
|
static const MTLBlendFactor invalidBlendFactor = (MTLBlendFactor)0xFFFFFFFF;
|
||||||
NSString *fragfn, const SDL_BlendMode blendmode)
|
|
||||||
|
static MTLBlendOperation
|
||||||
|
GetBlendOperation(SDL_BlendOperation operation)
|
||||||
{
|
{
|
||||||
id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:vertfn];
|
switch (operation) {
|
||||||
id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:fragfn];
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSString *
|
||||||
|
GetFragmentFunctionName(SDL_MetalFragmentFunction function)
|
||||||
|
{
|
||||||
|
switch (function) {
|
||||||
|
case SDL_METAL_FRAGMENT_SOLID: return @"SDL_Solid_fragment";
|
||||||
|
case SDL_METAL_FRAGMENT_COPY_NEAREST: return @"SDL_Copy_fragment_nearest";
|
||||||
|
case SDL_METAL_FRAGMENT_COPY_LINEAR: return @"SDL_Copy_fragment_linear";
|
||||||
|
default: return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static id<MTLRenderPipelineState>
|
||||||
|
MakePipelineState(METAL_RenderData *data, METAL_PipelineCache *cache,
|
||||||
|
NSString *blendlabel, SDL_BlendMode blendmode)
|
||||||
|
{
|
||||||
|
id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:GetVertexFunctionName(cache->vertexFunction)];
|
||||||
|
id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:GetFragmentFunctionName(cache->fragmentFunction)];
|
||||||
SDL_assert(mtlvertfn != nil);
|
SDL_assert(mtlvertfn != nil);
|
||||||
SDL_assert(mtlfragfn != nil);
|
SDL_assert(mtlfragfn != nil);
|
||||||
|
|
||||||
MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
|
MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
mtlpipedesc.vertexFunction = mtlvertfn;
|
mtlpipedesc.vertexFunction = mtlvertfn;
|
||||||
mtlpipedesc.fragmentFunction = mtlfragfn;
|
mtlpipedesc.fragmentFunction = mtlfragfn;
|
||||||
mtlpipedesc.colorAttachments[0].pixelFormat = data.mtllayer.pixelFormat;
|
|
||||||
|
|
||||||
switch (blendmode) {
|
MTLRenderPipelineColorAttachmentDescriptor *rtdesc = mtlpipedesc.colorAttachments[0];
|
||||||
case SDL_BLENDMODE_BLEND:
|
|
||||||
mtlpipedesc.colorAttachments[0].blendingEnabled = YES;
|
|
||||||
mtlpipedesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
|
||||||
mtlpipedesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
|
||||||
mtlpipedesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
|
||||||
mtlpipedesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
|
||||||
mtlpipedesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
|
||||||
mtlpipedesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_BLENDMODE_ADD:
|
// !!! FIXME: This should be part of the pipeline state cache.
|
||||||
mtlpipedesc.colorAttachments[0].blendingEnabled = YES;
|
rtdesc.pixelFormat = data.mtllayer.pixelFormat;
|
||||||
mtlpipedesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
|
||||||
mtlpipedesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
|
||||||
mtlpipedesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
|
||||||
mtlpipedesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne;
|
|
||||||
mtlpipedesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorZero;
|
|
||||||
mtlpipedesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_BLENDMODE_MOD:
|
if (blendmode != SDL_BLENDMODE_NONE) {
|
||||||
mtlpipedesc.colorAttachments[0].blendingEnabled = YES;
|
rtdesc.blendingEnabled = YES;
|
||||||
mtlpipedesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
rtdesc.sourceRGBBlendFactor = GetBlendFactor(SDL_GetBlendModeSrcColorFactor(blendmode));
|
||||||
mtlpipedesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
rtdesc.destinationRGBBlendFactor = GetBlendFactor(SDL_GetBlendModeDstColorFactor(blendmode));
|
||||||
mtlpipedesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorZero;
|
rtdesc.rgbBlendOperation = GetBlendOperation(SDL_GetBlendModeColorOperation(blendmode));
|
||||||
mtlpipedesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorSourceColor;
|
rtdesc.sourceAlphaBlendFactor = GetBlendFactor(SDL_GetBlendModeSrcAlphaFactor(blendmode));
|
||||||
mtlpipedesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorZero;
|
rtdesc.destinationAlphaBlendFactor = GetBlendFactor(SDL_GetBlendModeDstAlphaFactor(blendmode));
|
||||||
mtlpipedesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne;
|
rtdesc.alphaBlendOperation = GetBlendOperation(SDL_GetBlendModeAlphaOperation(blendmode));
|
||||||
break;
|
} else {
|
||||||
|
rtdesc.blendingEnabled = NO;
|
||||||
default:
|
|
||||||
mtlpipedesc.colorAttachments[0].blendingEnabled = NO;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mtlpipedesc.label = label;
|
mtlpipedesc.label = [@(cache->label) stringByAppendingString:blendlabel];
|
||||||
|
|
||||||
NSError *err = nil;
|
NSError *err = nil;
|
||||||
id<MTLRenderPipelineState> retval = [data.mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err];
|
id<MTLRenderPipelineState> state = [data.mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err];
|
||||||
SDL_assert(err == nil);
|
SDL_assert(err == nil);
|
||||||
|
|
||||||
|
METAL_PipelineState pipeline;
|
||||||
|
pipeline.blendMode = blendmode;
|
||||||
|
pipeline.pipe = (void *)CFBridgingRetain(state);
|
||||||
|
|
||||||
|
METAL_PipelineState *states = SDL_realloc(cache->states, (cache->count + 1) * sizeof(pipeline));
|
||||||
|
|
||||||
#if !__has_feature(objc_arc)
|
#if !__has_feature(objc_arc)
|
||||||
[mtlpipedesc release]; // !!! FIXME: can these be reused for each creation, or does the pipeline obtain it?
|
[mtlpipedesc release]; // !!! FIXME: can these be reused for each creation, or does the pipeline obtain it?
|
||||||
[mtlvertfn release];
|
[mtlvertfn release];
|
||||||
[mtlfragfn release];
|
[mtlfragfn release];
|
||||||
[label release];
|
[state release];
|
||||||
#endif
|
#endif
|
||||||
return retval;
|
|
||||||
|
if (states) {
|
||||||
|
states[cache->count++] = pipeline;
|
||||||
|
cache->states = states;
|
||||||
|
return (__bridge id<MTLRenderPipelineState>)pipeline.pipe;
|
||||||
|
} else {
|
||||||
|
CFBridgingRelease(pipeline.pipe);
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static METAL_PipelineCache *
|
||||||
|
MakePipelineCache(METAL_RenderData *data, const char *label, SDL_MetalVertexFunction vertfn, SDL_MetalFragmentFunction fragfn)
|
||||||
|
{
|
||||||
|
METAL_PipelineCache *cache = SDL_malloc(sizeof(METAL_PipelineCache));
|
||||||
|
|
||||||
|
if (!cache) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_zerop(cache);
|
||||||
|
|
||||||
|
cache->vertexFunction = vertfn;
|
||||||
|
cache->fragmentFunction = fragfn;
|
||||||
|
cache->label = label;
|
||||||
|
|
||||||
|
/* Create pipeline states for the default blend modes. Custom blend modes
|
||||||
|
* will be added to the cache on-demand. */
|
||||||
|
MakePipelineState(data, cache, @"(blend=none)", SDL_BLENDMODE_NONE);
|
||||||
|
MakePipelineState(data, cache, @"(blend=blend)", SDL_BLENDMODE_BLEND);
|
||||||
|
MakePipelineState(data, cache, @"(blend=add)", SDL_BLENDMODE_ADD);
|
||||||
|
MakePipelineState(data, cache, @"(blend=mod)", SDL_BLENDMODE_MOD);
|
||||||
|
|
||||||
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
MakePipelineStates(METAL_RenderData *data, NSMutableArray *states,
|
DestroyPipelineCache(METAL_PipelineCache *cache)
|
||||||
NSString *label, NSString *vertfn, NSString *fragfn)
|
|
||||||
{
|
{
|
||||||
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=none)"], vertfn, fragfn, SDL_BLENDMODE_NONE)];
|
if (cache != NULL) {
|
||||||
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=blend)"], vertfn, fragfn, SDL_BLENDMODE_BLEND)];
|
for (int i = 0; i < cache->count; i++) {
|
||||||
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=add)"], vertfn, fragfn, SDL_BLENDMODE_ADD)];
|
CFBridgingRelease(cache->states[i].pipe);
|
||||||
[states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD)];
|
}
|
||||||
|
|
||||||
|
SDL_free(cache->states);
|
||||||
|
SDL_free(cache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline id<MTLRenderPipelineState>
|
static inline id<MTLRenderPipelineState>
|
||||||
ChoosePipelineState(NSMutableArray *states, const SDL_BlendMode blendmode)
|
ChoosePipelineState(METAL_RenderData *data, METAL_PipelineCache *cache, const SDL_BlendMode blendmode)
|
||||||
{
|
{
|
||||||
switch (blendmode) {
|
for (int i = 0; i < cache->count; i++) {
|
||||||
case SDL_BLENDMODE_BLEND: return (id<MTLRenderPipelineState>)states[1];
|
if (cache->states[i].blendMode == blendmode) {
|
||||||
case SDL_BLENDMODE_ADD: return (id<MTLRenderPipelineState>)states[2];
|
return (__bridge id<MTLRenderPipelineState>)cache->states[i].pipe;
|
||||||
case SDL_BLENDMODE_MOD: return (id<MTLRenderPipelineState>)states[3];
|
|
||||||
default: return (id<MTLRenderPipelineState>)states[0];
|
|
||||||
}
|
}
|
||||||
return nil;
|
}
|
||||||
|
|
||||||
|
return MakePipelineState(data, cache, [NSString stringWithFormat:@"(blend=custom 0x%x)", blendmode], blendmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_Renderer *
|
static SDL_Renderer *
|
||||||
|
@ -285,8 +394,6 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
||||||
|
|
||||||
layer.device = mtldevice;
|
layer.device = mtldevice;
|
||||||
|
|
||||||
// !!! FIXME: We might want this to be NO for RenderReadPixels.
|
|
||||||
layer.framebufferOnly = YES;
|
|
||||||
//layer.colorspace = nil;
|
//layer.colorspace = nil;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -294,6 +401,9 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
||||||
CAMetalLayer *layer = (CAMetalLayer *)[view layer];
|
CAMetalLayer *layer = (CAMetalLayer *)[view layer];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Necessary for RenderReadPixels.
|
||||||
|
layer.framebufferOnly = NO;
|
||||||
|
|
||||||
data.mtldevice = layer.device;
|
data.mtldevice = layer.device;
|
||||||
data.mtllayer = layer;
|
data.mtllayer = layer;
|
||||||
data.mtlcmdqueue = [data.mtldevice newCommandQueue];
|
data.mtlcmdqueue = [data.mtldevice newCommandQueue];
|
||||||
|
@ -312,12 +422,9 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
||||||
#endif
|
#endif
|
||||||
data.mtllibrary.label = @"SDL Metal renderer shader library";
|
data.mtllibrary.label = @"SDL Metal renderer shader library";
|
||||||
|
|
||||||
data.mtlpipelineprims = [[NSMutableArray alloc] init];
|
data.mtlpipelineprims = MakePipelineCache(data, "SDL primitives pipeline ", SDL_METAL_VERTEX_SOLID, SDL_METAL_FRAGMENT_SOLID);
|
||||||
MakePipelineStates(data, data.mtlpipelineprims, @"SDL primitives pipeline", @"SDL_Solid_vertex", @"SDL_Solid_fragment");
|
data.mtlpipelinecopynearest = MakePipelineCache(data, "SDL texture pipeline (nearest) ", SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY_NEAREST);
|
||||||
data.mtlpipelinecopynearest = [[NSMutableArray alloc] init];
|
data.mtlpipelinecopylinear = MakePipelineCache(data, "SDL texture pipeline (linear) ", SDL_METAL_VERTEX_COPY, SDL_METAL_FRAGMENT_COPY_LINEAR);
|
||||||
MakePipelineStates(data, data.mtlpipelinecopynearest, @"SDL texture pipeline (nearest)", @"SDL_Copy_vertex", @"SDL_Copy_fragment_nearest");
|
|
||||||
data.mtlpipelinecopylinear = [[NSMutableArray alloc] init];
|
|
||||||
MakePipelineStates(data, data.mtlpipelinecopylinear, @"SDL texture pipeline (linear)", @"SDL_Copy_vertex", @"SDL_Copy_fragment_linear");
|
|
||||||
|
|
||||||
static const float clearverts[] = { 0, 0, 0, 3, 3, 0 };
|
static const float clearverts[] = { 0, 0, 0, 3, 3, 0 };
|
||||||
data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined];
|
data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined];
|
||||||
|
@ -333,6 +440,7 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
||||||
|
|
||||||
renderer->WindowEvent = METAL_WindowEvent;
|
renderer->WindowEvent = METAL_WindowEvent;
|
||||||
renderer->GetOutputSize = METAL_GetOutputSize;
|
renderer->GetOutputSize = METAL_GetOutputSize;
|
||||||
|
renderer->SupportsBlendMode = METAL_SupportsBlendMode;
|
||||||
renderer->CreateTexture = METAL_CreateTexture;
|
renderer->CreateTexture = METAL_CreateTexture;
|
||||||
renderer->UpdateTexture = METAL_UpdateTexture;
|
renderer->UpdateTexture = METAL_UpdateTexture;
|
||||||
renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
|
renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
|
||||||
|
@ -415,6 +523,27 @@ METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
|
||||||
return 0;
|
return 0;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
static SDL_bool
|
||||||
|
METAL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
|
||||||
|
{
|
||||||
|
SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
|
||||||
|
SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
|
||||||
|
SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
|
||||||
|
SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
|
||||||
|
SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
|
||||||
|
SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
|
||||||
|
|
||||||
|
if (GetBlendFactor(srcColorFactor) == invalidBlendFactor ||
|
||||||
|
GetBlendFactor(srcAlphaFactor) == invalidBlendFactor ||
|
||||||
|
GetBlendOperation(colorOperation) == invalidBlendOperation ||
|
||||||
|
GetBlendFactor(dstColorFactor) == invalidBlendFactor ||
|
||||||
|
GetBlendFactor(dstAlphaFactor) == invalidBlendFactor ||
|
||||||
|
GetBlendOperation(alphaOperation) == invalidBlendOperation) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
|
METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
|
||||||
{ @autoreleasepool {
|
{ @autoreleasepool {
|
||||||
|
@ -616,7 +745,7 @@ METAL_RenderClear(SDL_Renderer * renderer)
|
||||||
// Draw a simple filled fullscreen triangle now.
|
// Draw a simple filled fullscreen triangle now.
|
||||||
METAL_SetOrthographicProjection(renderer, 1, 1);
|
METAL_SetOrthographicProjection(renderer, 1, 1);
|
||||||
[data.mtlcmdencoder setViewport:viewport];
|
[data.mtlcmdencoder setViewport:viewport];
|
||||||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
|
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.mtlpipelineprims, SDL_BLENDMODE_NONE)];
|
||||||
[data.mtlcmdencoder setVertexBuffer:data.mtlbufclearverts offset:0 atIndex:0];
|
[data.mtlcmdencoder setVertexBuffer:data.mtlbufclearverts offset:0 atIndex:0];
|
||||||
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
||||||
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
|
[data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
|
||||||
|
@ -654,7 +783,7 @@ DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
|
||||||
// !!! FIXME: render color should live in a dedicated uniform buffer.
|
// !!! FIXME: render color should live in a dedicated uniform buffer.
|
||||||
const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
|
const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
|
||||||
|
|
||||||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
|
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.mtlpipelineprims, renderer->blendMode)];
|
||||||
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
||||||
[data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
|
[data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
|
||||||
[data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
|
[data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
|
||||||
|
@ -682,7 +811,7 @@ METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int coun
|
||||||
// !!! FIXME: render color should live in a dedicated uniform buffer.
|
// !!! FIXME: render color should live in a dedicated uniform buffer.
|
||||||
const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
|
const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
|
||||||
|
|
||||||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
|
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.mtlpipelineprims, renderer->blendMode)];
|
||||||
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
[data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
|
||||||
|
|
||||||
for (int i = 0; i < count; i++, rects++) {
|
for (int i = 0; i < count; i++, rects++) {
|
||||||
|
@ -734,7 +863,7 @@ METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
color[3] = ((float)texture->a) / 255.0f;
|
color[3] = ((float)texture->a) / 255.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(texturedata.mtlpipeline, texture->blendMode)];
|
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, texturedata.mtlpipeline, texture->blendMode)];
|
||||||
[data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
|
[data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
|
||||||
[data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
|
[data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
|
||||||
[data.mtlcmdencoder setVertexBuffer:data.mtlbufidentitytransform offset:0 atIndex:3];
|
[data.mtlcmdencoder setVertexBuffer:data.mtlbufidentitytransform offset:0 atIndex:3];
|
||||||
|
@ -816,7 +945,7 @@ METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||||
color[3] = ((float)texture->a) / 255.0f;
|
color[3] = ((float)texture->a) / 255.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(texturedata.mtlpipeline, texture->blendMode)];
|
[data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, texturedata.mtlpipeline, texture->blendMode)];
|
||||||
[data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
|
[data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
|
||||||
[data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
|
[data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
|
||||||
[data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
|
[data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
|
||||||
|
@ -836,14 +965,7 @@ METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
|
||||||
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
|
||||||
MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
|
MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
|
||||||
id<MTLTexture> mtltexture = colorAttachment.texture;
|
id<MTLTexture> mtltexture = colorAttachment.texture;
|
||||||
MTLRegion mtlregion;
|
MTLRegion mtlregion = MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h);
|
||||||
|
|
||||||
mtlregion.origin.x = rect->x;
|
|
||||||
mtlregion.origin.y = rect->y;
|
|
||||||
mtlregion.origin.z = 0;
|
|
||||||
mtlregion.size.width = rect->w;
|
|
||||||
mtlregion.size.height = rect->w;
|
|
||||||
mtlregion.size.depth = 1;
|
|
||||||
|
|
||||||
// we only do BGRA8 or RGBA8 at the moment, so 4 will do.
|
// we only do BGRA8 or RGBA8 at the moment, so 4 will do.
|
||||||
const int temp_pitch = rect->w * 4;
|
const int temp_pitch = rect->w * 4;
|
||||||
|
@ -903,14 +1025,6 @@ METAL_DestroyRenderer(SDL_Renderer * renderer)
|
||||||
[data.mtlcmdencoder release];
|
[data.mtlcmdencoder release];
|
||||||
[data.mtlcmdbuffer release];
|
[data.mtlcmdbuffer release];
|
||||||
[data.mtlcmdqueue release];
|
[data.mtlcmdqueue release];
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
[data.mtlpipelineprims[i] release];
|
|
||||||
[data.mtlpipelinecopynearest[i] release];
|
|
||||||
[data.mtlpipelinecopylinear[i] release];
|
|
||||||
}
|
|
||||||
[data.mtlpipelineprims release];
|
|
||||||
[data.mtlpipelinecopynearest release];
|
|
||||||
[data.mtlpipelinecopylinear release];
|
|
||||||
[data.mtlbufclearverts release];
|
[data.mtlbufclearverts release];
|
||||||
[data.mtlbufidentitytransform release];
|
[data.mtlbufidentitytransform release];
|
||||||
[data.mtllibrary release];
|
[data.mtllibrary release];
|
||||||
|
@ -918,6 +1032,10 @@ METAL_DestroyRenderer(SDL_Renderer * renderer)
|
||||||
[data.mtlpassdesc release];
|
[data.mtlpassdesc release];
|
||||||
[data.mtllayer release];
|
[data.mtllayer release];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DestroyPipelineCache(data.mtlpipelineprims);
|
||||||
|
DestroyPipelineCache(data.mtlpipelinecopynearest);
|
||||||
|
DestroyPipelineCache(data.mtlpipelinecopylinear);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(renderer);
|
SDL_free(renderer);
|
||||||
|
|
Loading…
Reference in a new issue