From ffafa5cfc79f83cbec73f666b37da615467abb8b Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 4 Feb 2023 21:35:47 +0100 Subject: [PATCH] NSGLView: clean up, allow optional scaling --- libs/gtkmm2ext/gtkmm2ext/nsglview.h | 1 + libs/gtkmm2ext/nsglview.mm | 219 ++++++++++++++++------------ 2 files changed, 125 insertions(+), 95 deletions(-) diff --git a/libs/gtkmm2ext/gtkmm2ext/nsglview.h b/libs/gtkmm2ext/gtkmm2ext/nsglview.h index da3010a068..d57c2b67bf 100644 --- a/libs/gtkmm2ext/gtkmm2ext/nsglview.h +++ b/libs/gtkmm2ext/gtkmm2ext/nsglview.h @@ -26,6 +26,7 @@ namespace Gtkmm2ext class CairoCanvas; void* nsglview_create (CairoCanvas*); + void* nsglview_create (CairoCanvas*, bool use_backing_scale); void nsglview_overlay (void*, GdkWindow*); void nsglview_resize (void*, int x, int y, int w, int h); void nsglview_queue_draw (void*, int x, int y, int w, int h); diff --git a/libs/gtkmm2ext/nsglview.mm b/libs/gtkmm2ext/nsglview.mm index 7b149edca7..0479ad7a29 100644 --- a/libs/gtkmm2ext/nsglview.mm +++ b/libs/gtkmm2ext/nsglview.mm @@ -51,27 +51,31 @@ __attribute__ ((visibility ("hidden"))) @interface ArdourCanvasOpenGLView : NSOpenGLView { @private - unsigned int _texture_id; - int _width; - int _height; - Cairo::RefPtr surf; - Gtkmm2ext::CairoCanvas *cairo_canvas; - NSInteger _tag; + Cairo::RefPtr _surf; + Gtkmm2ext::CairoCanvas* _cairo_canvas; + NSInteger _tag; + unsigned int _texture_id; + int _width; + int _height; + float _scale; + bool _use_backing_scale; GdkRectangle _expose_area; } @property (readwrite) NSInteger tag; +- (instancetype)initWithScale:(BOOL)use_backing_scale; - (id) initWithFrame:(NSRect)frame; - (void) dealloc; -- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c; +- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)canvas; - (void) reshape; - (void) setNeedsDisplayInRect:(NSRect)rect; - (void) setNeedsDisplay:(BOOL)yn; - (void) drawRect:(NSRect)rect; - (BOOL) canBecomeKeyWindow:(id)sender; - (BOOL) acceptsFirstResponder:(id)sender; +- (void) reallocateTexture; @end @@ -103,9 +107,11 @@ __attribute__ ((visibility ("hidden"))) } _texture_id = 0; - _width = 0; - _height = 0; - _expose_area.x = _expose_area.y = _expose_area.width = _expose_area.height = 0; + _width = 0; + _height = 0; + _scale = 1.; + + _expose_area.x = _expose_area.y = _expose_area.width = _expose_area.height = 0; if (self) { self.tag = ARDOUR_CANVAS_NSVIEW_TAG; @@ -117,12 +123,12 @@ __attribute__ ((visibility ("hidden"))) glEnable (GL_TEXTURE_RECTANGLE_ARB); [NSOpenGLContext clearCurrentContext]; -#if 1 - [self setWantsBestResolutionOpenGLSurface:YES]; - [self setWantsLayer:YES]; -#else - [self setWantsBestResolutionOpenGLSurface:NO]; -#endif + if (_use_backing_scale) { + [self setWantsBestResolutionOpenGLSurface:YES]; + [self setWantsLayer:YES]; + } else { + [self setWantsBestResolutionOpenGLSurface:NO]; + } [self reshape]; } @@ -130,6 +136,14 @@ __attribute__ ((visibility ("hidden"))) return self; } +- (instancetype)initWithScale:(BOOL)use_backing_scale +{ + _use_backing_scale = use_backing_scale; + [super init]; + return self; +} + + - (void) dealloc { [[self openGLContext] makeCurrentContext]; glDeleteTextures (1, &_texture_id); @@ -138,9 +152,9 @@ __attribute__ ((visibility ("hidden"))) [super dealloc]; } -- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c +- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)canvas { - cairo_canvas = c; + _cairo_canvas = canvas; } - (BOOL) canBecomeKeyWindow:(id)sender{ @@ -151,27 +165,13 @@ __attribute__ ((visibility ("hidden"))) return NO; } -- (void) reshape +- (void) reallocateTexture { - [super reshape]; - [[self openGLContext] update]; + /* must be called withing GLContext */ + int const w = _width * _scale; + int const h = _height * _scale; - NSRect bounds = [self bounds]; - int width = bounds.size.width; - int height = bounds.size.height; - - if (_width == width && _height == height) { - return; - } - - float scale = 1.0; - if ([self window]) { - scale = [[self window] backingScaleFactor]; - } - - [[self openGLContext] makeCurrentContext]; - - glViewport (0, 0, width * scale, height * scale); + glViewport (0, 0, w, h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); @@ -182,31 +182,55 @@ __attribute__ ((visibility ("hidden"))) glGenTextures (1, &_texture_id); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _texture_id); glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, - width * scale, height * scale, 0, + w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - [NSOpenGLContext clearCurrentContext]; + + _expose_area.x = _expose_area.y = 0; + _expose_area.width = _width; + _expose_area.height = _height; +} + +- (void) reshape +{ + [super reshape]; + [[self openGLContext] update]; + + NSRect bounds = [self bounds]; + int width = bounds.size.width; + int height = bounds.size.height; + float scale = 1.0; + + if (_use_backing_scale && [self window]) { + scale = [[self window] backingScaleFactor]; + } + + if (_width == width && _height == height && _scale == scale) { + return; + } _width = width; _height = height; + _scale = scale; - _expose_area.x = _expose_area.y = 0; - _expose_area.width = width; - _expose_area.height = height; + [[self openGLContext] makeCurrentContext]; + [self reallocateTexture]; + [NSOpenGLContext clearCurrentContext]; } - (void) setNeedsDisplay:(BOOL)yn { if (yn) { - _expose_area.x = _expose_area.y = 0; - _expose_area.width = _width; + _expose_area.x = 0; + _expose_area.y = 0; + _expose_area.width = _width; _expose_area.height = _height; #ifdef DEBUG_NSVIEW_EXPOSURE - printf ("needsDisplay: FULL %d x %d\n", _width, _height); + printf ("setNeedsDisplay: %4d x %4d\n", _width, _height); #endif } [super setNeedsDisplay:yn]; @@ -215,15 +239,14 @@ __attribute__ ((visibility ("hidden"))) - (void) setNeedsDisplayInRect:(NSRect)rect { #ifdef DEBUG_NSVIEW_EXPOSURE - printf ("needsDisplay: %5.1f %5.1f %5.1f %5.1f\n", - rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + printf ("setNeedsDisplayInRect: %4.0f x %4.0f @ %.0f + %.0f\n", + rect.size.width, rect.size.height, rect.origin.x, rect.origin.y); #endif - //GdkRectangle r2 = {_expose_area.x, _expose_area.y, _expose_area.width, _expose_area.height }; if (_expose_area.width == 0 && _expose_area.height == 0) { - _expose_area.x = rect.origin.x; - _expose_area.y = rect.origin.y; - _expose_area.width = rect.size.width; + _expose_area.x = rect.origin.x; + _expose_area.y = rect.origin.y; + _expose_area.width = rect.size.width; _expose_area.height = rect.size.height; } else { GdkRectangle r1 = {(int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height}; @@ -242,12 +265,20 @@ __attribute__ ((visibility ("hidden"))) const int64_t start = g_get_monotonic_time (); #endif - float scale = 1.0; - if ([self window]) { + float scale = 1.0; + + if (_use_backing_scale && [self window]) { scale = [[self window] backingScaleFactor]; } - [[self openGLContext] makeCurrentContext]; + if ( _scale != scale) { + _scale = scale; + [[self openGLContext] update]; + [[self openGLContext] makeCurrentContext]; + [self reallocateTexture]; + } else { + [[self openGLContext] makeCurrentContext]; + } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -256,51 +287,48 @@ __attribute__ ((visibility ("hidden"))) /* call back into CairoCanvas */ cairo_rectangle_t cairo_rect; -#if 0 - cairo_rect.x = rect.origin.x; - cairo_rect.y = rect.origin.y; - cairo_rect.width = rect.size.width; - cairo_rect.height = rect.size.height; -#else - cairo_rect.x = _expose_area.x; - cairo_rect.y = _expose_area.y; - cairo_rect.width = _expose_area.width; + cairo_rect.x = _expose_area.x; + cairo_rect.y = _expose_area.y; + cairo_rect.width = _expose_area.width; cairo_rect.height = _expose_area.height; -#endif - _expose_area.x = _expose_area.y = _expose_area.width = _expose_area.height = 0; + _expose_area.x = _expose_area.y = _expose_area.width = _expose_area.height = 0; - if (!surf || surf->get_width () != _width * scale || surf->get_height() != _height * scale) { - surf = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, _width * scale, _height * scale); + int const w = _width * _scale; + int const h = _height * _scale; + + if (!_surf || _surf->get_width () != w || _surf->get_height() != h) { + _surf = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, w, h); cairo_rect.x = 0; cairo_rect.y = 0; - cairo_rect.width = _width; + cairo_rect.width = _width; cairo_rect.height = _height; } - Cairo::RefPtr ctx = Cairo::Context::create (surf); - ctx->scale (scale, scale); +#ifdef DEBUG_NSVIEW_EXPOSURE + printf ("NSGL::drawRect: ...... %4.0f x %4.0f @ %.0f + %.0f\n", + cairo_rect.width, cairo_rect.height, cairo_rect.x, cairo_rect.y); +#endif + + + Cairo::RefPtr ctx = Cairo::Context::create (_surf); + ctx->scale (_scale, _scale); ctx->rectangle (cairo_rect.x, cairo_rect.y, cairo_rect.width, cairo_rect.height); - ctx->clip_preserve (); + ctx->clip (); { /* draw background color */ - uint32_t col = cairo_canvas->background_color (); + uint32_t col = _cairo_canvas->background_color (); int r, g, b, a; UINT_TO_RGBA (col, &r, &g, &b, &a); ctx->set_source_rgba (r/255.0, g/255.0, b/255.0, a/255.0); + ctx->paint (); } - ctx->fill (); -#ifdef DEBUG_NSVIEW_EXPOSURE - printf ("drawRect: %.1f %.1f %.1f %1.f\n", - cairo_rect.x, cairo_rect.y, cairo_rect.width, cairo_rect.height); -#endif + _cairo_canvas->render (ctx, &cairo_rect); - cairo_canvas->render (ctx, &cairo_rect); - - surf->flush (); - uint8_t* imgdata = surf->get_data (); + _surf->flush (); + uint8_t* imgdata = _surf->get_data (); /* NOTE for big-endian (PPC), we'd need to flip byte-order * RGBA <> RGBA for the texture. @@ -313,20 +341,20 @@ __attribute__ ((visibility ("hidden"))) glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture_id); glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, - _width * scale, _height * scale, /*border*/ 0, + w, h, /*border*/ 0, GL_BGRA, GL_UNSIGNED_BYTE, imgdata); glBegin(GL_QUADS); - glTexCoord2f( 0.0f, (GLfloat) _height * scale); + glTexCoord2f(0.0f, (GLfloat) h); glVertex2f(-1.0f, -1.0f); - glTexCoord2f((GLfloat) _width * scale, (GLfloat) _height * scale); - glVertex2f( 1.0f, -1.0f); + glTexCoord2f((GLfloat) w, (GLfloat) h); + glVertex2f(1.0f, -1.0f); - glTexCoord2f((GLfloat) _width * scale, 0.0f); - glVertex2f( 1.0f, 1.0f); + glTexCoord2f((GLfloat) w, 0.0f); + glVertex2f(1.0f, 1.0f); - glTexCoord2f( 0.0f, 0.0f); + glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, 1.0f); glEnd(); @@ -341,15 +369,19 @@ __attribute__ ((visibility ("hidden"))) #ifdef NSVIEW_PROFILE const int64_t end = g_get_monotonic_time (); const int64_t elapsed = end - start; - printf ("NSGL::drawRect (%d x %d) * %.1f in %f ms\n", _width, _height, scale, elapsed / 1000.f); + printf ("NSGL::drawRect (%d x %d) * %.1f in %f ms\n", _width, _height, _scale, elapsed / 1000.f); #endif - } @end - void* Gtkmm2ext::nsglview_create (Gtkmm2ext::CairoCanvas* canvas) +{ + return nsglview_create (canvas, true); +} + +void* +Gtkmm2ext::nsglview_create (Gtkmm2ext::CairoCanvas* canvas, bool use_backing_scale) { if (g_getenv ("ARDOUR_NSGL") && (0 == atoi (g_getenv ("ARDOUR_NSGL")))) { return 0; @@ -361,7 +393,7 @@ Gtkmm2ext::nsglview_create (Gtkmm2ext::CairoCanvas* canvas) #ifdef __ppc__ return 0; #endif - ArdourCanvasOpenGLView* gl_view = [ArdourCanvasOpenGLView new]; + ArdourCanvasOpenGLView* gl_view = [[ArdourCanvasOpenGLView alloc] initWithScale:use_backing_scale]; if (!gl_view) { return 0; } @@ -390,9 +422,6 @@ Gtkmm2ext::nsglview_queue_draw (void* glv, int x, int y, int w, int h) { ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv; [gl_view setNeedsDisplayInRect:NSMakeRect(x, y, w, h)]; -#ifdef DEBUG_NSVIEW_EXPOSURE - printf ("Queue Draw %5d %5d %5d %5d\n", x, y, w, h); -#endif } void