BioGTK  6.5.0
A .NET library & program for annotating, editing various microscopy imaging formats using Bioformats supported images. Including whole slide, pyramidal, and series.
Loading...
Searching...
No Matches
BioGTK.SlideGLArea Class Reference

A GTK GLArea widget that renders pyramidal slide tiles directly on the GPU. Eliminates ReadPixels overhead by rendering to screen instead of copying to CPU. Supports SkiaSharp overlay for annotations via GRContext. More...

Inheritance diagram for BioGTK.SlideGLArea:

Public Member Functions

void UploadTileTexture (TileIndex index, byte[] pixelData, int tileWidth, int tileHeight)
 Upload a tile texture to the GPU. Call from the main thread.
 
void GetUploadedTileSize (TileIndex index, out int w, out int h)
 Get the uploaded texture dimensions for a cached tile. Returns (0,0) if the tile is not in the cache.
 
bool HasTileTexture (TileIndex index)
 Check if a tile texture is already in the GPU cache.
 
void ReleaseTileTexture (TileIndex index)
 Release a specific tile texture.
 
void ReleaseLevelTextures (int level)
 Release all textures for a specific pyramid level.
 
void ClearTextureCache ()
 Clear all cached textures.
 
void RequestRedraw ()
 Request a redraw of the GLArea.
 
void SetTilesToRender (IEnumerable< TileRenderInfo > tiles)
 Prepare tiles for rendering. Call before RequestRedraw().
 
byte[] ReadPixels ()
 Read pixels from the current framebuffer (for export/save operations). This is slow - only use for export, not display.
 

Properties

List< TileRenderInfoTilesToRender = new() [get]
 
bool NeedsRedraw = true [get, set]
 
bool PreservePreviousFrameWhileIncomplete = false [get, set]
 
float ImageScreenX = -1 [get, set]
 
float ImageScreenY = -1 [get, set]
 
float ImageScreenW = -1 [get, set]
 
float ImageScreenH = -1 [get, set]
 
int CachedTextureCount [get]
 

Events

Action< SKCanvas, int, int > OnSkiaRender
 Event fired during Skia rendering phase for annotation drawing.
 

Detailed Description

A GTK GLArea widget that renders pyramidal slide tiles directly on the GPU. Eliminates ReadPixels overhead by rendering to screen instead of copying to CPU. Supports SkiaSharp overlay for annotations via GRContext.

Definition at line 19 of file SlideGLArea.cs.

Constructor & Destructor Documentation

◆ SlideGLArea()

BioGTK.SlideGLArea.SlideGLArea ( )

Definition at line 135 of file SlideGLArea.cs.

136 {
137 HasDepthBuffer = false;
138 HasStencilBuffer = false;
139 AutoRender = false; // We control when to render
140
141 Realized += OnRealized;
142 //Unrealize += OnUnrealize;
143 Render += OnRender;
144 Resize += OnResized;
145 }

Member Function Documentation

◆ ClearTextureCache()

void BioGTK.SlideGLArea.ClearTextureCache ( )

Clear all cached textures.

Definition at line 607 of file SlideGLArea.cs.

608 {
609 if (!_glInitialized) return;
610
611 MakeCurrent();
612
613 foreach (var tex in _textureCache.Values)
614 {
615 GL.DeleteTexture(tex);
616 }
617 _textureCache.Clear();
618 _textureSizes.Clear();
619 _textureBytes = 0;
620 }

◆ GetUploadedTileSize()

void BioGTK.SlideGLArea.GetUploadedTileSize ( TileIndex index,
out int w,
out int h )

Get the uploaded texture dimensions for a cached tile. Returns (0,0) if the tile is not in the cache.

Definition at line 548 of file SlideGLArea.cs.

549 {
550 if (_textureSizes.TryGetValue(index, out var sz))
551 { w = sz.w; h = sz.h; }
552 else
553 { w = 0; h = 0; }
554 }

◆ HasTileTexture()

bool BioGTK.SlideGLArea.HasTileTexture ( TileIndex index)

Check if a tile texture is already in the GPU cache.

Definition at line 559 of file SlideGLArea.cs.

