From 1f3a0d12e657245bb7b72ba44b3835cece8bf351 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 30 Sep 2024 20:40:54 -0700 Subject: [PATCH] Made texture size and format public in the API Also added refcount to textures so they can be retained by application code. --- include/SDL3/SDL_render.h | 16 ++++++++++++++++ src/SDL_internal.h | 3 +++ src/render/SDL_render.c | 12 ++++++++---- src/render/SDL_sysrender.h | 31 ++++++++++++++++++------------- test/testautomation_render.c | 36 +++++++++++++++--------------------- test/testcamera.c | 13 +++++-------- test/testnative.c | 16 ++++++---------- test/testviewport.c | 15 +++++---------- 8 files changed, 76 insertions(+), 66 deletions(-) diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index 3096dc3b8..1ea737e98 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -118,11 +118,27 @@ typedef enum SDL_RendererLogicalPresentation */ typedef struct SDL_Renderer SDL_Renderer; +#ifndef SDL_INTERNAL /** * An efficient driver-specific representation of pixel data * * \since This struct is available since SDL 3.0.0. + * + * \sa SDL_CreateTexture + * \sa SDL_CreateTextureFromSurface + * \sa SDL_CreateTextureWithProperties + * \sa SDL_DestroyTexture */ +struct SDL_Texture +{ + SDL_PixelFormat format; /**< The format of the texture, read-only */ + int w; /**< The width of the texture, read-only. */ + int h; /**< The height of the texture, read-only. */ + + int refcount; /**< Application reference count, used when freeing texture */ +}; +#endif /* !SDL_INTERNAL */ + typedef struct SDL_Texture SDL_Texture; /* Function prototypes */ diff --git a/src/SDL_internal.h b/src/SDL_internal.h index 4a83cf4c7..498021849 100644 --- a/src/SDL_internal.h +++ b/src/SDL_internal.h @@ -222,6 +222,9 @@ #define SDL_EndThreadFunction NULL #endif +/* Enable internal definitions in SDL API headers */ +#define SDL_INTERNAL + #include #include diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 8663776a9..8d69e1ce1 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -1362,6 +1362,7 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert if (!texture) { return NULL; } + texture->refcount = 1; SDL_SetObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE, true); texture->colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace); texture->format = format; @@ -4990,12 +4991,10 @@ bool SDL_RenderPresent(SDL_Renderer *renderer) return true; } -static bool SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying) +static void SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying) { SDL_Renderer *renderer; - CHECK_TEXTURE_MAGIC(texture, false); - SDL_DestroyProperties(texture->props); renderer = texture->renderer; @@ -5036,11 +5035,16 @@ static bool SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying) texture->locked_surface = NULL; SDL_free(texture); - return true; } void SDL_DestroyTexture(SDL_Texture *texture) { + CHECK_TEXTURE_MAGIC(texture, ); + + if (--texture->refcount > 0) { + return; + } + SDL_DestroyTextureInternal(texture, false /* is_destroying */); } diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 0ae18fe98..203c7b0f1 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -71,17 +71,22 @@ typedef struct SDL_RenderViewState // Define the SDL texture structure struct SDL_Texture { - SDL_Colorspace colorspace; /**< The colorspace of the texture */ - float SDR_white_point; /**< The SDR white point for this content */ - float HDR_headroom; /**< The HDR headroom needed by this content */ - SDL_PixelFormat format; /**< The pixel format of the texture */ - SDL_TextureAccess access; /**< The texture access mode */ - int w; /**< The width of the texture */ - int h; /**< The height of the texture */ - SDL_BlendMode blendMode; /**< The texture blend mode */ - SDL_ScaleMode scaleMode; /**< The texture scale mode */ - SDL_FColor color; /**< Texture modulation values */ - SDL_RenderViewState view; /**< Target texture view state */ + // Public API definition + SDL_PixelFormat format; /**< The format of the texture, read-only */ + int w; /**< The width of the texture, read-only. */ + int h; /**< The height of the texture, read-only. */ + + int refcount; /**< Application reference count, used when freeing texture */ + + // Private API definition + SDL_Colorspace colorspace; // The colorspace of the texture + float SDR_white_point; // The SDR white point for this content + float HDR_headroom; // The HDR headroom needed by this content + SDL_TextureAccess access; // The texture access mode + SDL_BlendMode blendMode; // The texture blend mode + SDL_ScaleMode scaleMode; // The texture scale mode + SDL_FColor color; // Texture modulation values + SDL_RenderViewState view; // Target texture view state SDL_Renderer *renderer; @@ -91,13 +96,13 @@ struct SDL_Texture void *pixels; int pitch; SDL_Rect locked_rect; - SDL_Surface *locked_surface; /**< Locked region exposed as a SDL surface */ + SDL_Surface *locked_surface; // Locked region exposed as a SDL surface Uint32 last_command_generation; // last command queue generation this texture was in. SDL_PropertiesID props; - void *internal; /**< Driver specific texture representation */ + void *internal; // Driver specific texture representation SDL_Texture *prev; SDL_Texture *next; diff --git a/test/testautomation_render.c b/test/testautomation_render.c index 5e75ad0ec..9a74d7c1c 100644 --- a/test/testautomation_render.c +++ b/test/testautomation_render.c @@ -239,8 +239,7 @@ static int SDLCALL render_testBlit(void *arg) SDL_FRect rect; SDL_Texture *tface; SDL_Surface *referenceSurface = NULL; - float tw, th; - float i, j, ni, nj; + int i, j, ni, nj; int checkFailCount1; /* Clear surface. */ @@ -257,19 +256,18 @@ static int SDLCALL render_testBlit(void *arg) } /* Constant values. */ - CHECK_FUNC(SDL_GetTextureSize, (tface, &tw, &th)) - rect.w = tw; - rect.h = th; - ni = TESTRENDER_SCREEN_W - tw; - nj = TESTRENDER_SCREEN_H - th; + rect.w = (float)tface->w; + rect.h = (float)tface->h; + ni = TESTRENDER_SCREEN_W - tface->w; + nj = TESTRENDER_SCREEN_H - tface->h; /* Loop blit. */ checkFailCount1 = 0; for (j = 0; j <= nj; j += 4) { for (i = 0; i <= ni; i += 4) { /* Blitting. */ - rect.x = i; - rect.y = j; + rect.x = (float)i; + rect.y = (float)j; ret = SDL_RenderTexture(renderer, tface, NULL, &rect); if (!ret) { checkFailCount1++; @@ -631,7 +629,6 @@ static int SDLCALL render_testBlitColor(void *arg) SDL_FRect rect; SDL_Texture *tface; SDL_Surface *referenceSurface = NULL; - float tw, th; int i, j, ni, nj; int checkFailCount1; int checkFailCount2; @@ -647,11 +644,10 @@ static int SDLCALL render_testBlitColor(void *arg) } /* Constant values. */ - CHECK_FUNC(SDL_GetTextureSize, (tface, &tw, &th)) - rect.w = tw; - rect.h = th; - ni = TESTRENDER_SCREEN_W - (int)tw; - nj = TESTRENDER_SCREEN_H - (int)th; + rect.w = (float)tface->w; + rect.h = (float)tface->h; + ni = TESTRENDER_SCREEN_W - tface->w; + nj = TESTRENDER_SCREEN_H - tface->h; /* Test blitting with color mod. */ checkFailCount1 = 0; @@ -1423,7 +1419,6 @@ static int SDLCALL render_testUVWrapping(void *arg) SDL_Vertex vertices[6]; SDL_Vertex *verts = vertices; SDL_FColor color = { 1.0f, 1.0f, 1.0f, 1.0f }; - float tw, th; SDL_FRect rect; float min_U = -0.5f; float max_U = 1.5f; @@ -1442,11 +1437,10 @@ static int SDLCALL render_testUVWrapping(void *arg) return TEST_ABORTED; } - CHECK_FUNC(SDL_GetTextureSize, (tface, &tw, &th)) - rect.w = tw * 2; - rect.h = th * 2; - rect.x = (TESTRENDER_SCREEN_W - rect.w) / 2; - rect.y = (TESTRENDER_SCREEN_H - rect.h) / 2; + rect.w = (float)tface->w * 2; + rect.h = (float)tface->h * 2; + rect.x = (float)(TESTRENDER_SCREEN_W - rect.w) / 2; + rect.y = (float)(TESTRENDER_SCREEN_H - rect.h) / 2; /* * 0--1 diff --git a/test/testcamera.c b/test/testcamera.c index 893af6711..3855b3b1a 100644 --- a/test/testcamera.c +++ b/test/testcamera.c @@ -278,7 +278,6 @@ SDL_AppResult SDL_AppIterate(void *appstate) SDL_RenderClear(renderer); int win_w, win_h; - float tw, th; SDL_FRect d; Uint64 timestampNS = 0; SDL_Surface *frame_next = camera ? SDL_AcquireCameraFrame(camera, ×tampNS) : NULL; @@ -305,8 +304,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) if (frame_current) { if (!texture || - !SDL_GetTextureSize(texture, &tw, &th) || - (int)tw != frame_current->w || (int)th != frame_current->h) { + texture->w != frame_current->w || texture->h != frame_current->h) { /* Resize the window to match */ SDL_SetWindowSize(window, frame_current->w, frame_current->h); @@ -337,12 +335,11 @@ SDL_AppResult SDL_AppIterate(void *appstate) texture_updated = true; } - SDL_GetTextureSize(texture, &tw, &th); SDL_GetRenderOutputSize(renderer, &win_w, &win_h); - d.x = ((win_w - tw) / 2); - d.y = ((win_h - th) / 2); - d.w = tw; - d.h = th; + d.x = ((win_w - texture->w) / 2.0f); + d.y = ((win_h - texture->h) / 2.0f); + d.w = (float)texture->w; + d.h = (float)texture->h; SDL_RenderTexture(renderer, texture, NULL, &d); } diff --git a/test/testnative.c b/test/testnative.c index 95fb1c203..1a6238411 100644 --- a/test/testnative.c +++ b/test/testnative.c @@ -63,14 +63,12 @@ quit(int rc) static void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite) { - float sprite_w, sprite_h; int i; SDL_Rect viewport; SDL_FRect *position, *velocity; /* Query the sizes */ SDL_GetRenderViewport(renderer, &viewport); - SDL_GetTextureSize(sprite, &sprite_w, &sprite_h); /* Draw a gray background */ SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); @@ -81,12 +79,12 @@ static void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite) position = &positions[i]; velocity = &velocities[i]; position->x += velocity->x; - if ((position->x < 0) || (position->x >= (viewport.w - sprite_w))) { + if ((position->x < 0) || (position->x >= (viewport.w - sprite->w))) { velocity->x = -velocity->x; position->x += velocity->x; } position->y += velocity->y; - if ((position->y < 0) || (position->y >= (viewport.h - sprite_h))) { + if ((position->y < 0) || (position->y >= (viewport.h - sprite->h))) { velocity->y = -velocity->y; position->y += velocity->y; } @@ -108,7 +106,6 @@ int main(int argc, char *argv[]) SDL_Renderer *renderer; SDL_Texture *sprite; int window_w, window_h; - float sprite_w, sprite_h; SDL_Event event; /* Initialize test framework */ @@ -178,7 +175,6 @@ int main(int argc, char *argv[]) /* Allocate memory for the sprite info */ SDL_GetWindowSize(window, &window_w, &window_h); - SDL_GetTextureSize(sprite, &sprite_w, &sprite_h); positions = (SDL_FRect *)SDL_malloc(NUM_SPRITES * sizeof(*positions)); velocities = (SDL_FRect *)SDL_malloc(NUM_SPRITES * sizeof(*velocities)); if (!positions || !velocities) { @@ -186,10 +182,10 @@ int main(int argc, char *argv[]) quit(2); } for (i = 0; i < NUM_SPRITES; ++i) { - positions[i].x = (float)(SDL_rand(window_w - (int)sprite_w)); - positions[i].y = (float)(SDL_rand(window_h - (int)sprite_h)); - positions[i].w = sprite_w; - positions[i].h = sprite_h; + positions[i].x = (float)SDL_rand(window_w - sprite->w); + positions[i].y = (float)SDL_rand(window_h - sprite->h); + positions[i].w = (float)sprite->w; + positions[i].h = (float)sprite->h; velocities[i].x = 0.0f; velocities[i].y = 0.0f; while (velocities[i].x == 0.f && velocities[i].y == 0.f) { diff --git a/test/testviewport.c b/test/testviewport.c index 6943145ac..d4480b860 100644 --- a/test/testviewport.c +++ b/test/testviewport.c @@ -48,7 +48,6 @@ static void DrawOnViewport(SDL_Renderer *renderer) { SDL_FRect rect; SDL_Rect cliprect; - float w, h; /* Set the viewport */ SDL_SetRenderViewport(renderer, &viewport); @@ -91,15 +90,11 @@ static void DrawOnViewport(SDL_Renderer *renderer) SDL_RenderFillRect(renderer, &rect); /* Add a clip rect and fill it with the sprite */ - SDL_GetTextureSize(sprite, &w, &h); - rect.x = (viewport.w - w) / 2; - rect.y = (viewport.h - h) / 2; - rect.w = w; - rect.h = h; - cliprect.x = (int)rect.x; - cliprect.y = (int)rect.y; - cliprect.w = (int)rect.w; - cliprect.h = (int)rect.h; + cliprect.x = (viewport.w - sprite->w) / 2; + cliprect.y = (viewport.h - sprite->h) / 2; + cliprect.w = sprite->w; + cliprect.h = sprite->h; + SDL_RectToFRect(&cliprect, &rect); SDL_SetRenderClipRect(renderer, &cliprect); SDL_RenderTexture(renderer, sprite, NULL, &rect); SDL_SetRenderClipRect(renderer, NULL);