From b53ab6f04ab98aa5cb7c509ef048ec2a2a15f63c Mon Sep 17 00:00:00 2001 From: Graham Date: Mon, 2 Sep 2019 19:05:20 +0100 Subject: [PATCH] Reduce screen corruption when resizing This commit clears framebuffers when they are created, copies the contents of the previous framebuffer to the new framebuffer when resizing and moves all the resizing code into the blit method. All of these help to reduce screen corruption, although a small amount still remains if you resize quickly. --- gl-natives/src/main/c/jaggl.c | 108 +++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/gl-natives/src/main/c/jaggl.c b/gl-natives/src/main/c/jaggl.c index 4a88e77b..0f04a4fc 100644 --- a/gl-natives/src/main/c/jaggl.c +++ b/gl-natives/src/main/c/jaggl.c @@ -226,42 +226,72 @@ static void *jaggl_proc_addr(const char *name) { [super dealloc]; } -- (void)genFramebuffer { - framebuffer_width = (GLint) self.bounds.size.width; - framebuffer_height = (GLint) self.bounds.size.height; +- (void)blit { + [lock lock]; - glGenFramebuffersEXT(1, &framebuffer); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer); + /* get current size */ + NSSize size = self.bounds.size; + GLint width = (GLint) size.width; + GLint height = (GLint) size.height; - glGenRenderbuffersEXT(1, &renderbuffer_color); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer_color); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, framebuffer_width, framebuffer_height); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, renderbuffer_color); + /* check if we need to resize the framebuffer/off-screen window */ + bool resized = width != framebuffer_width || height != framebuffer_height; - glGenRenderbuffersEXT(1, &renderbuffer_depth); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer_depth); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, framebuffer_width, framebuffer_height); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, renderbuffer_depth); + if (!framebuffer || resized) { + /* create new framebuffer */ + GLuint new_framebuffer, new_renderbuffer_color, new_renderbuffer_depth; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -} + glGenFramebuffersEXT(1, &new_framebuffer); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, new_framebuffer); -- (void)deleteFramebuffer { - glDeleteRenderbuffersEXT(1, &renderbuffer_depth); - glDeleteRenderbuffersEXT(1, &renderbuffer_color); - glDeleteFramebuffersEXT(1, &framebuffer); -} + glGenRenderbuffersEXT(1, &new_renderbuffer_color); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, new_renderbuffer_color); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, width, height); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, new_renderbuffer_color); -- (void)blit { - [lock lock]; + glGenRenderbuffersEXT(1, &new_renderbuffer_depth); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, new_renderbuffer_depth); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, new_renderbuffer_depth); - if (!framebuffer) { - return; + /* clear the framebuffer */ + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* copy the old framebuffer to the new framebuffer */ + if (framebuffer) { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, new_framebuffer); + + glBlitFramebufferEXT(0, 0, framebuffer_width, framebuffer_height, 0, 0, framebuffer_width, framebuffer_height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + /* delete the old framebuffer */ + if (framebuffer) { + glDeleteRenderbuffersEXT(1, &renderbuffer_depth); + glDeleteRenderbuffersEXT(1, &renderbuffer_color); + glDeleteFramebuffersEXT(1, &framebuffer); + } + + /* update framebuffer_* vars */ + framebuffer = new_framebuffer; + renderbuffer_color = new_renderbuffer_color; + renderbuffer_depth = new_renderbuffer_depth; + framebuffer_width = width; + framebuffer_height = height; } + /* bind the existing framebuffer */ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, framebuffer); + /* clear the framebuffer */ + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* copy current off-screen contents to the framebuffer */ glBlitFramebufferEXT(0, 0, framebuffer_width, framebuffer_height, 0, 0, framebuffer_width, framebuffer_height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); @@ -270,6 +300,12 @@ static void *jaggl_proc_addr(const char *name) { dispatch_sync(dispatch_get_main_queue(), ^{ [self setNeedsDisplay]; + + if (resized) { + jaggl_view.frame = NSMakeRect(0, 0, width, height); + [jaggl_window setFrame:[jaggl_window frameRectForContentRect:jaggl_view.frame] display:YES]; + [jaggl_context_appkit update]; + } }); } @@ -286,25 +322,17 @@ static void *jaggl_proc_addr(const char *name) { displayTime:(const CVTimeStamp *)displayTime { CGLSetCurrentContext(context); - GLint width = (GLint) self.bounds.size.width; - GLint height = (GLint) self.bounds.size.height; - [lock lock]; - /* TODO(gpe): improve resize support (fix corruption, do we need to resize the NSView/NSWindow?) */ - if (width != framebuffer_width || height != framebuffer_height) { - [self deleteFramebuffer]; - [self genFramebuffer]; + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - jaggl_view.frame = NSMakeRect(0, 0, width, height); - [jaggl_window setFrame:[jaggl_window frameRectForContentRect:jaggl_view.frame] display:YES]; - [jaggl_context_appkit update]; + if (framebuffer) { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebuffer); + glBlitFramebufferEXT(0, 0, framebuffer_width, framebuffer_height, 0, 0, framebuffer_width, framebuffer_height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); } - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebuffer); - glBlitFramebufferEXT(0, 0, framebuffer_width, framebuffer_height, 0, 0, framebuffer_width, framebuffer_height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); - [lock unlock]; [super drawInCGLContext:context pixelFormat:pixelFormat forLayerTime:layerTime displayTime:displayTime]; @@ -319,10 +347,6 @@ static void *jaggl_proc_addr(const char *name) { } - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pix { - CGLSetCurrentContext(jaggl_onscreen_context); - [lock lock]; - [self genFramebuffer]; - [lock unlock]; return jaggl_onscreen_context; }