560 {
561 return _textureCache.ContainsKey(index);
562 }

◆ ReadPixels()

byte[] BioGTK.SlideGLArea.ReadPixels ( )

Read pixels from the current framebuffer (for export/save operations). This is slow - only use for export, not display.

Definition at line 674 of file SlideGLArea.cs.

675 {
676 if (!_glInitialized) return null;
677
678 MakeCurrent();
679
680 int width = AllocatedWidth;
681 int height = AllocatedHeight;
682
683 byte[] pixels = new byte[width * height * 4];
684 GL.ReadPixels(0, 0, width, height, PixelFormat.Rgba, PixelType.UnsignedByte, pixels);
685
686 return pixels;
687 }

◆ ReleaseLevelTextures()

void BioGTK.SlideGLArea.ReleaseLevelTextures ( int level)

Release all textures for a specific pyramid level.

Definition at line 585 of file SlideGLArea.cs.

586 {
587 if (!_glInitialized) return;
588
589 MakeCurrent();
590
591 var toRemove = _textureCache.Where(kvp => kvp.Key.Level == level).ToList();
592 foreach (var kvp in toRemove)
593 {
594 GL.DeleteTexture(kvp.Value);
595 if (_textureSizes.TryGetValue(kvp.Key, out var sz))
596 {
597 _textureBytes -= (long)sz.w * sz.h * 4;
598 _textureSizes.Remove(kvp.Key);
599 }
600 _textureCache.Remove(kvp.Key);
601 }
602 }

◆ ReleaseTileTexture()

void BioGTK.SlideGLArea.ReleaseTileTexture ( TileIndex index)

Release a specific tile texture.

Definition at line 567 of file SlideGLArea.cs.

568 {
569 if (_textureCache.TryGetValue(index, out int tex))
570 {
571 MakeCurrent();
572 GL.DeleteTexture(tex);
573 _textureCache.Remove(index);
574 if (_textureSizes.TryGetValue(index, out var sz))
575 {
576 _textureBytes -= (long)sz.w * sz.h * 4;
577 _textureSizes.Remove(index);
578 }
579 }
580 }

◆ RequestRedraw()

void BioGTK.SlideGLArea.RequestRedraw ( )

Request a redraw of the GLArea.

Definition at line 645 of file SlideGLArea.cs.

646 {
647 NeedsRedraw = true;
648 QueueRender();
649 QueueDraw();
650
651 if (IsRealized && Window != null)
652 {
653 Window.InvalidateRect(Allocation, false);
654 Window.ProcessUpdates(true);
655 }
656 }

◆ SetTilesToRender()

void BioGTK.SlideGLArea.SetTilesToRender ( IEnumerable< TileRenderInfo > tiles)

Prepare tiles for rendering. Call before RequestRedraw().

Definition at line 661 of file SlideGLArea.cs.

662 {
663 TilesToRender.Clear();
664 TilesToRender.AddRange(tiles);
665 LogDiag($"[SetTilesToRender] count={TilesToRender.Count}");
666 }

◆ UploadTileTexture()

void BioGTK.SlideGLArea.UploadTileTexture ( TileIndex index,
byte[] pixelData,
int tileWidth,
int tileHeight )

Upload a tile texture to the GPU. Call from the main thread.

Definition at line 458 of file SlideGLArea.cs.

