///|
fn render_frame_descriptor_array_contains_key(
descriptors : Array[RendererResourceDescriptor],
key : RendererResourceKey,
) -> Bool {
let mut found = false
for descriptor in descriptors {
if descriptor.key == key {
found = true
}
}
found
}
///|
fn render_frame_resource_descriptors(
target : SurfaceTargetDescriptor,
command_list : RenderCommandList,
) -> Array[RendererResourceDescriptor] {
let descriptors = target.resource_descriptors()
let pass_surface_key = command_list.pass.resource_descriptor().key
for descriptor in command_list.resource_descriptors() {
if descriptor.key != pass_surface_key &&
!render_frame_descriptor_array_contains_key(descriptors, descriptor.key) {
descriptors.push(descriptor)
}
}
descriptors
}
///|
/// Validation outcome for a finalized render frame.
pub(all) enum RenderFrameValidationStatus {
FrameReady
FrameTargetMismatch
FrameUnbalancedState
FrameMissingGpuContext
FrameMissingPresent
} derive(Debug, Eq)
///|
pub fn RenderFrameValidationStatus::is_ready(
self : RenderFrameValidationStatus,
) -> Bool {
self is FrameReady
}
///|
/// Frame-level value boundary for a target plus its finalized render commands.
pub(all) struct RenderFrameDescriptor {
target : SurfaceTargetDescriptor
command_list : RenderCommandList
resource_plan : RendererResourcePlan
stats : RenderCommandStats
touched_bounds : Rect?
} derive(Debug, Eq)
///|
pub fn RenderFrameDescriptor::new(
target : SurfaceTargetDescriptor,
command_list : RenderCommandList,
) -> RenderFrameDescriptor {
let command_list = command_list.finish()
let resource_plan = RendererResourcePlan::new(
render_frame_resource_descriptors(target, command_list),
)
{
target,
command_list,
resource_plan,
stats: command_list.stats(),
touched_bounds: command_list.touched_bounds(),
}
}
///|
pub fn RenderFrameDescriptor::empty(
target : SurfaceTargetDescriptor,
) -> RenderFrameDescriptor {
RenderFrameDescriptor::new(target, RenderCommandList::for_target(target))
}
///|
pub fn RenderFrameDescriptor::is_target_consistent(
self : RenderFrameDescriptor,
) -> Bool {
self.command_list.pass.is_bound_to_target(self.target)
}
///|
pub fn RenderFrameDescriptor::needs_present(
self : RenderFrameDescriptor,
) -> Bool {
self.target.needs_present()
}
///|
pub fn RenderFrameDescriptor::has_present(self : RenderFrameDescriptor) -> Bool {
self.command_list.has_present()
}
///|
pub fn RenderFrameDescriptor::requires_gpu_context(
self : RenderFrameDescriptor,
) -> Bool {
self.target.surface.is_gpu()
}
///|
pub fn RenderFrameDescriptor::has_gpu_context(
self : RenderFrameDescriptor,
) -> Bool {
self.target.has_gpu_context()
}
///|
pub fn RenderFrameDescriptor::validation_status(
self : RenderFrameDescriptor,
) -> RenderFrameValidationStatus {
if !self.is_target_consistent() {
FrameTargetMismatch
} else if !self.stats.is_state_balanced() {
FrameUnbalancedState
} else if self.requires_gpu_context() && !self.has_gpu_context() {
FrameMissingGpuContext
} else if self.needs_present() && !self.has_present() {
FrameMissingPresent
} else {
FrameReady
}
}
///|
pub fn RenderFrameDescriptor::is_ready(self : RenderFrameDescriptor) -> Bool {
self.validation_status().is_ready()
}
///|
pub fn RenderFrameDescriptor::cache_resources(
self : RenderFrameDescriptor,
cache : ResourceCache[RendererResourceKey, RendererResourceDescriptor],
) -> Int {
cache.insert_resource_plan(self.resource_plan)
}
///|
pub fn RenderFrameDescriptor::cacheable_resource_plan(
self : RenderFrameDescriptor,
) -> RendererResourcePlan {
self.resource_plan.cacheable_resource_plan()
}
///|
pub fn RenderFrameDescriptor::uncacheable_resource_plan(
self : RenderFrameDescriptor,
) -> RendererResourcePlan {
self.resource_plan.uncacheable_resource_plan()
}
///|
pub fn RenderFrameDescriptor::cached_cacheable_resource_plan(
self : RenderFrameDescriptor,
cache : ResourceCache[RendererResourceKey, RendererResourceDescriptor],
) -> RendererResourcePlan {
cache.cached_cacheable_resource_plan(self.resource_plan)
}
///|
pub fn RenderFrameDescriptor::missing_cacheable_resource_plan(
self : RenderFrameDescriptor,
cache : ResourceCache[RendererResourceKey, RendererResourceDescriptor],
) -> RendererResourcePlan {
cache.missing_cacheable_resource_plan(self.resource_plan)
}
///|
pub fn RenderFrameDescriptor::present_descriptor(
self : RenderFrameDescriptor,
frame_index? : Int = 0,
buffer_index? : Int = -1,
) -> SurfacePresentDescriptor? {
if self.is_ready() && self.needs_present() && self.has_present() {
Some(self.target.present_descriptor(frame_index~, buffer_index~))
} else {
None
}
}
///|
pub fn RenderFrameDescriptor::present_resource_plan(
self : RenderFrameDescriptor,
frame_index? : Int = 0,
buffer_index? : Int = -1,
) -> RendererResourcePlan {
match self.present_descriptor(frame_index~, buffer_index~) {
Some(descriptor) => descriptor.resource_plan()
None => RendererResourcePlan::empty()
}
}
///|
pub fn RenderCommandList::frame_descriptor(
self : RenderCommandList,
target : SurfaceTargetDescriptor,
) -> RenderFrameDescriptor {
RenderFrameDescriptor::new(target, self)
}