Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a per component cache in the renderer #466

Merged
merged 1 commit into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ ttf-parser = { version = "0.12.0", optional = true }
font-kit = { version = "0.10.0", optional = true }

# Software Rendering
tiny-skia = { version = "0.6.0", optional = true }
tiny-skia = { version = "0.6.0", default-features = false, features = ["std", "simd"], optional = true }

# Networking
splits-io-api = { version = "0.2.0", optional = true }
Expand Down
16 changes: 13 additions & 3 deletions src/rendering/component/detailed_timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,22 @@ use crate::{
},
};

pub struct Cache<I> {
icon: Option<Icon<I>>,
}

impl<I> Cache<I> {
pub const fn new() -> Self {
Self { icon: None }
}
}

pub(in crate::rendering) fn render<B: ResourceAllocator>(
cache: &mut Cache<B::Image>,
context: &mut RenderContext<'_, B>,
[width, height]: [f32; 2],
component: &State,
layout_state: &LayoutState,
detailed_timer_icon: &mut Option<Icon<B::Image>>,
) {
context.render_rectangle([0.0, 0.0], [width, height], &component.background);

Expand All @@ -26,10 +36,10 @@ pub(in crate::rendering) fn render<B: ResourceAllocator>(
let icon_size = height - 2.0 * vertical_padding;

if let Some(icon) = &component.icon_change {
*detailed_timer_icon = context.create_icon(icon);
cache.icon = context.create_icon(icon);
}

let left_side = if let Some(icon) = detailed_timer_icon {
let left_side = if let Some(icon) = &cache.icon {
context.render_icon([PADDING, vertical_padding], [icon_size, icon_size], icon);
BOTH_PADDINGS + icon_size
} else {
Expand Down
88 changes: 72 additions & 16 deletions src/rendering/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::layout::{ComponentState, LayoutState};
use super::{
consts::{DEFAULT_COMPONENT_HEIGHT, PSEUDO_PIXELS, SEPARATOR_THICKNESS, TWO_ROW_HEIGHT},
resource::ResourceAllocator,
IconCache, RenderContext,
RenderContext,
};

pub mod blank_space;
Expand All @@ -16,6 +16,50 @@ pub mod text;
pub mod timer;
pub mod title;

pub enum Cache<I> {
DetailedTimer(detailed_timer::Cache<I>),
Splits(splits::Cache<I>),
Title(title::Cache<I>),
Empty,
}

macro_rules! accessors {
($($variant:ident $module:ident),*) => {
$(
fn $module(&mut self) -> &mut $module::Cache<I> {
match self {
Self::$variant(c) => c,
_ => {
*self = Self::$variant($module::Cache::new());
self.$module()
}
}
}
)*
};
}

impl<I> Cache<I> {
pub const fn new(component: &ComponentState) -> Self {
match component {
ComponentState::DetailedTimer(_) => Self::DetailedTimer(detailed_timer::Cache::new()),
ComponentState::Splits(_) => Self::Splits(splits::Cache::new()),
ComponentState::Title(_) => Self::Title(title::Cache::new()),
_ => Self::Empty,
}
}

fn make_empty(&mut self) {
*self = Self::Empty;
}

accessors! {
DetailedTimer detailed_timer,
Splits splits,
Title title
}
}

pub fn layout_width(layout: &LayoutState) -> f32 {
layout.components.iter().map(width).sum()
}
Expand Down Expand Up @@ -81,33 +125,45 @@ pub fn height(component: &ComponentState) -> f32 {
}

pub(super) fn render<A: ResourceAllocator>(
cache: &mut Cache<A::Image>,
context: &mut RenderContext<'_, A>,
icons: &mut IconCache<A::Image>,
component: &ComponentState,
state: &LayoutState,
dim: [f32; 2],
) {
match component {
ComponentState::BlankSpace(state) => blank_space::render(context, dim, state),
ComponentState::DetailedTimer(component) => detailed_timer::render(
context,
dim,
component,
state,
&mut icons.detailed_timer_icon,
),
ComponentState::Graph(component) => graph::render(context, dim, component, state),
ComponentState::KeyValue(component) => key_value::render(context, dim, component, state),
ComponentState::Separator(component) => separator::render(context, dim, component, state),
ComponentState::BlankSpace(state) => {
cache.make_empty();
blank_space::render(context, dim, state)
}
ComponentState::DetailedTimer(component) => {
detailed_timer::render(cache.detailed_timer(), context, dim, component, state)
}
ComponentState::Graph(component) => {
cache.make_empty();
graph::render(context, dim, component, state)
}
ComponentState::KeyValue(component) => {
cache.make_empty();
key_value::render(context, dim, component, state)
}
ComponentState::Separator(component) => {
cache.make_empty();
separator::render(context, dim, component, state)
}
ComponentState::Splits(component) => {
splits::render(context, dim, component, state, &mut icons.split_icons)
splits::render(cache.splits(), context, dim, component, state)
}
ComponentState::Text(component) => {
cache.make_empty();
text::render(context, dim, component, state)
}
ComponentState::Text(component) => text::render(context, dim, component, state),
ComponentState::Timer(component) => {
cache.make_empty();
timer::render(context, dim, component);
}
ComponentState::Title(component) => {
title::render(context, dim, component, state, &mut icons.game_icon)
title::render(cache.title(), context, dim, component, state)
}
}
}
22 changes: 17 additions & 5 deletions src/rendering/component/splits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,22 @@ use crate::{

pub const COLUMN_WIDTH: f32 = 2.75;

pub struct Cache<I> {
icons: Vec<Option<Icon<I>>>,
}

impl<I> Cache<I> {
pub const fn new() -> Self {
Self { icons: Vec::new() }
}
}

pub(in crate::rendering) fn render<B: ResourceAllocator>(
cache: &mut Cache<B::Image>,
context: &mut RenderContext<'_, B>,
[width, height]: [f32; 2],
component: &State,
layout_state: &LayoutState,
split_icons: &mut Vec<Option<Icon<B::Image>>>,
) {
let text_color = solid(&layout_state.text_color);

Expand Down Expand Up @@ -67,10 +77,12 @@ pub(in crate::rendering) fn render<B: ResourceAllocator>(
let transform = context.transform;

for icon_change in &component.icon_changes {
if icon_change.segment_index >= split_icons.len() {
split_icons.extend((0..=icon_change.segment_index - split_icons.len()).map(|_| None));
if icon_change.segment_index >= cache.icons.len() {
cache
.icons
.resize_with(icon_change.segment_index + 1, || None);
}
split_icons[icon_change.segment_index] = context.create_icon(&icon_change.icon);
cache.icons[icon_change.segment_index] = context.create_icon(&icon_change.icon);
}

if let Some(column_labels) = &component.column_labels {
Expand Down Expand Up @@ -125,7 +137,7 @@ pub(in crate::rendering) fn render<B: ResourceAllocator>(
}

{
if let Some(Some(icon)) = split_icons.get(split.index) {
if let Some(Some(icon)) = cache.icons.get(split.index) {
context.render_icon([PADDING, icon_y], [icon_size, icon_size], icon);
}

Expand Down
16 changes: 13 additions & 3 deletions src/rendering/component/title.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,32 @@ use crate::{
},
};

pub struct Cache<I> {
game_icon: Option<Icon<I>>,
}

impl<I> Cache<I> {
pub const fn new() -> Self {
Self { game_icon: None }
}
}

pub(in crate::rendering) fn render<B: ResourceAllocator>(
cache: &mut Cache<B::Image>,
context: &mut RenderContext<'_, B>,
[width, height]: [f32; 2],
component: &State,
layout_state: &LayoutState,
game_icon: &mut Option<Icon<B::Image>>,
) {
context.render_rectangle([0.0, 0.0], [width, height], &component.background);
let text_color = component.text_color.unwrap_or(layout_state.text_color);
let text_color = solid(&text_color);

if let Some(icon) = &component.icon_change {
*game_icon = context.create_icon(icon);
cache.game_icon = context.create_icon(icon);
}

let left_bound = if let Some(icon) = game_icon {
let left_bound = if let Some(icon) = &cache.game_icon {
let vertical_padding = vertical_padding(height);
let icon_size = height - 2.0 * vertical_padding;
context.render_icon([PADDING, vertical_padding], [icon_size, icon_size], icon);
Expand Down
8 changes: 3 additions & 5 deletions src/rendering/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@ pub fn calculate_hash<P, I>(background: &Option<FillShader>, entities: &[Entity<
hasher.finish()
}

fn hash_float(x: f32, state: &mut impl Hasher) {
u32::from_ne_bytes(x.to_ne_bytes()).hash(state);
fn hash_float(f: f32, state: &mut impl Hasher) {
u32::hash(&bytemuck::cast(f), state);
}

fn hash_floats(f: &[f32], state: &mut impl Hasher) {
for &f in f {
hash_float(f, state);
}
u32::hash_slice(bytemuck::cast_slice(f), state);
}

fn hash_shader(shader: &FillShader, state: &mut impl Hasher) {
Expand Down
37 changes: 14 additions & 23 deletions src/rendering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,11 @@ enum CachedSize {
pub struct SceneManager<P, I> {
scene: Scene<P, I>,
fonts: FontCache<P>,
icons: IconCache<I>,
components: Vec<component::Cache<I>>,
next_id: usize,
cached_size: Option<CachedSize>,
}

struct IconCache<I> {
game_icon: Option<Icon<I>>,
split_icons: Vec<Option<Icon<I>>>,
detailed_timer_icon: Option<Icon<I>>,
}

impl<P: SharedOwnership, I: SharedOwnership> SceneManager<P, I> {
/// Creates a new scene manager.
pub fn new(mut allocator: impl ResourceAllocator<Path = P, Image = I>) -> Self {
Expand All @@ -168,11 +162,7 @@ impl<P: SharedOwnership, I: SharedOwnership> SceneManager<P, I> {

Self {
fonts: FontCache::new().unwrap(),
icons: IconCache {
game_icon: None,
split_icons: Vec::new(),
detailed_timer_icon: None,
},
components: Vec::new(),
// We use 0 for the rectangle.
next_id: 1,
scene: Scene::new(rectangle),
Expand Down Expand Up @@ -207,6 +197,14 @@ impl<P: SharedOwnership, I: SharedOwnership> SceneManager<P, I> {
self.scene
.set_background(decode_gradient(&state.background));

// Ensure we have exactly as many cached components as the layout state.
if let Some(new_components) = state.components.get(self.components.len()..) {
self.components
.extend(new_components.iter().map(component::Cache::new));
} else {
self.components.truncate(state.components.len());
}

let new_dimensions = match state.direction {
LayoutDirection::Vertical => self.render_vertical(allocator, resolution, state),
LayoutDirection::Horizontal => self.render_horizontal(allocator, resolution, state),
Expand Down Expand Up @@ -271,10 +269,10 @@ impl<P: SharedOwnership, I: SharedOwnership> SceneManager<P, I> {
// mode, all the components have the same width.
let width = aspect_ratio * total_height;

for component in &state.components {
for (component, cache) in state.components.iter().zip(&mut self.components) {
let height = component::height(component);
let dim = [width, height];
component::render(&mut context, &mut self.icons, component, state, dim);
component::render(cache, &mut context, component, state, dim);
// We translate the coordinate space to the Component Coordinate
// Space of the next component by shifting by the height of the
// current component in the Component Coordinate Space.
Expand Down Expand Up @@ -342,11 +340,11 @@ impl<P: SharedOwnership, I: SharedOwnership> SceneManager<P, I> {
// distribute to each of the components. This factor is this adjustment.
let width_scaling = TWO_ROW_HEIGHT * aspect_ratio / total_width;

for component in &state.components {
for (component, cache) in state.components.iter().zip(&mut self.components) {
let width = component::width(component) * width_scaling;
let height = TWO_ROW_HEIGHT;
let dim = [width, height];
component::render(&mut context, &mut self.icons, component, state, dim);
component::render(cache, &mut context, component, state, dim);
// We translate the coordinate space to the Component Coordinate
// Space of the next component by shifting by the width of the
// current component in the Component Coordinate Space.
Expand Down Expand Up @@ -531,7 +529,6 @@ impl<A: ResourceAllocator> RenderContext<'_, A> {

let mut buffer = self.fonts.buffer.take().unwrap_or_default();
buffer.push_str(text.trim());
buffer.guess_segment_properties();

let font = self.fonts.text.font.scale(scale);
let glyphs = font.shape(buffer);
Expand Down Expand Up @@ -564,7 +561,6 @@ impl<A: ResourceAllocator> RenderContext<'_, A> {

let mut buffer = self.fonts.buffer.take().unwrap_or_default();
buffer.push_str(text.trim());
buffer.guess_segment_properties();

let font = self.fonts.text.font.scale(scale);
let glyphs = font.shape(buffer);
Expand Down Expand Up @@ -594,7 +590,6 @@ impl<A: ResourceAllocator> RenderContext<'_, A> {

let mut buffer = self.fonts.buffer.take().unwrap_or_default();
buffer.push_str(text.trim());
buffer.guess_segment_properties();

let font = self.fonts.text.font.scale(scale);
let glyphs = font.shape(buffer);
Expand Down Expand Up @@ -643,7 +638,6 @@ impl<A: ResourceAllocator> RenderContext<'_, A> {

let mut buffer = self.fonts.buffer.take().unwrap_or_default();
buffer.push_str(text.trim());
buffer.guess_segment_properties();

let font = self.fonts.times.font.scale(scale);
let glyphs = font.shape_tabular_numbers(buffer);
Expand Down Expand Up @@ -675,7 +669,6 @@ impl<A: ResourceAllocator> RenderContext<'_, A> {

let mut buffer = self.fonts.buffer.take().unwrap_or_default();
buffer.push_str(text.trim());
buffer.guess_segment_properties();

let font = self.fonts.timer.font.scale(scale);
let glyphs = font.shape_tabular_numbers(buffer);
Expand Down Expand Up @@ -733,7 +726,6 @@ impl<A: ResourceAllocator> RenderContext<'_, A> {
fn measure_text(&mut self, text: &str, scale: f32) -> f32 {
let mut buffer = self.fonts.buffer.take().unwrap_or_default();
buffer.push_str(text.trim());
buffer.guess_segment_properties();

let glyphs = self.fonts.text.font.scale(scale).shape(buffer);
let width = glyphs.width();
Expand All @@ -748,7 +740,6 @@ impl<A: ResourceAllocator> RenderContext<'_, A> {

let mut buffer = self.fonts.buffer.take().unwrap_or_default();
buffer.push_str(text.trim());
buffer.guess_segment_properties();

let glyphs = self
.fonts
Expand Down