Each application palette corresponds to one hardware palette

When the application modifies the palette, any textures that use it will automatically be updated.
This commit is contained in:
Sam Lantinga
2025-09-28 18:31:23 -07:00
parent 5d311635cf
commit b65590159b
11 changed files with 832 additions and 451 deletions

View File

@@ -347,6 +347,15 @@ static bool FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture)
return true; return true;
} }
static bool FlushRenderCommandsIfPaletteNeeded(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
if (palette->last_command_generation == renderer->render_command_generation) {
// the current command queue depends on this palette, flush the queue now before it changes
return FlushRenderCommands(renderer);
}
return true;
}
static bool FlushRenderCommandsIfGPURenderStateNeeded(SDL_GPURenderState *state) static bool FlushRenderCommandsIfGPURenderStateNeeded(SDL_GPURenderState *state)
{ {
SDL_Renderer *renderer = state->renderer; SDL_Renderer *renderer = state->renderer;
@@ -700,20 +709,22 @@ static bool QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, co
static bool UpdateTexturePalette(SDL_Texture *texture) static bool UpdateTexturePalette(SDL_Texture *texture)
{ {
SDL_Renderer *renderer = texture->renderer; SDL_Renderer *renderer = texture->renderer;
SDL_Palette *public = texture->public_palette;
if (!SDL_ISPIXELFORMAT_INDEXED(texture->format)) { if (!SDL_ISPIXELFORMAT_INDEXED(texture->format)) {
return true; return true;
} }
if (!texture->palette) { if (!public) {
return SDL_SetError("Texture doesn't have a palette"); return SDL_SetError("Texture doesn't have a palette");
} }
if (texture->palette_version == texture->palette->version) {
return true;
}
if (texture->native) { if (texture->native) {
// Keep the native texture in sync with palette updates
if (texture->palette_version == public->version) {
return true;
}
if (!FlushRenderCommandsIfTextureNeeded(texture->native)) { if (!FlushRenderCommandsIfTextureNeeded(texture->native)) {
return false; return false;
} }
@@ -727,17 +738,25 @@ static bool UpdateTexturePalette(SDL_Texture *texture)
if (!result) { if (!result) {
return false; return false;
} }
} else { texture->palette_version = public->version;
if (!FlushRenderCommandsIfTextureNeeded(texture)) { return true;
return false;
}
if (!renderer->UpdateTexturePalette(renderer, texture)) {
return false;
}
} }
texture->palette_version = texture->palette->version; SDL_TexturePalette *palette = texture->palette;
if (palette->version != public->version) {
// Keep the native palette in sync with palette updates
if (!FlushRenderCommandsIfPaletteNeeded(renderer, palette)) {
return false;
}
if (!renderer->UpdatePalette(renderer, palette, public->ncolors, public->colors)) {
return false;
}
palette->version = public->version;
}
palette->last_command_generation = renderer->render_command_generation;
return true; return true;
} }
@@ -1143,6 +1162,11 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
UpdatePixelClipRect(renderer, &renderer->main_view); UpdatePixelClipRect(renderer, &renderer->main_view);
UpdateMainViewDimensions(renderer); UpdateMainViewDimensions(renderer);
renderer->palettes = SDL_CreateHashTable(0, false, SDL_HashPointer, SDL_KeyMatchPointer, SDL_DestroyHashValue, NULL);
if (!renderer->palettes) {
goto error;
}
// new textures start at zero, so we start at 1 so first render doesn't flush by accident. // new textures start at zero, so we start at 1 so first render doesn't flush by accident.
renderer->render_command_generation = 1; renderer->render_command_generation = 1;
@@ -1656,7 +1680,7 @@ static bool SDL_UpdateTextureFromSurface(SDL_Texture *texture, SDL_Rect *rect, S
bool direct_update; bool direct_update;
if (surface->format == texture->format && if (surface->format == texture->format &&
surface->palette == texture->palette && surface->palette == texture->public_palette &&
SDL_GetSurfaceColorspace(surface) == texture->colorspace) { SDL_GetSurfaceColorspace(surface) == texture->colorspace) {
if (SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) { if (SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) {
/* Surface and Renderer formats are identical. /* Surface and Renderer formats are identical.
@@ -1682,7 +1706,7 @@ static bool SDL_UpdateTextureFromSurface(SDL_Texture *texture, SDL_Rect *rect, S
} }
} else { } else {
// Set up a destination surface for the texture update // Set up a destination surface for the texture update
SDL_Surface *temp = SDL_ConvertSurfaceAndColorspace(surface, texture->format, texture->palette, texture->colorspace, SDL_GetSurfaceProperties(surface)); SDL_Surface *temp = SDL_ConvertSurfaceAndColorspace(surface, texture->format, texture->public_palette, texture->colorspace, SDL_GetSurfaceProperties(surface));
if (temp) { if (temp) {
SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch); SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
SDL_DestroySurface(temp); SDL_DestroySurface(temp);
@@ -1901,16 +1925,56 @@ bool SDL_SetTexturePalette(SDL_Texture *texture, SDL_Palette *palette)
return SDL_SetError("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format"); return SDL_SetError("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
} }
if (palette != texture->palette) { if (palette != texture->public_palette) {
if (texture->palette) { SDL_Renderer *renderer = texture->renderer;
SDL_DestroyPalette(texture->palette);
if (texture->public_palette) {
SDL_DestroyPalette(texture->public_palette);
if (!texture->native) {
// Clean up the texture palette
--texture->palette->refcount;
if (texture->palette->refcount == 0) {
renderer->DestroyPalette(renderer, texture->palette);
SDL_RemoveFromHashTable(renderer->palettes, texture->public_palette);
}
texture->palette = NULL;
}
} }
texture->palette = palette; texture->public_palette = palette;
texture->palette_version = 0; texture->palette_version = 0;
if (texture->palette) { if (texture->public_palette) {
++texture->palette->refcount; ++texture->public_palette->refcount;
if (!texture->native) {
if (SDL_FindInHashTable(renderer->palettes, palette, (const void **)&texture->palette)) {
++texture->palette->refcount;
} else {
SDL_TexturePalette *texture_palette = (SDL_TexturePalette *)SDL_calloc(1, sizeof(*texture_palette));
if (!texture_palette) {
SDL_SetTexturePalette(texture, NULL);
return false;
}
if (!renderer->CreatePalette(renderer, texture_palette)) {
renderer->DestroyPalette(renderer, texture_palette);
SDL_SetTexturePalette(texture, NULL);
return false;
}
texture->palette = texture_palette;
texture->palette->refcount = 1;
if (!SDL_InsertIntoHashTable(renderer->palettes, palette, texture->palette, false)) {
SDL_SetTexturePalette(texture, NULL);
return false;
}
}
}
if (!texture->native && renderer->ChangeTexturePalette) {
renderer->ChangeTexturePalette(renderer, texture);
}
} }
if (texture->palette_surface) { if (texture->palette_surface) {
@@ -1924,7 +1988,7 @@ SDL_Palette *SDL_GetTexturePalette(SDL_Texture *texture)
{ {
CHECK_TEXTURE_MAGIC(texture, NULL); CHECK_TEXTURE_MAGIC(texture, NULL);
return texture->palette; return texture->public_palette;
} }
bool SDL_SetTextureColorMod(SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b) bool SDL_SetTextureColorMod(SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b)
@@ -2602,8 +2666,8 @@ bool SDL_LockTextureToSurface(SDL_Texture *texture, const SDL_Rect *rect, SDL_Su
SDL_UnlockTexture(texture); SDL_UnlockTexture(texture);
return false; return false;
} }
if (texture->palette) { if (texture->public_palette) {
SDL_SetSurfacePalette(texture->locked_surface, texture->palette); SDL_SetSurfacePalette(texture->locked_surface, texture->public_palette);
} }
*surface = texture->locked_surface; *surface = texture->locked_surface;
@@ -5513,7 +5577,7 @@ static void SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying)
{ {
SDL_Renderer *renderer; SDL_Renderer *renderer;
if (texture->palette) { if (texture->public_palette) {
SDL_SetTexturePalette(texture, NULL); SDL_SetTexturePalette(texture, NULL);
} }
@@ -5634,6 +5698,13 @@ void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer)
SDL_assert(tex != renderer->textures); // satisfy static analysis. SDL_assert(tex != renderer->textures); // satisfy static analysis.
} }
// Free palette cache, which should be empty now
if (renderer->palettes) {
SDL_assert(SDL_HashTableEmpty(renderer->palettes));
SDL_DestroyHashTable(renderer->palettes);
renderer->palettes = NULL;
}
// Clean up renderer-specific resources // Clean up renderer-specific resources
if (renderer->DestroyRenderer) { if (renderer->DestroyRenderer) {
renderer->DestroyRenderer(renderer); renderer->DestroyRenderer(renderer);

View File

@@ -70,6 +70,15 @@ typedef struct SDL_RenderViewState
SDL_FPoint current_scale; // this is just `scale * logical_scale`, precalculated, since we use it a lot. SDL_FPoint current_scale; // this is just `scale * logical_scale`, precalculated, since we use it a lot.
} SDL_RenderViewState; } SDL_RenderViewState;
// Define the SDL texture palette structure
typedef struct SDL_TexturePalette
{
int refcount;
Uint32 version;
Uint32 last_command_generation; // last command queue generation this palette was in.
void *internal; // Driver specific palette representation
} SDL_TexturePalette;
// Define the SDL texture structure // Define the SDL texture structure
struct SDL_Texture struct SDL_Texture
{ {
@@ -90,7 +99,8 @@ struct SDL_Texture
SDL_ScaleMode scaleMode; // The texture scale mode SDL_ScaleMode scaleMode; // The texture scale mode
SDL_FColor color; // Texture modulation values SDL_FColor color; // Texture modulation values
SDL_RenderViewState view; // Target texture view state SDL_RenderViewState view; // Target texture view state
SDL_Palette *palette; SDL_Palette *public_palette;
SDL_TexturePalette *palette;
Uint32 palette_version; Uint32 palette_version;
SDL_Surface *palette_surface; SDL_Surface *palette_surface;
@@ -235,7 +245,10 @@ struct SDL_Renderer
void (*InvalidateCachedState)(SDL_Renderer *renderer); void (*InvalidateCachedState)(SDL_Renderer *renderer);
bool (*RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize); bool (*RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
bool (*UpdateTexturePalette)(SDL_Renderer *renderer, SDL_Texture *texture); bool (*CreatePalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette);
bool (*UpdatePalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors);
void (*DestroyPalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette);
bool (*ChangeTexturePalette)(SDL_Renderer *renderer, SDL_Texture *texture);
bool (*UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, bool (*UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const void *pixels, const SDL_Rect *rect, const void *pixels,
int pitch); int pitch);
@@ -301,6 +314,9 @@ struct SDL_Renderer
SDL_Texture *target; SDL_Texture *target;
SDL_Mutex *target_mutex; SDL_Mutex *target_mutex;
// The list of palettes
SDL_HashTable *palettes;
SDL_Colorspace output_colorspace; SDL_Colorspace output_colorspace;
float SDR_white_point; float SDR_white_point;
float HDR_headroom; float HDR_headroom;

View File

@@ -48,6 +48,26 @@ typedef struct
const float *shader_params; const float *shader_params;
} D3D_DrawStateCache; } D3D_DrawStateCache;
typedef struct
{
bool dirty;
int w, h;
DWORD usage;
Uint32 format;
D3DFORMAT d3dfmt;
IDirect3DTexture9 *texture;
IDirect3DTexture9 *staging;
} D3D_TextureRep;
struct D3D_PaletteData
{
D3D_TextureRep texture;
struct D3D_PaletteData *prev;
struct D3D_PaletteData *next;
};
typedef struct D3D_PaletteData D3D_PaletteData;
// Direct3D renderer implementation // Direct3D renderer implementation
typedef struct typedef struct
@@ -74,23 +94,12 @@ typedef struct
int currentVertexBuffer; int currentVertexBuffer;
bool reportedVboProblem; bool reportedVboProblem;
D3D_DrawStateCache drawstate; D3D_DrawStateCache drawstate;
D3D_PaletteData *palettes;
} D3D_RenderData; } D3D_RenderData;
typedef struct
{
bool dirty;
int w, h;
DWORD usage;
Uint32 format;
D3DFORMAT d3dfmt;
IDirect3DTexture9 *texture;
IDirect3DTexture9 *staging;
} D3D_TextureRep;
typedef struct typedef struct
{ {
D3D_TextureRep texture; D3D_TextureRep texture;
D3D_TextureRep palette;
D3D9_Shader shader; D3D9_Shader shader;
const float *shader_params; const float *shader_params;
@@ -532,6 +541,99 @@ static void D3D_DestroyTextureRep(D3D_TextureRep *texture)
} }
} }
static bool D3D_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
D3D_PaletteData *palettedata = (D3D_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
if (!palettedata) {
return false;
}
palette->internal = palettedata;
if (!D3D_CreateTextureRep(data->device, &palettedata->texture, 0, SDL_PIXELFORMAT_ARGB8888, D3DFMT_A8R8G8B8, 256, 1)) {
SDL_free(palettedata);
return false;
}
// Keep a reference to the palette so we can restore the texture if we lose the D3D device
if (data->palettes) {
palettedata->next = data->palettes;
data->palettes->prev = palettedata;
}
data->palettes = palettedata;
return true;
}
static bool D3D_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
D3D_PaletteData *palettedata = (D3D_PaletteData *)palette->internal;
bool retval;
Uint32 *entries = SDL_stack_alloc(Uint32, ncolors);
if (!entries) {
return false;
}
for (int i = 0; i < ncolors; ++i) {
entries[i] = (colors[i].a << 24) | (colors[i].r << 16) | (colors[i].g << 8) | colors[i].b;
}
retval = D3D_UpdateTextureRep(data->device, &palettedata->texture, 0, 0, ncolors, 1, entries, ncolors * sizeof(*entries));
SDL_stack_free(entries);
return retval;
}
static void D3D_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
D3D_PaletteData *palettedata = (D3D_PaletteData *)palette->internal;
if (palettedata) {
D3D_DestroyTextureRep(&palettedata->texture);
if (data->palettes == palettedata) {
data->palettes = palettedata->next;
} else if (palettedata->prev) {
palettedata->prev->next = palettedata->next;
}
if (palettedata->next) {
palettedata->next->prev = palettedata->prev;
}
SDL_free(palettedata);
}
}
static bool D3D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const void *pixels, int pitch)
{
D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
if (!texturedata) {
return SDL_SetError("Texture is not currently available");
}
if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) {
return false;
}
#ifdef SDL_HAVE_YUV
if (texturedata->yuv) {
// Skip to the correct offset into the next texture
pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
return false;
}
// Skip to the correct offset into the next texture
pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
return false;
}
}
#endif
return true;
}
static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
D3D_RenderData *data = (D3D_RenderData *)renderer->internal; D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
@@ -555,10 +657,6 @@ static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
return false; return false;
} }
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->format == SDL_PIXELFORMAT_INDEX8) {
if (!D3D_CreateTextureRep(data->device, &texturedata->palette, usage, SDL_PIXELFORMAT_ARGB8888, D3DFMT_A8R8G8B8, 256, 1)) {
return false;
}
texturedata->shader = SHADER_PALETTE; texturedata->shader = SHADER_PALETTE;
} }
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
@@ -596,12 +694,6 @@ static bool D3D_RecreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
if (!D3D_RecreateTextureRep(data->device, &texturedata->texture)) { if (!D3D_RecreateTextureRep(data->device, &texturedata->texture)) {
return false; return false;
} }
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
if (!D3D_RecreateTextureRep(data->device, &texturedata->palette)) {
return false;
}
texture->palette_version = 0;
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (texturedata->yuv) { if (texturedata->yuv) {
if (!D3D_RecreateTextureRep(data->device, &texturedata->utexture)) { if (!D3D_RecreateTextureRep(data->device, &texturedata->utexture)) {
@@ -616,56 +708,6 @@ static bool D3D_RecreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
return true; return true;
} }
static bool D3D_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
const int ncolors = texture->palette->ncolors;
const SDL_Color *colors = texture->palette->colors;
Uint32 palette[256];
if (!texturedata) {
return SDL_SetError("Texture is not currently available");
}
for (int i = 0; i < ncolors; ++i) {
palette[i] = (colors[i].a << 24) | (colors[i].r << 16) | (colors[i].g << 8) | colors[i].b;
}
return D3D_UpdateTextureRep(data->device, &texturedata->palette, 0, 0, 256, 1, palette, sizeof(palette));
}
static bool D3D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const void *pixels, int pitch)
{
D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
if (!texturedata) {
return SDL_SetError("Texture is not currently available");
}
if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) {
return false;
}
#ifdef SDL_HAVE_YUV
if (texturedata->yuv) {
// Skip to the correct offset into the next texture
pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
return false;
}
// Skip to the correct offset into the next texture
pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
return false;
}
}
#endif
return true;
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
static bool D3D_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, static bool D3D_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const SDL_Rect *rect,
@@ -1013,8 +1055,9 @@ static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, D3D9_S
if (!BindTextureRep(data->device, &texturedata->texture, 0)) { if (!BindTextureRep(data->device, &texturedata->texture, 0)) {
return false; return false;
} }
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->palette) {
if (!BindTextureRep(data->device, &texturedata->palette, 1)) { D3D_PaletteData *palette = (D3D_PaletteData *)texture->palette->internal;
if (!BindTextureRep(data->device, &palette->texture, 1)) {
return false; return false;
} }
} }
@@ -1046,8 +1089,8 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
if (!texture) { if (!texture) {
IDirect3DDevice9_SetTexture(data->device, 0, NULL); IDirect3DDevice9_SetTexture(data->device, 0, NULL);
} }
if ((!newtexturedata || (texture->format != SDL_PIXELFORMAT_INDEX8)) && if ((!newtexturedata || !texture->palette) &&
(oldtexturedata && (data->drawstate.texture->format == SDL_PIXELFORMAT_INDEX8))) { (oldtexturedata && (data->drawstate.texture->palette))) {
IDirect3DDevice9_SetTexture(data->device, 1, NULL); IDirect3DDevice9_SetTexture(data->device, 1, NULL);
} }
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
@@ -1086,8 +1129,9 @@ static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
if (texturedata) { if (texturedata) {
UpdateDirtyTexture(data->device, &texturedata->texture); UpdateDirtyTexture(data->device, &texturedata->texture);
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->palette) {
UpdateDirtyTexture(data->device, &texturedata->palette); D3D_PaletteData *palettedata = (D3D_PaletteData *)texture->palette->internal;
UpdateDirtyTexture(data->device, &palettedata->texture);
} }
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (texturedata->yuv) { if (texturedata->yuv) {
@@ -1488,7 +1532,7 @@ static void D3D_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
renderdata->drawstate.shader_params = NULL; renderdata->drawstate.shader_params = NULL;
IDirect3DDevice9_SetPixelShader(renderdata->device, NULL); IDirect3DDevice9_SetPixelShader(renderdata->device, NULL);
IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL); IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL);
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->palette) {
IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL); IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL);
} }
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
@@ -1520,6 +1564,9 @@ static void D3D_DestroyRenderer(SDL_Renderer *renderer)
if (data) { if (data) {
int i; int i;
// Make sure the palettes have been freed
SDL_assert(!data->palettes);
// Release the render target // Release the render target
if (data->defaultRenderTarget) { if (data->defaultRenderTarget) {
IDirect3DSurface9_Release(data->defaultRenderTarget); IDirect3DSurface9_Release(data->defaultRenderTarget);
@@ -1560,6 +1607,7 @@ static bool D3D_Reset(SDL_Renderer *renderer)
const Float4X4 d3dmatrix = MatrixIdentity(); const Float4X4 d3dmatrix = MatrixIdentity();
HRESULT result; HRESULT result;
SDL_Texture *texture; SDL_Texture *texture;
D3D_PaletteData *palette;
int i; int i;
// Cancel any scene that we've started // Cancel any scene that we've started
@@ -1587,6 +1635,11 @@ static bool D3D_Reset(SDL_Renderer *renderer)
} }
} }
// Release all palettes
for (palette = data->palettes; palette; palette = palette->next) {
D3D_RecreateTextureRep(data->device, &palette->texture);
}
// Release all vertex buffers // Release all vertex buffers
for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) { for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
if (data->vertexBuffers[i]) { if (data->vertexBuffers[i]) {
@@ -1711,8 +1764,10 @@ static bool D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
renderer->WindowEvent = D3D_WindowEvent; renderer->WindowEvent = D3D_WindowEvent;
renderer->SupportsBlendMode = D3D_SupportsBlendMode; renderer->SupportsBlendMode = D3D_SupportsBlendMode;
renderer->CreatePalette = D3D_CreatePalette;
renderer->UpdatePalette = D3D_UpdatePalette;
renderer->DestroyPalette = D3D_DestroyPalette;
renderer->CreateTexture = D3D_CreateTexture; renderer->CreateTexture = D3D_CreateTexture;
renderer->UpdateTexturePalette = D3D_UpdateTexturePalette;
renderer->UpdateTexture = D3D_UpdateTexture; renderer->UpdateTexture = D3D_UpdateTexture;
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
renderer->UpdateTextureYUV = D3D_UpdateTextureYUV; renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;

View File

@@ -114,6 +114,13 @@ typedef struct
SDL_FColor color; SDL_FColor color;
} D3D11_VertexPositionColor; } D3D11_VertexPositionColor;
// Per-palette data
typedef struct
{
ID3D11Texture2D *texture;
ID3D11ShaderResourceView *resourceView;
} D3D11_PaletteData;
// Per-texture data // Per-texture data
typedef struct typedef struct
{ {
@@ -121,8 +128,6 @@ typedef struct
ID3D11Texture2D *mainTexture; ID3D11Texture2D *mainTexture;
ID3D11ShaderResourceView *mainTextureResourceView; ID3D11ShaderResourceView *mainTextureResourceView;
ID3D11RenderTargetView *mainTextureRenderTargetView; ID3D11RenderTargetView *mainTextureRenderTargetView;
ID3D11Texture2D *paletteTexture;
ID3D11ShaderResourceView *paletteTextureResourceView;
ID3D11Texture2D *stagingTexture; ID3D11Texture2D *stagingTexture;
int lockedTexturePositionX; int lockedTexturePositionX;
int lockedTexturePositionY; int lockedTexturePositionY;
@@ -232,6 +237,8 @@ static const GUID SDL_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
static bool D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *texture, int bpp, int x, int y, int w, int h, const void *pixels, int pitch);
SDL_PixelFormat D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) SDL_PixelFormat D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
{ {
switch (dxgiFormat) { switch (dxgiFormat) {
@@ -1179,6 +1186,73 @@ static bool GetTextureProperty(SDL_PropertiesID props, const char *name, ID3D11T
return true; return true;
} }
static bool D3D11_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal;
D3D11_PaletteData *palettedata = (D3D11_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
if (!palettedata) {
return false;
}
palette->internal = palettedata;
if (!data->d3dDevice) {
return SDL_SetError("Device lost and couldn't be recovered");
}
D3D11_TEXTURE2D_DESC textureDesc;
SDL_zero(textureDesc);
textureDesc.Width = 256;
textureDesc.Height = 1;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = SDLPixelFormatToDXGITextureFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace);
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.MiscFlags = 0;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.CPUAccessFlags = 0;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
HRESULT result = ID3D11Device_CreateTexture2D(data->d3dDevice, &textureDesc, NULL, &palettedata->texture);
if (FAILED(result)) {
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
}
D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
SDL_zero(resourceViewDesc);
resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace);
resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
resourceViewDesc.Texture2D.MostDetailedMip = 0;
resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
result = ID3D11Device_CreateShaderResourceView(data->d3dDevice,
(ID3D11Resource *)palettedata->texture,
&resourceViewDesc,
&palettedata->resourceView);
if (FAILED(result)) {
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result);
}
return true;
}
static bool D3D11_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal;
D3D11_PaletteData *palettedata = (D3D11_PaletteData *)palette->internal;
return D3D11_UpdateTextureInternal(data, palettedata->texture, 4, 0, 0, ncolors, 1, colors, ncolors * sizeof(*colors));
}
static void D3D11_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
D3D11_PaletteData *palettedata = (D3D11_PaletteData *)palette->internal;
if (palettedata) {
SAFE_RELEASE(palettedata->texture);
SAFE_RELEASE(palettedata->resourceView);
SDL_free(palettedata);
}
}
static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal;
@@ -1252,24 +1326,6 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
} }
SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_POINTER, textureData->mainTexture); SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_POINTER, textureData->mainTexture);
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
textureDesc.Width = 256;
textureDesc.Height = 1;
if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
} else {
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
}
result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
&textureDesc,
NULL,
&textureData->paletteTexture);
if (FAILED(result)) {
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
}
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (texture->format == SDL_PIXELFORMAT_YV12 || if (texture->format == SDL_PIXELFORMAT_YV12 ||
texture->format == SDL_PIXELFORMAT_IYUV) { texture->format == SDL_PIXELFORMAT_IYUV) {
@@ -1345,17 +1401,6 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result);
} }
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
resourceViewDesc.Format = textureDesc.Format;
result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice,
(ID3D11Resource *)textureData->paletteTexture,
&resourceViewDesc,
&textureData->paletteTextureResourceView);
if (FAILED(result)) {
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result);
}
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (textureData->yuv) { if (textureData->yuv) {
result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice,
@@ -1424,8 +1469,6 @@ static void D3D11_DestroyTexture(SDL_Renderer *renderer,
SAFE_RELEASE(data->mainTexture); SAFE_RELEASE(data->mainTexture);
SAFE_RELEASE(data->mainTextureResourceView); SAFE_RELEASE(data->mainTextureResourceView);
SAFE_RELEASE(data->mainTextureRenderTargetView); SAFE_RELEASE(data->mainTextureRenderTargetView);
SAFE_RELEASE(data->paletteTexture);
SAFE_RELEASE(data->paletteTextureResourceView);
SAFE_RELEASE(data->stagingTexture); SAFE_RELEASE(data->stagingTexture);
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
SAFE_RELEASE(data->mainTextureU); SAFE_RELEASE(data->mainTextureU);
@@ -1542,19 +1585,6 @@ static bool D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Te
return true; return true;
} }
static bool D3D11_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal;
D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal;
SDL_Palette *palette = texture->palette;
if (!textureData) {
return SDL_SetError("Texture is not currently available");
}
return D3D11_UpdateTextureInternal(rendererData, textureData->paletteTexture, 4, 0, 0, palette->ncolors, 1, palette->colors, palette->ncolors * sizeof(*palette->colors));
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
static bool D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture, static bool D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const SDL_Rect *rect,
@@ -2491,8 +2521,10 @@ static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
} }
++numShaderSamplers; ++numShaderSamplers;
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->palette) {
shaderResources[numShaderResources++] = textureData->paletteTextureResourceView; D3D11_PaletteData *palette = (D3D11_PaletteData *)texture->palette->internal;
shaderResources[numShaderResources++] = palette->resourceView;
shaderSamplers[numShaderSamplers] = D3D11_GetSamplerState(rendererData, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); shaderSamplers[numShaderSamplers] = D3D11_GetSamplerState(rendererData, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
if (!shaderSamplers[numShaderSamplers]) { if (!shaderSamplers[numShaderSamplers]) {
@@ -2846,8 +2878,10 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
renderer->WindowEvent = D3D11_WindowEvent; renderer->WindowEvent = D3D11_WindowEvent;
renderer->SupportsBlendMode = D3D11_SupportsBlendMode; renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
renderer->CreatePalette = D3D11_CreatePalette;
renderer->UpdatePalette = D3D11_UpdatePalette;
renderer->DestroyPalette = D3D11_DestroyPalette;
renderer->CreateTexture = D3D11_CreateTexture; renderer->CreateTexture = D3D11_CreateTexture;
renderer->UpdateTexturePalette = D3D11_UpdateTexturePalette;
renderer->UpdateTexture = D3D11_UpdateTexture; renderer->UpdateTexture = D3D11_UpdateTexture;
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV; renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV;

View File

@@ -109,6 +109,15 @@ typedef struct
SDL_FColor color; SDL_FColor color;
} D3D12_VertexPositionColor; } D3D12_VertexPositionColor;
// Per-palette data
typedef struct
{
ID3D12Resource *texture;
D3D12_CPU_DESCRIPTOR_HANDLE resourceView;
D3D12_RESOURCE_STATES resourceState;
SIZE_T SRVIndex;
} D3D12_PaletteData;
// Per-texture data // Per-texture data
typedef struct typedef struct
{ {
@@ -119,10 +128,6 @@ typedef struct
SIZE_T mainSRVIndex; SIZE_T mainSRVIndex;
D3D12_CPU_DESCRIPTOR_HANDLE mainTextureRenderTargetView; D3D12_CPU_DESCRIPTOR_HANDLE mainTextureRenderTargetView;
DXGI_FORMAT mainTextureFormat; DXGI_FORMAT mainTextureFormat;
ID3D12Resource *paletteTexture;
D3D12_CPU_DESCRIPTOR_HANDLE paletteTextureResourceView;
D3D12_RESOURCE_STATES paletteResourceState;
SIZE_T paletteSRVIndex;
ID3D12Resource *stagingBuffer; ID3D12Resource *stagingBuffer;
D3D12_RESOURCE_STATES stagingResourceState; D3D12_RESOURCE_STATES stagingResourceState;
const float *YCbCr_matrix; const float *YCbCr_matrix;
@@ -289,6 +294,8 @@ static const GUID SDL_IID_ID3D12InfoQueue = { 0x0742a90b, 0xc387, 0x483f, { 0xb9
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
static bool D3D12_UpdateTextureInternal(D3D12_RenderData *rendererData, ID3D12Resource *texture, int plane, int x, int y, int w, int h, const void *pixels, int pitch, D3D12_RESOURCE_STATES *resourceState);
static UINT D3D12_Align(UINT location, UINT alignment) static UINT D3D12_Align(UINT location, UINT alignment)
{ {
return (location + (alignment - 1)) & ~(alignment - 1); return (location + (alignment - 1)) & ~(alignment - 1);
@@ -1537,6 +1544,88 @@ static bool GetTextureProperty(SDL_PropertiesID props, const char *name, ID3D12R
return true; return true;
} }
static bool D3D12_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
D3D12_RenderData *data = (D3D12_RenderData *)renderer->internal;
D3D12_PaletteData *palettedata = (D3D12_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
if (!palettedata) {
return false;
}
palette->internal = palettedata;
if (!data->d3dDevice) {
return SDL_SetError("Device lost and couldn't be recovered");
}
D3D12_RESOURCE_DESC textureDesc;
SDL_zero(textureDesc);
textureDesc.Width = 256;
textureDesc.Height = 1;
textureDesc.MipLevels = 1;
textureDesc.DepthOrArraySize = 1;
textureDesc.Format = SDLPixelFormatToDXGITextureFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace);
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
D3D12_HEAP_PROPERTIES heapProps;
SDL_zero(heapProps);
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
heapProps.CreationNodeMask = 1;
heapProps.VisibleNodeMask = 1;
HRESULT result = ID3D12Device1_CreateCommittedResource(data->d3dDevice,
&heapProps,
D3D12_HEAP_FLAG_NONE,
&textureDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
NULL,
D3D_GUID(SDL_IID_ID3D12Resource),
(void **)&palettedata->texture);
if (FAILED(result)) {
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D12Device::CreateCommittedResource [texture]"), result);
}
palettedata->resourceState = D3D12_RESOURCE_STATE_COPY_DEST;
D3D12_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
SDL_zero(resourceViewDesc);
resourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace);
resourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
D3D_CALL_RET(data->srvDescriptorHeap, GetCPUDescriptorHandleForHeapStart, &palettedata->resourceView);
palettedata->SRVIndex = D3D12_GetAvailableSRVIndex(renderer);
palettedata->resourceView.ptr += palettedata->SRVIndex * data->srvDescriptorSize;
ID3D12Device1_CreateShaderResourceView(data->d3dDevice,
palettedata->texture,
&resourceViewDesc,
palettedata->resourceView);
return true;
}
static bool D3D12_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
D3D12_RenderData *data = (D3D12_RenderData *)renderer->internal;
D3D12_PaletteData *palettedata = (D3D12_PaletteData *)palette->internal;
return D3D12_UpdateTextureInternal(data, palettedata->texture, 0, 0, 0, ncolors, 1, colors, ncolors * sizeof(*colors), &palettedata->resourceState);
}
static void D3D12_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
D3D12_PaletteData *palettedata = (D3D12_PaletteData *)palette->internal;
if (palettedata) {
D3D_SAFE_RELEASE(palettedata->texture);
D3D12_FreeSRVIndex(renderer, palettedata->SRVIndex);
SDL_free(palettedata);
}
}
static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
D3D12_RenderData *rendererData = (D3D12_RenderData *)renderer->internal; D3D12_RenderData *rendererData = (D3D12_RenderData *)renderer->internal;
@@ -1612,29 +1701,6 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
textureData->mainResourceState = D3D12_RESOURCE_STATE_COPY_DEST; textureData->mainResourceState = D3D12_RESOURCE_STATE_COPY_DEST;
SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D12_TEXTURE_POINTER, textureData->mainTexture); SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D12_TEXTURE_POINTER, textureData->mainTexture);
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
textureDesc.Width = 256;
textureDesc.Height = 1;
if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
} else {
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
}
result = ID3D12Device1_CreateCommittedResource(rendererData->d3dDevice,
&heapProps,
D3D12_HEAP_FLAG_NONE,
&textureDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
NULL,
D3D_GUID(SDL_IID_ID3D12Resource),
(void **)&textureData->paletteTexture);
if (FAILED(result)) {
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D12Device::CreateCommittedResource [texture]"), result);
}
textureData->paletteResourceState = D3D12_RESOURCE_STATE_COPY_DEST;
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (texture->format == SDL_PIXELFORMAT_YV12 || if (texture->format == SDL_PIXELFORMAT_YV12 ||
texture->format == SDL_PIXELFORMAT_IYUV) { texture->format == SDL_PIXELFORMAT_IYUV) {
@@ -1723,19 +1789,6 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
&resourceViewDesc, &resourceViewDesc,
textureData->mainTextureResourceView); textureData->mainTextureResourceView);
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
resourceViewDesc.Format = textureDesc.Format;
D3D_CALL_RET(rendererData->srvDescriptorHeap, GetCPUDescriptorHandleForHeapStart, &textureData->paletteTextureResourceView);
textureData->paletteSRVIndex = D3D12_GetAvailableSRVIndex(renderer);
textureData->paletteTextureResourceView.ptr += textureData->paletteSRVIndex * rendererData->srvDescriptorSize;
ID3D12Device1_CreateShaderResourceView(rendererData->d3dDevice,
textureData->paletteTexture,
&resourceViewDesc,
textureData->paletteTextureResourceView);
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (textureData->yuv) { if (textureData->yuv) {
D3D_CALL_RET(rendererData->srvDescriptorHeap, GetCPUDescriptorHandleForHeapStart, &textureData->mainTextureResourceViewU); D3D_CALL_RET(rendererData->srvDescriptorHeap, GetCPUDescriptorHandleForHeapStart, &textureData->mainTextureResourceViewU);
@@ -1811,10 +1864,6 @@ static void D3D12_DestroyTexture(SDL_Renderer *renderer,
D3D_SAFE_RELEASE(textureData->mainTexture); D3D_SAFE_RELEASE(textureData->mainTexture);
D3D_SAFE_RELEASE(textureData->stagingBuffer); D3D_SAFE_RELEASE(textureData->stagingBuffer);
D3D12_FreeSRVIndex(renderer, textureData->mainSRVIndex); D3D12_FreeSRVIndex(renderer, textureData->mainSRVIndex);
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
D3D_SAFE_RELEASE(textureData->paletteTexture);
D3D12_FreeSRVIndex(renderer, textureData->paletteSRVIndex);
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
D3D_SAFE_RELEASE(textureData->mainTextureU); D3D_SAFE_RELEASE(textureData->mainTextureU);
D3D_SAFE_RELEASE(textureData->mainTextureV); D3D_SAFE_RELEASE(textureData->mainTextureV);
@@ -1969,19 +2018,6 @@ static bool D3D12_UpdateTextureInternal(D3D12_RenderData *rendererData, ID3D12Re
return true; return true;
} }
static bool D3D12_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
D3D12_RenderData *rendererData = (D3D12_RenderData *)renderer->internal;
D3D12_TextureData *textureData = (D3D12_TextureData *)texture->internal;
SDL_Palette *palette = texture->palette;
if (!textureData) {
return SDL_SetError("Texture is not currently available");
}
return D3D12_UpdateTextureInternal(rendererData, textureData->paletteTexture, 0, 0, 0, palette->ncolors, 1, palette->colors, palette->ncolors * sizeof(*palette->colors), &textureData->paletteResourceState);
}
static bool D3D12_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, static bool D3D12_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const void *srcPixels, const SDL_Rect *rect, const void *srcPixels,
int srcPitch) int srcPitch)
@@ -2902,10 +2938,12 @@ static bool D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *
} }
shaderSamplers[numShaderSamplers++] = *textureSampler; shaderSamplers[numShaderSamplers++] = *textureSampler;
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->palette) {
D3D12_TransitionResource(rendererData, textureData->paletteTexture, textureData->paletteResourceState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); D3D12_PaletteData *palette = (D3D12_PaletteData *)texture->palette->internal;
textureData->paletteResourceState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
shaderResources[numShaderResources++] = textureData->paletteTextureResourceView; D3D12_TransitionResource(rendererData, palette->texture, palette->resourceState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
palette->resourceState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
shaderResources[numShaderResources++] = palette->resourceView;
textureSampler = D3D12_GetSamplerState(rendererData, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); textureSampler = D3D12_GetSamplerState(rendererData, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
if (!textureSampler) { if (!textureSampler) {
@@ -3366,8 +3404,10 @@ bool D3D12_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Proper
renderer->WindowEvent = D3D12_WindowEvent; renderer->WindowEvent = D3D12_WindowEvent;
renderer->SupportsBlendMode = D3D12_SupportsBlendMode; renderer->SupportsBlendMode = D3D12_SupportsBlendMode;
renderer->CreatePalette = D3D12_CreatePalette;
renderer->UpdatePalette = D3D12_UpdatePalette;
renderer->DestroyPalette = D3D12_DestroyPalette;
renderer->CreateTexture = D3D12_CreateTexture; renderer->CreateTexture = D3D12_CreateTexture;
renderer->UpdateTexturePalette = D3D12_UpdateTexturePalette;
renderer->UpdateTexture = D3D12_UpdateTexture; renderer->UpdateTexture = D3D12_UpdateTexture;
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
renderer->UpdateTextureYUV = D3D12_UpdateTextureYUV; renderer->UpdateTextureYUV = D3D12_UpdateTextureYUV;

View File

@@ -86,10 +86,14 @@ typedef struct GPU_RenderData
SDL_GPUSampler *samplers[RENDER_SAMPLER_COUNT]; SDL_GPUSampler *samplers[RENDER_SAMPLER_COUNT];
} GPU_RenderData; } GPU_RenderData;
typedef struct GPU_PaletteData
{
SDL_GPUTexture *texture;
} GPU_PaletteData;
typedef struct GPU_TextureData typedef struct GPU_TextureData
{ {
SDL_GPUTexture *texture; SDL_GPUTexture *texture;
SDL_GPUTexture *palette;
SDL_GPUTextureFormat format; SDL_GPUTextureFormat format;
GPU_FragmentShaderID shader; GPU_FragmentShaderID shader;
void *pixels; void *pixels;
@@ -118,6 +122,88 @@ static bool GPU_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMod
return true; return true;
} }
static bool GPU_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
GPU_PaletteData *palettedata = (GPU_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
if (!palettedata) {
return false;
}
palette->internal = palettedata;
SDL_GPUTextureCreateInfo tci;
SDL_zero(tci);
tci.format = SDL_GetGPUTextureFormatFromPixelFormat(SDL_PIXELFORMAT_RGBA32);
tci.layer_count_or_depth = 1;
tci.num_levels = 1;
tci.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
tci.width = 256;
tci.height = 1;
tci.sample_count = SDL_GPU_SAMPLECOUNT_1;
palettedata->texture = SDL_CreateGPUTexture(data->device, &tci);
if (!palettedata->texture) {
return false;
}
return true;
}
static bool GPU_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
GPU_PaletteData *palettedata = (GPU_PaletteData *)palette->internal;
const Uint32 data_size = ncolors * sizeof(*colors);
SDL_GPUTransferBufferCreateInfo tbci;
SDL_zero(tbci);
tbci.size = data_size;
tbci.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
SDL_GPUTransferBuffer *tbuf = SDL_CreateGPUTransferBuffer(data->device, &tbci);
if (tbuf == NULL) {
return false;
}
Uint8 *output = SDL_MapGPUTransferBuffer(data->device, tbuf, false);
SDL_memcpy(output, colors, data_size);
SDL_UnmapGPUTransferBuffer(data->device, tbuf);
SDL_GPUCommandBuffer *cbuf = data->state.command_buffer;
SDL_GPUCopyPass *cpass = SDL_BeginGPUCopyPass(cbuf);
SDL_GPUTextureTransferInfo tex_src;
SDL_zero(tex_src);
tex_src.transfer_buffer = tbuf;
tex_src.rows_per_layer = 1;
tex_src.pixels_per_row = ncolors;
SDL_GPUTextureRegion tex_dst;
SDL_zero(tex_dst);
tex_dst.texture = palettedata->texture;
tex_dst.x = 0;
tex_dst.y = 0;
tex_dst.w = ncolors;
tex_dst.h = 1;
tex_dst.d = 1;
SDL_UploadToGPUTexture(cpass, &tex_src, &tex_dst, false);
SDL_EndGPUCopyPass(cpass);
SDL_ReleaseGPUTransferBuffer(data->device, tbuf);
return true;
}
static void GPU_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
GPU_PaletteData *palettedata = (GPU_PaletteData *)palette->internal;
if (palettedata) {
SDL_ReleaseGPUTexture(data->device, palettedata->texture);
SDL_free(palettedata);
}
}
static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal; GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal;
@@ -184,16 +270,6 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
return false; return false;
} }
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
tci.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
tci.width = 256;
tci.height = 1;
data->palette = SDL_CreateGPUTexture(renderdata->device, &tci);
if (!data->palette) {
return false;
}
}
SDL_PropertiesID props = SDL_GetTextureProperties(texture); SDL_PropertiesID props = SDL_GetTextureProperties(texture);
SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER, data->texture); SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER, data->texture);
@@ -206,52 +282,6 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
return true; return true;
} }
static bool GPU_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal;
GPU_TextureData *data = (GPU_TextureData *)texture->internal;
SDL_Palette *palette = texture->palette;
const Uint32 data_size = palette->ncolors * sizeof(*palette->colors);
SDL_GPUTransferBufferCreateInfo tbci;
SDL_zero(tbci);
tbci.size = data_size;
tbci.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
SDL_GPUTransferBuffer *tbuf = SDL_CreateGPUTransferBuffer(renderdata->device, &tbci);
if (tbuf == NULL) {
return false;
}
Uint8 *output = SDL_MapGPUTransferBuffer(renderdata->device, tbuf, false);
SDL_memcpy(output, palette->colors, data_size);
SDL_UnmapGPUTransferBuffer(renderdata->device, tbuf);
SDL_GPUCommandBuffer *cbuf = renderdata->state.command_buffer;
SDL_GPUCopyPass *cpass = SDL_BeginGPUCopyPass(cbuf);
SDL_GPUTextureTransferInfo tex_src;
SDL_zero(tex_src);
tex_src.transfer_buffer = tbuf;
tex_src.rows_per_layer = 1;
tex_src.pixels_per_row = palette->ncolors;
SDL_GPUTextureRegion tex_dst;
SDL_zero(tex_dst);
tex_dst.texture = data->palette;
tex_dst.x = 0;
tex_dst.y = 0;
tex_dst.w = palette->ncolors;
tex_dst.h = 1;
tex_dst.d = 1;
SDL_UploadToGPUTexture(cpass, &tex_src, &tex_dst, false);
SDL_EndGPUCopyPass(cpass);
SDL_ReleaseGPUTransferBuffer(renderdata->device, tbuf);
return true;
}
static bool GPU_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, static bool GPU_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)
{ {
@@ -663,9 +693,11 @@ static void Draw(
sampler_bind.texture = tdata->texture; sampler_bind.texture = tdata->texture;
SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1); SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->palette) {
GPU_PaletteData *palette = (GPU_PaletteData *)texture->palette->internal;
sampler_bind.sampler = GetSampler(data, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); sampler_bind.sampler = GetSampler(data, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
sampler_bind.texture = tdata->palette; sampler_bind.texture = palette->texture;
SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1); SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
} }
} }
@@ -1128,7 +1160,6 @@ static void GPU_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
} }
SDL_ReleaseGPUTexture(renderdata->device, data->texture); SDL_ReleaseGPUTexture(renderdata->device, data->texture);
SDL_ReleaseGPUTexture(renderdata->device, data->palette);
SDL_free(data->pixels); SDL_free(data->pixels);
SDL_free(data); SDL_free(data);
texture->internal = NULL; texture->internal = NULL;
@@ -1242,8 +1273,10 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
} }
renderer->SupportsBlendMode = GPU_SupportsBlendMode; renderer->SupportsBlendMode = GPU_SupportsBlendMode;
renderer->CreatePalette = GPU_CreatePalette;
renderer->UpdatePalette = GPU_UpdatePalette;
renderer->DestroyPalette = GPU_DestroyPalette;
renderer->CreateTexture = GPU_CreateTexture; renderer->CreateTexture = GPU_CreateTexture;
renderer->UpdateTexturePalette = GPU_UpdateTexturePalette;
renderer->UpdateTexture = GPU_UpdateTexture; renderer->UpdateTexture = GPU_UpdateTexture;
renderer->LockTexture = GPU_LockTexture; renderer->LockTexture = GPU_LockTexture;
renderer->UnlockTexture = GPU_UnlockTexture; renderer->UnlockTexture = GPU_UnlockTexture;

View File

@@ -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) { if (texture->palette) {
[data.mtlcmdencoder setFragmentTexture:texturedata.mtlpalette atIndex:1]; 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;

View File

@@ -125,6 +125,11 @@ typedef struct
GL_DrawStateCache drawstate; GL_DrawStateCache drawstate;
} GL_RenderData; } GL_RenderData;
typedef struct
{
GLuint texture;
} GL_PaletteData;
typedef struct typedef struct
{ {
GLuint texture; GLuint texture;
@@ -133,7 +138,6 @@ typedef struct
GLfloat texh; GLfloat texh;
GLenum format; GLenum format;
GLenum formattype; GLenum formattype;
GLuint palette;
GL_Shader shader; GL_Shader shader;
float texel_size[4]; float texel_size[4];
const float *shader_params; const float *shader_params;
@@ -481,6 +485,58 @@ static void SetTextureAddressMode(GL_RenderData *data, GLenum textype, SDL_Textu
data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, TranslateAddressMode(addressModeV)); data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, TranslateAddressMode(addressModeV));
} }
static bool GL_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
GL_RenderData *data = (GL_RenderData *)renderer->internal;
GL_PaletteData *palettedata = (GL_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
if (!palettedata) {
return false;
}
palette->internal = palettedata;
data->drawstate.texture = NULL; // we trash this state.
const GLenum textype = data->textype;
data->glGenTextures(1, &palettedata->texture);
data->glBindTexture(textype, palettedata->texture);
data->glTexImage2D(textype, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if (!GL_CheckError("glTexImage2D()", renderer)) {
return false;
}
SetTextureScaleMode(data, textype, SDL_SCALEMODE_NEAREST);
SetTextureAddressMode(data, textype, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
return true;
}
static bool GL_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
GL_RenderData *data = (GL_RenderData *)renderer->internal;
GL_PaletteData *palettedata = (GL_PaletteData *)palette->internal;
GL_ActivateRenderer(renderer);
data->drawstate.texture = NULL; // we trash this state.
const GLenum textype = data->textype;
data->glBindTexture(textype, palettedata->texture);
data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
data->glPixelStorei(GL_UNPACK_ROW_LENGTH, ncolors);
data->glTexSubImage2D(textype, 0, 0, 0, ncolors, 1, GL_RGBA, GL_UNSIGNED_BYTE, colors);
return GL_CheckError("glTexSubImage2D()", renderer);
}
static void GL_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
GL_RenderData *data = (GL_RenderData *)renderer->internal;
GL_PaletteData *palettedata = (GL_PaletteData *)palette->internal;
if (palettedata) {
data->glDeleteTextures(1, &palettedata->texture);
SDL_free(palettedata);
}
}
static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
GL_RenderData *renderdata = (GL_RenderData *)renderer->internal; GL_RenderData *renderdata = (GL_RenderData *)renderer->internal;
@@ -621,14 +677,6 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
SetTextureScaleMode(renderdata, textype, data->texture_scale_mode); SetTextureScaleMode(renderdata, textype, data->texture_scale_mode);
SetTextureAddressMode(renderdata, textype, data->texture_address_mode_u, data->texture_address_mode_v); SetTextureAddressMode(renderdata, textype, data->texture_address_mode_u, data->texture_address_mode_v);
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
renderdata->glGenTextures(1, &data->palette);
renderdata->glBindTexture(textype, data->palette);
renderdata->glTexImage2D(textype, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
SetTextureScaleMode(renderdata, textype, SDL_SCALEMODE_NEAREST);
SetTextureAddressMode(renderdata, textype, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (texture->format == SDL_PIXELFORMAT_YV12 || if (texture->format == SDL_PIXELFORMAT_YV12 ||
texture->format == SDL_PIXELFORMAT_IYUV) { texture->format == SDL_PIXELFORMAT_IYUV) {
@@ -723,25 +771,6 @@ static bool GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
return GL_CheckError("", renderer); return GL_CheckError("", renderer);
} }
static bool GL_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
GL_RenderData *renderdata = (GL_RenderData *)renderer->internal;
const GLenum textype = renderdata->textype;
GL_TextureData *data = (GL_TextureData *)texture->internal;
SDL_Palette *palette = texture->palette;
GL_ActivateRenderer(renderer);
renderdata->drawstate.texture = NULL; // we trash this state.
renderdata->glBindTexture(textype, data->palette);
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, palette->ncolors);
renderdata->glTexSubImage2D(textype, 0, 0, 0, palette->ncolors, 1, GL_RGBA, GL_UNSIGNED_BYTE, palette->colors);
return GL_CheckError("glTexSubImage2D()", renderer);
}
static bool GL_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, static bool GL_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)
{ {
@@ -1205,8 +1234,9 @@ static bool SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd)
} }
#endif #endif
if (texture->palette) { if (texture->palette) {
GL_PaletteData *palette = (GL_PaletteData *)texture->palette->internal;
data->glActiveTextureARB(GL_TEXTURE1_ARB); data->glActiveTextureARB(GL_TEXTURE1_ARB);
data->glBindTexture(textype, texturedata->palette); data->glBindTexture(textype, palette->texture);
} }
if (data->GL_ARB_multitexture_supported) { if (data->GL_ARB_multitexture_supported) {
data->glActiveTextureARB(GL_TEXTURE0_ARB); data->glActiveTextureARB(GL_TEXTURE0_ARB);
@@ -1631,9 +1661,6 @@ static void GL_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
if (data->texture && !data->texture_external) { if (data->texture && !data->texture_external) {
renderdata->glDeleteTextures(1, &data->texture); renderdata->glDeleteTextures(1, &data->texture);
} }
if (data->palette) {
renderdata->glDeleteTextures(1, &data->palette);
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (data->yuv) { if (data->yuv) {
if (!data->utexture_external) { if (!data->utexture_external) {
@@ -1753,8 +1780,10 @@ static bool GL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Pr
renderer->WindowEvent = GL_WindowEvent; renderer->WindowEvent = GL_WindowEvent;
renderer->SupportsBlendMode = GL_SupportsBlendMode; renderer->SupportsBlendMode = GL_SupportsBlendMode;
renderer->CreatePalette = GL_CreatePalette;
renderer->UpdatePalette = GL_UpdatePalette;
renderer->DestroyPalette = GL_DestroyPalette;
renderer->CreateTexture = GL_CreateTexture; renderer->CreateTexture = GL_CreateTexture;
renderer->UpdateTexturePalette = GL_UpdateTexturePalette;
renderer->UpdateTexture = GL_UpdateTexture; renderer->UpdateTexture = GL_UpdateTexture;
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
renderer->UpdateTextureYUV = GL_UpdateTextureYUV; renderer->UpdateTextureYUV = GL_UpdateTextureYUV;

View File

@@ -58,14 +58,18 @@ struct GLES2_FBOList
GLES2_FBOList *next; GLES2_FBOList *next;
}; };
typedef struct GLES2_TextureData typedef struct
{
GLuint texture;
} GLES2_PaletteData;
typedef struct
{ {
GLuint texture; GLuint texture;
bool texture_external; bool texture_external;
GLenum texture_type; GLenum texture_type;
GLenum pixel_format; GLenum pixel_format;
GLenum pixel_type; GLenum pixel_type;
GLuint palette;
void *pixel_data; void *pixel_data;
int pitch; int pitch;
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
@@ -1277,8 +1281,9 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, v
} }
#endif #endif
if (texture->palette) { if (texture->palette) {
GLES2_PaletteData *palette = (GLES2_PaletteData *)texture->palette->internal;
data->glActiveTexture(GL_TEXTURE1); data->glActiveTexture(GL_TEXTURE1);
data->glBindTexture(tdata->texture_type, tdata->palette); data->glBindTexture(tdata->texture_type, palette->texture);
data->glActiveTexture(GL_TEXTURE0); data->glActiveTexture(GL_TEXTURE0);
} }
@@ -1633,6 +1638,58 @@ static void GLES2_DestroyRenderer(SDL_Renderer *renderer)
} }
} }
static bool GLES2_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
GLES2_PaletteData *palettedata = (GLES2_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
if (!palettedata) {
return false;
}
palette->internal = palettedata;
data->drawstate.texture = NULL; // we trash this state.
data->glGenTextures(1, &palettedata->texture);
if (!GL_CheckError("glGenTexures()", renderer)) {
return false;
}
data->glActiveTexture(GL_TEXTURE1);
data->glBindTexture(GL_TEXTURE_2D, palettedata->texture);
data->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if (!GL_CheckError("glTexImage2D()", renderer)) {
return false;
}
SetTextureScaleMode(data, GL_TEXTURE_2D, SDL_SCALEMODE_NEAREST);
SetTextureAddressMode(data, GL_TEXTURE_2D, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
return true;
}
static bool GLES2_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
GLES2_PaletteData *palettedata = (GLES2_PaletteData *)palette->internal;
GLES2_ActivateRenderer(renderer);
data->drawstate.texture = NULL; // we trash this state.
data->glBindTexture(GL_TEXTURE_2D, palettedata->texture);
data->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ncolors, 1, GL_RGBA, GL_UNSIGNED_BYTE, colors);
return GL_CheckError("glTexSubImage2D()", renderer);
}
static void GLES2_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
GLES2_PaletteData *palettedata = (GLES2_PaletteData *)palette->internal;
if (palettedata) {
data->glDeleteTextures(1, &palettedata->texture);
SDL_free(palettedata);
}
}
static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->internal; GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->internal;
@@ -1731,25 +1788,6 @@ static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
data->texel_size[0] = 1.0f / data->texel_size[2]; data->texel_size[0] = 1.0f / data->texel_size[2];
data->texel_size[1] = 1.0f / data->texel_size[3]; data->texel_size[1] = 1.0f / data->texel_size[3];
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
renderdata->glGenTextures(1, &data->palette);
if (!GL_CheckError("glGenTexures()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
renderdata->glActiveTexture(GL_TEXTURE1);
renderdata->glBindTexture(data->texture_type, data->palette);
renderdata->glTexImage2D(data->texture_type, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if (!GL_CheckError("glTexImage2D()", renderer)) {
SDL_free(data->pixel_data);
SDL_free(data);
return false;
}
SetTextureScaleMode(renderdata, data->texture_type, SDL_SCALEMODE_NEAREST);
SetTextureAddressMode(renderdata, data->texture_type, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (data->yuv) { if (data->yuv) {
data->texture_v = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER, 0); data->texture_v = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER, 0);
@@ -1904,22 +1942,6 @@ static bool GLES2_TexSubImage2D(GLES2_RenderData *data, GLenum target, GLint xof
return true; return true;
} }
static bool GLES2_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal;
GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal;
SDL_Palette *palette = texture->palette;
GLES2_ActivateRenderer(renderer);
data->drawstate.texture = NULL; /* we trash this state. */
data->glBindTexture(tdata->texture_type, tdata->palette);
data->glTexSubImage2D(tdata->texture_type, 0, 0, 0, palette->ncolors, 1, GL_RGBA, GL_UNSIGNED_BYTE, palette->colors);
return GL_CheckError("glTexSubImage2D()", renderer);
}
static bool GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, static bool GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
const void *pixels, int pitch) const void *pixels, int pitch)
{ {
@@ -2160,9 +2182,6 @@ static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
if (tdata->texture && !tdata->texture_external) { if (tdata->texture && !tdata->texture_external) {
data->glDeleteTextures(1, &tdata->texture); data->glDeleteTextures(1, &tdata->texture);
} }
if (tdata->palette) {
data->glDeleteTextures(1, &tdata->palette);
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (tdata->texture_v && !tdata->texture_v_external) { if (tdata->texture_v && !tdata->texture_v_external) {
data->glDeleteTextures(1, &tdata->texture_v); data->glDeleteTextures(1, &tdata->texture_v);
@@ -2290,8 +2309,10 @@ static bool GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
// Populate the function pointers for the module // Populate the function pointers for the module
renderer->WindowEvent = GLES2_WindowEvent; renderer->WindowEvent = GLES2_WindowEvent;
renderer->SupportsBlendMode = GLES2_SupportsBlendMode; renderer->SupportsBlendMode = GLES2_SupportsBlendMode;
renderer->CreatePalette = GLES2_CreatePalette;
renderer->UpdatePalette = GLES2_UpdatePalette;
renderer->DestroyPalette = GLES2_DestroyPalette;
renderer->CreateTexture = GLES2_CreateTexture; renderer->CreateTexture = GLES2_CreateTexture;
renderer->UpdateTexturePalette = GLES2_UpdateTexturePalette;
renderer->UpdateTexture = GLES2_UpdateTexture; renderer->UpdateTexture = GLES2_UpdateTexture;
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
renderer->UpdateTextureYUV = GLES2_UpdateTextureYUV; renderer->UpdateTextureYUV = GLES2_UpdateTextureYUV;

View File

@@ -99,6 +99,38 @@ static bool SW_GetOutputSize(SDL_Renderer *renderer, int *w, int *h)
return SDL_SetError("Software renderer doesn't have an output surface"); return SDL_SetError("Software renderer doesn't have an output surface");
} }
static bool SW_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
SDL_Palette *surface_palette = SDL_CreatePalette(256);
if (!surface_palette) {
return false;
}
palette->internal = surface_palette;
return true;
}
static bool SW_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
SDL_Palette *surface_palette = (SDL_Palette *)palette->internal;
return SDL_SetPaletteColors(surface_palette, colors, 0, ncolors);
}
static void SW_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
SDL_Palette *surface_palette = (SDL_Palette *)palette->internal;
SDL_DestroyPalette(surface_palette);
}
static bool SW_ChangeTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
SDL_Surface *surface = (SDL_Surface *)texture->internal;
SDL_Palette *surface_palette = NULL;
if (texture->palette) {
surface_palette = (SDL_Palette *)texture->palette->internal;
}
return SDL_SetSurfacePalette(surface, surface_palette);
}
static bool SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
SDL_Surface *surface = SDL_CreateSurface(texture->w, texture->h, texture->format); SDL_Surface *surface = SDL_CreateSurface(texture->w, texture->h, texture->format);
@@ -132,14 +164,6 @@ static bool SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_P
return true; return true;
} }
static bool SW_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
SDL_Surface *surface = (SDL_Surface *)texture->internal;
SDL_Palette *palette = texture->palette;
return SDL_SetPaletteColors(surface->palette, palette->colors, 0, palette->ncolors);
}
static bool SW_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, static bool SW_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)
{ {
@@ -1158,8 +1182,11 @@ bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, S
renderer->WindowEvent = SW_WindowEvent; renderer->WindowEvent = SW_WindowEvent;
renderer->GetOutputSize = SW_GetOutputSize; renderer->GetOutputSize = SW_GetOutputSize;
renderer->CreatePalette = SW_CreatePalette;
renderer->UpdatePalette = SW_UpdatePalette;
renderer->DestroyPalette = SW_DestroyPalette;
renderer->ChangeTexturePalette = SW_ChangeTexturePalette;
renderer->CreateTexture = SW_CreateTexture; renderer->CreateTexture = SW_CreateTexture;
renderer->UpdateTexturePalette = SW_UpdateTexturePalette;
renderer->UpdateTexture = SW_UpdateTexture; renderer->UpdateTexture = SW_UpdateTexture;
renderer->LockTexture = SW_LockTexture; renderer->LockTexture = SW_LockTexture;
renderer->UnlockTexture = SW_UnlockTexture; renderer->UnlockTexture = SW_UnlockTexture;

View File

@@ -240,11 +240,16 @@ typedef struct
VkFormat format; VkFormat format;
} VULKAN_Image; } VULKAN_Image;
// Per-palette data
typedef struct
{
VULKAN_Image image;
} VULKAN_PaletteData;
// Per-texture data // Per-texture data
typedef struct typedef struct
{ {
VULKAN_Image mainImage; VULKAN_Image mainImage;
VULKAN_Image paletteImage;
VkRenderPass mainRenderpasses[VULKAN_RENDERPASS_COUNT]; VkRenderPass mainRenderpasses[VULKAN_RENDERPASS_COUNT];
VkFramebuffer mainFramebuffer; VkFramebuffer mainFramebuffer;
VULKAN_Buffer stagingBuffer; VULKAN_Buffer stagingBuffer;
@@ -384,6 +389,8 @@ typedef struct
bool issueBatch; bool issueBatch;
} VULKAN_RenderData; } VULKAN_RenderData;
static bool VULKAN_UpdateTextureInternal(VULKAN_RenderData *rendererData, VkImage image, VkFormat format, int plane, int x, int y, int w, int h, const void *pixels, int pitch, VkImageLayout *imageLayout);
static SDL_PixelFormat VULKAN_VkFormatToSDLPixelFormat(VkFormat vkFormat) static SDL_PixelFormat VULKAN_VkFormatToSDLPixelFormat(VkFormat vkFormat)
{ {
switch (vkFormat) { switch (vkFormat) {
@@ -2533,6 +2540,45 @@ static bool VULKAN_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blend
return true; return true;
} }
static bool VULKAN_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
VULKAN_RenderData *data = (VULKAN_RenderData *)renderer->internal;
VULKAN_PaletteData *palettedata = (VULKAN_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
if (!palettedata) {
return false;
}
palette->internal = palettedata;
VkFormat format = SDLPixelFormatToVkTextureFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace);
VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkComponentMapping imageViewSwizzle = data->identitySwizzle;
VkResult result = VULKAN_AllocateImage(data, 0, 256, 1, format, usage, imageViewSwizzle, VK_NULL_HANDLE, &palettedata->image);
if (result != VK_SUCCESS) {
SET_ERROR_CODE("VULKAN_AllocateImage()", result);
return false;
}
return true;
}
static bool VULKAN_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
{
VULKAN_RenderData *data = (VULKAN_RenderData *)renderer->internal;
VULKAN_PaletteData *palettedata = (VULKAN_PaletteData *)palette->internal;
return VULKAN_UpdateTextureInternal(data, palettedata->image.image, palettedata->image.format, 0, 0, 0, ncolors, 1, colors, ncolors * sizeof(*colors), &palettedata->image.imageLayout);
}
static void VULKAN_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
{
VULKAN_RenderData *data = (VULKAN_RenderData *)renderer->internal;
VULKAN_PaletteData *palettedata = (VULKAN_PaletteData *)palette->internal;
if (palettedata) {
VULKAN_DestroyImage(data, &palettedata->image);
SDL_free(palettedata);
}
}
static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
{ {
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
@@ -2694,21 +2740,6 @@ static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, S
return false; return false;
} }
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
VkFormat paletteFormat;
if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
paletteFormat = VK_FORMAT_R8G8B8A8_SRGB;
} else {
paletteFormat = VK_FORMAT_R8G8B8A8_UNORM;
}
result = VULKAN_AllocateImage(rendererData, 0, 256, 1, paletteFormat, usage, imageViewSwizzle, textureData->samplerYcbcrConversion, &textureData->paletteImage);
if (result != VK_SUCCESS) {
SET_ERROR_CODE("VULKAN_AllocateImage()", result);
return false;
}
}
SDL_PropertiesID props = SDL_GetTextureProperties(texture); SDL_PropertiesID props = SDL_GetTextureProperties(texture);
SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_VULKAN_TEXTURE_NUMBER, (Sint64)textureData->mainImage.image); SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_VULKAN_TEXTURE_NUMBER, (Sint64)textureData->mainImage.image);
@@ -2746,10 +2777,6 @@ static void VULKAN_DestroyTexture(SDL_Renderer *renderer,
VULKAN_DestroyImage(rendererData, &textureData->mainImage); VULKAN_DestroyImage(rendererData, &textureData->mainImage);
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
VULKAN_DestroyImage(rendererData, &textureData->paletteImage);
}
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
if (textureData->samplerYcbcrConversion != VK_NULL_HANDLE) { if (textureData->samplerYcbcrConversion != VK_NULL_HANDLE) {
vkDestroySamplerYcbcrConversionKHR(rendererData->device, textureData->samplerYcbcrConversion, NULL); vkDestroySamplerYcbcrConversionKHR(rendererData->device, textureData->samplerYcbcrConversion, NULL);
@@ -2876,20 +2903,6 @@ static bool VULKAN_UpdateTextureInternal(VULKAN_RenderData *rendererData, VkImag
return true; return true;
} }
static bool VULKAN_UpdateTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture)
{
VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal;
VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal;
SDL_Palette *palette = texture->palette;
if (!textureData) {
return SDL_SetError("Texture is not currently available");
}
return VULKAN_UpdateTextureInternal(rendererData, textureData->paletteImage.image, textureData->paletteImage.format, 0, 0, 0, palette->ncolors, 1, palette->colors, palette->ncolors * sizeof(*palette->colors), &textureData->paletteImage.imageLayout);
}
static bool VULKAN_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, static bool VULKAN_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const void *srcPixels, const SDL_Rect *rect, const void *srcPixels,
int srcPitch) int srcPitch)
@@ -3900,8 +3913,9 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
} }
++numSamplers; ++numSamplers;
if (texture->format == SDL_PIXELFORMAT_INDEX8) { if (texture->palette) {
if (textureData->paletteImage.imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { VULKAN_PaletteData *palette = (VULKAN_PaletteData *)texture->palette->internal;
if (palette->image.imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
bool stoppedRenderPass = false; bool stoppedRenderPass = false;
if (rendererData->currentRenderPass != VK_NULL_HANDLE) { if (rendererData->currentRenderPass != VK_NULL_HANDLE) {
vkCmdEndRenderPass(rendererData->currentCommandBuffer); vkCmdEndRenderPass(rendererData->currentCommandBuffer);
@@ -3915,14 +3929,14 @@ static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand
VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
textureData->paletteImage.image, palette->image.image,
&textureData->paletteImage.imageLayout); &palette->image.imageLayout);
if (stoppedRenderPass) { if (stoppedRenderPass) {
VULKAN_BeginRenderPass(rendererData, VK_ATTACHMENT_LOAD_OP_LOAD, NULL); VULKAN_BeginRenderPass(rendererData, VK_ATTACHMENT_LOAD_OP_LOAD, NULL);
} }
} }
imageViews[numImageViews++] = textureData->paletteImage.imageView; imageViews[numImageViews++] = palette->image.imageView;
samplers[numSamplers] = VULKAN_GetSampler(rendererData, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); samplers[numSamplers] = VULKAN_GetSampler(rendererData, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
if (samplers[numSamplers] == VK_NULL_HANDLE) { if (samplers[numSamplers] == VK_NULL_HANDLE) {
@@ -4391,8 +4405,10 @@ static bool VULKAN_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SD
renderer->WindowEvent = VULKAN_WindowEvent; renderer->WindowEvent = VULKAN_WindowEvent;
renderer->SupportsBlendMode = VULKAN_SupportsBlendMode; renderer->SupportsBlendMode = VULKAN_SupportsBlendMode;
renderer->CreatePalette = VULKAN_CreatePalette;
renderer->UpdatePalette = VULKAN_UpdatePalette;
renderer->DestroyPalette = VULKAN_DestroyPalette;
renderer->CreateTexture = VULKAN_CreateTexture; renderer->CreateTexture = VULKAN_CreateTexture;
renderer->UpdateTexturePalette = VULKAN_UpdateTexturePalette;
renderer->UpdateTexture = VULKAN_UpdateTexture; renderer->UpdateTexture = VULKAN_UpdateTexture;
#ifdef SDL_HAVE_YUV #ifdef SDL_HAVE_YUV
renderer->UpdateTextureYUV = VULKAN_UpdateTextureYUV; renderer->UpdateTextureYUV = VULKAN_UpdateTextureYUV;