459 {
460 if (!_glInitialized)
461 {
462 LogDiag($"[UploadTileTexture] gl-not-initialized tile={index}");
463 return;
464 }
465
466 if (pixelData == null || pixelData.Length == 0)
467 {
468 LogDiag($"[UploadTileTexture] empty pixel data tile={index}");
469 return;
470 }
471
472 // The buffer is always BGRA = 4 bytes per pixel.
473 // GetTile pads every tile — including edge tiles — to exactly
474 // tileWidth x tileHeight pixels, so the dimensions passed by SlideRenderer
475 // (the schema tile size) always match the buffer. We just validate and bail
476 // on any genuine mismatch rather than trying to guess new dimensions.
477 if (tileWidth <= 0 || tileHeight <= 0)
478 {
479 LogDiag($"[UploadTileTexture] invalid dimensions tile={index} size={tileWidth}x{tileHeight}");
480 return;
481 }
482
483 int expectedBytes = tileWidth * tileHeight * 4;
484 if (pixelData.Length < expectedBytes)
485 {
486 LogDiag($"[UploadTileTexture] buffer too small tile={index} need={expectedBytes} got={pixelData.Length}");
487 return;
488 }
489
490 MakeCurrent();
491
492 // Check if already cached
493 if (_textureCache.ContainsKey(index))
494 {
495 LogDiag($"[UploadTileTexture] already cached tile={index}");
496 return;
497 }
498
499 long newTextureBytes = (long)tileWidth * tileHeight * 4;
500
501 // Evict old textures if the cache is full or if the new upload would
502 // push the total texture budget over its byte cap.
503 while (_textureCache.Count > 0 &&
504 (_textureCache.Count >= MAX_CACHED_TEXTURES ||
505 _textureBytes + newTextureBytes > MAX_CACHED_TEXTURE_BYTES))
506 {
507 EvictOldestTextures(1);
508 }
509
510 // Create and upload texture.
511 // Pin the managed array explicitly so the GC cannot relocate it while the
512 // driver is reading from the pointer (avoids ExecutionEngineException).
513 // PixelFormat.Bgra matches the byte order produced by ReadRegionAsync.
514 int tex = GL.GenTexture();
515 GL.BindTexture(TextureTarget.Texture2D, tex);
516 GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);
517
518 var handle = System.Runtime.InteropServices.GCHandle.Alloc(pixelData, System.Runtime.InteropServices.GCHandleType.Pinned);
519 try
520 {
521 GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
522 tileWidth, tileHeight, 0,
523 PixelFormat.Bgra, PixelType.UnsignedByte,
524 handle.AddrOfPinnedObject());
525 }
526 finally
527 {
528 handle.Free();
529 }
530
531 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
532 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
533 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
534 GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
535
536 GL.BindTexture(TextureTarget.Texture2D, 0);
537
538 _textureCache[index] = tex;
539 _textureSizes[index] = (tileWidth, tileHeight);
540 _textureBytes += newTextureBytes;
541 LogDiag($"[UploadTileTexture] uploaded tile={index} tex={tex} size={tileWidth}x{tileHeight} bytes={pixelData.Length}");
542 }

Property Documentation

◆ CachedTextureCount

int BioGTK.SlideGLArea.CachedTextureCount
get

Definition at line 668 of file SlideGLArea.cs.

◆ ImageScreenH

float BioGTK.SlideGLArea.ImageScreenH = -1
getset

Definition at line 72 of file SlideGLArea.cs.

72{ get; set; } = -1;

◆ ImageScreenW

float BioGTK.SlideGLArea.ImageScreenW = -1
getset

Definition at line 71 of file SlideGLArea.cs.

71{ get; set; } = -1;

◆ ImageScreenX

float BioGTK.SlideGLArea.ImageScreenX = -1
getset

Definition at line 69 of file SlideGLArea.cs.

69{ get; set; } = -1;

◆ ImageScreenY

float BioGTK.SlideGLArea.ImageScreenY = -1
getset

Definition at line 70 of file SlideGLArea.cs.

70{ get; set; } = -1;

◆ NeedsRedraw

bool BioGTK.SlideGLArea.NeedsRedraw = true
getset

Definition at line 63 of file SlideGLArea.cs.

63{ get; set; } = true;

◆ PreservePreviousFrameWhileIncomplete

bool BioGTK.SlideGLArea.PreservePreviousFrameWhileIncomplete = false
getset

Definition at line 64 of file SlideGLArea.cs.

64{ get; set; } = false;

◆ TilesToRender

List<TileRenderInfo> BioGTK.SlideGLArea.TilesToRender = new()
get

Definition at line 62 of file SlideGLArea.cs.

62{ get; } = new();

Event Documentation

◆ OnSkiaRender

Action<SKCanvas, int, int> BioGTK.SlideGLArea.OnSkiaRender

Event fired during Skia rendering phase for annotation drawing.

Definition at line 77 of file SlideGLArea.cs.


The documentation for this class was generated from the following file: