13
0

NSGLView: clean up, allow optional scaling

This commit is contained in:
Robin Gareus 2023-02-04 21:35:47 +01:00
parent d12dd4015d
commit ffafa5cfc7
2 changed files with 125 additions and 95 deletions

View File

@ -26,6 +26,7 @@ namespace Gtkmm2ext
class CairoCanvas; class CairoCanvas;
void* nsglview_create (CairoCanvas*); void* nsglview_create (CairoCanvas*);
void* nsglview_create (CairoCanvas*, bool use_backing_scale);
void nsglview_overlay (void*, GdkWindow*); void nsglview_overlay (void*, GdkWindow*);
void nsglview_resize (void*, int x, int y, int w, int h); 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); void nsglview_queue_draw (void*, int x, int y, int w, int h);

View File

@ -51,27 +51,31 @@ __attribute__ ((visibility ("hidden")))
@interface ArdourCanvasOpenGLView : NSOpenGLView @interface ArdourCanvasOpenGLView : NSOpenGLView
{ {
@private @private
unsigned int _texture_id; Cairo::RefPtr<Cairo::ImageSurface> _surf;
int _width; Gtkmm2ext::CairoCanvas* _cairo_canvas;
int _height;
Cairo::RefPtr<Cairo::ImageSurface> surf;
Gtkmm2ext::CairoCanvas *cairo_canvas;
NSInteger _tag;
NSInteger _tag;
unsigned int _texture_id;
int _width;
int _height;
float _scale;
bool _use_backing_scale;
GdkRectangle _expose_area; GdkRectangle _expose_area;
} }
@property (readwrite) NSInteger tag; @property (readwrite) NSInteger tag;
- (instancetype)initWithScale:(BOOL)use_backing_scale;
- (id) initWithFrame:(NSRect)frame; - (id) initWithFrame:(NSRect)frame;
- (void) dealloc; - (void) dealloc;
- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c; - (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)canvas;
- (void) reshape; - (void) reshape;
- (void) setNeedsDisplayInRect:(NSRect)rect; - (void) setNeedsDisplayInRect:(NSRect)rect;
- (void) setNeedsDisplay:(BOOL)yn; - (void) setNeedsDisplay:(BOOL)yn;
- (void) drawRect:(NSRect)rect; - (void) drawRect:(NSRect)rect;
- (BOOL) canBecomeKeyWindow:(id)sender; - (BOOL) canBecomeKeyWindow:(id)sender;
- (BOOL) acceptsFirstResponder:(id)sender; - (BOOL) acceptsFirstResponder:(id)sender;
- (void) reallocateTexture;
@end @end
@ -103,9 +107,11 @@ __attribute__ ((visibility ("hidden")))
} }
_texture_id = 0; _texture_id = 0;
_width = 0; _width = 0;
_height = 0; _height = 0;
_expose_area.x = _expose_area.y = _expose_area.width = _expose_area.height = 0; _scale = 1.;
_expose_area.x = _expose_area.y = _expose_area.width = _expose_area.height = 0;
if (self) { if (self) {
self.tag = ARDOUR_CANVAS_NSVIEW_TAG; self.tag = ARDOUR_CANVAS_NSVIEW_TAG;
@ -117,12 +123,12 @@ __attribute__ ((visibility ("hidden")))
glEnable (GL_TEXTURE_RECTANGLE_ARB); glEnable (GL_TEXTURE_RECTANGLE_ARB);
[NSOpenGLContext clearCurrentContext]; [NSOpenGLContext clearCurrentContext];
#if 1 if (_use_backing_scale) {
[self setWantsBestResolutionOpenGLSurface:YES]; [self setWantsBestResolutionOpenGLSurface:YES];
[self setWantsLayer:YES]; [self setWantsLayer:YES];
#else } else {
[self setWantsBestResolutionOpenGLSurface:NO]; [self setWantsBestResolutionOpenGLSurface:NO];
#endif }
[self reshape]; [self reshape];
} }
@ -130,6 +136,14 @@ __attribute__ ((visibility ("hidden")))
return self; return self;
} }
- (instancetype)initWithScale:(BOOL)use_backing_scale
{
_use_backing_scale = use_backing_scale;
[super init];
return self;
}
- (void) dealloc { - (void) dealloc {
[[self openGLContext] makeCurrentContext]; [[self openGLContext] makeCurrentContext];
glDeleteTextures (1, &_texture_id); glDeleteTextures (1, &_texture_id);
@ -138,9 +152,9 @@ __attribute__ ((visibility ("hidden")))
[super dealloc]; [super dealloc];
} }
- (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c - (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)canvas
{ {
cairo_canvas = c; _cairo_canvas = canvas;
} }
- (BOOL) canBecomeKeyWindow:(id)sender{ - (BOOL) canBecomeKeyWindow:(id)sender{
@ -151,27 +165,13 @@ __attribute__ ((visibility ("hidden")))
return NO; return NO;
} }
- (void) reshape - (void) reallocateTexture
{ {
[super reshape]; /* must be called withing GLContext */
[[self openGLContext] update]; int const w = _width * _scale;
int const h = _height * _scale;
NSRect bounds = [self bounds]; glViewport (0, 0, w, h);
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);
glMatrixMode (GL_PROJECTION); glMatrixMode (GL_PROJECTION);
glLoadIdentity (); glLoadIdentity ();
glOrtho (-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); glOrtho (-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
@ -182,31 +182,55 @@ __attribute__ ((visibility ("hidden")))
glGenTextures (1, &_texture_id); glGenTextures (1, &_texture_id);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _texture_id); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _texture_id);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
width * scale, height * scale, 0, w, h, 0,
GL_BGRA, GL_UNSIGNED_BYTE, NULL); GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 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; _width = width;
_height = height; _height = height;
_scale = scale;
_expose_area.x = _expose_area.y = 0; [[self openGLContext] makeCurrentContext];
_expose_area.width = width; [self reallocateTexture];
_expose_area.height = height; [NSOpenGLContext clearCurrentContext];
} }
- (void) setNeedsDisplay:(BOOL)yn - (void) setNeedsDisplay:(BOOL)yn
{ {
if (yn) { if (yn) {
_expose_area.x = _expose_area.y = 0; _expose_area.x = 0;
_expose_area.width = _width; _expose_area.y = 0;
_expose_area.width = _width;
_expose_area.height = _height; _expose_area.height = _height;
#ifdef DEBUG_NSVIEW_EXPOSURE #ifdef DEBUG_NSVIEW_EXPOSURE
printf ("needsDisplay: FULL %d x %d\n", _width, _height); printf ("setNeedsDisplay: %4d x %4d\n", _width, _height);
#endif #endif
} }
[super setNeedsDisplay:yn]; [super setNeedsDisplay:yn];
@ -215,15 +239,14 @@ __attribute__ ((visibility ("hidden")))
- (void) setNeedsDisplayInRect:(NSRect)rect - (void) setNeedsDisplayInRect:(NSRect)rect
{ {
#ifdef DEBUG_NSVIEW_EXPOSURE #ifdef DEBUG_NSVIEW_EXPOSURE
printf ("needsDisplay: %5.1f %5.1f %5.1f %5.1f\n", printf ("setNeedsDisplayInRect: %4.0f x %4.0f @ %.0f + %.0f\n",
rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); rect.size.width, rect.size.height, rect.origin.x, rect.origin.y);
#endif #endif
//GdkRectangle r2 = {_expose_area.x, _expose_area.y, _expose_area.width, _expose_area.height };
if (_expose_area.width == 0 && _expose_area.height == 0) { if (_expose_area.width == 0 && _expose_area.height == 0) {
_expose_area.x = rect.origin.x; _expose_area.x = rect.origin.x;
_expose_area.y = rect.origin.y; _expose_area.y = rect.origin.y;
_expose_area.width = rect.size.width; _expose_area.width = rect.size.width;
_expose_area.height = rect.size.height; _expose_area.height = rect.size.height;
} else { } else {
GdkRectangle r1 = {(int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height}; 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 (); const int64_t start = g_get_monotonic_time ();
#endif #endif
float scale = 1.0; float scale = 1.0;
if ([self window]) {
if (_use_backing_scale && [self window]) {
scale = [[self window] backingScaleFactor]; 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); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
@ -256,51 +287,48 @@ __attribute__ ((visibility ("hidden")))
/* call back into CairoCanvas */ /* call back into CairoCanvas */
cairo_rectangle_t cairo_rect; cairo_rectangle_t cairo_rect;
#if 0 cairo_rect.x = _expose_area.x;
cairo_rect.x = rect.origin.x; cairo_rect.y = _expose_area.y;
cairo_rect.y = rect.origin.y; cairo_rect.width = _expose_area.width;
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.height = _expose_area.height; 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) { int const w = _width * _scale;
surf = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, _width * scale, _height * 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.x = 0;
cairo_rect.y = 0; cairo_rect.y = 0;
cairo_rect.width = _width; cairo_rect.width = _width;
cairo_rect.height = _height; cairo_rect.height = _height;
} }
Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create (surf); #ifdef DEBUG_NSVIEW_EXPOSURE
ctx->scale (scale, scale); 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<Cairo::Context> ctx = Cairo::Context::create (_surf);
ctx->scale (_scale, _scale);
ctx->rectangle (cairo_rect.x, cairo_rect.y, cairo_rect.width, cairo_rect.height); ctx->rectangle (cairo_rect.x, cairo_rect.y, cairo_rect.width, cairo_rect.height);
ctx->clip_preserve (); ctx->clip ();
{ {
/* draw background color */ /* draw background color */
uint32_t col = cairo_canvas->background_color (); uint32_t col = _cairo_canvas->background_color ();
int r, g, b, a; int r, g, b, a;
UINT_TO_RGBA (col, &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->set_source_rgba (r/255.0, g/255.0, b/255.0, a/255.0);
ctx->paint ();
} }
ctx->fill ();
#ifdef DEBUG_NSVIEW_EXPOSURE _cairo_canvas->render (ctx, &cairo_rect);
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); _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 /* NOTE for big-endian (PPC), we'd need to flip byte-order
* RGBA <> RGBA for the texture. * RGBA <> RGBA for the texture.
@ -313,20 +341,20 @@ __attribute__ ((visibility ("hidden")))
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture_id); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture_id);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
_width * scale, _height * scale, /*border*/ 0, w, h, /*border*/ 0,
GL_BGRA, GL_UNSIGNED_BYTE, imgdata); GL_BGRA, GL_UNSIGNED_BYTE, imgdata);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2f( 0.0f, (GLfloat) _height * scale); glTexCoord2f(0.0f, (GLfloat) h);
glVertex2f(-1.0f, -1.0f); glVertex2f(-1.0f, -1.0f);
glTexCoord2f((GLfloat) _width * scale, (GLfloat) _height * scale); glTexCoord2f((GLfloat) w, (GLfloat) h);
glVertex2f( 1.0f, -1.0f); glVertex2f(1.0f, -1.0f);
glTexCoord2f((GLfloat) _width * scale, 0.0f); glTexCoord2f((GLfloat) w, 0.0f);
glVertex2f( 1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
glTexCoord2f( 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
glEnd(); glEnd();
@ -341,15 +369,19 @@ __attribute__ ((visibility ("hidden")))
#ifdef NSVIEW_PROFILE #ifdef NSVIEW_PROFILE
const int64_t end = g_get_monotonic_time (); const int64_t end = g_get_monotonic_time ();
const int64_t elapsed = end - start; 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 #endif
} }
@end @end
void* void*
Gtkmm2ext::nsglview_create (Gtkmm2ext::CairoCanvas* canvas) 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")))) { if (g_getenv ("ARDOUR_NSGL") && (0 == atoi (g_getenv ("ARDOUR_NSGL")))) {
return 0; return 0;
@ -361,7 +393,7 @@ Gtkmm2ext::nsglview_create (Gtkmm2ext::CairoCanvas* canvas)
#ifdef __ppc__ #ifdef __ppc__
return 0; return 0;
#endif #endif
ArdourCanvasOpenGLView* gl_view = [ArdourCanvasOpenGLView new]; ArdourCanvasOpenGLView* gl_view = [[ArdourCanvasOpenGLView alloc] initWithScale:use_backing_scale];
if (!gl_view) { if (!gl_view) {
return 0; 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; ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
[gl_view setNeedsDisplayInRect:NSMakeRect(x, y, w, h)]; [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 void