|
@@ -144,6 +144,14 @@ typedef struct METAL_ShaderPipelines
|
|
@implementation SDL3METAL_RenderData
|
|
@implementation SDL3METAL_RenderData
|
|
@end
|
|
@end
|
|
|
|
|
|
|
|
+@interface SDL3METAL_PaletteData : NSObject
|
|
|
|
+@property(nonatomic, retain) id<MTLTexture> mtltexture;
|
|
|
|
+@property(nonatomic, assign) BOOL hasdata;
|
|
|
|
+@end
|
|
|
|
+
|
|
|
|
+@implementation SDL3METAL_PaletteData
|
|
|
|
+@end
|
|
|
|
+
|
|
@interface SDL3METAL_TextureData : NSObject
|
|
@interface SDL3METAL_TextureData : NSObject
|
|
@property(nonatomic, retain) id<MTLTexture> mtltexture;
|
|
@property(nonatomic, retain) id<MTLTexture> mtltexture;
|
|
@property(nonatomic, retain) id<MTLTexture> mtlpalette;
|
|
@property(nonatomic, retain) id<MTLTexture> mtlpalette;
|
|
@@ -162,6 +170,10 @@ typedef struct METAL_ShaderPipelines
|
|
@implementation SDL3METAL_TextureData
|
|
@implementation SDL3METAL_TextureData
|
|
@end
|
|
@end
|
|
|
|
|
|
|
|
+static bool METAL_UpdateTextureInternal(SDL_Renderer *renderer, BOOL hasdata,
|
|
|
|
+ id<MTLTexture> texture, SDL_Rect rect, int slice,
|
|
|
|
+ const void *pixels, int pitch);
|
|
|
|
+
|
|
static const MTLBlendOperation invalidBlendOperation = (MTLBlendOperation)0xFFFFFFFF;
|
|
static const MTLBlendOperation invalidBlendOperation = (MTLBlendOperation)0xFFFFFFFF;
|
|
static const MTLBlendFactor invalidBlendFactor = (MTLBlendFactor)0xFFFFFFFF;
|
|
static const MTLBlendFactor invalidBlendFactor = (MTLBlendFactor)0xFFFFFFFF;
|
|
|
|
|
|
@@ -611,13 +623,68 @@ size_t GetYCbCRtoRGBConversionMatrix(SDL_Colorspace colorspace, int w, int h, in
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool METAL_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
|
|
|
|
+{
|
|
|
|
+ @autoreleasepool {
|
|
|
|
+ SDL3METAL_RenderData *data = (__bridge SDL3METAL_RenderData *)renderer->internal;
|
|
|
|
+ MTLPixelFormat pixfmt;
|
|
|
|
+ MTLTextureDescriptor *mtltexdesc;
|
|
|
|
+ id<MTLTexture> mtltexture = nil;
|
|
|
|
+ SDL3METAL_PaletteData *palettedata;
|
|
|
|
+
|
|
|
|
+ if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
|
|
|
|
+ pixfmt = MTLPixelFormatRGBA8Unorm_sRGB;
|
|
|
|
+ } else {
|
|
|
|
+ pixfmt = MTLPixelFormatRGBA8Unorm;
|
|
|
|
+ }
|
|
|
|
+ mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
|
|
|
|
+ width:256
|
|
|
|
+ height:1
|
|
|
|
+ mipmapped:NO];
|
|
|
|
+ mtltexdesc.usage = MTLTextureUsageShaderRead;
|
|
|
|
+
|
|
|
|
+ mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
|
|
|
|
+ if (mtltexture == nil) {
|
|
|
|
+ return SDL_SetError("Palette allocation failed");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ palettedata = [[SDL3METAL_PaletteData alloc] init];
|
|
|
|
+ palettedata.mtltexture = mtltexture;
|
|
|
|
+ palette->internal = (void *)CFBridgingRetain(palettedata);
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool METAL_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
|
|
|
|
+{
|
|
|
|
+ @autoreleasepool {
|
|
|
|
+ SDL3METAL_PaletteData *palettedata = (__bridge SDL3METAL_PaletteData *)palette->internal;
|
|
|
|
+ SDL_Rect rect = { 0, 0, ncolors, 1 };
|
|
|
|
+
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, palettedata.hasdata, palettedata.mtltexture, rect, 0, colors, ncolors * sizeof(*colors))) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ palettedata.hasdata = true;
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void METAL_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
|
|
|
|
+{
|
|
|
|
+ @autoreleasepool {
|
|
|
|
+ CFBridgingRelease(palette->internal);
|
|
|
|
+ palette->internal = NULL;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
|
|
static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
|
|
{
|
|
{
|
|
@autoreleasepool {
|
|
@autoreleasepool {
|
|
SDL3METAL_RenderData *data = (__bridge SDL3METAL_RenderData *)renderer->internal;
|
|
SDL3METAL_RenderData *data = (__bridge SDL3METAL_RenderData *)renderer->internal;
|
|
MTLPixelFormat pixfmt;
|
|
MTLPixelFormat pixfmt;
|
|
MTLTextureDescriptor *mtltexdesc;
|
|
MTLTextureDescriptor *mtltexdesc;
|
|
- id<MTLTexture> mtltexture = nil, mtltextureUv = nil, mtlpalette = nil;
|
|
|
|
|
|
+ id<MTLTexture> mtltexture = nil, mtltextureUv = nil;
|
|
SDL3METAL_TextureData *texturedata;
|
|
SDL3METAL_TextureData *texturedata;
|
|
CVPixelBufferRef pixelbuffer = nil;
|
|
CVPixelBufferRef pixelbuffer = nil;
|
|
IOSurfaceRef surface = nil;
|
|
IOSurfaceRef surface = nil;
|
|
@@ -688,25 +755,6 @@ static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
|
|
return SDL_SetError("Texture allocation failed");
|
|
return SDL_SetError("Texture allocation failed");
|
|
}
|
|
}
|
|
|
|
|
|
- if (texture->format == SDL_PIXELFORMAT_INDEX8) {
|
|
|
|
- if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
|
|
|
|
- pixfmt = MTLPixelFormatBGRA8Unorm_sRGB;
|
|
|
|
- } else {
|
|
|
|
- pixfmt = MTLPixelFormatBGRA8Unorm;
|
|
|
|
- }
|
|
|
|
- mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixfmt
|
|
|
|
- width:256
|
|
|
|
- height:1
|
|
|
|
- mipmapped:NO];
|
|
|
|
-
|
|
|
|
- mtltexdesc.usage = MTLTextureUsageShaderRead;
|
|
|
|
-
|
|
|
|
- mtlpalette = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
|
|
|
|
- if (mtlpalette == nil) {
|
|
|
|
- return SDL_SetError("Palette allocation failed");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
mtltextureUv = nil;
|
|
mtltextureUv = nil;
|
|
#ifdef SDL_HAVE_YUV
|
|
#ifdef SDL_HAVE_YUV
|
|
BOOL yuv = (texture->format == SDL_PIXELFORMAT_IYUV || texture->format == SDL_PIXELFORMAT_YV12);
|
|
BOOL yuv = (texture->format == SDL_PIXELFORMAT_IYUV || texture->format == SDL_PIXELFORMAT_YV12);
|
|
@@ -753,7 +801,6 @@ static bool METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
|
|
texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
|
|
texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY;
|
|
}
|
|
}
|
|
texturedata.mtltexture = mtltexture;
|
|
texturedata.mtltexture = mtltexture;
|
|
- texturedata.mtlpalette = mtlpalette;
|
|
|
|
texturedata.mtltextureUv = mtltextureUv;
|
|
texturedata.mtltextureUv = mtltextureUv;
|
|
#ifdef SDL_HAVE_YUV
|
|
#ifdef SDL_HAVE_YUV
|
|
texturedata.yuv = yuv;
|
|
texturedata.yuv = yuv;
|
|
@@ -788,7 +835,7 @@ static MTLStorageMode METAL_GetStorageMode(id<MTLResource> resource)
|
|
return resource.storageMode;
|
|
return resource.storageMode;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool METAL_UpdateTextureInternal(SDL_Renderer *renderer, SDL3METAL_TextureData *texturedata,
|
|
|
|
|
|
+static bool METAL_UpdateTextureInternal(SDL_Renderer *renderer, BOOL hasdata,
|
|
id<MTLTexture> texture, SDL_Rect rect, int slice,
|
|
id<MTLTexture> texture, SDL_Rect rect, int slice,
|
|
const void *pixels, int pitch)
|
|
const void *pixels, int pitch)
|
|
{
|
|
{
|
|
@@ -801,7 +848,7 @@ static bool METAL_UpdateTextureInternal(SDL_Renderer *renderer, SDL3METAL_Textur
|
|
/* If the texture is managed or shared and this is the first upload, we can
|
|
/* If the texture is managed or shared and this is the first upload, we can
|
|
* use replaceRegion to upload to it directly. Otherwise we upload the data
|
|
* use replaceRegion to upload to it directly. Otherwise we upload the data
|
|
* to a staging texture and copy that over. */
|
|
* to a staging texture and copy that over. */
|
|
- if (!texturedata.hasdata && METAL_GetStorageMode(texture) != MTLStorageModePrivate) {
|
|
|
|
|
|
+ if (!hasdata && METAL_GetStorageMode(texture) != MTLStorageModePrivate) {
|
|
METAL_UploadTextureData(texture, rect, slice, pixels, pitch);
|
|
METAL_UploadTextureData(texture, rect, slice, pixels, pitch);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -856,24 +903,13 @@ static bool METAL_UpdateTextureInternal(SDL_Renderer *renderer, SDL3METAL_Textur
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool METAL_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
|
|
|
|
-{
|
|
|
|
- @autoreleasepool {
|
|
|
|
- SDL3METAL_TextureData *texturedata = (__bridge SDL3METAL_TextureData *)texture->internal;
|
|
|
|
- SDL_Palette *palette = texture->palette;
|
|
|
|
- SDL_Rect rect = { 0, 0, palette->ncolors, 1 };
|
|
|
|
-
|
|
|
|
- return METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtlpalette, rect, 0, palette->colors, palette->ncolors * sizeof(*palette->colors));
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static bool METAL_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
static bool METAL_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
const SDL_Rect *rect, const void *pixels, int pitch)
|
|
const SDL_Rect *rect, const void *pixels, int pitch)
|
|
{
|
|
{
|
|
@autoreleasepool {
|
|
@autoreleasepool {
|
|
SDL3METAL_TextureData *texturedata = (__bridge SDL3METAL_TextureData *)texture->internal;
|
|
SDL3METAL_TextureData *texturedata = (__bridge SDL3METAL_TextureData *)texture->internal;
|
|
|
|
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, pixels, pitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltexture, *rect, 0, pixels, pitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
#ifdef SDL_HAVE_YUV
|
|
#ifdef SDL_HAVE_YUV
|
|
@@ -885,13 +921,13 @@ static bool METAL_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
|
|
|
|
// Skip to the correct offset into the next texture
|
|
// Skip to the correct offset into the next texture
|
|
pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
|
|
pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltextureUv, UVrect, Uslice, pixels, UVpitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltextureUv, UVrect, Uslice, pixels, UVpitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
// Skip to the correct offset into the next texture
|
|
// Skip to the correct offset into the next texture
|
|
pixels = (const void *)((const Uint8 *)pixels + UVrect.h * UVpitch);
|
|
pixels = (const void *)((const Uint8 *)pixels + UVrect.h * UVpitch);
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltextureUv, UVrect, Vslice, pixels, UVpitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltextureUv, UVrect, Vslice, pixels, UVpitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -902,7 +938,7 @@ static bool METAL_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
|
|
|
|
// Skip to the correct offset into the next texture
|
|
// Skip to the correct offset into the next texture
|
|
pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
|
|
pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltextureUv, UVrect, 0, pixels, UVpitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltextureUv, UVrect, 0, pixels, UVpitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -931,13 +967,13 @@ static bool METAL_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltextureUv, UVrect, Uslice, Uplane, Upitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltextureUv, UVrect, Uslice, Uplane, Upitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltextureUv, UVrect, Vslice, Vplane, Vpitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltextureUv, UVrect, Vslice, Vplane, Vpitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -961,11 +997,11 @@ static bool METAL_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltexture, *rect, 0, Yplane, Ypitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltextureUv, UVrect, 0, UVplane, UVpitch)) {
|
|
|
|
|
|
+ if (!METAL_UpdateTextureInternal(renderer, texturedata.hasdata, texturedata.mtltextureUv, UVrect, 0, UVplane, UVpitch)) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1568,8 +1604,9 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|
|
|
|
|
if (texture != statecache->texture) {
|
|
if (texture != statecache->texture) {
|
|
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
|
|
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
|
|
- if (texture->format == SDL_PIXELFORMAT_INDEX8) {
|
|
|
|
- [data.mtlcmdencoder setFragmentTexture:texturedata.mtlpalette atIndex:1];
|
|
|
|
|
|
+ if (texture->palette) {
|
|
|
|
+ SDL3METAL_PaletteData *palette = (__bridge SDL3METAL_PaletteData *)texture->palette->internal;
|
|
|
|
+ [data.mtlcmdencoder setFragmentTexture:palette.mtltexture atIndex:1];
|
|
}
|
|
}
|
|
#ifdef SDL_HAVE_YUV
|
|
#ifdef SDL_HAVE_YUV
|
|
if (texturedata.yuv || texturedata.nv12) {
|
|
if (texturedata.yuv || texturedata.nv12) {
|
|
@@ -1593,7 +1630,7 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
|
|
statecache->texture_address_mode_u = cmd->data.draw.texture_address_mode_u;
|
|
statecache->texture_address_mode_u = cmd->data.draw.texture_address_mode_u;
|
|
statecache->texture_address_mode_v = cmd->data.draw.texture_address_mode_v;
|
|
statecache->texture_address_mode_v = cmd->data.draw.texture_address_mode_v;
|
|
}
|
|
}
|
|
- if (texture->format == SDL_PIXELFORMAT_INDEX8) {
|
|
|
|
|
|
+ if (texture->palette) {
|
|
if (!statecache->texture_palette) {
|
|
if (!statecache->texture_palette) {
|
|
id<MTLSamplerState> mtlsampler = GetSampler(data, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
|
|
id<MTLSamplerState> mtlsampler = GetSampler(data, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
|
|
if (mtlsampler == nil) {
|
|
if (mtlsampler == nil) {
|
|
@@ -2201,8 +2238,10 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
|
|
renderer->WindowEvent = METAL_WindowEvent;
|
|
renderer->WindowEvent = METAL_WindowEvent;
|
|
renderer->GetOutputSize = METAL_GetOutputSize;
|
|
renderer->GetOutputSize = METAL_GetOutputSize;
|
|
renderer->SupportsBlendMode = METAL_SupportsBlendMode;
|
|
renderer->SupportsBlendMode = METAL_SupportsBlendMode;
|
|
|
|
+ renderer->CreatePalette = METAL_CreatePalette;
|
|
|
|
+ renderer->UpdatePalette = METAL_UpdatePalette;
|
|
|
|
+ renderer->DestroyPalette = METAL_DestroyPalette;
|
|
renderer->CreateTexture = METAL_CreateTexture;
|
|
renderer->CreateTexture = METAL_CreateTexture;
|
|
- renderer->UpdateTexturePalette = METAL_UpdateTexturePalette;
|
|
|
|
renderer->UpdateTexture = METAL_UpdateTexture;
|
|
renderer->UpdateTexture = METAL_UpdateTexture;
|
|
#ifdef SDL_HAVE_YUV
|
|
#ifdef SDL_HAVE_YUV
|
|
renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
|
|
renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
|