///|
pub struct RendererPlatformViewCapability {
priv draw_platform_view_pixels_fn : (
Bytes,
Int,
Int,
Int,
Double,
Double,
Double,
Double,
) -> Unit
priv set_platform_view_draw_fn_fn : ((() -> Unit)?) -> Unit
}
///|
pub struct RendererGpuRecoveryCapability {
priv inject_context_loss_fn : () -> Unit
priv gpu_recovery_count_fn : () -> Int
priv gpu_fallback_active_fn : () -> Bool
}
///|
/// Complete live renderer lifecycle for one host surface.
pub struct RendererSession {
priv resize_fn : (@core.SurfaceMetrics) -> Unit
priv render_frame_fn : (RenderFrameSubmission) -> RenderFrameResult
priv drain_events_fn : () -> Array[RendererEvent]
priv text_system_fn : () -> @core.TextSystem
priv image_records_fn : () -> Array[ImageResourceRecord]
priv apply_image_load_completion_fn : (ImageResourceLoadCompletion) -> Bool
priv image_source : HostImageSource
priv image_decoder : RendererImageDecoder?
priv mut next_image_token : Int64
priv mut image_tokens : Array[RendererImageLoadToken]
priv mut image_sources : Array[String]
priv mut image_events : Array[RendererEvent]
priv present_count_fn : () -> Int
priv recover_fn : (String) -> RecoveryResult
priv dispose_fn : () -> Unit
priv native_surface : NativeSurface?
priv mut disposed : Bool
priv platform_view : RendererPlatformViewCapability
priv gpu_recovery : RendererGpuRecoveryCapability
}
///|
pub fn RendererPlatformViewCapability::new(
draw_platform_view_pixels? : (
Bytes,
Int,
Int,
Int,
Double,
Double,
Double,
Double,
) -> Unit = fn(_pixels, _w, _h, _s, _dx, _dy, _dw, _dh) { },
set_platform_view_draw_fn? : ((() -> Unit)?) -> Unit = _fn => (),
) -> RendererPlatformViewCapability {
{
draw_platform_view_pixels_fn: draw_platform_view_pixels,
set_platform_view_draw_fn_fn: set_platform_view_draw_fn,
}
}
///|
pub fn RendererGpuRecoveryCapability::new(
inject_context_loss? : () -> Unit = () => (),
gpu_recovery_count? : () -> Int = () => 0,
gpu_fallback_active? : () -> Bool = () => false,
) -> RendererGpuRecoveryCapability {
{
inject_context_loss_fn: inject_context_loss,
gpu_recovery_count_fn: gpu_recovery_count,
gpu_fallback_active_fn: gpu_fallback_active,
}
}
///|
pub fn RendererSession::new(
resize~ : (@core.SurfaceMetrics) -> Unit,
render_frame~ : (RenderFrameSubmission) -> RenderFrameResult,
drain_events? : (() -> Array[RendererEvent])? = None,
text_system~ : () -> @core.TextSystem,
present_count? : () -> Int = () => 0,
recover? : (String) -> RecoveryResult = _ => RecoverySucceeded,
dispose? : () -> Unit = () => (),
image_records? : () -> Array[ImageResourceRecord] = () => [],
apply_image_load_completion? : (ImageResourceLoadCompletion) -> Bool = _ => {
false
},
image_source? : HostImageSource = HostImageSource::unavailable(),
image_decoder? : RendererImageDecoder? = None,
native_surface? : NativeSurface? = None,
platform_view? : RendererPlatformViewCapability = RendererPlatformViewCapability::new(),
gpu_recovery? : RendererGpuRecoveryCapability = RendererGpuRecoveryCapability::new(),
) -> RendererSession {
let drain_events_fn = match drain_events {
Some(drain) => drain
None => () => []
}
{
resize_fn: resize,
render_frame_fn: render_frame,
drain_events_fn,
text_system_fn: text_system,
image_records_fn: image_records,
apply_image_load_completion_fn: apply_image_load_completion,
image_source,
image_decoder,
next_image_token: 1L,
image_tokens: [],
image_sources: [],
image_events: [],
present_count_fn: present_count,
recover_fn: recover,
dispose_fn: dispose,
native_surface,
disposed: false,
platform_view,
gpu_recovery,
}
}
///|
pub fn RendererSession::resize(
self : RendererSession,
metrics : @core.SurfaceMetrics,
) -> Unit {
if !self.disposed {
(self.resize_fn)(metrics)
}
}
///|
pub fn RendererSession::render_frame(
self : RendererSession,
submission : RenderFrameSubmission,
) -> RenderFrameResult {
if self.disposed {
return RenderFrameResult::new(presented=false)
}
let result = (self.render_frame_fn)(submission)
self.queue_image_requests()
result
}
///|
pub fn RendererSession::drain_events(
self : RendererSession,
) -> Array[RendererEvent] {
if self.disposed {
return []
}
self.queue_image_requests()
let events = (self.drain_events_fn)()
events.append(self.image_events)
self.image_events = []
events
}
///|
pub fn render_present_completion_is_presented(
completion : RenderPresentCompletion,
) -> Bool {
completion.status() is RenderPresentStatus::Presented
}
///|
pub fn render_present_completions_have_presented(
completions : Array[RenderPresentCompletion],
) -> Bool {
completions.any(render_present_completion_is_presented)
}
///|
pub fn render_present_completions_have_terminal(
completions : Array[RenderPresentCompletion],
) -> Bool {
completions.any(completion => {
match completion.status() {
RenderPresentStatus::Presented
| RenderPresentStatus::Dropped
| RenderPresentStatus::FallbackToRaster => true
RenderPresentStatus::Recorded => false
}
})
}
///|
pub fn RendererSession::text_system(self : RendererSession) -> @core.TextSystem {
(self.text_system_fn)()
}
///|
pub fn RendererSession::apply_image_load_completion(
self : RendererSession,
completion : RendererImageLoadCompletion,
) -> RendererImageCompletionResult {
if self.disposed {
return RendererImageCompletionResult::Disposed
}
guard self.take_image_request(completion.token()) is Some(source) else {
return RendererImageCompletionResult::Stale
}
if source != completion.result().source {
return RendererImageCompletionResult::Stale
}
RendererImageCompletionResult::Applied(
(self.apply_image_load_completion_fn)(completion.result()),
)
}
///|
pub fn RendererSession::image_diagnostics(
self : RendererSession,
) -> RendererImageDiagnostics {
RendererImageDiagnostics::new(
records=(self.image_records_fn)(),
pending_request_count=self.image_tokens.length(),
)
}
///|
pub fn RendererSession::present_count(self : RendererSession) -> Int {
(self.present_count_fn)()
}
///|
pub fn RendererSession::recover(
self : RendererSession,
reason : String,
) -> RecoveryResult {
if self.disposed {
RecoveryFailed("renderer session is disposed")
} else {
(self.recover_fn)(reason)
}
}
///|
pub fn RendererSession::inject_context_loss(self : RendererSession) -> Unit {
if !self.disposed {
(self.gpu_recovery.inject_context_loss_fn)()
}
}
///|
pub fn RendererSession::gpu_recovery_count(self : RendererSession) -> Int {
(self.gpu_recovery.gpu_recovery_count_fn)()
}
///|
pub fn RendererSession::gpu_fallback_active(self : RendererSession) -> Bool {
(self.gpu_recovery.gpu_fallback_active_fn)()
}
///|
pub fn RendererSession::dispose(self : RendererSession) -> Unit {
if !self.disposed {
self.disposed = true
self.image_tokens = []
self.image_sources = []
self.image_events = []
(self.dispose_fn)()
match self.native_surface {
Some(surface) => surface.dispose()
None => ()
}
}
}
///|
pub fn RendererSession::draw_platform_view_pixels(
self : RendererSession,
pixels : Bytes,
src_width : Int,
src_height : Int,
src_stride : Int,
dst_x : Double,
dst_y : Double,
dst_width : Double,
dst_height : Double,
) -> Unit {
(self.platform_view.draw_platform_view_pixels_fn)(
pixels, src_width, src_height, src_stride, dst_x, dst_y, dst_width, dst_height,
)
}
///|
pub fn RendererSession::set_platform_view_draw_fn(
self : RendererSession,
draw_fn : (() -> Unit)?,
) -> Unit {
(self.platform_view.set_platform_view_draw_fn_fn)(draw_fn)
}
///|
fn RendererSession::queue_image_requests(self : RendererSession) -> Unit {
guard self.image_decoder is Some(decoder) else { return }
for record in (self.image_records_fn)() {
if record.status == ImageResourceStatus::ImageLoading &&
!self.image_sources.any(source => source == record.source) {
let token = RendererImageLoadToken::new(self.next_image_token)
self.next_image_token = self.next_image_token + 1L
self.image_tokens.push(token)
self.image_sources.push(record.source)
self.image_events.push(
RendererEvent::ImageLoadRequested(
RendererImageLoadRequest::new(
token~,
source=record.source,
image_source=self.image_source,
decoder~,
),
),
)
}
}
}
///|
fn RendererSession::take_image_request(
self : RendererSession,
token : RendererImageLoadToken,
) -> String? {
let mut source = None
let tokens : Array[RendererImageLoadToken] = []
let sources : Array[String] = []
for index, current in self.image_tokens {
if source is None && current == token && index < self.image_sources.length() {
source = Some(self.image_sources[index])
} else if index < self.image_sources.length() {
tokens.push(current)
sources.push(self.image_sources[index])
}
}
self.image_tokens = tokens
self.image_sources = sources
source
}