From d9ec2267f7e8a4eeb06b495f9b6dbe804196fd9f Mon Sep 17 00:00:00 2001
From: vanfanel <redwindwanderer@gmail.com>
Date: Wed, 18 Oct 2017 12:06:58 +0000
Subject: [PATCH] Change max_swapchain=2 implementation to actually working
 code.

---
 gfx/drivers_context/vc_egl_ctx.c | 55 +++++++++++++++++++++++++++++---
 1 file changed, 51 insertions(+), 4 deletions(-)

diff --git a/gfx/drivers_context/vc_egl_ctx.c b/gfx/drivers_context/vc_egl_ctx.c
index 0c1761b92a..c9b5647acd 100644
--- a/gfx/drivers_context/vc_egl_ctx.c
+++ b/gfx/drivers_context/vc_egl_ctx.c
@@ -24,6 +24,7 @@
 
 #include <VG/openvg.h>
 #include <bcm_host.h>
+#include <rthreads/rthreads.h>
 
 #ifdef HAVE_CONFIG_H
 #include "../../config.h"
@@ -59,6 +60,12 @@ typedef struct
    egl_ctx_data_t egl;
 #endif
    EGL_DISPMANX_WINDOW_T native_window;
+   DISPMANX_DISPLAY_HANDLE_T dispman_display;
+
+   /* For vsync wait after eglSwapBuffers when max_swapchain < 3 */
+   scond_t *vsync_condition;
+   slock_t *vsync_condition_mutex;
+   bool vsync_callback_set;
 
    bool resize;
    unsigned fb_width, fb_height;
@@ -134,6 +141,15 @@ static void gfx_ctx_vc_get_video_size(void *data,
    }
 }
 
+static void dispmanx_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data)
+{
+   vc_ctx_data_t *vc = (vc_ctx_data_t*)data;
+
+   slock_lock(vc->vsync_condition_mutex);
+   scond_signal(vc->vsync_condition);
+   slock_unlock(vc->vsync_condition_mutex);
+}
+
 static void gfx_ctx_vc_destroy(void *data);
 
 static void *gfx_ctx_vc_init(video_frame_info_t *video_info, void *video_driver)
@@ -235,6 +251,7 @@ static void *gfx_ctx_vc_init(video_frame_info_t *video_info, void *video_driver)
    }
 
    dispman_display = vc_dispmanx_display_open(0 /* LCD */);
+   vc->dispman_display = dispman_display;
    vc_dispmanx_display_get_info(dispman_display, &dispman_modeinfo);
    dispman_update = vc_dispmanx_update_start(0);
 
@@ -281,6 +298,16 @@ static void *gfx_ctx_vc_init(video_frame_info_t *video_info, void *video_driver)
       goto error;
 #endif
 
+   /* For vsync after eglSwapBuffers when max_swapchain < 3 */
+   vc->vsync_condition       = scond_new();
+   vc->vsync_condition_mutex = slock_new();
+   vc->vsync_callback_set = false;
+   if (video_info->max_swapchain_images <= 2) {
+      /* Start sending vsync callbacks so we can wait for vsync after eglSwapBuffers */ 
+      vc_dispmanx_vsync_callback(vc->dispman_display, dispmanx_vsync_callback, (void*)vc);
+      vc->vsync_callback_set = true;
+   }
+
    return vc;
 
 error:
@@ -291,7 +318,6 @@ error:
 static void gfx_ctx_vc_set_swap_interval(void *data, unsigned swap_interval)
 {
    vc_ctx_data_t *vc = (vc_ctx_data_t*)data;
-   
 #ifdef HAVE_EGL
    egl_set_swap_interval(&vc->egl, swap_interval);
 #endif
@@ -305,18 +331,18 @@ static bool gfx_ctx_vc_set_video_mode(void *data,
     vc_ctx_data_t *vc = (vc_ctx_data_t*)data;
 
 #ifdef HAVE_EGL
+
    if (g_egl_inited)
       return false;
 
    frontend_driver_install_signal_handler();
-   gfx_ctx_vc_set_swap_interval(&vc->egl, vc->egl.interval);
 
    /* If we set this env variable, Broadcom's EGL implementation will block
     * on vsync with a double buffer when we call eglSwapBuffers. Less input lag!  */
-   if (video_info->max_swapchain_images <= 2)
+   /*if (video_info->max_swapchain_images <= 2)
       setenv("V3D_DOUBLE_BUFFER", "1", 1);
    else
-      setenv("V3D_DOUBLE_BUFFER", "0", 1);
+      setenv("V3D_DOUBLE_BUFFER", "0", 1);*/
 
    gfx_ctx_vc_set_swap_interval(&vc->egl, vc->egl.interval);
 
@@ -436,6 +462,10 @@ static void gfx_ctx_vc_destroy(void *data)
       vc->eglBuffer[i]     = NULL;
       vc->vgimage[i] = 0;
    }
+
+   /* Destroy mutexes and conditions. */
+   slock_free(vc->vsync_condition_mutex);
+   scond_free(vc->vsync_condition);
 }
 
 static void gfx_ctx_vc_input_driver(void *data,
@@ -593,9 +623,26 @@ error:
 static void gfx_ctx_vc_swap_buffers(void *data, void *data2)
 {
    vc_ctx_data_t *vc = (vc_ctx_data_t*)data;
+   video_frame_info_t *video_info = (video_frame_info_t*)data2;
 
 #ifdef HAVE_EGL
    egl_swap_buffers(&vc->egl);
+
+   /* Wait for vsync immediately if we don't wait egl_swap_buffers to triple-buffer */
+   if (video_info->max_swapchain_images <= 2) {
+      /* We DON'T wait to wait without callback function ready! */
+      if(!vc->vsync_callback_set) {
+         vc_dispmanx_vsync_callback(vc->dispman_display, dispmanx_vsync_callback, (void*)vc);
+         vc->vsync_callback_set = true;
+      }
+      slock_lock(vc->vsync_condition_mutex);
+      scond_wait(vc->vsync_condition, vc->vsync_condition_mutex);
+      slock_unlock(vc->vsync_condition_mutex);      
+   }
+   else if (vc->vsync_callback_set) {
+      /* Stop generating vsync callbacks from now on */
+      vc_dispmanx_vsync_callback(vc->dispman_display, NULL, NULL);
+   }
 #endif
 }