From c2004953197c1e09bd4f78c6056ad4861a817248 Mon Sep 17 00:00:00 2001 From: Nikita Kogut Date: Thu, 2 Jan 2025 07:49:24 +0200 Subject: [PATCH 1/6] render: add integration of SDL Renderer into custom GPU code --- include/SDL3/SDL_render.h | 237 ++++++++++++++++++------------ src/dynapi/SDL_dynapi.sym | 2 + src/dynapi/SDL_dynapi_overrides.h | 2 + src/dynapi/SDL_dynapi_procs.h | 2 + src/render/SDL_render.c | 231 ++++++++++++++++------------- src/render/SDL_sysrender.h | 72 ++++----- src/render/gpu/SDL_render_gpu.c | 86 ++++++++--- test/CMakeLists.txt | 1 + test/testgpu_with_sdlrender.c | 198 +++++++++++++++++++++++++ 9 files changed, 588 insertions(+), 243 deletions(-) create mode 100644 test/testgpu_with_sdlrender.c diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index f356b480ac37d..a5bda8d30edf6 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -50,13 +50,13 @@ #ifndef SDL_render_h_ #define SDL_render_h_ -#include #include #include #include #include #include #include +#include #include #include @@ -71,7 +71,7 @@ extern "C" { * * \since This macro is available since SDL 3.1.3. */ -#define SDL_SOFTWARE_RENDERER "software" +#define SDL_SOFTWARE_RENDERER "software" /** * Vertex structure. @@ -80,9 +80,9 @@ extern "C" { */ typedef struct SDL_Vertex { - SDL_FPoint position; /**< Vertex position, in SDL_Renderer coordinates */ - SDL_FColor color; /**< Vertex color */ - SDL_FPoint tex_coord; /**< Normalized texture coordinates, if needed */ + SDL_FPoint position; /**< Vertex position, in SDL_Renderer coordinates */ + SDL_FColor color; /**< Vertex color */ + SDL_FPoint tex_coord; /**< Normalized texture coordinates, if needed */ } SDL_Vertex; /** @@ -104,11 +104,11 @@ typedef enum SDL_TextureAccess */ typedef enum SDL_RendererLogicalPresentation { - SDL_LOGICAL_PRESENTATION_DISABLED, /**< There is no logical size in effect */ - SDL_LOGICAL_PRESENTATION_STRETCH, /**< The rendered content is stretched to the output resolution */ - SDL_LOGICAL_PRESENTATION_LETTERBOX, /**< The rendered content is fit to the largest dimension and the other dimension is letterboxed with black bars */ - SDL_LOGICAL_PRESENTATION_OVERSCAN, /**< The rendered content is fit to the smallest dimension and the other dimension extends beyond the output bounds */ - SDL_LOGICAL_PRESENTATION_INTEGER_SCALE /**< The rendered content is scaled up by integer multiples to fit the output resolution */ + SDL_LOGICAL_PRESENTATION_DISABLED, /**< There is no logical size in effect */ + SDL_LOGICAL_PRESENTATION_STRETCH, /**< The rendered content is stretched to the output resolution */ + SDL_LOGICAL_PRESENTATION_LETTERBOX, /**< The rendered content is fit to the largest dimension and the other dimension is letterboxed with black bars */ + SDL_LOGICAL_PRESENTATION_OVERSCAN, /**< The rendered content is fit to the smallest dimension and the other dimension extends beyond the output bounds */ + SDL_LOGICAL_PRESENTATION_INTEGER_SCALE /**< The rendered content is scaled up by integer multiples to fit the output resolution */ } SDL_RendererLogicalPresentation; /** @@ -132,11 +132,11 @@ typedef struct SDL_Renderer SDL_Renderer; */ 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. */ + 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 */ + int refcount; /**< Application reference count, used when freeing texture */ }; #endif /* !SDL_INTERNAL */ @@ -186,7 +186,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_GetNumRenderDrivers(void); * * \sa SDL_GetNumRenderDrivers */ -extern SDL_DECLSPEC const char * SDLCALL SDL_GetRenderDriver(int index); +extern SDL_DECLSPEC const char *SDLCALL SDL_GetRenderDriver(int index); /** * Create a window and default renderer. @@ -240,7 +240,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CreateWindowAndRenderer(const char *title, * \sa SDL_GetRenderDriver * \sa SDL_GetRendererName */ -extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window, const char *name); +extern SDL_DECLSPEC SDL_Renderer *SDLCALL SDL_CreateRenderer(SDL_Window *window, const char *name); /** * Create a 2D rendering context for a window, with the specified properties. @@ -279,6 +279,13 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window * - `SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER`: the * queue family index used for presentation. * + * With the gpu renderer: + * + * - `SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER`: user-provided SDL_GPUDevice pointer. + * You may use it if you want to combine custom SDL GPU rendering with 2D rendering from SDL_Renderer. + * This will switch the renderer into "user-managed" mode and in that case, + * you must also manually provide command buffer and swapchain texture for each frame. + * * \param props the properties to use. * \returns a valid rendering context or NULL if there was an error; call * SDL_GetError() for more information. @@ -293,19 +300,20 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window * \sa SDL_DestroyRenderer * \sa SDL_GetRendererName */ -extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_PropertiesID props); +extern SDL_DECLSPEC SDL_Renderer *SDLCALL SDL_CreateRendererWithProperties(SDL_PropertiesID props); -#define SDL_PROP_RENDERER_CREATE_NAME_STRING "SDL.renderer.create.name" -#define SDL_PROP_RENDERER_CREATE_WINDOW_POINTER "SDL.renderer.create.window" -#define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER "SDL.renderer.create.surface" -#define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER "SDL.renderer.create.output_colorspace" -#define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER "SDL.renderer.create.present_vsync" -#define SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER "SDL.renderer.create.vulkan.instance" -#define SDL_PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER "SDL.renderer.create.vulkan.surface" -#define SDL_PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER "SDL.renderer.create.vulkan.physical_device" -#define SDL_PROP_RENDERER_CREATE_VULKAN_DEVICE_POINTER "SDL.renderer.create.vulkan.device" -#define SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER "SDL.renderer.create.vulkan.graphics_queue_family_index" -#define SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER "SDL.renderer.create.vulkan.present_queue_family_index" +#define SDL_PROP_RENDERER_CREATE_NAME_STRING "SDL.renderer.create.name" +#define SDL_PROP_RENDERER_CREATE_WINDOW_POINTER "SDL.renderer.create.window" +#define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER "SDL.renderer.create.surface" +#define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER "SDL.renderer.create.output_colorspace" +#define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER "SDL.renderer.create.present_vsync" +#define SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER "SDL.renderer.create.vulkan.instance" +#define SDL_PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER "SDL.renderer.create.vulkan.surface" +#define SDL_PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER "SDL.renderer.create.vulkan.physical_device" +#define SDL_PROP_RENDERER_CREATE_VULKAN_DEVICE_POINTER "SDL.renderer.create.vulkan.device" +#define SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER "SDL.renderer.create.vulkan.graphics_queue_family_index" +#define SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER "SDL.renderer.create.vulkan.present_queue_family_index" +#define SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER "SDL.renderer.create.user_gpu_device" /** * Create a 2D software rendering context for a surface. @@ -326,7 +334,7 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_ * * \sa SDL_DestroyRenderer */ -extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateSoftwareRenderer(SDL_Surface *surface); +extern SDL_DECLSPEC SDL_Renderer *SDLCALL SDL_CreateSoftwareRenderer(SDL_Surface *surface); /** * Get the renderer associated with a window. @@ -339,7 +347,7 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateSoftwareRenderer(SDL_Surfac * * \since This function is available since SDL 3.1.3. */ -extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_GetRenderer(SDL_Window *window); +extern SDL_DECLSPEC SDL_Renderer *SDLCALL SDL_GetRenderer(SDL_Window *window); /** * Get the window associated with a renderer. @@ -352,7 +360,7 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_GetRenderer(SDL_Window *window); * * \since This function is available since SDL 3.1.3. */ -extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetRenderWindow(SDL_Renderer *renderer); +extern SDL_DECLSPEC SDL_Window *SDLCALL SDL_GetRenderWindow(SDL_Renderer *renderer); /** * Get the name of a renderer. @@ -368,7 +376,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetRenderWindow(SDL_Renderer *rende * \sa SDL_CreateRenderer * \sa SDL_CreateRendererWithProperties */ -extern SDL_DECLSPEC const char * SDLCALL SDL_GetRendererName(SDL_Renderer *renderer); +extern SDL_DECLSPEC const char *SDLCALL SDL_GetRendererName(SDL_Renderer *renderer); /** * Get the properties associated with a renderer. @@ -546,7 +554,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetCurrentRenderOutputSize(SDL_Renderer *re * \sa SDL_GetTextureSize * \sa SDL_UpdateTexture */ -extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer *renderer, SDL_PixelFormat format, SDL_TextureAccess access, int w, int h); +extern SDL_DECLSPEC SDL_Texture *SDLCALL SDL_CreateTexture(SDL_Renderer *renderer, SDL_PixelFormat format, SDL_TextureAccess access, int w, int h); /** * Create a texture from an existing surface. @@ -574,7 +582,7 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer *render * \sa SDL_CreateTextureWithProperties * \sa SDL_DestroyTexture */ -extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *surface); +extern SDL_DECLSPEC SDL_Texture *SDLCALL SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *surface); /** * Create a texture for a rendering context with the specified properties. @@ -686,7 +694,7 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Rende * \sa SDL_GetTextureSize * \sa SDL_UpdateTexture */ -extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_PropertiesID props); +extern SDL_DECLSPEC SDL_Texture *SDLCALL SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_PropertiesID props); #define SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER "SDL.texture.create.colorspace" #define SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER "SDL.texture.create.format" @@ -800,32 +808,32 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Re */ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetTextureProperties(SDL_Texture *texture); -#define SDL_PROP_TEXTURE_COLORSPACE_NUMBER "SDL.texture.colorspace" -#define SDL_PROP_TEXTURE_FORMAT_NUMBER "SDL.texture.format" -#define SDL_PROP_TEXTURE_ACCESS_NUMBER "SDL.texture.access" -#define SDL_PROP_TEXTURE_WIDTH_NUMBER "SDL.texture.width" -#define SDL_PROP_TEXTURE_HEIGHT_NUMBER "SDL.texture.height" -#define SDL_PROP_TEXTURE_SDR_WHITE_POINT_FLOAT "SDL.texture.SDR_white_point" -#define SDL_PROP_TEXTURE_HDR_HEADROOM_FLOAT "SDL.texture.HDR_headroom" -#define SDL_PROP_TEXTURE_D3D11_TEXTURE_POINTER "SDL.texture.d3d11.texture" -#define SDL_PROP_TEXTURE_D3D11_TEXTURE_U_POINTER "SDL.texture.d3d11.texture_u" -#define SDL_PROP_TEXTURE_D3D11_TEXTURE_V_POINTER "SDL.texture.d3d11.texture_v" -#define SDL_PROP_TEXTURE_D3D12_TEXTURE_POINTER "SDL.texture.d3d12.texture" -#define SDL_PROP_TEXTURE_D3D12_TEXTURE_U_POINTER "SDL.texture.d3d12.texture_u" -#define SDL_PROP_TEXTURE_D3D12_TEXTURE_V_POINTER "SDL.texture.d3d12.texture_v" -#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER "SDL.texture.opengl.texture" -#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_UV_NUMBER "SDL.texture.opengl.texture_uv" -#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_U_NUMBER "SDL.texture.opengl.texture_u" -#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_V_NUMBER "SDL.texture.opengl.texture_v" -#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_TARGET_NUMBER "SDL.texture.opengl.target" -#define SDL_PROP_TEXTURE_OPENGL_TEX_W_FLOAT "SDL.texture.opengl.tex_w" -#define SDL_PROP_TEXTURE_OPENGL_TEX_H_FLOAT "SDL.texture.opengl.tex_h" -#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_NUMBER "SDL.texture.opengles2.texture" -#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_UV_NUMBER "SDL.texture.opengles2.texture_uv" -#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_U_NUMBER "SDL.texture.opengles2.texture_u" -#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER "SDL.texture.opengles2.texture_v" -#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER "SDL.texture.opengles2.target" -#define SDL_PROP_TEXTURE_VULKAN_TEXTURE_NUMBER "SDL.texture.vulkan.texture" +#define SDL_PROP_TEXTURE_COLORSPACE_NUMBER "SDL.texture.colorspace" +#define SDL_PROP_TEXTURE_FORMAT_NUMBER "SDL.texture.format" +#define SDL_PROP_TEXTURE_ACCESS_NUMBER "SDL.texture.access" +#define SDL_PROP_TEXTURE_WIDTH_NUMBER "SDL.texture.width" +#define SDL_PROP_TEXTURE_HEIGHT_NUMBER "SDL.texture.height" +#define SDL_PROP_TEXTURE_SDR_WHITE_POINT_FLOAT "SDL.texture.SDR_white_point" +#define SDL_PROP_TEXTURE_HDR_HEADROOM_FLOAT "SDL.texture.HDR_headroom" +#define SDL_PROP_TEXTURE_D3D11_TEXTURE_POINTER "SDL.texture.d3d11.texture" +#define SDL_PROP_TEXTURE_D3D11_TEXTURE_U_POINTER "SDL.texture.d3d11.texture_u" +#define SDL_PROP_TEXTURE_D3D11_TEXTURE_V_POINTER "SDL.texture.d3d11.texture_v" +#define SDL_PROP_TEXTURE_D3D12_TEXTURE_POINTER "SDL.texture.d3d12.texture" +#define SDL_PROP_TEXTURE_D3D12_TEXTURE_U_POINTER "SDL.texture.d3d12.texture_u" +#define SDL_PROP_TEXTURE_D3D12_TEXTURE_V_POINTER "SDL.texture.d3d12.texture_v" +#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER "SDL.texture.opengl.texture" +#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_UV_NUMBER "SDL.texture.opengl.texture_uv" +#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_U_NUMBER "SDL.texture.opengl.texture_u" +#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_V_NUMBER "SDL.texture.opengl.texture_v" +#define SDL_PROP_TEXTURE_OPENGL_TEXTURE_TARGET_NUMBER "SDL.texture.opengl.target" +#define SDL_PROP_TEXTURE_OPENGL_TEX_W_FLOAT "SDL.texture.opengl.tex_w" +#define SDL_PROP_TEXTURE_OPENGL_TEX_H_FLOAT "SDL.texture.opengl.tex_h" +#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_NUMBER "SDL.texture.opengles2.texture" +#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_UV_NUMBER "SDL.texture.opengles2.texture_uv" +#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_U_NUMBER "SDL.texture.opengles2.texture_u" +#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER "SDL.texture.opengles2.texture_v" +#define SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER "SDL.texture.opengles2.target" +#define SDL_PROP_TEXTURE_VULKAN_TEXTURE_NUMBER "SDL.texture.vulkan.texture" /** * Get the renderer that created an SDL_Texture. @@ -838,7 +846,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetTextureProperties(SDL_Textur * * \since This function is available since SDL 3.1.3. */ -extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_GetRendererFromTexture(SDL_Texture *texture); +extern SDL_DECLSPEC SDL_Renderer *SDLCALL SDL_GetRendererFromTexture(SDL_Texture *texture); /** * Get the size of a texture, as floating point values. @@ -886,7 +894,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetTextureSize(SDL_Texture *texture, float */ extern SDL_DECLSPEC bool SDLCALL SDL_SetTextureColorMod(SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b); - /** * Set an additional color value multiplied into render copy operations. * @@ -916,7 +923,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetTextureColorMod(SDL_Texture *texture, Ui */ extern SDL_DECLSPEC bool SDLCALL SDL_SetTextureColorModFloat(SDL_Texture *texture, float r, float g, float b); - /** * Get the additional color value multiplied into render copy operations. * @@ -1181,10 +1187,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_UpdateTexture(SDL_Texture *texture, const S * \sa SDL_UpdateTexture */ extern SDL_DECLSPEC bool SDLCALL SDL_UpdateYUVTexture(SDL_Texture *texture, - const SDL_Rect *rect, - const Uint8 *Yplane, int Ypitch, - const Uint8 *Uplane, int Upitch, - const Uint8 *Vplane, int Vpitch); + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch); /** * Update a rectangle within a planar NV12 or NV21 texture with new pixels. @@ -1213,9 +1219,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_UpdateYUVTexture(SDL_Texture *texture, * \sa SDL_UpdateYUVTexture */ extern SDL_DECLSPEC bool SDLCALL SDL_UpdateNVTexture(SDL_Texture *texture, - const SDL_Rect *rect, - const Uint8 *Yplane, int Ypitch, - const Uint8 *UVplane, int UVpitch); + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch); /** * Lock a portion of the texture for **write-only** pixel access. @@ -1248,8 +1254,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_UpdateNVTexture(SDL_Texture *texture, * \sa SDL_UnlockTexture */ extern SDL_DECLSPEC bool SDLCALL SDL_LockTexture(SDL_Texture *texture, - const SDL_Rect *rect, - void **pixels, int *pitch); + const SDL_Rect *rect, + void **pixels, int *pitch); /** * Lock a portion of the texture for **write-only** pixel access, and expose @@ -1345,7 +1351,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer, SDL * * \sa SDL_SetRenderTarget */ -extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *renderer); +extern SDL_DECLSPEC SDL_Texture *SDLCALL SDL_GetRenderTarget(SDL_Renderer *renderer); /** * Set a device independent resolution and presentation mode for rendering. @@ -2076,9 +2082,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture(SDL_Renderer *renderer, SDL_T * \sa SDL_RenderTexture */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_FRect *srcrect, const SDL_FRect *dstrect, - double angle, const SDL_FPoint *center, - SDL_FlipMode flip); + const SDL_FRect *srcrect, const SDL_FRect *dstrect, + double angle, const SDL_FPoint *center, + SDL_FlipMode flip); /** * Copy a portion of the source texture to the current rendering target, with @@ -2107,8 +2113,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTextureRotated(SDL_Renderer *renderer * \sa SDL_RenderTexture */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_FRect *srcrect, const SDL_FPoint *origin, - const SDL_FPoint *right, const SDL_FPoint *down); + const SDL_FRect *srcrect, const SDL_FPoint *origin, + const SDL_FPoint *right, const SDL_FPoint *down); /** * Tile a portion of the texture to the current rendering target at subpixel @@ -2194,9 +2200,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9Grid(SDL_Renderer *renderer, * \sa SDL_RenderGeometryRaw */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, - SDL_Texture *texture, - const SDL_Vertex *vertices, int num_vertices, - const int *indices, int num_indices); + SDL_Texture *texture, + const SDL_Vertex *vertices, int num_vertices, + const int *indices, int num_indices); /** * Render a list of triangles, optionally using a texture and indices into the @@ -2226,12 +2232,12 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, * \sa SDL_RenderGeometry */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, - SDL_Texture *texture, - const float *xy, int xy_stride, - const SDL_FColor *color, int color_stride, - const float *uv, int uv_stride, - int num_vertices, - const void *indices, int num_indices, int size_indices); + SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride, + int num_vertices, + const void *indices, int num_indices, int size_indices); /** * Read pixels from the current rendering target. @@ -2252,7 +2258,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, * * \since This function is available since SDL 3.1.3. */ -extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect); +extern SDL_DECLSPEC SDL_Surface *SDLCALL SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect); /** * Update the screen with any rendering performed since the previous call. @@ -2386,7 +2392,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlushRenderer(SDL_Renderer *renderer); * * \sa SDL_GetRenderMetalCommandEncoder */ -extern SDL_DECLSPEC void * SDLCALL SDL_GetRenderMetalLayer(SDL_Renderer *renderer); +extern SDL_DECLSPEC void *SDLCALL SDL_GetRenderMetalLayer(SDL_Renderer *renderer); /** * Get the Metal command encoder for the current frame. @@ -2409,8 +2415,7 @@ extern SDL_DECLSPEC void * SDLCALL SDL_GetRenderMetalLayer(SDL_Renderer *rendere * * \sa SDL_GetRenderMetalLayer */ -extern SDL_DECLSPEC void * SDLCALL SDL_GetRenderMetalCommandEncoder(SDL_Renderer *renderer); - +extern SDL_DECLSPEC void *SDLCALL SDL_GetRenderMetalCommandEncoder(SDL_Renderer *renderer); /** * Add a set of synchronization semaphores for the current frame. @@ -2567,6 +2572,54 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, flo */ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(4); +/** + * Set custom swapchain texture for a GPU-based renderer. + * + * This function will set a custom swapchain texture for a GPU-based renderer, and make it ready for SDL_RenderPresent. + * Tihs function also has effect only on SDL_Renderer that was created with SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER property. + * Renderer must be created with a SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER property in order for this function to have effect. + * Please note, it's on user's respsonsibility to acquire and provide a valid swapchain texture before calling SDL_RenderPresent. + * If the texture is invalid or not provided, nothing will be rendered. + * For acquiring a swapchain texture, please refer to SDL_WaitAndAcquireGPUSwapchainTexture. + * + * \param renderer the renderer + * \param swapchain_texture the swapchain texture to be used for rendering + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetRenderGPUCommandBuffer + * \sa SDL_WaitAndAcquireGPUSwapchainTexture + * \sa SDL_RenderPresent + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderGPUSwapchainTexture(SDL_Renderer *renderer, SDL_GPUTexture *swapchain_texture); + +/** + * Set custom command buffer for a GPU-based renderer. + * + * This function will set a custom command buffer for a GPU-based renderer. + * It has affect only on SDL_Renderer that was created with SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER property. + * It is user responsibility to provide a valid command buffer before any render or upload calls of SDL_Renderer. + * All SDL_Render and texture creation calls require a valid command buffer to be set before calling. + * Note, such SDL_Renderer does not submit the command buffer automatically. + * + * \param renderer the renderer + * \param command_buffer the command buffer to be used to queue draw calls + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should only be called on the main thread. + * + * \since This function is available since SDL 3.2.0. + * + * \sa SDL_SetRenderGPUSwapchainTexture + * \sa SDL_AcquireGPUCommandBuffer + */ +extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderGPUCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *command_buffer); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 47ddb603d4150..1dc24f3da31ed 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1230,6 +1230,8 @@ SDL3_0.0.0 { SDL_GetTrayMenuParentEntry; SDL_GetTrayMenuParentTray; SDL_GetThreadState; + SDL_SetRenderGPUSwapchainTexture; + SDL_SetRenderGPUCommandBuffer; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 04828a5654c23..f53b22d865628 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1255,3 +1255,5 @@ #define SDL_GetTrayMenuParentEntry SDL_GetTrayMenuParentEntry_REAL #define SDL_GetTrayMenuParentTray SDL_GetTrayMenuParentTray_REAL #define SDL_GetThreadState SDL_GetThreadState_REAL +#define SDL_SetRenderGPUSwapchainTexture SDL_SetRenderGPUSwapchainTexture_REAL +#define SDL_SetRenderGPUCommandBuffer SDL_SetRenderGPUCommandBuffer_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 98e23b98f5740..14507d7da0ebf 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1263,3 +1263,5 @@ SDL_DYNAPI_PROC(SDL_TrayMenu*,SDL_GetTrayEntryParent,(SDL_TrayEntry *a),(a),retu SDL_DYNAPI_PROC(SDL_TrayEntry*,SDL_GetTrayMenuParentEntry,(SDL_TrayMenu *a),(a),return) SDL_DYNAPI_PROC(SDL_Tray*,SDL_GetTrayMenuParentTray,(SDL_TrayMenu *a),(a),return) SDL_DYNAPI_PROC(SDL_ThreadState,SDL_GetThreadState,(SDL_Thread *a),(a),return) +SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUSwapchainTexture,(SDL_Renderer *a,SDL_GPUTexture *b),(a,b),return) +SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUCommandBuffer,(SDL_Renderer *a,SDL_GPUCommandBuffer *b),(a,b),return) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 5ef2f7c1cbf4d..78ac20e538c4e 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -22,11 +22,11 @@ // The SDL 2D rendering system -#include "SDL_sysrender.h" -#include "SDL_render_debug_font.h" -#include "software/SDL_render_sw_c.h" #include "../video/SDL_pixels_c.h" #include "../video/SDL_video_c.h" +#include "SDL_render_debug_font.h" +#include "SDL_sysrender.h" +#include "software/SDL_render_sw_c.h" #ifdef SDL_PLATFORM_ANDROID #include "../core/android/SDL_android.h" @@ -46,25 +46,25 @@ this should probably be removed at some point in the future. --ryan. */ #endif #define SDL_PROP_WINDOW_RENDERER_POINTER "SDL.internal.window.renderer" -#define SDL_PROP_TEXTURE_PARENT_POINTER "SDL.internal.texture.parent" +#define SDL_PROP_TEXTURE_PARENT_POINTER "SDL.internal.texture.parent" -#define CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result) \ - if (!SDL_ObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER)) { \ - SDL_InvalidParamError("renderer"); \ - return result; \ +#define CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result) \ + if (!SDL_ObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER)) { \ + SDL_InvalidParamError("renderer"); \ + return result; \ } -#define CHECK_RENDERER_MAGIC(renderer, result) \ - CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result); \ - if ((renderer)->destroyed) { \ +#define CHECK_RENDERER_MAGIC(renderer, result) \ + CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result); \ + if ((renderer)->destroyed) { \ SDL_SetError("Renderer's window has been destroyed, can't use further"); \ - return result; \ + return result; \ } -#define CHECK_TEXTURE_MAGIC(texture, result) \ - if (!SDL_ObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE)) { \ - SDL_InvalidParamError("texture"); \ - return result; \ +#define CHECK_TEXTURE_MAGIC(texture, result) \ + if (!SDL_ObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE)) { \ + SDL_InvalidParamError("texture"); \ + return result; \ } // Predefined blend modes @@ -93,8 +93,8 @@ this should probably be removed at some point in the future. --ryan. */ SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, \ SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) -#define SDL_BLENDMODE_ADD_PREMULTIPLIED_FULL \ - SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, \ +#define SDL_BLENDMODE_ADD_PREMULTIPLIED_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, \ SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) #define SDL_BLENDMODE_MOD_FULL \ @@ -690,8 +690,8 @@ static bool QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL } static bool QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_FRect *srcquad, const SDL_FRect *dstrect, - const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y) + const SDL_FRect *srcquad, const SDL_FRect *dstrect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y) { SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_COPY_EX, texture); bool result = false; @@ -705,12 +705,12 @@ static bool QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, } static bool QueueCmdGeometry(SDL_Renderer *renderer, SDL_Texture *texture, - const float *xy, int xy_stride, - const SDL_FColor *color, int color_stride, - const float *uv, int uv_stride, - int num_vertices, - const void *indices, int num_indices, int size_indices, - float scale_x, float scale_y, SDL_TextureAddressMode texture_address_mode) + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride, + int num_vertices, + const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y, SDL_TextureAddressMode texture_address_mode) { SDL_RenderCommand *cmd; bool result = false; @@ -796,7 +796,6 @@ static void UpdateHDRProperties(SDL_Renderer *renderer) static void UpdateLogicalPresentation(SDL_Renderer *renderer); - int SDL_GetNumRenderDrivers(void) { #ifndef SDL_RENDER_DISABLED @@ -811,7 +810,7 @@ const char *SDL_GetRenderDriver(int index) #ifndef SDL_RENDER_DISABLED if (index < 0 || index >= SDL_GetNumRenderDrivers()) { SDL_SetError("index must be in the range of 0 - %d", - SDL_GetNumRenderDrivers() - 1); + SDL_GetNumRenderDrivers() - 1); return NULL; } return render_drivers[index]->name; @@ -952,7 +951,6 @@ static void SDL_CalculateSimulatedVSyncInterval(SDL_Renderer *renderer, SDL_Wind #endif // !SDL_RENDER_DISABLED - SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) { #ifndef SDL_RENDER_DISABLED @@ -1029,10 +1027,10 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) ++attempted; rc = driver->CreateRenderer(renderer, window, props); if (rc) { - break; // Yay, we got one! + break; // Yay, we got one! } SDL_DestroyRendererWithoutFreeing(renderer); - SDL_zerop(renderer); // make sure we don't leave function pointers from a previous CreateRenderer() in this struct. + SDL_zerop(renderer); // make sure we don't leave function pointers from a previous CreateRenderer() in this struct. } } @@ -1973,7 +1971,7 @@ bool SDL_GetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode *scaleMode) #ifdef SDL_HAVE_YUV static bool SDL_UpdateTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, - const void *pixels, int pitch) + const void *pixels, int pitch) { SDL_Texture *native = texture->native; SDL_Rect full_rect; @@ -2019,7 +2017,7 @@ static bool SDL_UpdateTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, #endif // SDL_HAVE_YUV static bool SDL_UpdateTextureNative(SDL_Texture *texture, const SDL_Rect *rect, - const void *pixels, int pitch) + const void *pixels, int pitch) { SDL_Texture *native = texture->native; @@ -2100,9 +2098,9 @@ bool SDL_UpdateTexture(SDL_Texture *texture, const SDL_Rect *rect, const void *p #ifdef SDL_HAVE_YUV static bool SDL_UpdateTextureYUVPlanar(SDL_Texture *texture, const SDL_Rect *rect, - const Uint8 *Yplane, int Ypitch, - const Uint8 *Uplane, int Upitch, - const Uint8 *Vplane, int Vpitch) + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch) { SDL_Texture *native = texture->native; SDL_Rect full_rect; @@ -2151,8 +2149,8 @@ static bool SDL_UpdateTextureYUVPlanar(SDL_Texture *texture, const SDL_Rect *rec } static bool SDL_UpdateTextureNVPlanar(SDL_Texture *texture, const SDL_Rect *rect, - const Uint8 *Yplane, int Ypitch, - const Uint8 *UVplane, int UVpitch) + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) { SDL_Texture *native = texture->native; SDL_Rect full_rect; @@ -2203,9 +2201,9 @@ static bool SDL_UpdateTextureNVPlanar(SDL_Texture *texture, const SDL_Rect *rect #endif // SDL_HAVE_YUV bool SDL_UpdateYUVTexture(SDL_Texture *texture, const SDL_Rect *rect, - const Uint8 *Yplane, int Ypitch, - const Uint8 *Uplane, int Upitch, - const Uint8 *Vplane, int Vpitch) + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch) { #ifdef SDL_HAVE_YUV SDL_Renderer *renderer; @@ -2270,8 +2268,8 @@ bool SDL_UpdateYUVTexture(SDL_Texture *texture, const SDL_Rect *rect, } bool SDL_UpdateNVTexture(SDL_Texture *texture, const SDL_Rect *rect, - const Uint8 *Yplane, int Ypitch, - const Uint8 *UVplane, int UVpitch) + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) { #ifdef SDL_HAVE_YUV SDL_Renderer *renderer; @@ -2331,14 +2329,14 @@ bool SDL_UpdateNVTexture(SDL_Texture *texture, const SDL_Rect *rect, #ifdef SDL_HAVE_YUV static bool SDL_LockTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, - void **pixels, int *pitch) + void **pixels, int *pitch) { return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch); } #endif // SDL_HAVE_YUV static bool SDL_LockTextureNative(SDL_Texture *texture, const SDL_Rect *rect, - void **pixels, int *pitch) + void **pixels, int *pitch) { texture->locked_rect = *rect; *pixels = (void *)((Uint8 *)texture->pixels + @@ -2462,7 +2460,7 @@ static void SDL_UnlockTextureNative(SDL_Texture *texture) void SDL_UnlockTexture(SDL_Texture *texture) { - CHECK_TEXTURE_MAGIC(texture,); + CHECK_TEXTURE_MAGIC(texture, ); if (texture->access != SDL_TEXTUREACCESS_STREAMING) { return; @@ -2541,7 +2539,7 @@ SDL_Texture *SDL_GetRenderTarget(SDL_Renderer *renderer) if (!renderer->target) { return NULL; } - return (SDL_Texture *) SDL_GetPointerProperty(SDL_GetTextureProperties(renderer->target), SDL_PROP_TEXTURE_PARENT_POINTER, renderer->target); + return (SDL_Texture *)SDL_GetPointerProperty(SDL_GetTextureProperties(renderer->target), SDL_PROP_TEXTURE_PARENT_POINTER, renderer->target); } static void UpdateLogicalPresentation(SDL_Renderer *renderer) @@ -2549,11 +2547,11 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer) if (renderer->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED) { renderer->main_view.logical_offset.x = renderer->main_view.logical_offset.y = 0.0f; renderer->main_view.logical_scale.x = renderer->main_view.logical_scale.y = 1.0f; - renderer->main_view.current_scale.x = renderer->main_view.scale.x; // skip the multiplications against 1.0f. + renderer->main_view.current_scale.x = renderer->main_view.scale.x; // skip the multiplications against 1.0f. renderer->main_view.current_scale.y = renderer->main_view.scale.y; UpdateMainViewDimensions(renderer); UpdatePixelClipRect(renderer, &renderer->main_view); - return; // All done! + return; // All done! } int iwidth, iheight; @@ -2642,9 +2640,9 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer) renderer->main_view.logical_offset.x = renderer->logical_dst_rect.x; renderer->main_view.logical_offset.y = renderer->logical_dst_rect.y; - UpdateMainViewDimensions(renderer); // this will replace pixel_w and pixel_h while making sure the dpi_scale is right. - renderer->main_view.pixel_w = (int) renderer->logical_dst_rect.w; - renderer->main_view.pixel_h = (int) renderer->logical_dst_rect.h; + UpdateMainViewDimensions(renderer); // this will replace pixel_w and pixel_h while making sure the dpi_scale is right. + renderer->main_view.pixel_w = (int)renderer->logical_dst_rect.w; + renderer->main_view.pixel_h = (int)renderer->logical_dst_rect.h; UpdatePixelViewport(renderer, &renderer->main_view); UpdatePixelClipRect(renderer, &renderer->main_view); } @@ -2664,7 +2662,10 @@ bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_ bool SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL_RendererLogicalPresentation *mode) { - #define SETVAL(ptr, val) if (ptr) { *ptr = val; } +#define SETVAL(ptr, val) \ + if (ptr) { \ + *ptr = val; \ + } SETVAL(w, 0); SETVAL(h, 0); @@ -2676,7 +2677,7 @@ bool SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SD SETVAL(h, renderer->logical_h); SETVAL(mode, renderer->logical_presentation_mode); - #undef SETVAL +#undef SETVAL return true; } @@ -3531,7 +3532,7 @@ static bool RenderLinesWithRectsF(SDL_Renderer *renderer, const SDL_FPoint *poin } } else { result &= RenderLineBresenham(renderer, (int)SDL_roundf(points[i].x), (int)SDL_roundf(points[i].y), - (int)SDL_roundf(points[i + 1].x), (int)SDL_roundf(points[i + 1].y), draw_last); + (int)SDL_roundf(points[i + 1].x), (int)SDL_roundf(points[i + 1].y), draw_last); } drew_line = true; } @@ -3609,10 +3610,10 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count *ptr_xy++ = q.x; *ptr_xy++ = q.y + scale_y; -#define ADD_TRIANGLE(i1, i2, i3) \ - *ptr_indices++ = cur_index + (i1); \ - *ptr_indices++ = cur_index + (i2); \ - *ptr_indices++ = cur_index + (i3); \ +#define ADD_TRIANGLE(i1, i2, i3) \ + *ptr_indices++ = cur_index + (i1); \ + *ptr_indices++ = cur_index + (i2); \ + *ptr_indices++ = cur_index + (i3); \ num_indices += 3; // closed polyline, donĀ“t draw twice the point @@ -3688,7 +3689,7 @@ bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count } else if (renderer->line_method == SDL_RENDERLINEMETHOD_POINTS) { result = RenderLinesWithRectsF(renderer, points, count); - } else if (renderer->view->scale.x != 1.0f || renderer->view->scale.y != 1.0f) { /* we checked for logical scale elsewhere. */ + } else if (renderer->view->scale.x != 1.0f || renderer->view->scale.y != 1.0f) { /* we checked for logical scale elsewhere. */ result = RenderLinesWithRectsF(renderer, points, count); } else { result = QueueCmdDrawLines(renderer, points, count); @@ -3914,7 +3915,7 @@ bool SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_F } bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_FRect *srcrect, const SDL_FPoint *origin, const SDL_FPoint *right, const SDL_FPoint *down) + const SDL_FRect *srcrect, const SDL_FPoint *origin, const SDL_FPoint *right, const SDL_FPoint *down) { SDL_FRect real_srcrect; SDL_FRect real_dstrect; @@ -4024,15 +4025,14 @@ bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, &texture->color, 0 /* color_stride */, uv, uv_stride, num_vertices, indices, num_indices, size_indices, - scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP - ); + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); } return result; } bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_FRect *srcrect, const SDL_FRect *dstrect, - const double angle, const SDL_FPoint *center, const SDL_FlipMode flip) + const SDL_FRect *srcrect, const SDL_FRect *dstrect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip) { SDL_FRect real_srcrect; SDL_FRect real_dstrect; @@ -4481,9 +4481,9 @@ bool SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const } bool SDL_RenderGeometry(SDL_Renderer *renderer, - SDL_Texture *texture, - const SDL_Vertex *vertices, int num_vertices, - const int *indices, int num_indices) + SDL_Texture *texture, + const SDL_Vertex *vertices, int num_vertices, + const int *indices, int num_indices) { if (vertices) { const float *xy = &vertices->position.x; @@ -4563,12 +4563,12 @@ static int remap_indices( #define DEBUG_SW_RENDER_GEOMETRY 0 // For the software renderer, try to reinterpret triangles as SDL_Rect static bool SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, - SDL_Texture *texture, - const float *xy, int xy_stride, - const SDL_FColor *color, int color_stride, - const float *uv, int uv_stride, - int num_vertices, - const void *indices, int num_indices, int size_indices) + SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride, + int num_vertices, + const void *indices, int num_indices, int size_indices) { int i; bool result = true; @@ -4871,12 +4871,12 @@ static bool SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, #endif // SDL_VIDEO_RENDER_SW bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, - SDL_Texture *texture, - const float *xy, int xy_stride, - const SDL_FColor *color, int color_stride, - const float *uv, int uv_stride, - int num_vertices, - const void *indices, int num_indices, int size_indices) + SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride, + int num_vertices, + const void *indices, int num_indices, int size_indices) { int i; int count = indices ? num_indices : num_vertices; @@ -5033,9 +5033,9 @@ static void SDL_RenderApplyWindowShape(SDL_Renderer *renderer) renderer->shape_texture = SDL_CreateTextureFromSurface(renderer, shape); SDL_SetTextureBlendMode(renderer->shape_texture, - SDL_ComposeCustomBlendMode( - SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD, - SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD)); + SDL_ComposeCustomBlendMode( + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD, + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD)); } renderer->shape_surface = shape; } @@ -5097,7 +5097,7 @@ bool SDL_RenderPresent(SDL_Renderer *renderer) presented = false; } else #endif - if (!renderer->RenderPresent(renderer)) { + if (!renderer->RenderPresent(renderer)) { presented = false; } @@ -5247,7 +5247,7 @@ void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer) void SDL_DestroyRenderer(SDL_Renderer *renderer) { - CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer,); + CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, ); // if we've already destroyed the renderer through SDL_DestroyWindow, we just need // to free the renderer pointer. This lets apps destroy the window and renderer @@ -5271,7 +5271,7 @@ void SDL_DestroyRenderer(SDL_Renderer *renderer) curr = curr->next; } - SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, false); // It's no longer magical... + SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, false); // It's no longer magical... SDL_free(renderer); } @@ -5465,12 +5465,11 @@ bool SDL_GetRenderVSync(SDL_Renderer *renderer, int *vsync) return true; } - #define SDL_DEBUG_FONT_GLYPHS_PER_ROW 14 static bool CreateDebugTextAtlas(SDL_Renderer *renderer) { - SDL_assert(renderer->debug_char_texture_atlas == NULL); // don't double-create it! + SDL_assert(renderer->debug_char_texture_atlas == NULL); // don't double-create it! const int charWidth = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; const int charHeight = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; @@ -5489,7 +5488,7 @@ static bool CreateDebugTextAtlas(SDL_Renderer *renderer) int row = 0; for (int glyph = 0; glyph < SDL_DEBUG_FONT_NUM_GLYPHS; glyph++) { // find top-left of this glyph in destination surface. The +2's account for glyph padding. - Uint8 *linepos = (((Uint8 *)atlas->pixels) + ((row * (charHeight + 2) + 1) * pitch)) + ((column * (charWidth + 2) + 1) * sizeof (Uint32)); + Uint8 *linepos = (((Uint8 *)atlas->pixels) + ((row * (charHeight + 2) + 1) * pitch)) + ((column * (charWidth + 2) + 1) * sizeof(Uint32)); const Uint8 *charpos = SDL_RenderDebugTextFontData + (glyph * 8); // Draw the glyph to the surface... @@ -5515,7 +5514,7 @@ static bool CreateDebugTextAtlas(SDL_Renderer *renderer) } } - SDL_assert((row < rows) || ((row == rows) && (column == 0))); // make sure we didn't overflow the surface. + SDL_assert((row < rows) || ((row == rows) && (column == 0))); // make sure we didn't overflow the surface. // Convert temp surface into texture SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, atlas); @@ -5530,7 +5529,7 @@ static bool CreateDebugTextAtlas(SDL_Renderer *renderer) static bool DrawDebugCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c) { - SDL_assert(renderer->debug_char_texture_atlas != NULL); // should have been created by now! + SDL_assert(renderer->debug_char_texture_atlas != NULL); // should have been created by now! const int charWidth = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; const int charHeight = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; @@ -5538,21 +5537,21 @@ static bool DrawDebugCharacter(SDL_Renderer *renderer, float x, float y, Uint32 // Character index in cache Uint32 ci = c; if ((ci <= 32) || ((ci >= 127) && (ci <= 160))) { - return true; // these are just completely blank chars, don't bother doing anything. + return true; // these are just completely blank chars, don't bother doing anything. } else if (ci >= SDL_DEBUG_FONT_NUM_GLYPHS) { - ci = SDL_DEBUG_FONT_NUM_GLYPHS - 1; // use our "not a valid/supported character" glyph. + ci = SDL_DEBUG_FONT_NUM_GLYPHS - 1; // use our "not a valid/supported character" glyph. } else if (ci < 127) { - ci -= 33; // adjust for the 33 blank glyphs at the start + ci -= 33; // adjust for the 33 blank glyphs at the start } else { - ci -= 67; // adjust for the 33 blank glyphs at the start AND the 34 gap in the middle. + ci -= 67; // adjust for the 33 blank glyphs at the start AND the 34 gap in the middle. } - const float src_x = (float) (((ci % SDL_DEBUG_FONT_GLYPHS_PER_ROW) * (charWidth + 2)) + 1); - const float src_y = (float) (((ci / SDL_DEBUG_FONT_GLYPHS_PER_ROW) * (charHeight + 2)) + 1); + const float src_x = (float)(((ci % SDL_DEBUG_FONT_GLYPHS_PER_ROW) * (charWidth + 2)) + 1); + const float src_y = (float)(((ci / SDL_DEBUG_FONT_GLYPHS_PER_ROW) * (charHeight + 2)) + 1); // Draw texture onto destination - const SDL_FRect srect = { src_x, src_y, (float) charWidth, (float) charHeight }; - const SDL_FRect drect = { x, y, (float) charWidth, (float) charHeight }; + const SDL_FRect srect = { src_x, src_y, (float)charWidth, (float)charHeight }; + const SDL_FRect drect = { x, y, (float)charWidth, (float)charHeight }; return SDL_RenderTexture(renderer, renderer->debug_char_texture_atlas, &srect, &drect); } @@ -5610,3 +5609,37 @@ bool SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRI SDL_free(str); return retval; } + +bool SDL_SetRenderGPUSwapchainTexture(SDL_Renderer *renderer, SDL_GPUTexture *swapchain_texture) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + if (strncmp(renderer->name, "gpu", 3) != 0) { + return SDL_SetError("SDL_SetRenderGPUSwapchainTexture must be called on a GPU-based renderer, got '%s'", renderer->name); + } + + if (!swapchain_texture) { + return SDL_SetError("swapchain_texture must not be NULL"); + } + + SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER, swapchain_texture); + + return true; +} + +bool SDL_SetRenderGPUCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *command_buffer) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + if (strncmp(renderer->name, "gpu", 3) != 0) { + return SDL_SetError("SDL_SetRenderGPUCommandBuffer must be called on a GPU-based renderer, got '%s'", renderer->name); + } + + if (!command_buffer) { + return SDL_SetError("command_buffer must not be NULL"); + } + + GPU_SetCommandBuffer(renderer, command_buffer); + + return true; +} \ No newline at end of file diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 9c39bb1de71f4..2810b67970516 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -32,6 +32,9 @@ extern "C" { #endif +// Used by GPU driver to retrieve user-provided swapchain texture +#define SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER "SDL.internal.renderer.gpu.swapchain" + typedef enum SDL_TextureAddressMode { SDL_TEXTURE_ADDRESS_AUTO, @@ -67,28 +70,28 @@ typedef struct SDL_RenderViewState SDL_FPoint scale; SDL_FPoint logical_scale; SDL_FPoint logical_offset; - 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; // Define the SDL texture structure struct SDL_Texture { // 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. */ + 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 */ + 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_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; @@ -104,7 +107,7 @@ struct SDL_Texture SDL_PropertiesID props; - void *internal; // Driver specific texture representation + void *internal; // Driver specific texture representation SDL_Texture *prev; SDL_Texture *next; @@ -183,39 +186,39 @@ struct SDL_Renderer bool (*QueueSetViewport)(SDL_Renderer *renderer, SDL_RenderCommand *cmd); bool (*QueueSetDrawColor)(SDL_Renderer *renderer, SDL_RenderCommand *cmd); bool (*QueueDrawPoints)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, - int count); + int count); bool (*QueueDrawLines)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, - int count); + int count); bool (*QueueFillRects)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, - int count); + int count); bool (*QueueCopy)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, - const SDL_FRect *srcrect, const SDL_FRect *dstrect); + const SDL_FRect *srcrect, const SDL_FRect *dstrect); bool (*QueueCopyEx)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, - const SDL_FRect *srcquad, const SDL_FRect *dstrect, - const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y); + const SDL_FRect *srcquad, const SDL_FRect *dstrect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y); bool (*QueueGeometry)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, - const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, - int num_vertices, const void *indices, int num_indices, int size_indices, - float scale_x, float scale_y); + const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, + int num_vertices, const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y); void (*InvalidateCachedState)(SDL_Renderer *renderer); bool (*RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize); bool (*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); #ifdef SDL_HAVE_YUV bool (*UpdateTextureYUV)(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch); + bool (*UpdateTextureNV)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const Uint8 *Yplane, int Ypitch, - const Uint8 *Uplane, int Upitch, - const Uint8 *Vplane, int Vpitch); - bool (*UpdateTextureNV)(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_Rect *rect, - const Uint8 *Yplane, int Ypitch, - const Uint8 *UVplane, int UVpitch); + const Uint8 *UVplane, int UVpitch); #endif bool (*LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_Rect *rect, void **pixels, int *pitch); + const SDL_Rect *rect, void **pixels, int *pitch); void (*UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture); void (*SetTextureScaleMode)(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode); bool (*SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture); @@ -307,7 +310,7 @@ struct SDL_Renderer SDL_Texture *debug_char_texture_atlas; - bool destroyed; // already destroyed by SDL_DestroyWindow; just free this struct in SDL_DestroyRenderer. + bool destroyed; // already destroyed by SDL_DestroyWindow; just free this struct in SDL_DestroyRenderer. void *internal; @@ -366,6 +369,9 @@ extern void *SDL_AllocateRenderVertices(SDL_Renderer *renderer, size_t numbytes, // Let the video subsystem destroy a renderer without making its pointer invalid. extern void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer); +// We must expose this function for manual control over renderer command buffer +extern void GPU_SetCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *cmd_buf); + // Ends C function definitions when using C++ #ifdef __cplusplus } diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index 10c0f6c905982..5386cfae60ffa 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -41,6 +41,7 @@ typedef struct GPU_RenderData SDL_GPUDevice *device; GPU_Shaders shaders; GPU_PipelineCache pipeline_cache; + bool user_managed_device; struct { @@ -255,6 +256,10 @@ static bool GPU_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, return SDL_SetError("update size overflow"); } + if (renderdata->user_managed_device && !renderdata->state.command_buffer) { + return SDL_SetError("Command buffer must be set for a renderer with user-managed device to upload textures"); + } + SDL_GPUTransferBufferCreateInfo tbci; SDL_zero(tbci); tbci.size = (Uint32)data_size; @@ -528,6 +533,10 @@ static void Draw( RestartRenderPass(data); } + if (!data->state.command_buffer) { + return; + } + GPU_VertexShaderID v_shader; GPU_FragmentShaderID f_shader; SDL_GPURenderPass *pass = data->state.render_pass; @@ -905,7 +914,8 @@ static SDL_Surface *GPU_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect SDL_GPUFence *fence = SDL_SubmitGPUCommandBufferAndAcquireFence(data->state.command_buffer); SDL_WaitForGPUFences(data->device, true, &fence, 1); SDL_ReleaseGPUFence(data->device, fence); - data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device); + if (!data->user_managed_device) + data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device); void *mapped_tbuf = SDL_MapGPUTransferBuffer(data->device, tbuf, false); @@ -958,10 +968,26 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) SDL_GPUTexture *swapchain; Uint32 swapchain_texture_width, swapchain_texture_height; - bool result = SDL_WaitAndAcquireGPUSwapchainTexture(data->state.command_buffer, renderer->window, &swapchain, &swapchain_texture_width, &swapchain_texture_height); + if (!data->user_managed_device) { + bool result = SDL_WaitAndAcquireGPUSwapchainTexture(data->state.command_buffer, renderer->window, &swapchain, &swapchain_texture_width, &swapchain_texture_height); + + if (!result) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to acquire swapchain texture: %s", SDL_GetError()); + } + } else { + SDL_PropertiesID props = SDL_GetRendererProperties(renderer); + if (SDL_HasProperty(props, SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER)) { + swapchain = SDL_GetPointerProperty(props, SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER, NULL); + swapchain_texture_width = renderer->output_pixel_w; + swapchain_texture_height = renderer->output_pixel_h; + } else { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer with user-managed GPU device requires a swapchain texture pointer"); + swapchain = NULL; + } - if (!result) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to acquire swapchain texture: %s", SDL_GetError()); + if (!data->state.command_buffer) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer with user-managed GPU device requires a command buffer"); + } } if (swapchain != NULL) { @@ -979,17 +1005,23 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) SDL_BlitGPUTexture(data->state.command_buffer, &blit_info); - SDL_SubmitGPUCommandBuffer(data->state.command_buffer); + if (!data->user_managed_device) + SDL_SubmitGPUCommandBuffer(data->state.command_buffer); if (swapchain_texture_width != data->backbuffer.width || swapchain_texture_height != data->backbuffer.height) { SDL_ReleaseGPUTexture(data->device, data->backbuffer.texture); CreateBackbuffer(data, swapchain_texture_width, swapchain_texture_height, SDL_GetGPUSwapchainTextureFormat(data->device, renderer->window)); } } else { - SDL_SubmitGPUCommandBuffer(data->state.command_buffer); + if (!data->user_managed_device) + SDL_SubmitGPUCommandBuffer(data->state.command_buffer); } - data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device); + if (data->user_managed_device) { + data->state.command_buffer = NULL; + } else { + data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device); + } return true; } @@ -1021,7 +1053,7 @@ static void GPU_DestroyRenderer(SDL_Renderer *renderer) return; } - if (data->state.command_buffer) { + if (!data->user_managed_device && data->state.command_buffer) { SDL_SubmitGPUCommandBuffer(data->state.command_buffer); data->state.command_buffer = NULL; } @@ -1034,14 +1066,15 @@ static void GPU_DestroyRenderer(SDL_Renderer *renderer) SDL_ReleaseGPUTexture(data->device, data->backbuffer.texture); } - if (renderer->window) { + if (!data->user_managed_device && renderer->window) { SDL_ReleaseWindowFromGPUDevice(data->device, renderer->window); } ReleaseVertexBuffer(data); GPU_DestroyPipelineCache(&data->pipeline_cache); GPU_ReleaseShaders(&data->shaders, data->device); - SDL_DestroyGPUDevice(data->device); + if (!data->user_managed_device) + SDL_DestroyGPUDevice(data->device); SDL_free(data); } @@ -1205,7 +1238,13 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, lowpower); GPU_FillSupportedShaderFormats(create_props); - data->device = SDL_CreateGPUDeviceWithProperties(create_props); + + if (SDL_HasProperty(create_props, SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER)) { + data->device = (SDL_GPUDevice *)SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER, NULL); + data->user_managed_device = true; + } else { + data->device = SDL_CreateGPUDeviceWithProperties(create_props); + } if (!data->device) { return false; @@ -1228,19 +1267,22 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P return false; } - if (!SDL_ClaimWindowForGPUDevice(data->device, window)) { - return false; + if (!data->user_managed_device) { + if (!SDL_ClaimWindowForGPUDevice(data->device, window)) { + return false; + } } data->swapchain.composition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR; data->swapchain.present_mode = SDL_GPU_PRESENTMODE_VSYNC; - int vsync = (int)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); - ChoosePresentMode(data->device, window, vsync, &data->swapchain.present_mode); - - SDL_SetGPUSwapchainParameters(data->device, window, data->swapchain.composition, data->swapchain.present_mode); + if (!data->user_managed_device) { + int vsync = (int)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); + ChoosePresentMode(data->device, window, vsync, &data->swapchain.present_mode); + SDL_SetGPUSwapchainParameters(data->device, window, data->swapchain.composition, data->swapchain.present_mode); - SDL_SetGPUAllowedFramesInFlight(data->device, 1); + SDL_SetGPUAllowedFramesInFlight(data->device, 1); + } SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32); SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); @@ -1255,7 +1297,7 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P data->state.draw_color.a = 1.0f; data->state.viewport.min_depth = 0; data->state.viewport.max_depth = 1; - data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device); + data->state.command_buffer = data->user_managed_device ? NULL : SDL_AcquireGPUCommandBuffer(data->device); int w, h; SDL_GetWindowSizeInPixels(window, &w, &h); @@ -1269,6 +1311,12 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P return true; } +void GPU_SetCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *command_buffer) +{ + GPU_RenderData *data = (GPU_RenderData *)renderer->internal; + data->state.command_buffer = command_buffer; +} + SDL_RenderDriver GPU_RenderDriver = { GPU_CreateRenderer, "gpu" }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c6e9b4853ab50..2766444901adc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -347,6 +347,7 @@ add_sdl_test_executable(testgeometry TESTUTILS SOURCES testgeometry.c) add_sdl_test_executable(testgl SOURCES testgl.c) add_sdl_test_executable(testgles SOURCES testgles.c) add_sdl_test_executable(testgpu_simple_clear SOURCES testgpu_simple_clear.c) +add_sdl_test_executable(testgpu_with_sdlrender SOURCES testgpu_with_sdlrender.c) add_sdl_test_executable(testgpu_spinning_cube SOURCES testgpu_spinning_cube.c) if(ANDROID) target_link_libraries(testgles PRIVATE GLESv1_CM) diff --git a/test/testgpu_with_sdlrender.c b/test/testgpu_with_sdlrender.c new file mode 100644 index 0000000000000..da1e9e6acf4e6 --- /dev/null +++ b/test/testgpu_with_sdlrender.c @@ -0,0 +1,198 @@ +/* + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +#define SDL_MAIN_USE_CALLBACKS 1 +#include +#include +#include + +/* we don't actually use any shaders in this one, so just give us lots of options for backends. */ +#define TESTGPU_SUPPORTED_FORMATS (SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXBC | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB) + +static SDLTest_CommonState *state; +static SDL_GPUDevice *gpu_device; +static Uint64 then = 0; +static Uint64 frames = 0; +static SDL_Renderer *renderer = NULL; +static SDL_Texture *icon_texture = NULL; + +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + const SDL_DisplayMode *mode; + int dw, dh; + + /* Initialize test framework */ + state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); + if (!state) { + return SDL_APP_FAILURE; + } + + state->skip_renderer = 1; + + if (!SDLTest_CommonDefaultArgs(state, argc, argv) || !SDLTest_CommonInit(state)) { + SDLTest_CommonQuit(state); + return SDL_APP_FAILURE; + } + + gpu_device = SDL_CreateGPUDevice(TESTGPU_SUPPORTED_FORMATS, true, NULL); + if (!gpu_device) { + SDL_Log("SDL_CreateGPUDevice failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_ClaimWindowForGPUDevice(gpu_device, state->windows[0])) { + SDL_Log("SDL_ClaimWindowForGPUDevice failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); + if (mode) { + SDL_Log("Screen BPP : %d\n", SDL_BITSPERPIXEL(mode->format)); + } + SDL_GetWindowSize(state->windows[0], &dw, &dh); + SDL_Log("Window Size : %d,%d\n", dw, dh); + SDL_GetWindowSizeInPixels(state->windows[0], &dw, &dh); + SDL_Log("Draw Size : %d,%d\n", dw, dh); + SDL_Log("\n"); + + SDL_PropertiesID props = SDL_CreateProperties(); + + SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, "gpu"); + SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, state->windows[0]); + SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER, gpu_device); + + renderer = SDL_CreateRendererWithProperties( + props); + + if (!renderer) { + SDL_Log("SDL_CreateRendererWithProperties failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + SDL_Surface *bmp_surf = SDL_LoadBMP("icon.bmp"); + + if (!bmp_surf) { + SDL_Log("SDL_LoadBMP failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + /* Creation of any resources with manually controlled GPU renderer require a command buffer to be set*/ + SDL_GPUCommandBuffer *cmdbuf = SDL_AcquireGPUCommandBuffer(gpu_device); + + if (cmdbuf == NULL) { + SDL_Log("SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_SetRenderGPUCommandBuffer(renderer, cmdbuf)) { + SDL_Log("SDL_SetRenderGPUCommandBuffer failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + icon_texture = SDL_CreateTextureFromSurface(renderer, bmp_surf); + + SDL_SubmitGPUCommandBuffer(cmdbuf); + + SDL_DestroySurface(bmp_surf); + + if (!icon_texture) { + SDL_Log("SDL_LoadBMP failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + then = SDL_GetTicks(); + + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + return SDLTest_CommonEventMainCallbacks(state, event); +} + +SDL_AppResult SDL_AppIterate(void *appstate) +{ + SDL_GPUCommandBuffer *cmdbuf = SDL_AcquireGPUCommandBuffer(gpu_device); + + if (cmdbuf == NULL) { + SDL_Log("SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + SDL_GPUTexture *swapchainTexture; + if (!SDL_WaitAndAcquireGPUSwapchainTexture(cmdbuf, state->windows[0], &swapchainTexture, NULL, NULL)) { + SDL_Log("SDL_AcquireGPUSwapchainTexture failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (swapchainTexture != NULL) { + const double currentTime = (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); + SDL_GPURenderPass *renderPass; + SDL_GPUColorTargetInfo color_target_info; + SDL_zero(color_target_info); + color_target_info.texture = swapchainTexture; + color_target_info.clear_color.r = (float)(0.5 + 0.5 * SDL_sin(currentTime)); + color_target_info.clear_color.g = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 2 / 3)); + color_target_info.clear_color.b = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 4 / 3)); + color_target_info.clear_color.a = 1.0f; + color_target_info.load_op = SDL_GPU_LOADOP_CLEAR; + color_target_info.store_op = SDL_GPU_STOREOP_STORE; + + /* Custom GPU rendering */ + renderPass = SDL_BeginGPURenderPass(cmdbuf, &color_target_info, 1, NULL); + /* Render universe or whatever */ + SDL_EndGPURenderPass(renderPass); + + /* 2D rendering with SDL renderer */ + if (!SDL_SetRenderGPUCommandBuffer(renderer, cmdbuf)) { + SDL_Log("SDL_SetRenderGPUCommandBuffer failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (!SDL_SetRenderGPUSwapchainTexture(renderer, swapchainTexture)) { + SDL_Log("SDL_SetRenderGPUSwapchainTexture failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + SDL_FRect rect = { 32, 32, 64, 64 }; + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + SDL_RenderFillRect(renderer, &rect); + SDL_FRect tex_rect = { 150, 150, 32, 32 }; + SDL_RenderTexture(renderer, icon_texture, NULL, &tex_rect); + + SDL_RenderPresent(renderer); + + SDL_SubmitGPUCommandBuffer(cmdbuf); + } else { + /* Swapchain is unavailable, cancel work */ + SDL_CancelGPUCommandBuffer(cmdbuf); + } + + frames++; + + return SDL_APP_CONTINUE; +} + +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + /* Print out some timing information */ + const Uint64 now = SDL_GetTicks(); + if (now > then) { + SDL_Log("%2.2f frames per second\n", ((double)frames * 1000) / (now - then)); + } + + SDL_DestroyTexture(icon_texture); + SDL_DestroyRenderer(renderer); + SDL_ReleaseWindowFromGPUDevice(gpu_device, state->windows[0]); + SDL_DestroyGPUDevice(gpu_device); + SDLTest_CommonQuit(state); +} From 8986153d3035a460a90c9f2628b1b3d4c2a0c596 Mon Sep 17 00:00:00 2001 From: Nikita Kogut Date: Fri, 3 Jan 2025 01:26:16 +0200 Subject: [PATCH 2/6] Reimplement GPU present renderer for managed device --- include/SDL3/SDL_render.h | 18 ++- src/dynapi/SDL_dynapi.sym | 2 +- src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 2 +- src/render/SDL_render.c | 179 +++++++++++++-------------- src/render/SDL_sysrender.h | 1 + src/render/gpu/SDL_render_gpu.c | 195 +++++++++++++++++++++++++----- test/testgpu_with_sdlrender.c | 21 ++-- 8 files changed, 281 insertions(+), 138 deletions(-) diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index a5bda8d30edf6..1731e504a99bc 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -2573,17 +2573,16 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, flo extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(4); /** - * Set custom swapchain texture for a GPU-based renderer. + * Draw all queued render commands to SDL_GPUTexture * - * This function will set a custom swapchain texture for a GPU-based renderer, and make it ready for SDL_RenderPresent. - * Tihs function also has effect only on SDL_Renderer that was created with SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER property. - * Renderer must be created with a SDL_PROP_RENDERER_CREATE_USER_GPU_DEVICE_POINTER property in order for this function to have effect. - * Please note, it's on user's respsonsibility to acquire and provide a valid swapchain texture before calling SDL_RenderPresent. + * This function is only useful for GPU-based renderers, especially when the GPU device is manually controlled. * If the texture is invalid or not provided, nothing will be rendered. - * For acquiring a swapchain texture, please refer to SDL_WaitAndAcquireGPUSwapchainTexture. + * The target texture may also be a swapchain texture, obtained from SDL_WaitAndAcquireGPUSwapchainTexture, + * which is the recommended way to combine GPU and SDL_Renderer usage. * * \param renderer the renderer - * \param swapchain_texture the swapchain texture to be used for rendering + * \param target the GPU texture to render to + * \param format the format of the target texture * \returns true on success or false on failure; call SDL_GetError() for more * information. * @@ -2591,11 +2590,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextFormat(SDL_Renderer *rendere * * \since This function is available since SDL 3.2.0. * - * \sa SDL_SetRenderGPUCommandBuffer - * \sa SDL_WaitAndAcquireGPUSwapchainTexture * \sa SDL_RenderPresent + * \sa SDL_WaitAndAcquireGPUSwapchainTexture */ -extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderGPUSwapchainTexture(SDL_Renderer *renderer, SDL_GPUTexture *swapchain_texture); +extern SDL_DECLSPEC bool SDLCALL SDL_RenderPresentToGPUTexture(SDL_Renderer *renderer, SDL_GPUTexture *target, SDL_GPUTextureFormat format); /** * Set custom command buffer for a GPU-based renderer. diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 1dc24f3da31ed..b21957f70efe3 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1230,8 +1230,8 @@ SDL3_0.0.0 { SDL_GetTrayMenuParentEntry; SDL_GetTrayMenuParentTray; SDL_GetThreadState; - SDL_SetRenderGPUSwapchainTexture; SDL_SetRenderGPUCommandBuffer; + SDL_RenderPresentToGPUTexture; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index f53b22d865628..699be3d33a454 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1257,3 +1257,4 @@ #define SDL_GetThreadState SDL_GetThreadState_REAL #define SDL_SetRenderGPUSwapchainTexture SDL_SetRenderGPUSwapchainTexture_REAL #define SDL_SetRenderGPUCommandBuffer SDL_SetRenderGPUCommandBuffer_REAL +#define SDL_RenderPresentToGPUTexture SDL_RenderPresentToGPUTexture_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 14507d7da0ebf..e9fd466b9cbe3 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1263,5 +1263,5 @@ SDL_DYNAPI_PROC(SDL_TrayMenu*,SDL_GetTrayEntryParent,(SDL_TrayEntry *a),(a),retu SDL_DYNAPI_PROC(SDL_TrayEntry*,SDL_GetTrayMenuParentEntry,(SDL_TrayMenu *a),(a),return) SDL_DYNAPI_PROC(SDL_Tray*,SDL_GetTrayMenuParentTray,(SDL_TrayMenu *a),(a),return) SDL_DYNAPI_PROC(SDL_ThreadState,SDL_GetThreadState,(SDL_Thread *a),(a),return) -SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUSwapchainTexture,(SDL_Renderer *a,SDL_GPUTexture *b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUCommandBuffer,(SDL_Renderer *a,SDL_GPUCommandBuffer *b),(a,b),return) +SDL_DYNAPI_PROC(bool,SDL_RenderPresentToGPUTexture,(SDL_Renderer *a,SDL_GPUTexture *b,SDL_GPUTextureFormat c),(a,b,c),return) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 78ac20e538c4e..154f95cbbe937 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -212,93 +212,91 @@ static SDL_INLINE void DebugLogRenderCommands(const SDL_RenderCommand *cmd) SDL_Log("Render commands to flush:"); while (cmd) { switch (cmd->command) { - case SDL_RENDERCMD_NO_OP: - SDL_Log(" %u. no-op", i++); - break; - - case SDL_RENDERCMD_SETVIEWPORT: - SDL_Log(" %u. set viewport (first=%u, rect={(%d, %d), %dx%d})", i++, - (unsigned int) cmd->data.viewport.first, - cmd->data.viewport.rect.x, cmd->data.viewport.rect.y, - cmd->data.viewport.rect.w, cmd->data.viewport.rect.h); - break; - - case SDL_RENDERCMD_SETCLIPRECT: - SDL_Log(" %u. set cliprect (enabled=%s, rect={(%d, %d), %dx%d})", i++, - cmd->data.cliprect.enabled ? "true" : "false", - cmd->data.cliprect.rect.x, cmd->data.cliprect.rect.y, - cmd->data.cliprect.rect.w, cmd->data.cliprect.rect.h); - break; + case SDL_RENDERCMD_NO_OP: + SDL_Log(" %u. no-op", i++); + break; - case SDL_RENDERCMD_SETDRAWCOLOR: - SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++, - (unsigned int) cmd->data.color.first, - (int) cmd->data.color.color.r, (int) cmd->data.color.color.g, - (int) cmd->data.color.color.b, (int) cmd->data.color.color.a, cmd->data.color.color_scale); - break; + case SDL_RENDERCMD_SETVIEWPORT: + SDL_Log(" %u. set viewport (first=%u, rect={(%d, %d), %dx%d})", i++, + (unsigned int)cmd->data.viewport.first, + cmd->data.viewport.rect.x, cmd->data.viewport.rect.y, + cmd->data.viewport.rect.w, cmd->data.viewport.rect.h); + break; - case SDL_RENDERCMD_CLEAR: - SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++, - (unsigned int) cmd->data.color.first, - (int) cmd->data.color.color.r, (int) cmd->data.color.color.g, - (int) cmd->data.color.color.b, (int) cmd->data.color.color.a, cmd->data.color.color_scale); - break; + case SDL_RENDERCMD_SETCLIPRECT: + SDL_Log(" %u. set cliprect (enabled=%s, rect={(%d, %d), %dx%d})", i++, + cmd->data.cliprect.enabled ? "true" : "false", + cmd->data.cliprect.rect.x, cmd->data.cliprect.rect.y, + cmd->data.cliprect.rect.w, cmd->data.cliprect.rect.h); + break; - case SDL_RENDERCMD_DRAW_POINTS: - SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, - (unsigned int) cmd->data.draw.first, - (unsigned int) cmd->data.draw.count, - (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, - (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, - (int) cmd->data.draw.blend, cmd->data.draw.color_scale); - break; + case SDL_RENDERCMD_SETDRAWCOLOR: + SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++, + (unsigned int)cmd->data.color.first, + (int)cmd->data.color.color.r, (int)cmd->data.color.color.g, + (int)cmd->data.color.color.b, (int)cmd->data.color.color.a, cmd->data.color.color_scale); + break; - case SDL_RENDERCMD_DRAW_LINES: - SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, - (unsigned int) cmd->data.draw.first, - (unsigned int) cmd->data.draw.count, - (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, - (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, - (int) cmd->data.draw.blend, cmd->data.draw.color_scale); - break; + case SDL_RENDERCMD_CLEAR: + SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++, + (unsigned int)cmd->data.color.first, + (int)cmd->data.color.color.r, (int)cmd->data.color.color.g, + (int)cmd->data.color.color.b, (int)cmd->data.color.color.a, cmd->data.color.color_scale); + break; - case SDL_RENDERCMD_FILL_RECTS: - SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, - (unsigned int) cmd->data.draw.first, - (unsigned int) cmd->data.draw.count, - (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, - (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, - (int) cmd->data.draw.blend, cmd->data.draw.color_scale); - break; + case SDL_RENDERCMD_DRAW_POINTS: + SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, + (unsigned int)cmd->data.draw.first, + (unsigned int)cmd->data.draw.count, + (int)cmd->data.draw.color.r, (int)cmd->data.draw.color.g, + (int)cmd->data.draw.color.b, (int)cmd->data.draw.color.a, + (int)cmd->data.draw.blend, cmd->data.draw.color_scale); + break; - case SDL_RENDERCMD_COPY: - SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, - (unsigned int) cmd->data.draw.first, - (unsigned int) cmd->data.draw.count, - (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, - (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, - (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); - break; + case SDL_RENDERCMD_DRAW_LINES: + SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, + (unsigned int)cmd->data.draw.first, + (unsigned int)cmd->data.draw.count, + (int)cmd->data.draw.color.r, (int)cmd->data.draw.color.g, + (int)cmd->data.draw.color.b, (int)cmd->data.draw.color.a, + (int)cmd->data.draw.blend, cmd->data.draw.color_scale); + break; + case SDL_RENDERCMD_FILL_RECTS: + SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, + (unsigned int)cmd->data.draw.first, + (unsigned int)cmd->data.draw.count, + (int)cmd->data.draw.color.r, (int)cmd->data.draw.color.g, + (int)cmd->data.draw.color.b, (int)cmd->data.draw.color.a, + (int)cmd->data.draw.blend, cmd->data.draw.color_scale); + break; - case SDL_RENDERCMD_COPY_EX: - SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, - (unsigned int) cmd->data.draw.first, - (unsigned int) cmd->data.draw.count, - (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, - (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, - (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); - break; + case SDL_RENDERCMD_COPY: + SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, + (unsigned int)cmd->data.draw.first, + (unsigned int)cmd->data.draw.count, + (int)cmd->data.draw.color.r, (int)cmd->data.draw.color.g, + (int)cmd->data.draw.color.b, (int)cmd->data.draw.color.a, + (int)cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); + break; - case SDL_RENDERCMD_GEOMETRY: - SDL_Log(" %u. geometry (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, - (unsigned int) cmd->data.draw.first, - (unsigned int) cmd->data.draw.count, - (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, - (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, - (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); - break; + case SDL_RENDERCMD_COPY_EX: + SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, + (unsigned int)cmd->data.draw.first, + (unsigned int)cmd->data.draw.count, + (int)cmd->data.draw.color.r, (int)cmd->data.draw.color.g, + (int)cmd->data.draw.color.b, (int)cmd->data.draw.color.a, + (int)cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); + break; + case SDL_RENDERCMD_GEOMETRY: + SDL_Log(" %u. geometry (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, + (unsigned int)cmd->data.draw.first, + (unsigned int)cmd->data.draw.count, + (int)cmd->data.draw.color.r, (int)cmd->data.draw.color.g, + (int)cmd->data.draw.color.b, (int)cmd->data.draw.color.a, + (int)cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); + break; } cmd = cmd->next; } @@ -5610,36 +5608,39 @@ bool SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRI return retval; } -bool SDL_SetRenderGPUSwapchainTexture(SDL_Renderer *renderer, SDL_GPUTexture *swapchain_texture) +bool SDL_SetRenderGPUCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *command_buffer) { CHECK_RENDERER_MAGIC(renderer, false); if (strncmp(renderer->name, "gpu", 3) != 0) { - return SDL_SetError("SDL_SetRenderGPUSwapchainTexture must be called on a GPU-based renderer, got '%s'", renderer->name); + return SDL_SetError("SDL_SetRenderGPUCommandBuffer must be called on a GPU-based renderer, got '%s'", renderer->name); } - if (!swapchain_texture) { - return SDL_SetError("swapchain_texture must not be NULL"); + if (!command_buffer) { + return SDL_SetError("command_buffer must not be NULL"); } - SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER, swapchain_texture); + GPU_SetCommandBuffer(renderer, command_buffer); return true; } -bool SDL_SetRenderGPUCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *command_buffer) +bool SDL_RenderPresentToGPUTexture(SDL_Renderer *renderer, SDL_GPUTexture *target, SDL_GPUTextureFormat format) { CHECK_RENDERER_MAGIC(renderer, false); if (strncmp(renderer->name, "gpu", 3) != 0) { - return SDL_SetError("SDL_SetRenderGPUCommandBuffer must be called on a GPU-based renderer, got '%s'", renderer->name); + return SDL_SetError("SDL_RenderPresentToGPUTexture must be called on a GPU-based renderer, got '%s'", renderer->name); } - if (!command_buffer) { - return SDL_SetError("command_buffer must not be NULL"); + if (!target) { + return SDL_SetError("target must not be NULL"); } - GPU_SetCommandBuffer(renderer, command_buffer); + // Hack: We need to flush the command buffer before we present the texture + if (!SDL_RenderPresent(renderer)) { + return false; + } - return true; -} \ No newline at end of file + return GPU_PresentToUserTexture(renderer, target, format); +} diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 2810b67970516..47f5d5e8aacd2 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -371,6 +371,7 @@ extern void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer); // We must expose this function for manual control over renderer command buffer extern void GPU_SetCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *cmd_buf); +extern bool GPU_PresentToUserTexture(SDL_Renderer *renderer, SDL_GPUTexture *textur, SDL_GPUTextureFormat format); // Ends C function definitions when using C++ #ifdef __cplusplus diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index 5386cfae60ffa..657e76611058d 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -62,6 +62,8 @@ typedef struct GPU_RenderData SDL_GPUTransferBuffer *transfer_buf; SDL_GPUBuffer *buffer; Uint32 buffer_size; + + SDL_GPUBuffer *present_quad_buffer; } vertices; struct @@ -639,6 +641,77 @@ static bool InitVertexBuffer(GPU_RenderData *data, Uint32 size) return true; } +static bool InitPresentQuadBuffer(GPU_RenderData *data) +{ + SDL_GPUBufferCreateInfo create_buf_info; + SDL_zero(create_buf_info); + create_buf_info.size = sizeof(SDL_Vertex) * 6; + create_buf_info.usage = SDL_GPU_BUFFERUSAGE_VERTEX; + + data->vertices.present_quad_buffer = SDL_CreateGPUBuffer(data->device, &create_buf_info); + + if (!data->vertices.present_quad_buffer) { + return false; + } + + SDL_GPUCommandBuffer *cbuf = SDL_AcquireGPUCommandBuffer(data->device); + + if (!cbuf) { + return false; + } + + SDL_GPUCopyPass *cpass = SDL_BeginGPUCopyPass(cbuf); + + if (!cpass) { + SDL_CancelGPUCommandBuffer(cbuf); + return false; + } + + SDL_GPUTransferBufferCreateInfo tbci; + SDL_zero(tbci); + tbci.size = create_buf_info.size; + tbci.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + + SDL_GPUTransferBuffer *transfer_buf = SDL_CreateGPUTransferBuffer(data->device, &tbci); + + if (!transfer_buf) { + SDL_CancelGPUCommandBuffer(cbuf); + return false; + } + + SDL_Vertex *verts = (SDL_Vertex *)SDL_MapGPUTransferBuffer(data->device, transfer_buf, false); + + SDL_FColor vert_color = { 1.0f, 1.0f, 1.0f, 1.0f }; + + verts[0] = (SDL_Vertex){ { -1.0f, -1.0f }, vert_color, { 0.0f, 1.0f } }; + verts[1] = (SDL_Vertex){ { 1.0f, -1.0f }, vert_color, { 1.0f, 1.0f } }; + verts[2] = (SDL_Vertex){ { 1.0f, 1.0f }, vert_color, { 1.0f, 0.0f } }; + verts[3] = (SDL_Vertex){ { -1.0f, -1.0f }, vert_color, { 0.0f, 1.0f } }; + verts[4] = (SDL_Vertex){ { 1.0f, 1.0f }, vert_color, { 1.0f, 0.0f } }; + verts[5] = (SDL_Vertex){ { -1.0f, 1.0f }, vert_color, { 0.0f, 0.0f } }; + + SDL_UnmapGPUTransferBuffer(data->device, transfer_buf); + + SDL_GPUTransferBufferLocation src; + SDL_zero(src); + src.transfer_buffer = transfer_buf; + + SDL_GPUBufferRegion dst; + SDL_zero(dst); + dst.buffer = data->vertices.present_quad_buffer; + dst.size = create_buf_info.size; + + SDL_UploadToGPUBuffer(cpass, &src, &dst, true); + + SDL_EndGPUCopyPass(cpass); + + SDL_SubmitGPUCommandBuffer(cbuf); + + SDL_ReleaseGPUTransferBuffer(data->device, transfer_buf); + + return true; +} + static bool UploadVertices(GPU_RenderData *data, void *vertices, size_t vertsize) { if (vertsize == 0) { @@ -966,28 +1039,16 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) { GPU_RenderData *data = (GPU_RenderData *)renderer->internal; + if (data->user_managed_device) { + return false; + } + SDL_GPUTexture *swapchain; Uint32 swapchain_texture_width, swapchain_texture_height; - if (!data->user_managed_device) { - bool result = SDL_WaitAndAcquireGPUSwapchainTexture(data->state.command_buffer, renderer->window, &swapchain, &swapchain_texture_width, &swapchain_texture_height); + bool result = SDL_WaitAndAcquireGPUSwapchainTexture(data->state.command_buffer, renderer->window, &swapchain, &swapchain_texture_width, &swapchain_texture_height); - if (!result) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to acquire swapchain texture: %s", SDL_GetError()); - } - } else { - SDL_PropertiesID props = SDL_GetRendererProperties(renderer); - if (SDL_HasProperty(props, SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER)) { - swapchain = SDL_GetPointerProperty(props, SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER, NULL); - swapchain_texture_width = renderer->output_pixel_w; - swapchain_texture_height = renderer->output_pixel_h; - } else { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer with user-managed GPU device requires a swapchain texture pointer"); - swapchain = NULL; - } - - if (!data->state.command_buffer) { - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer with user-managed GPU device requires a command buffer"); - } + if (!result) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to acquire swapchain texture: %s", SDL_GetError()); } if (swapchain != NULL) { @@ -1000,28 +1061,22 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) blit_info.destination.texture = swapchain; blit_info.destination.w = swapchain_texture_width; blit_info.destination.h = swapchain_texture_height; - blit_info.load_op = SDL_GPU_LOADOP_DONT_CARE; + blit_info.load_op = SDL_GPU_LOADOP_LOAD; blit_info.filter = SDL_GPU_FILTER_LINEAR; SDL_BlitGPUTexture(data->state.command_buffer, &blit_info); - if (!data->user_managed_device) - SDL_SubmitGPUCommandBuffer(data->state.command_buffer); + SDL_SubmitGPUCommandBuffer(data->state.command_buffer); if (swapchain_texture_width != data->backbuffer.width || swapchain_texture_height != data->backbuffer.height) { SDL_ReleaseGPUTexture(data->device, data->backbuffer.texture); CreateBackbuffer(data, swapchain_texture_width, swapchain_texture_height, SDL_GetGPUSwapchainTextureFormat(data->device, renderer->window)); } } else { - if (!data->user_managed_device) - SDL_SubmitGPUCommandBuffer(data->state.command_buffer); + SDL_SubmitGPUCommandBuffer(data->state.command_buffer); } - if (data->user_managed_device) { - data->state.command_buffer = NULL; - } else { - data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device); - } + data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device); return true; } @@ -1267,6 +1322,10 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P return false; } + if (data->user_managed_device && !InitPresentQuadBuffer(data)) { + return false; + } + if (!data->user_managed_device) { if (!SDL_ClaimWindowForGPUDevice(data->device, window)) { return false; @@ -1317,6 +1376,84 @@ void GPU_SetCommandBuffer(SDL_Renderer *renderer, SDL_GPUCommandBuffer *command_ data->state.command_buffer = command_buffer; } +bool GPU_PresentToUserTexture(SDL_Renderer *renderer, SDL_GPUTexture *texture, SDL_GPUTextureFormat format) +{ + GPU_RenderData *data = (GPU_RenderData *)renderer->internal; + + if (!data->user_managed_device) { + return SDL_SetError("Renderer is not using a user-managed device"); + } + + if (!data->state.command_buffer) { + return SDL_SetError("No command buffer set"); + } + + GPU_PipelineParameters pipe_params; + SDL_zero(pipe_params); + pipe_params.blend_mode = SDL_BLENDMODE_BLEND; + pipe_params.vert_shader = VERT_SHADER_TRI_TEXTURE; + pipe_params.frag_shader = FRAG_SHADER_TEXTURE_RGBA; + pipe_params.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; + pipe_params.attachment_format = format; + + SDL_GPUGraphicsPipeline *pipeline = GPU_GetPipeline(&data->pipeline_cache, &data->shaders, data->device, &pipe_params); + + if (!pipeline) { + return false; + } + + SDL_GPUColorTargetInfo color_attachment; + SDL_zero(color_attachment); + color_attachment.load_op = SDL_GPU_LOADOP_LOAD; + color_attachment.store_op = SDL_GPU_STOREOP_STORE; + color_attachment.texture = texture; + + SDL_GPURenderPass *present_pass = SDL_BeginGPURenderPass( + data->state.command_buffer, &color_attachment, 1, NULL); + + if (!present_pass) { + return false; + } + + SDL_GPUTextureSamplerBinding sampler_bind; + SDL_zero(sampler_bind); + sampler_bind.sampler = *SamplerPointer(data, SDL_TEXTURE_ADDRESS_CLAMP, SDL_SCALEMODE_LINEAR); + sampler_bind.texture = data->backbuffer.texture; + + SDL_GPUBufferBinding buffer_bind; + SDL_zero(buffer_bind); + buffer_bind.buffer = data->vertices.present_quad_buffer; + buffer_bind.offset = 0; + + /* + * Present quad already has normalized coordinates, so we supply identity matrix as for MVP. + */ + GPU_ShaderUniformData uniforms; + SDL_zero(uniforms); + uniforms.mvp.v._11 = 1.0f; + uniforms.mvp.v._22 = 1.0f; + uniforms.mvp.v._33 = 1.0f; + uniforms.mvp.v._44 = 1.0f; + + uniforms.color = (SDL_FColor){ 1.0f, 1.0f, 1.0f, 1.0f }; + + /* + Vertex shader divides input coordinates by texture size, but present quad already has them normalized + so we set it to (1,1) here to avoid any scaling. + */ + uniforms.texture_size[0] = 1.0f; + uniforms.texture_size[1] = 1.0f; + + SDL_BindGPUGraphicsPipeline(present_pass, pipeline); + SDL_BindGPUVertexBuffers(present_pass, 0, &buffer_bind, 1); + SDL_BindGPUFragmentSamplers(present_pass, 0, &sampler_bind, 1); + SDL_PushGPUVertexUniformData(data->state.command_buffer, 0, &uniforms, sizeof(uniforms)); + SDL_DrawGPUPrimitives(present_pass, 6, 1, 0, 0); + SDL_EndGPURenderPass(present_pass); + + return true; +} + SDL_RenderDriver GPU_RenderDriver = { GPU_CreateRenderer, "gpu" }; diff --git a/test/testgpu_with_sdlrender.c b/test/testgpu_with_sdlrender.c index da1e9e6acf4e6..06570ac77c39d 100644 --- a/test/testgpu_with_sdlrender.c +++ b/test/testgpu_with_sdlrender.c @@ -24,6 +24,7 @@ static Uint64 then = 0; static Uint64 frames = 0; static SDL_Renderer *renderer = NULL; static SDL_Texture *icon_texture = NULL; +static float icon_pos_x = 0.0f; SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { @@ -116,6 +117,10 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { + if (event->type == SDL_EVENT_KEY_DOWN) { + icon_pos_x += 16.0f; + } + return SDLTest_CommonEventMainCallbacks(state, event); } @@ -149,7 +154,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) /* Custom GPU rendering */ renderPass = SDL_BeginGPURenderPass(cmdbuf, &color_target_info, 1, NULL); - /* Render universe or whatever */ + /* Render Half-Life 3 or whatever */ SDL_EndGPURenderPass(renderPass); /* 2D rendering with SDL renderer */ @@ -158,18 +163,18 @@ SDL_AppResult SDL_AppIterate(void *appstate) return SDL_APP_FAILURE; } - if (!SDL_SetRenderGPUSwapchainTexture(renderer, swapchainTexture)) { - SDL_Log("SDL_SetRenderGPUSwapchainTexture failed: %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - SDL_FRect rect = { 32, 32, 64, 64 }; + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); SDL_RenderFillRect(renderer, &rect); - SDL_FRect tex_rect = { 150, 150, 32, 32 }; + SDL_FRect tex_rect = { 150 + icon_pos_x, 150, 32, 32 }; SDL_RenderTexture(renderer, icon_texture, NULL, &tex_rect); - SDL_RenderPresent(renderer); + if (!SDL_RenderPresentToGPUTexture(renderer, swapchainTexture, SDL_GetGPUSwapchainTextureFormat(gpu_device, state->windows[0]))) { + SDL_Log("SDL_RenderPresentToGPUTexture failed: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } SDL_SubmitGPUCommandBuffer(cmdbuf); } else { From 7a79751c8eaae4f73e36b60a9c958e000eb8de30 Mon Sep 17 00:00:00 2001 From: Nikita Kogut Date: Fri, 3 Jan 2025 01:29:44 +0200 Subject: [PATCH 3/6] Cleanup dynapi overrides --- src/dynapi/SDL_dynapi_overrides.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 699be3d33a454..89eccaf5e4514 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1255,6 +1255,5 @@ #define SDL_GetTrayMenuParentEntry SDL_GetTrayMenuParentEntry_REAL #define SDL_GetTrayMenuParentTray SDL_GetTrayMenuParentTray_REAL #define SDL_GetThreadState SDL_GetThreadState_REAL -#define SDL_SetRenderGPUSwapchainTexture SDL_SetRenderGPUSwapchainTexture_REAL #define SDL_SetRenderGPUCommandBuffer SDL_SetRenderGPUCommandBuffer_REAL #define SDL_RenderPresentToGPUTexture SDL_RenderPresentToGPUTexture_REAL From e5f4cab305c780a7912ab2204f49477ffd2df7e4 Mon Sep 17 00:00:00 2001 From: Nikita Kogut Date: Fri, 3 Jan 2025 01:30:58 +0200 Subject: [PATCH 4/6] Cleanup define for prop --- src/render/SDL_sysrender.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 47f5d5e8aacd2..f58b860b8fecd 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -32,9 +32,6 @@ extern "C" { #endif -// Used by GPU driver to retrieve user-provided swapchain texture -#define SDL_PROP_RENDERER_GPU_INTERNAL_SWAPCHAIN_TEXTURE_POINTER "SDL.internal.renderer.gpu.swapchain" - typedef enum SDL_TextureAddressMode { SDL_TEXTURE_ADDRESS_AUTO, From 1c3359e5fa11871b606fa403c9b3ab38ed370256 Mon Sep 17 00:00:00 2001 From: Nikita Kogut Date: Fri, 3 Jan 2025 01:32:24 +0200 Subject: [PATCH 5/6] Restore load op to dont care --- src/render/gpu/SDL_render_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index 657e76611058d..39edb24ed4750 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -1061,7 +1061,7 @@ static bool GPU_RenderPresent(SDL_Renderer *renderer) blit_info.destination.texture = swapchain; blit_info.destination.w = swapchain_texture_width; blit_info.destination.h = swapchain_texture_height; - blit_info.load_op = SDL_GPU_LOADOP_LOAD; + blit_info.load_op = SDL_GPU_LOADOP_DONT_CARE; blit_info.filter = SDL_GPU_FILTER_LINEAR; SDL_BlitGPUTexture(data->state.command_buffer, &blit_info); From a13e9823f21984445eec5b4721f3b9efc52fd9fd Mon Sep 17 00:00:00 2001 From: Nikita Kogut Date: Fri, 3 Jan 2025 02:00:40 +0200 Subject: [PATCH 6/6] Cleanup fix --- src/render/gpu/SDL_render_gpu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index 39edb24ed4750..f58f14f9373a0 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -1121,6 +1121,10 @@ static void GPU_DestroyRenderer(SDL_Renderer *renderer) SDL_ReleaseGPUTexture(data->device, data->backbuffer.texture); } + if (data->vertices.present_quad_buffer) { + SDL_ReleaseGPUBuffer(data->device, data->vertices.present_quad_buffer); + } + if (!data->user_managed_device && renderer->window) { SDL_ReleaseWindowFromGPUDevice(data->device, renderer->window); } @@ -1404,6 +1408,7 @@ bool GPU_PresentToUserTexture(SDL_Renderer *renderer, SDL_GPUTexture *texture, S SDL_GPUColorTargetInfo color_attachment; SDL_zero(color_attachment); + /* Preserve the contents that were rendered by other GPU code, if any */ color_attachment.load_op = SDL_GPU_LOADOP_LOAD; color_attachment.store_op = SDL_GPU_STOREOP_STORE; color_attachment.texture = texture;