render: Batching is always enabled now!

Make sure your app uses SDL_RenderFlush() before it talks to D3D/OpenGL/etc!

Fixes #8584.
This commit is contained in:
Ryan C. Gordon 2023-11-20 20:26:12 -05:00
parent b24d6bd59a
commit 6ba90f7775
7 changed files with 24 additions and 78 deletions

View File

@ -559,6 +559,7 @@ The following hints have been removed:
* SDL_HINT_IME_SUPPORT_EXTENDED_TEXT - the normal text editing event has extended text
* SDL_HINT_MOUSE_RELATIVE_SCALING - mouse coordinates are no longer automatically scaled by the SDL renderer
* SDL_HINT_RENDER_LOGICAL_SIZE_MODE - the logical size mode is explicitly set with SDL_SetRenderLogicalPresentation()
* SDL_HINT_RENDER_BATCHING - Render batching is always enabled, apps should call SDL_FlushRenderer() before calling into a lower-level graphics API.
* SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL - replaced with the "opengl" property in SDL_CreateWindowWithProperties()
* SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN - replaced with the "vulkan" property in SDL_CreateWindowWithProperties()
* SDL_HINT_VIDEO_HIGHDPI_DISABLED - high DPI support is always enabled
@ -811,6 +812,13 @@ The following functions have been renamed:
## SDL_render.h
The 2D renderer API always uses batching in SDL3. There is no magic to turn
it on and off; it doesn't matter if you select a specific renderer or try to
use any hint. This means that all apps that use SDL3's 2D renderer and also
want to call directly into the platform's lower-layer graphics API _must_ call
SDL_RenderFlush() before doing so. This will make sure any pending rendering
work from SDL is done before the app starts directly drawing.
SDL_GetRenderDriverInfo() has been removed, since most of the information it reported were
estimates and could not be accurate before creating a renderer. Often times this function
was used to figure out the index of a driver, so one would call it in a for-loop, looking

View File

