summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2022-02-08 11:54:42 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2022-02-08 11:54:42 +0200
commitc6b294a22b9d4e75854dd4e2d5c75f9b063e7bed (patch)
treee582d8f50d2041cae6be61acfa2e554afb944111
parent1d978ce9fafd2658121a48288a6ddf16cfccecc6 (diff)
macOS: Attempting workaround for Metal refresh issues
For some reason, rendering to a separate render target instead of directly to the window helps with certain refresh glitches. More glitches still remain, though, perhaps related to not running window refresh at a constant rate but occasionally pausing to wait for input events.
-rw-r--r--src/app.c11
-rw-r--r--src/ui/scrollwidget.c20
-rw-r--r--src/ui/window.c38
-rw-r--r--src/ui/window.h2
4 files changed, 57 insertions, 14 deletions
diff --git a/src/app.c b/src/app.c
index 891f5d6e..b6c48062 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1644,13 +1644,14 @@ void refresh_App(void) {
1644 iWindow *win = j.ptr; 1644 iWindow *win = j.ptr;
1645 setCurrent_Window(win); 1645 setCurrent_Window(win);
1646 switch (win->type) { 1646 switch (win->type) {
1647 case main_WindowType: 1647 case main_WindowType: {
1648 // iTime draw; 1648// iTime draw;
1649 // initCurrent_Time(&draw); 1649// initCurrent_Time(&draw);
1650 draw_MainWindow(as_MainWindow(win)); 1650 draw_MainWindow(as_MainWindow(win));
1651 // printf("draw: %lld \u03bcs\n", (long long) (elapsedSeconds_Time(&draw) * 1000000)); 1651// printf("draw: %lld \u03bcs\n", (long long) (elapsedSeconds_Time(&draw) * 1000000));
1652 // fflush(stdout); 1652// fflush(stdout);
1653 break; 1653 break;
1654 }
1654 default: 1655 default:
1655 draw_Window(win); 1656 draw_Window(win);
1656 break; 1657 break;
diff --git a/src/ui/scrollwidget.c b/src/ui/scrollwidget.c
index 651669c6..71e4873f 100644
--- a/src/ui/scrollwidget.c
+++ b/src/ui/scrollwidget.c
@@ -239,15 +239,17 @@ static void draw_ScrollWidget_(const iScrollWidget *d) {
239 init_Paint(&p); 239 init_Paint(&p);
240 /* Blend if opacity is not at maximum. */ 240 /* Blend if opacity is not at maximum. */
241 p.alpha = 255 * value_Anim(&d->opacity); 241 p.alpha = 255 * value_Anim(&d->opacity);
242 SDL_Renderer *render = renderer_Window(get_Window()); 242 if (p.alpha > 0) {
243 if (p.alpha < 255) { 243 SDL_Renderer *render = renderer_Window(get_Window());
244 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND); 244 if (p.alpha < 255) {
245 } 245 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
246 const iRect thumbRect = shrunk_Rect( 246 }
247 thumbRect_ScrollWidget_(d), init_I2(isPressed ? gap_UI : (gap_UI * 4 / 3), gap_UI / 2)); 247 const iRect thumbRect = shrunk_Rect(
248 fillRect_Paint(&p, thumbRect, isPressed ? uiBackgroundPressed_ColorId : tmQuote_ColorId); 248 thumbRect_ScrollWidget_(d), init_I2(isPressed ? gap_UI : (gap_UI * 4 / 3), gap_UI / 2));
249 if (p.alpha < 255) { 249 fillRect_Paint(&p, thumbRect, isPressed ? uiBackgroundPressed_ColorId : tmQuote_ColorId);
250 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); 250 if (p.alpha < 255) {
251 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE);
252 }
251 } 253 }
252 } 254 }
253} 255}
diff --git a/src/ui/window.c b/src/ui/window.c
index 13abc5fa..c80bfbe0 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -539,10 +539,19 @@ void deinit_Window(iWindow *d) {
539void init_MainWindow(iMainWindow *d, iRect rect) { 539void init_MainWindow(iMainWindow *d, iRect rect) {
540 theWindow_ = &d->base; 540 theWindow_ = &d->base;
541 theMainWindow_ = d; 541 theMainWindow_ = d;
542 d->enableBackBuf = iFalse;
542 uint32_t flags = 0; 543 uint32_t flags = 0;
543#if defined (iPlatformAppleDesktop) 544#if defined (iPlatformAppleDesktop)
544 SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); 545 SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl");
545 flags |= shouldDefaultToMetalRenderer_MacOS() ? SDL_WINDOW_METAL : SDL_WINDOW_OPENGL; 546 flags |= shouldDefaultToMetalRenderer_MacOS() ? SDL_WINDOW_METAL : SDL_WINDOW_OPENGL;
547 if (flags & SDL_WINDOW_METAL) {
548 /* There are some really odd refresh glitches that only occur with the Metal
549 backend. It's perhaps related to it not expecting refresh to stop intermittently
550 to wait for input events. If forcing constant refreshing at full frame rate, the
551 problems seem to go away... Rendering everything to a separate render target
552 appears to sidestep some of the glitches. */
553 d->enableBackBuf = iTrue;
554 }
546#elif defined (iPlatformAppleMobile) 555#elif defined (iPlatformAppleMobile)
547 SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal"); 556 SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");
548 flags |= SDL_WINDOW_METAL; 557 flags |= SDL_WINDOW_METAL;
@@ -566,6 +575,7 @@ void init_MainWindow(iMainWindow *d, iRect rect) {
566 d->place.lastNotifiedSize = zero_I2(); 575 d->place.lastNotifiedSize = zero_I2();
567 d->place.snap = 0; 576 d->place.snap = 0;
568 d->keyboardHeight = 0; 577 d->keyboardHeight = 0;
578 d->backBuf = NULL;
569#if defined(iPlatformMobile) 579#if defined(iPlatformMobile)
570 const iInt2 minSize = zero_I2(); /* windows aren't independently resizable */ 580 const iInt2 minSize = zero_I2(); /* windows aren't independently resizable */
571#else 581#else
@@ -637,6 +647,9 @@ void init_MainWindow(iMainWindow *d, iRect rect) {
637} 647}
638 648
639void deinit_MainWindow(iMainWindow *d) { 649void deinit_MainWindow(iMainWindow *d) {
650 if (d->backBuf) {
651 SDL_DestroyTexture(d->backBuf);
652 }
640 deinitRoots_Window_(as_Window(d)); 653 deinitRoots_Window_(as_Window(d));
641 if (theWindow_ == as_Window(d)) { 654 if (theWindow_ == as_Window(d)) {
642 theWindow_ = NULL; 655 theWindow_ = NULL;
@@ -682,6 +695,10 @@ iRoot *otherRoot_Window(const iWindow *d, iRoot *root) {
682static void invalidate_MainWindow_(iMainWindow *d, iBool forced) { 695static void invalidate_MainWindow_(iMainWindow *d, iBool forced) {
683 if (d && (!d->base.isInvalidated || forced)) { 696 if (d && (!d->base.isInvalidated || forced)) {
684 d->base.isInvalidated = iTrue; 697 d->base.isInvalidated = iTrue;
698 if (d->enableBackBuf && d->backBuf) {
699 SDL_DestroyTexture(d->backBuf);
700 d->backBuf = NULL;
701 }
685 resetFonts_Text(text_Window(d)); 702 resetFonts_Text(text_Window(d));
686 postCommand_App("theme.changed auto:1"); /* forces UI invalidation */ 703 postCommand_App("theme.changed auto:1"); /* forces UI invalidation */
687 } 704 }
@@ -1272,11 +1289,28 @@ void draw_MainWindow(iMainWindow *d) {
1272 d->maxDrawableHeight = renderSize.y; 1289 d->maxDrawableHeight = renderSize.y;
1273 } 1290 }
1274 } 1291 }
1292 if (d->enableBackBuf) {
1293 /* Possible resize the backing buffer. */
1294 if (!d->backBuf || !isEqual_I2(size_SDLTexture(d->backBuf), renderSize)) {
1295 if (d->backBuf) {
1296 SDL_DestroyTexture(d->backBuf);
1297 }
1298 d->backBuf = SDL_CreateTexture(d->base.render,
1299 SDL_PIXELFORMAT_RGB888,
1300 SDL_TEXTUREACCESS_TARGET,
1301 renderSize.x,
1302 renderSize.y);
1303 printf("NEW BACKING: %dx%d %p\n", renderSize.x, renderSize.y, d->backBuf); fflush(stdout);
1304 }
1305 }
1275 } 1306 }
1276 const int winFlags = SDL_GetWindowFlags(d->base.win); 1307 const int winFlags = SDL_GetWindowFlags(d->base.win);
1277 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0; 1308 const iBool gotFocus = (winFlags & SDL_WINDOW_INPUT_FOCUS) != 0;
1278 iPaint p; 1309 iPaint p;
1279 init_Paint(&p); 1310 init_Paint(&p);
1311 if (d->backBuf) {
1312 SDL_SetRenderTarget(d->base.render, d->backBuf);
1313 }
1280 /* Clear the window. The clear color is visible as a border around the window 1314 /* Clear the window. The clear color is visible as a border around the window
1281 when the custom frame is being used. */ { 1315 when the custom frame is being used. */ {
1282 setCurrent_Root(w->roots[0]); 1316 setCurrent_Root(w->roots[0]);
@@ -1359,6 +1393,10 @@ void draw_MainWindow(iMainWindow *d) {
1359 drawCount_ = 0; 1393 drawCount_ = 0;
1360#endif 1394#endif
1361 } 1395 }
1396 if (d->backBuf) {
1397 SDL_SetRenderTarget(d->base.render, NULL);
1398 SDL_RenderCopy(d->base.render, d->backBuf, NULL, NULL);
1399 }
1362#if 0 1400#if 0
1363 /* Text cache debugging. */ { 1401 /* Text cache debugging. */ {
1364 SDL_Rect rect = { d->roots[0]->widget->rect.size.x - 640, 0, 640, 2.5 * 640 }; 1402 SDL_Rect rect = { d->roots[0]->widget->rect.size.x - 640, 0, 640, 2.5 * 640 };
diff --git a/src/ui/window.h b/src/ui/window.h
index b4e348d2..5abf23eb 100644
--- a/src/ui/window.h
+++ b/src/ui/window.h
@@ -118,6 +118,8 @@ struct Impl_MainWindow {
118 SDL_Texture * appIcon; 118 SDL_Texture * appIcon;
119 int keyboardHeight; /* mobile software keyboards */ 119 int keyboardHeight; /* mobile software keyboards */
120 int maxDrawableHeight; 120 int maxDrawableHeight;
121 iBool enableBackBuf; /* only used on macOS with Metal (helps with refresh glitches for some reason??) */
122 SDL_Texture * backBuf; /* enables refreshing the window without redrawing anything */
121}; 123};
122 124
123iLocalDef enum iWindowType type_Window(const iAnyWindow *d) { 125iLocalDef enum iWindowType type_Window(const iAnyWindow *d) {