Skip to content

Commit b655901

Browse files
committed
Each application palette corresponds to one hardware palette
When the application modifies the palette, any textures that use it will automatically be updated.
1 parent 5d31163 commit b655901

File tree

11 files changed

+827
-446
lines changed

11 files changed

+827
-446
lines changed

src/render/SDL_render.c

Lines changed: 92 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,15 @@ static bool FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture)
347347
return true;
348348
}
349349

350+
static bool FlushRenderCommandsIfPaletteNeeded(SDL_Renderer *renderer, SDL_TexturePalette *palette)
351+
{
352+
if (palette->last_command_generation == renderer->render_command_generation) {
353+
// the current command queue depends on this palette, flush the queue now before it changes
354+
return FlushRenderCommands(renderer);
355+
}
356+
return true;
357+
}
358+
350359
static bool FlushRenderCommandsIfGPURenderStateNeeded(SDL_GPURenderState *state)
351360
{
352361
SDL_Renderer *renderer = state->renderer;
@@ -700,20 +709,22 @@ static bool QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, co
700709
static bool UpdateTexturePalette(SDL_Texture *texture)
701710
{
702711
SDL_Renderer *renderer = texture->renderer;
712+
SDL_Palette *public = texture->public_palette;
703713

704714
if (!SDL_ISPIXELFORMAT_INDEXED(texture->format)) {
705715
return true;
706716
}
707717

708-
if (!texture->palette) {
718+
if (!public) {
709719
return SDL_SetError("Texture doesn't have a palette");
710720
}
711721

712-
if (texture->palette_version == texture->palette->version) {
713-
return true;
714-
}
715-
716722
if (texture->native) {
723+
// Keep the native texture in sync with palette updates
724+
if (texture->palette_version == public->version) {
725+
return true;
726+
}
727+
717728
if (!FlushRenderCommandsIfTextureNeeded(texture->native)) {
718729
return false;
719730
}
@@ -727,17 +738,25 @@ static bool UpdateTexturePalette(SDL_Texture *texture)
727738
if (!result) {
728739
return false;
729740
}
730-
} else {
731-
if (!FlushRenderCommandsIfTextureNeeded(texture)) {
741+
texture->palette_version = public->version;
742+
return true;
743+
}
744+
745+
SDL_TexturePalette *palette = texture->palette;
746+
if (palette->version != public->version) {
747+
// Keep the native palette in sync with palette updates
748+
if (!FlushRenderCommandsIfPaletteNeeded(renderer, palette)) {
732749
return false;
733750
}
734751

735-
if (!renderer->UpdateTexturePalette(renderer, texture)) {
752+
if (!renderer->UpdatePalette(renderer, palette, public->ncolors, public->colors)) {
736753
return false;
737754
}
755+
756+
palette->version = public->version;
738757
}
739758

740-
texture->palette_version = texture->palette->version;
759+
palette->last_command_generation = renderer->render_command_generation;
741760
return true;
742761
}
743762

@@ -1143,6 +1162,11 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
11431162
UpdatePixelClipRect(renderer, &renderer->main_view);
11441163
UpdateMainViewDimensions(renderer);
11451164

1165+
renderer->palettes = SDL_CreateHashTable(0, false, SDL_HashPointer, SDL_KeyMatchPointer, SDL_DestroyHashValue, NULL);
1166+
if (!renderer->palettes) {
1167+
goto error;
1168+
}
1169+
11461170
// new textures start at zero, so we start at 1 so first render doesn't flush by accident.
11471171
renderer->render_command_generation = 1;
11481172

@@ -1656,7 +1680,7 @@ static bool SDL_UpdateTextureFromSurface(SDL_Texture *texture, SDL_Rect *rect, S
16561680
bool direct_update;
16571681

16581682
if (surface->format == texture->format &&
1659-
surface->palette == texture->palette &&
1683+
surface->palette == texture->public_palette &&
16601684
SDL_GetSurfaceColorspace(surface) == texture->colorspace) {
16611685
if (SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) {
16621686
/* Surface and Renderer formats are identical.
@@ -1682,7 +1706,7 @@ static bool SDL_UpdateTextureFromSurface(SDL_Texture *texture, SDL_Rect *rect, S
16821706
}
16831707
} else {
16841708
// Set up a destination surface for the texture update
1685-
SDL_Surface *temp = SDL_ConvertSurfaceAndColorspace(surface, texture->format, texture->palette, texture->colorspace, SDL_GetSurfaceProperties(surface));
1709+
SDL_Surface *temp = SDL_ConvertSurfaceAndColorspace(surface, texture->format, texture->public_palette, texture->colorspace, SDL_GetSurfaceProperties(surface));
16861710
if (temp) {
16871711
SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
16881712
SDL_DestroySurface(temp);
@@ -1901,16 +1925,56 @@ bool SDL_SetTexturePalette(SDL_Texture *texture, SDL_Palette *palette)
19011925
return SDL_SetError("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
19021926
}
19031927

1904-
if (palette != texture->palette) {
1905-
if (texture->palette) {
1906-
SDL_DestroyPalette(texture->palette);
1928+
if (palette != texture->public_palette) {
1929+
SDL_Renderer *renderer = texture->renderer;
1930+
1931+
if (texture->public_palette) {
1932+
SDL_DestroyPalette(texture->public_palette);
1933+
1934+
if (!texture->native) {
1935+
// Clean up the texture palette
1936+
--texture->palette->refcount;
1937+
if (texture->palette->refcount == 0) {
1938+
renderer->DestroyPalette(renderer, texture->palette);
1939+
SDL_RemoveFromHashTable(renderer->palettes, texture->public_palette);
1940+
}
1941+
texture->palette = NULL;
1942+
}
19071943
}
19081944

1909-
texture->palette = palette;
1945+
texture->public_palette = palette;
19101946
texture->palette_version = 0;
19111947

1912-
if (texture->palette) {
1913-
++texture->palette->refcount;
1948+
if (texture->public_palette) {
1949+
++texture->public_palette->refcount;
1950+
1951+
if (!texture->native) {
1952+
if (SDL_FindInHashTable(renderer->palettes, palette, (const void **)&texture->palette)) {
1953+
++texture->palette->refcount;
1954+
} else {
1955+
SDL_TexturePalette *texture_palette = (SDL_TexturePalette *)SDL_calloc(1, sizeof(*texture_palette));
1956+
if (!texture_palette) {
1957+
SDL_SetTexturePalette(texture, NULL);
1958+
return false;
1959+
}
1960+
if (!renderer->CreatePalette(renderer, texture_palette)) {
1961+
renderer->DestroyPalette(renderer, texture_palette);
1962+
SDL_SetTexturePalette(texture, NULL);
1963+
return false;
1964+
}
1965+
texture->palette = texture_palette;
1966+
texture->palette->refcount = 1;
1967+
1968+
if (!SDL_InsertIntoHashTable(renderer->palettes, palette, texture->palette, false)) {
1969+
SDL_SetTexturePalette(texture, NULL);
1970+
return false;
1971+
}
1972+
}
1973+
}
1974+
1975+
if (!texture->native && renderer->ChangeTexturePalette) {
1976+
renderer->ChangeTexturePalette(renderer, texture);
1977+
}
19141978
}
19151979

19161980
if (texture->palette_surface) {
@@ -1924,7 +1988,7 @@ SDL_Palette *SDL_GetTexturePalette(SDL_Texture *texture)
19241988
{
19251989
CHECK_TEXTURE_MAGIC(texture, NULL);
19261990

1927-
return texture->palette;
1991+
return texture->public_palette;
19281992
}
19291993

19301994
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
26022666
SDL_UnlockTexture(texture);
26032667
return false;
26042668
}
2605-
if (texture->palette) {
2606-
SDL_SetSurfacePalette(texture->locked_surface, texture->palette);
2669+
if (texture->public_palette) {
2670+
SDL_SetSurfacePalette(texture->locked_surface, texture->public_palette);
26072671
}
26082672

26092673
*surface = texture->locked_surface;
@@ -5513,7 +5577,7 @@ static void SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying)
55135577
{
55145578
SDL_Renderer *renderer;
55155579

5516-
if (texture->palette) {
5580+
if (texture->public_palette) {
55175581
SDL_SetTexturePalette(texture, NULL);
55185582
}
55195583

@@ -5634,6 +5698,13 @@ void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer)
56345698
SDL_assert(tex != renderer->textures); // satisfy static analysis.
56355699
}
56365700

5701+
// Free palette cache, which should be empty now
5702+
if (renderer->palettes) {
5703+
SDL_assert(SDL_HashTableEmpty(renderer->palettes));
5704+
SDL_DestroyHashTable(renderer->palettes);
5705+
renderer->palettes = NULL;
5706+
}
5707+
56375708
// Clean up renderer-specific resources
56385709
if (renderer->DestroyRenderer) {
56395710
renderer->DestroyRenderer(renderer);

src/render/SDL_sysrender.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ typedef struct SDL_RenderViewState
7070
SDL_FPoint current_scale; // this is just `scale * logical_scale`, precalculated, since we use it a lot.
7171
} SDL_RenderViewState;
7272

73+
// Define the SDL texture palette structure
74+
typedef struct SDL_TexturePalette
75+
{
76+
int refcount;
77+
Uint32 version;
78+
Uint32 last_command_generation; // last command queue generation this palette was in.
79+
void *internal; // Driver specific palette representation
80+
} SDL_TexturePalette;
81+
7382
// Define the SDL texture structure
7483
struct SDL_Texture
7584
{
@@ -90,7 +99,8 @@ struct SDL_Texture
9099
SDL_ScaleMode scaleMode; // The texture scale mode
91100
SDL_FColor color; // Texture modulation values
92101
SDL_RenderViewState view; // Target texture view state
93-
SDL_Palette *palette;
102+
SDL_Palette *public_palette;
103+
SDL_TexturePalette *palette;
94104
Uint32 palette_version;
95105
SDL_Surface *palette_surface;
96106

@@ -235,7 +245,10 @@ struct SDL_Renderer
235245

236246
void (*InvalidateCachedState)(SDL_Renderer *renderer);
237247
bool (*RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
238-
bool (*UpdateTexturePalette)(SDL_Renderer *renderer, SDL_Texture *texture);
248+
bool (*CreatePalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette);
249+
bool (*UpdatePalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors);
250+
void (*DestroyPalette)(SDL_Renderer *renderer, SDL_TexturePalette *palette);
251+
bool (*ChangeTexturePalette)(SDL_Renderer *renderer, SDL_Texture *texture);
239252
bool (*UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture,
240253
const SDL_Rect *rect, const void *pixels,
241254
int pitch);
@@ -301,6 +314,9 @@ struct SDL_Renderer
301314
SDL_Texture *target;
302315
SDL_Mutex *target_mutex;
303316

317+
// The list of palettes
318+
SDL_HashTable *palettes;
319+
304320
SDL_Colorspace output_colorspace;
305321
float SDR_white_point;
306322
float HDR_headroom;

0 commit comments

Comments
 (0)