@ -1387,30 +1387,6 @@ extern "C" {
*/
#define SDL_HINT_QTWAYLAND_WINDOW_FLAGS "SDL_QTWAYLAND_WINDOW_FLAGS"
/**
* A variable controlling whether the 2D render API is compatible or efficient.
*
* This variable can be set to the following values:
*
* "0" - Don't use batching to make rendering more efficient.
* "1" - Use batching, but might cause problems if app makes its own direct OpenGL calls.
*
* Up to SDL 2.0.9, the render API would draw immediately when requested. Now
* it batches up draw requests and sends them all to the GPU only when forced
* to (during SDL_RenderPresent, when changing render targets, by updating a
* texture that the batch needs, etc). This is significantly more efficient,
* but it can cause problems for apps that expect to render on top of the
* render API's output. As such, SDL will disable batching if a specific
* render backend is requested (since this might indicate that the app is
* planning to use the underlying graphics API directly). This hint can
* be used to explicitly request batching in this instance. It is a contract
* that you will either never use the underlying graphics API directly, or
* if you do, you will call SDL_RenderFlush() before you do so any current
* batch goes to the GPU before your work begins. Not following this contract
* will result in undefined behavior.
*/
#define SDL_HINT_RENDER_BATCHING "SDL_RENDER_BATCHING"
/**
* A variable controlling how the 2D render API renders lines
*

View File

@ -1559,20 +1559,12 @@ extern DECLSPEC void SDLCALL SDL_DestroyRenderer(SDL_Renderer *renderer);
* are planning to call into OpenGL/Direct3D/Metal/whatever directly in
* addition to using an SDL_Renderer.
*
* This is for a very-specific case: if you are using SDL's render API, you
* asked for a specific renderer backend (OpenGL, Direct3D, etc), you set
* SDL_HINT_RENDER_BATCHING to "1", and you plan to make OpenGL/D3D/whatever
* calls in addition to SDL render API calls. If all of this applies, you
* should call SDL_RenderFlush() between calls to SDL's render API and the
* low-level API you're using in cooperation.
* This is for a very-specific case: if you are using SDL's render API, and
* you plan to make OpenGL/D3D/whatever calls in addition to SDL render API
* calls. If this applies, you should call SDL_RenderFlush() between calls to
* SDL's render API and the low-level API you're using in cooperation.
*
* In all other cases, you can ignore this function. This is only here to get
* maximum performance out of a specific situation. In all other cases, SDL
* will do the right thing, perhaps at a performance loss.
*
* This function is first available in SDL 2.0.10, and is not needed in 2.0.9
* and earlier, as earlier versions did not queue rendering commands at all,
* instead flushing them to the OS immediately.
* In all other cases, you can ignore this function.
*
* \param renderer the rendering context
* \returns 0 on success or a negative error code on failure; call

View File

@ -265,11 +265,6 @@ static int FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture)
return 0;
}
static SDL_INLINE int FlushRenderCommandsIfNotBatching(SDL_Renderer *renderer)
{
return renderer->batching ? 0 : FlushRenderCommands(renderer);
}
int SDL_RenderFlush(SDL_Renderer *renderer)
{
return FlushRenderCommands(renderer);
@ -813,7 +808,6 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
const char *name = SDL_GetStringProperty(props, "name", NULL);
SDL_Renderer *renderer = NULL;
const int n = SDL_GetNumRenderDrivers();
SDL_bool batching = SDL_TRUE;
const char *hint;
int i;
@ -855,9 +849,6 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
if (SDL_strcasecmp(name, driver->info.name) == 0) {
/* Create a new renderer instance */
renderer = driver->CreateRenderer(window, props);
if (renderer) {
batching = SDL_FALSE;
}
break;
}
}
@ -890,14 +881,6 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
VerifyDrawQueueFunctions(renderer);
/* let app/user override batching decisions. */
if (renderer->always_batch) {
batching = SDL_TRUE;
} else if (SDL_GetHint(SDL_HINT_RENDER_BATCHING)) {
batching = SDL_GetHintBoolean(SDL_HINT_RENDER_BATCHING, SDL_TRUE);
}
renderer->batching = batching;
renderer->magic = &SDL_renderer_magic;
renderer->window = window;
renderer->target_mutex = SDL_CreateMutex();
@ -2106,7 +2089,7 @@ static int SDL_SetRenderTargetInternal(SDL_Renderer *renderer, SDL_Texture *text
}
/* All set! */
return FlushRenderCommandsIfNotBatching(renderer);
return 0;
}
int SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
@ -2506,7 +2489,6 @@ int SDL_ConvertEventToRenderCoordinates(SDL_Renderer *renderer, SDL_Event *event
int SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect)
{
int retval;
CHECK_RENDERER_MAGIC(renderer, -1);
if (rect) {
@ -2520,8 +2502,7 @@ int SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect)
renderer->view->viewport.w = -1;
renderer->view->viewport.h = -1;
}
retval = QueueCmdSetViewport(renderer);
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return QueueCmdSetViewport(renderer);
}
int SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect)
@ -2563,7 +2544,6 @@ static void GetRenderViewportSize(SDL_Renderer *renderer, SDL_FRect *rect)
int SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect)
{
int retval;
CHECK_RENDERER_MAGIC(renderer, -1)
if (rect && rect->w >= 0 && rect->h >= 0) {
@ -2577,8 +2557,7 @@ int SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect)
SDL_zero(renderer->view->clip_rect);
}
retval = QueueCmdSetClipRect(renderer);
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return QueueCmdSetClipRect(renderer);
}
int SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect)
@ -2617,7 +2596,7 @@ int SDL_SetRenderScale(SDL_Renderer *renderer, float scaleX, float scaleY)
/* The scale affects the existing viewport and clip rectangle */
retval += QueueCmdSetViewport(renderer);
retval += QueueCmdSetClipRect(renderer);
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_GetRenderScale(SDL_Renderer *renderer, float *scaleX, float *scaleY)
@ -2687,7 +2666,7 @@ int SDL_RenderClear(SDL_Renderer *renderer)
int retval;
CHECK_RENDERER_MAGIC(renderer, -1);
retval = QueueCmdClear(renderer);
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_RenderPoint(SDL_Renderer *renderer, float x, float y)
@ -2753,7 +2732,7 @@ int SDL_RenderPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count
} else {
retval = QueueCmdDrawPoints(renderer, points, count);
}
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_RenderLine(SDL_Renderer *renderer, float x1, float y1, float x2, float y2)
@ -3072,7 +3051,7 @@ int SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
retval = QueueCmdDrawLines(renderer, points, count);
}
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_RenderRect(SDL_Renderer *renderer, const SDL_FRect *rect)
@ -3181,7 +3160,7 @@ int SDL_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int coun
SDL_small_free(frects, isstack);
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect)
@ -3286,7 +3265,7 @@ int SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FR
retval = QueueCmdCopy(renderer, texture, &real_srcrect, &real_dstrect);
}
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
@ -3441,7 +3420,7 @@ int SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture,
renderer->view->scale.x,
renderer->view->scale.y);
}
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_RenderGeometry(SDL_Renderer *renderer,
@ -3798,8 +3777,6 @@ static int SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer,
renderer->view->scale.y);
if (retval < 0) {
goto end;
} else {
FlushRenderCommandsIfNotBatching(renderer);
}
}
@ -3821,8 +3798,6 @@ static int SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer,
renderer->view->scale.y);
if (retval < 0) {
goto end;
} else {
FlushRenderCommandsIfNotBatching(renderer);
}
}
@ -3944,7 +3919,7 @@ int SDL_RenderGeometryRaw(SDL_Renderer *renderer,
renderer->view->scale.x,
renderer->view->scale.y);
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
return retval;
}
int SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)

View File

@ -254,8 +254,6 @@ struct SDL_Renderer
SDL_Color color; /**< Color for drawing operations values */
SDL_BlendMode blendMode; /**< The drawing blend mode */
SDL_bool always_batch;
SDL_bool batching;
SDL_RenderCommand *render_commands;
SDL_RenderCommand *render_commands_tail;
SDL_RenderCommand *render_commands_pool;

View File

@ -1917,8 +1917,6 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
renderer->info = METAL_RenderDriver.info;
renderer->info.flags = SDL_RENDERER_ACCELERATED;
renderer->always_batch = SDL_TRUE;
#if (defined(__MACOS__) && defined(MAC_OS_X_VERSION_10_13)) || TARGET_OS_MACCATALYST
if (@available(macOS 10.13, *)) {
data.mtllayer.displaySyncEnabled = SDL_GetBooleanProperty(create_props, "present_vsync", SDL_FALSE);

View File

@ -228,7 +228,6 @@ int SDLTest_CommonArg(SDLTest_CommonState *state, int index)
}
state->renderdriver = argv[index];
SDL_SetHint(SDL_HINT_RENDER_DRIVER, state->renderdriver);
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
return 2;
}
if (SDL_strcasecmp(argv[index], "--gldebug") == 0) {