Fixed race condition where Android touch events could get scaled by a render target's viewport

This commit is contained in:
Sam Lantinga 2018-06-18 13:13:56 -07:00
parent 9924a8e392
commit 74ec7cabdb
2 changed files with 68 additions and 28 deletions

View File

@ -132,6 +132,16 @@ SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
#endif #endif
} }
static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_Rect *viewport, SDL_FPoint *scale)
{
SDL_LockMutex(renderer->target_mutex);
*logical_w = renderer->target ? renderer->logical_w_backup : renderer->logical_w;
*logical_h = renderer->target ? renderer->logical_h_backup : renderer->logical_h;
*viewport = renderer->target ? renderer->viewport_backup : renderer->viewport;
*scale = renderer->target ? renderer->scale_backup : renderer->scale;
SDL_UnlockMutex(renderer->target_mutex);
}
static int SDLCALL static int SDLCALL
SDL_RendererEventWatch(void *userdata, SDL_Event *event) SDL_RendererEventWatch(void *userdata, SDL_Event *event)
{ {
@ -197,35 +207,51 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
} }
} else if (event->type == SDL_MOUSEMOTION) { } else if (event->type == SDL_MOUSEMOTION) {
SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID); SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID);
if (renderer->logical_w && window == renderer->window) { if (window == renderer->window) {
event->motion.x -= (int)(renderer->viewport.x * renderer->dpi_scale.x); int logical_w, logical_h;
event->motion.y -= (int)(renderer->viewport.y * renderer->dpi_scale.y); SDL_Rect viewport;
event->motion.x = (int)(event->motion.x / (renderer->scale.x * renderer->dpi_scale.x)); SDL_FPoint scale;
event->motion.y = (int)(event->motion.y / (renderer->scale.y * renderer->dpi_scale.y)); GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
if (event->motion.xrel > 0) { if (logical_w) {
event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / (renderer->scale.x * renderer->dpi_scale.x))); event->motion.x -= (int)(viewport.x * renderer->dpi_scale.x);
} else if (event->motion.xrel < 0) { event->motion.y -= (int)(viewport.y * renderer->dpi_scale.y);
event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / (renderer->scale.x * renderer->dpi_scale.x))); event->motion.x = (int)(event->motion.x / (scale.x * renderer->dpi_scale.x));
} event->motion.y = (int)(event->motion.y / (scale.y * renderer->dpi_scale.y));
if (event->motion.yrel > 0) { if (event->motion.xrel > 0) {
event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / (renderer->scale.y * renderer->dpi_scale.y))); event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x)));
} else if (event->motion.yrel < 0) { } else if (event->motion.xrel < 0) {
event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / (renderer->scale.y * renderer->dpi_scale.y))); event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x)));
}
if (event->motion.yrel > 0) {
event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y)));
} else if (event->motion.yrel < 0) {
event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y)));
}
} }
} }
} else if (event->type == SDL_MOUSEBUTTONDOWN || } else if (event->type == SDL_MOUSEBUTTONDOWN ||
event->type == SDL_MOUSEBUTTONUP) { event->type == SDL_MOUSEBUTTONUP) {
SDL_Window *window = SDL_GetWindowFromID(event->button.windowID); SDL_Window *window = SDL_GetWindowFromID(event->button.windowID);
if (renderer->logical_w && window == renderer->window) { if (window == renderer->window) {
event->button.x -= (int)(renderer->viewport.x * renderer->dpi_scale.x); int logical_w, logical_h;
event->button.y -= (int)(renderer->viewport.y * renderer->dpi_scale.y); SDL_Rect viewport;
event->button.x = (int)(event->button.x / (renderer->scale.x * renderer->dpi_scale.x)); SDL_FPoint scale;
event->button.y = (int)(event->button.y / (renderer->scale.y * renderer->dpi_scale.y)); GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
if (logical_w) {
event->button.x -= (int)(viewport.x * renderer->dpi_scale.x);
event->button.y -= (int)(viewport.y * renderer->dpi_scale.y);
event->button.x = (int)(event->button.x / (scale.x * renderer->dpi_scale.x));
event->button.y = (int)(event->button.y / (scale.y * renderer->dpi_scale.y));
}
} }
} else if (event->type == SDL_FINGERDOWN || } else if (event->type == SDL_FINGERDOWN ||
event->type == SDL_FINGERUP || event->type == SDL_FINGERUP ||
event->type == SDL_FINGERMOTION) { event->type == SDL_FINGERMOTION) {
if (renderer->logical_w) { int logical_w, logical_h;
SDL_Rect viewport;
SDL_FPoint scale;
GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
if (logical_w) {
int w = 1; int w = 1;
int h = 1; int h = 1;
SDL_GetRendererOutputSize(renderer, &w, &h); SDL_GetRendererOutputSize(renderer, &w, &h);
@ -233,18 +259,18 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
event->tfinger.x *= (w - 1); event->tfinger.x *= (w - 1);
event->tfinger.y *= (h - 1); event->tfinger.y *= (h - 1);
event->tfinger.x -= (renderer->viewport.x * renderer->dpi_scale.x); event->tfinger.x -= (viewport.x * renderer->dpi_scale.x);
event->tfinger.y -= (renderer->viewport.y * renderer->dpi_scale.y); event->tfinger.y -= (viewport.y * renderer->dpi_scale.y);
event->tfinger.x = (event->tfinger.x / (renderer->scale.x * renderer->dpi_scale.x)); event->tfinger.x = (event->tfinger.x / (scale.x * renderer->dpi_scale.x));
event->tfinger.y = (event->tfinger.y / (renderer->scale.y * renderer->dpi_scale.y)); event->tfinger.y = (event->tfinger.y / (scale.y * renderer->dpi_scale.y));
if (renderer->logical_w > 1) { if (logical_w > 1) {
event->tfinger.x = event->tfinger.x / (renderer->logical_w - 1); event->tfinger.x = event->tfinger.x / (logical_w - 1);
} else { } else {
event->tfinger.x = 0.5f; event->tfinger.x = 0.5f;
} }
if (renderer->logical_h > 1) { if (logical_h > 1) {
event->tfinger.y = event->tfinger.y / (renderer->logical_h - 1); event->tfinger.y = event->tfinger.y / (logical_h - 1);
} else { } else {
event->tfinger.y = 0.5f; event->tfinger.y = 0.5f;
} }
@ -345,6 +371,7 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
if (renderer) { if (renderer) {
renderer->magic = &renderer_magic; renderer->magic = &renderer_magic;
renderer->window = window; renderer->window = window;
renderer->target_mutex = SDL_CreateMutex();
renderer->scale.x = 1.0f; renderer->scale.x = 1.0f;
renderer->scale.y = 1.0f; renderer->scale.y = 1.0f;
renderer->dpi_scale.x = 1.0f; renderer->dpi_scale.x = 1.0f;
@ -392,6 +419,7 @@ SDL_CreateSoftwareRenderer(SDL_Surface * surface)
if (renderer) { if (renderer) {
renderer->magic = &renderer_magic; renderer->magic = &renderer_magic;
renderer->target_mutex = SDL_CreateMutex();
renderer->scale.x = 1.0f; renderer->scale.x = 1.0f;
renderer->scale.y = 1.0f; renderer->scale.y = 1.0f;
@ -1203,6 +1231,8 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
} }
} }
SDL_LockMutex(renderer->target_mutex);
if (texture && !renderer->target) { if (texture && !renderer->target) {
/* Make a backup of the viewport */ /* Make a backup of the viewport */
renderer->viewport_backup = renderer->viewport; renderer->viewport_backup = renderer->viewport;
@ -1215,6 +1245,7 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
renderer->target = texture; renderer->target = texture;
if (renderer->SetRenderTarget(renderer, texture) < 0) { if (renderer->SetRenderTarget(renderer, texture) < 0) {
SDL_UnlockMutex(renderer->target_mutex);
return -1; return -1;
} }
@ -1237,6 +1268,9 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
renderer->logical_w = renderer->logical_w_backup; renderer->logical_w = renderer->logical_w_backup;
renderer->logical_h = renderer->logical_h_backup; renderer->logical_h = renderer->logical_h_backup;
} }
SDL_UnlockMutex(renderer->target_mutex);
if (renderer->UpdateViewport(renderer) < 0) { if (renderer->UpdateViewport(renderer) < 0) {
return -1; return -1;
} }
@ -2106,6 +2140,10 @@ SDL_DestroyRenderer(SDL_Renderer * renderer)
/* It's no longer magical... */ /* It's no longer magical... */
renderer->magic = NULL; renderer->magic = NULL;
/* Free the target mutex */
SDL_DestroyMutex(renderer->target_mutex);
renderer->target_mutex = NULL;
/* Free the renderer instance */ /* Free the renderer instance */
renderer->DestroyRenderer(renderer); renderer->DestroyRenderer(renderer);
} }

View File

@ -25,6 +25,7 @@
#include "SDL_render.h" #include "SDL_render.h"
#include "SDL_events.h" #include "SDL_events.h"
#include "SDL_mutex.h"
#include "SDL_yuv_sw_c.h" #include "SDL_yuv_sw_c.h"
/* The SDL 2D rendering system */ /* The SDL 2D rendering system */
@ -172,6 +173,7 @@ struct SDL_Renderer
/* The list of textures */ /* The list of textures */
SDL_Texture *textures; SDL_Texture *textures;
SDL_Texture *target; SDL_Texture *target;
SDL_mutex *target_mutex;
Uint8 r, g, b, a; /**< Color for drawing operations values */ Uint8 r, g, b, a; /**< Color for drawing operations values */
SDL_BlendMode blendMode; /**< The drawing blend mode */ SDL_BlendMode blendMode; /**< The drawing blend mode */