12 private sealed class PresentationState(int bufferWidth, int bufferHeight, int adapterWidth, int adapterHeight)
14 internal readonly
int BufferWidth = bufferWidth, BufferHeight = bufferHeight;
15 internal readonly
int AdapterWidth = adapterWidth, AdapterHeight = adapterHeight;
19 private readonly
object _presentationSync =
new();
20 private PresentationState _presentation =
new(1, 1, 0, 0);
21 internal bool InitialSizeAvailable {
get;
private set; }
29 internal void SetBackbufferSize(
int width,
int height)
31 lock (_presentationSync)
33 var state = _presentation;
34 Volatile.Write(ref _presentation,
new(width, height, state.AdapterWidth, state.AdapterHeight));
43 Presentation.TryAdapterPxToScreenPx(adapterPx, out var screen);
45 return new Point((
int)Math.Floor(screen.X), (
int)Math.Floor(screen.Y));
52 public void DrawImage(SKCanvas canvas, SKImage image, SKColor clearColor)
54 var state = Volatile.Read(ref _presentation);
57 var transform = image.Width == state.BufferWidth && image.Height == state.BufferHeight
58 ? state.Transform :
PresentationTransform.Fit(image.Width, image.Height, state.AdapterWidth, state.AdapterHeight);
59 canvas.Clear(clearColor);
60 if (transform.Scale <= 0)
return;
61 canvas.DrawImage(image, transform.DestinationRect, PresentationSampling);
64 internal static SKSamplingOptions PresentationSampling =>
new(
66 ? SKFilterMode.Nearest : SKFilterMode.Linear);
75 public event Action<RenderSurfaceAdapterResizedEventArgs>?
Resized;
83 get => Volatile.Read(ref _presentation).AdapterWidth;
93 get => Volatile.Read(ref _presentation).AdapterHeight;
103 : this(destWidth, destHeight, initialSizeAvailable: true) { }
112 InitialSizeAvailable = initialSizeAvailable;
126 var sizeAvailable = destWidth > 0 && destHeight > 0;
127 if (destWidth ==
Width && destHeight ==
Height && InitialSizeAvailable == sizeAvailable)
130 var oldWidth =
Width;
133 InitialSizeAvailable = sizeAvailable;
134 lock (_presentationSync)
136 var state = _presentation;
137 Volatile.Write(ref _presentation,
new(state.BufferWidth, state.BufferHeight, destWidth, destHeight));
151 public abstract void Present(SKImage bufferImage, SKRectI bufferRect, SKRect destRect);
int Width
Gets the current width of the render surface in pixels.
void Present(SKImage bufferImage, SKRectI bufferRect, SKRect destRect)
Presents the specified portion of the Backbuffer image to the destination rectangle on the RenderSurf...
RenderSurfaceAdapterBase(int destWidth, int destHeight, bool initialSizeAvailable)
Constructs an adapter whose initial layout may still be pending.
float PresentationScale
Current derived presentation scale; adapter resize does not resize the Backbuffer.
void SetDestinationSize(int destWidth, int destHeight)
Sets the destination size of the render surface and raises the Resized event if the dimensions have c...
PresentationTransform Presentation
Current immutable aspect-preserving mapping of Backbuffer ScreenPx to adapter pixels.
RenderSurfaceAdapterBase(int destWidth, int destHeight)
Initializes a new instance of the RenderSurfaceAdapterBase class with the specified dimensions.
Point AdapterPxToScreenPx(PointF adapterPx)
Converts adapter input to logical ScreenPx, retaining outside coordinates for capture/leave.
int Height
Gets the current height of the render surface in pixels.
Action< RenderSurfaceAdapterResizedEventArgs >? Resized
Occurs when the render surface adapter is resized.
void DrawImage(SKCanvas canvas, SKImage image, SKColor clearColor)
Presents a complete image using the same transform as pointer normalization.
Provides data for the RenderSurfaceAdapterBase.Resized event.
readonly record struct PresentationTransform(float Scale, SKRect DestinationRect)
Aspect-preserving mapping between logical Backbuffer ScreenPx and adapter pixels.
@ NearestNeighbor
Unfiltered nearest-pixel presentation for pixel art.