Skip to content

Commit

Permalink
enhancement: moving renderer to its own thread
Browse files Browse the repository at this point in the history
  • Loading branch information
twaik committed Dec 31, 2024
1 parent 2f0aea9 commit f7078cb
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 12 deletions.
4 changes: 2 additions & 2 deletions app/src/main/cpp/lorie/InitOutput.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ static Bool lorieRedraw(__unused ClientPtr pClient, __unused void *closure) {
int redrawn = FALSE;

LorieBuffer_unlock(pvfb->root.buffer);
redrawn = renderer_redraw(pvfb->env, pvfb->root.flip);
redrawn = renderer_redraw();
status = LorieBuffer_lock(pvfb->root.buffer, NULL, &((PixmapPtr) pScreenPtr->devPrivate)->devPrivate.ptr);
if (status)
FatalError("Failed to lock surface: %d\n", status);
Expand All @@ -476,7 +476,7 @@ static Bool lorieRedraw(__unused ClientPtr pClient, __unused void *closure) {
lorieRequestRender();
}
} else if (pvfb->state->cursor.moved) {
renderer_redraw(pvfb->env, pvfb->root.flip);
renderer_redraw();
lorieRequestRender();
}

Expand Down
64 changes: 55 additions & 9 deletions app/src/main/cpp/lorie/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ static jmethodID Surface_release = NULL;
static jmethodID Surface_destroy = NULL;

static pthread_mutex_t resLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static JNIEnv* renderEnv = NULL;
static volatile bool contextAvailable = false;
static volatile bool drawRequested = false;
static volatile bool bufferChanged = false;
static volatile bool surfaceChanged = false;
static volatile LorieBuffer* pendingBuffer = NULL;
Expand All @@ -163,6 +166,8 @@ static struct {
GLuint g_texture_program = 0, gv_pos = 0, gv_coords = 0;
GLuint g_texture_program_bgra = 0, gv_pos_bgra = 0, gv_coords_bgra = 0;

static void* renderer_thread(void* closure);

static inline __always_inline void bindLinearTexture(GLuint id) {
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Expand All @@ -172,6 +177,8 @@ static inline __always_inline void bindLinearTexture(GLuint id) {
}

int renderer_init(JNIEnv* env, int* legacy_drawing, uint8_t* flip) {
JavaVM* vm;
pthread_t t;
EGLint major, minor;
EGLint numConfigs;
EGLint configAttribs[] = {
Expand All @@ -192,6 +199,8 @@ int renderer_init(JNIEnv* env, int* legacy_drawing, uint8_t* flip) {
return 1;

pthread_mutex_init(&resLock, NULL);
pthread_cond_init(&cond, NULL);
(*env)->GetJavaVM(env, &vm);

jclass Surface = (*env)->FindClass(env, "android/view/Surface");
Surface_release = (*env)->GetMethodID(env, Surface, "release", "()V");
Expand Down Expand Up @@ -227,6 +236,8 @@ int renderer_init(JNIEnv* env, int* legacy_drawing, uint8_t* flip) {
if (eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE)
return printEglError("eglMakeCurrent failed", 0, __LINE__);

pthread_create(&t, NULL, renderer_thread, vm);

{
// Some devices do not support sampling from HAL_PIXEL_FORMAT_BGRA_8888, here we are checking it.
const EGLint imageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
Expand Down Expand Up @@ -338,8 +349,9 @@ __unused void renderer_set_shared_state(struct lorie_shared_server_state* new_st
}

void renderer_set_buffer(JNIEnv* env, LorieBuffer* buf) {
pthread_mutex_lock(&resLock);
if (buf == pendingBuffer)
return;
goto end;

if (pendingBuffer)
LorieBuffer_release(pendingBuffer);
Expand All @@ -349,23 +361,30 @@ void renderer_set_buffer(JNIEnv* env, LorieBuffer* buf) {

if (pendingBuffer)
LorieBuffer_acquire(pendingBuffer);

pthread_cond_signal(&cond);
end: pthread_mutex_unlock(&resLock);
}

void renderer_set_window(JNIEnv* env, jobject new_surface) {
pthread_mutex_lock(&resLock);
if (pendingSurface && new_surface && pendingSurface != new_surface && (*env)->IsSameObject(env, pendingSurface, new_surface)) {
(*env)->DeleteGlobalRef(env, new_surface);
pthread_mutex_unlock(&resLock);
return;
}

if (pendingSurface && pendingSurface == new_surface)
if (pendingSurface && pendingSurface == new_surface) {
pthread_mutex_unlock(&resLock);
return;
}

if (pendingSurface)
(*env)->DeleteGlobalRef(env, pendingSurface);

pendingSurface = new_surface;
surfaceChanged = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&resLock);
}

Expand All @@ -392,7 +411,6 @@ static inline __always_inline void release_win_and_surface(JNIEnv *env, jobject*
}

void renderer_refresh_context(JNIEnv* env) {
pthread_mutex_lock(&resLock);
uint32_t emptyData = {0};
ANativeWindow* window = pendingSurface ? ANativeWindow_fromSurface(env, pendingSurface) : NULL;
if ((pendingSurface && surface && pendingSurface != surface && (*env)->IsSameObject(env, pendingSurface, surface)) || (window && win == window)) {
Expand Down Expand Up @@ -421,8 +439,6 @@ void renderer_refresh_context(JNIEnv* env) {
pendingSurface = NULL;
surfaceChanged = FALSE;

pthread_mutex_unlock(&resLock);

if (!win) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
contextAvailable = false;
Expand Down Expand Up @@ -464,8 +480,6 @@ void renderer_refresh_context(JNIEnv* env) {
glGenTextures(1, &cursor.id);
}

eglSwapInterval(egl_display, 0);

glViewport(0, 0, ANativeWindow_getWidth(win), ANativeWindow_getHeight(win));
log("Xlorie: new surface applied: %p\n", sfc);

Expand All @@ -486,7 +500,7 @@ static void draw(GLuint id, float x0, float y0, float x1, float y1, uint8_t flip
static void draw_cursor(void);

int renderer_should_redraw(void) {
return contextAvailable || surfaceChanged || bufferChanged || (state && state->cursor.updated);
return contextAvailable || surfaceChanged || bufferChanged;
}

static void renderer_renew_image(void) {
Expand Down Expand Up @@ -525,14 +539,24 @@ static void renderer_renew_image(void) {
log("renderer: buffer changed %p %d %d", buffer, desc.width, desc.height);
}

int renderer_redraw(JNIEnv* env, uint8_t flip) {
int renderer_redraw(void) {
pthread_mutex_lock(&resLock);
drawRequested = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&resLock);
return contextAvailable;
}

int renderer_redraw_locked(JNIEnv* env) {
int err = EGL_SUCCESS;

pthread_mutex_lock(&resLock);
if (surfaceChanged)
renderer_refresh_context(env);

if (bufferChanged)
renderer_renew_image();
pthread_mutex_unlock(&resLock);

if (!contextAvailable)
return FALSE;
Expand All @@ -546,12 +570,16 @@ int renderer_redraw(JNIEnv* env, uint8_t flip) {
pthread_mutex_unlock(&state->cursor.lock);
}

// We should not read root window content while server is writing it.
pthread_mutex_lock(&state->lock);
if (display.desc.data) {
bindLinearTexture(display.id);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, display.desc.width, display.desc.height, display.desc.format == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM ? GL_BGRA_EXT : GL_RGBA, GL_UNSIGNED_BYTE, display.desc.data);
}

draw(display.id, -1.f, -1.f, 1.f, 1.f, display.desc.format != AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM);
pthread_mutex_unlock(&state->lock);

draw_cursor();
if (eglSwapBuffers(egl_display, sfc) != EGL_TRUE) {
printEglError("Failed to swap buffers", 0, __LINE__);
Expand All @@ -569,6 +597,24 @@ int renderer_redraw(JNIEnv* env, uint8_t flip) {
return TRUE;
}

__noreturn static void* renderer_thread(void* closure) {
JavaVM* vm = closure;
JNIEnv* env;
(*vm)->AttachCurrentThread(vm, &env, NULL);
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init(&m, NULL);

pthread_mutex_lock(&m); // We do not need this mutex, we only wait for the signal.
while (true) {
while (!drawRequested && !surfaceChanged && !bufferChanged && (!state || !state->cursor.updated))
pthread_cond_wait(&cond, &m);

drawRequested = FALSE;
renderer_redraw_locked(env);
}
pthread_mutex_unlock(&m);
}

void renderer_print_fps(float millis) {
if (renderedFrames)
log("%d frames in %.1f seconds = %.1f FPS",
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/lorie/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ __unused void renderer_set_buffer(JNIEnv* env, LorieBuffer* buffer);
__unused void renderer_set_window(JNIEnv* env, jobject surface);
__unused void renderer_set_shared_state(struct lorie_shared_server_state* state);
__unused int renderer_should_redraw(void);
__unused int renderer_redraw(JNIEnv* env, uint8_t flip);
__unused int renderer_redraw(void);
__unused void renderer_print_fps(float millis);

0 comments on commit f7078cb

Please sign in to comment.