xous-core/libs/blitstr2/codegen/lib/templates.go
bunnie 4477af6058 fix broken font rendering in rust 1.91
Rust 1.91 (or perhaps, more accurately llvm?) changed how link
ordering works.

Previously, modules would be linked in the order they were referenced
(e.g. pub mod b; pub mod a; would result in b being at a lower address
than a in the resulting binary).

However, apparently, this has changed and now someone in their
infinite wisdom decided that modules should be alphabetized before
linking.

I'm really not sure why the arbitrary ordering of the human alphabet
is superior to any other system, and also, if you really wanted
things alphabetized, you could just alphabetize them in your
reference order.

Previously the fonts were laid out in a way that tried to minimize
cache thrashing by co-locating certain sets of fonts together.

Now they are just sprayed around through the arbitrary and not
terribly useful permutation funtion of the english alphabet.

Rant off.

This changes the specification of the fonts in the code generator
to be in alphabetical order, making the screen once again legible.
2025-11-18 00:18:55 +08:00

196 lines
6.5 KiB
Go

// Copyright (c) 2022 Sam Blenny
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
package lib
import (
"bytes"
"strings"
"text/template"
)
type FontSummary struct {
Name string
Len int
}
type FontMap struct {
Name string
Len string
}
// Render the command line usage message
func RenderUsageTemplate(confirm string, debug string, fonts []FontSpec) string {
context := usageTemplateContext{confirm, debug, fonts}
return renderTemplate(usageTemplate, "usage", context)
}
// Render rust source code for font file with index functions and static arrays
func RenderFontFileTemplate(f FontSpec, gs GlyphSet) string {
fname := strings.ToUpper(f.Name)
context := fontFileTemplateContext{f, gs, fname}
return renderTemplate(fontFileTemplate, "fontfile", context)
}
func RenderLoaderFileTemplate(f FontSpec, gs GlyphSet) string {
fname := strings.ToUpper(f.Name)
context := loaderFileTemplateContext{f, gs, fname}
return renderTemplate(loaderFileTemplate, "loaderfile", context)
}
func RenderFontmapTemplate(fd []FontMap, small_fd []FontMap) string {
context := fontmapTemplateContext{fd, small_fd}
return renderTemplate(fontmapTemplate, "fontmap", context)
}
func RenderLoadermodTemplate(fd []FontSummary, small_fd []FontSummary) string {
context := loadermodTemplateContext{fd, small_fd}
return renderTemplate(loadermodTemplate, "loadermod", context)
}
// Holds data for rendering usageTemplate
type usageTemplateContext struct {
Confirm string
Debug string
Fonts []FontSpec
}
// Holds data for rendering fontFileTemplate
type fontFileTemplateContext struct {
Font FontSpec
GS GlyphSet
FontName string
}
// Holds data for rendering loaderFileTemplate
type loaderFileTemplateContext struct {
Font FontSpec
GS GlyphSet
FontName string
}
// Holds data for rendering fontmapTemplate
type fontmapTemplateContext struct {
FontDir []FontMap
SmallFontDir []FontMap
}
type loadermodTemplateContext struct {
FontDir []FontSummary
SmallFontDir []FontSummary
}
// Return a string from rendering the given template and context data
func renderTemplate(templateString string, name string, context interface{}) string {
fmap := template.FuncMap{"ToLower": strings.ToLower}
t := template.Must(template.New(name).Funcs(fmap).Parse(templateString))
var buf bytes.Buffer
err := t.Execute(&buf, context)
if err != nil {
panic(err)
}
return buf.String()
}
// Template with usage instructions for the command line tool
const usageTemplate = `
This tool generates fonts in the form of rust source code.
To confirm that you want to write the files, use the {{.Confirm}} switch.
To show debug info, use the {{.Debug}} switch.
Font files that will be generated:{{range $f := .Fonts}}
{{$f.RustOut}}
{{$f.LoaderOut}}{{end}}
Usage:
go run main.go {{.Confirm}}
`
// Template with rust source code for a outer structure of a font file
const fontFileTemplate = `#![cfg_attr(rustfmt, rustfmt_skip)]
// DO NOT MAKE EDITS HERE because this file is automatically generated.
// To make changes, see <xous_root>/libs/blitstr2/codegen/main.go
//
{{.Font.Legal}}
//! {{.Font.Name}} Font
#![allow(dead_code)]
/// Maximum height of glyph patterns in this bitmap typeface.
pub const MAX_HEIGHT: u8 = {{.Font.Size}};
/// Unicode character codepoints corresponding to glyph sprites in GLYPHS array.
/// Indended use:
/// 1. Do binary search on CODEPOINTS to find index of the codepoint corresponding
/// to the glyph you want to locate
/// 2. Multiply resulting CODEPOINTS index by 8 (<<3) to get index into GLYPHS for
/// the corresponding glyph sprite (because 16*16px sprite size is 8*u32)
pub const CODEPOINTS: [u32; {{.GS.CodepointsLen}}] = [
{{.GS.Codepoints}}];
#[cfg(any(feature="precursor", feature="renode"))]
pub static GLYPH_LOCATION: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
pub const GLYPH_LEN: usize = {{.GS.GlyphsLen}};
pub fn glyphs() -> &'static [u32] {
#[cfg(any(feature="precursor", feature="renode"))]
unsafe {
let data: *const u32 = core::ptr::with_exposed_provenance::<u32>(GLYPH_LOCATION.load(core::sync::atomic::Ordering::SeqCst) as usize);
core::slice::from_raw_parts(data, GLYPH_LEN)
}
#[cfg(any(not(target_os = "xous"), feature="bao1x"))]
&GLYPHS
}
#[cfg(any(not(target_os = "xous"), feature = "bao1x"))]
/// Packed 16px * 16px glyph pattern data.
/// Pixels are packed in row-major order with LSB of first pixel word
/// containing the top left pixel. Bit of 0 means clear, 1 means set
pub const GLYPHS: [u32; {{.GS.GlyphsLen}}] = [
{{.GS.Glyphs}}];
{{if .GS.Widths}}
/// Widths for proportional glyphs
pub const WIDTHS: [u8; {{.GS.WidthsLen}}] = [
{{.GS.Widths}}];
{{end}}
`
const loaderFileTemplate = `#![cfg_attr(rustfmt, rustfmt_skip)]
// DO NOT MAKE EDITS HERE because this file is automatically generated.
// To make changes, see <xous_root>/libs/blitstr2/codegen/main.go
{{.Font.Legal}}
//! {{.Font.Name}} Font
#![allow(dead_code)]
#[link_section = ".fontdata"]
#[no_mangle]
#[used]
/// Packed 16px * 16px glyph pattern data.
/// Pixels are packed in row-major order with LSB of first pixel word
/// containing the top left pixel. Bit of 0 means clear, 1 means set
pub static {{.FontName}}_GLYPHS: [u32; {{.GS.GlyphsLen}}] = [
{{.GS.Glyphs}}];{{if .GS.Widths}}{{end}}
`
const loadermodTemplate = `#![cfg_attr(rustfmt, rustfmt_skip)]
// DO NOT MAKE EDITS HERE because this file is automatically generated.
// The order of these modules affects the link order in the loader, which is referred to in the graphics engine.
// To make changes, see <xous_root>/libs/blitstr2/codegen/main.go
// NOTE: this list must be in alphabetical order since Rust 1.91.0. If it is not alphabetized,
// the linker will re-order them into allphabetical order, messing up the offsets.
{{range $f := .FontDir}}
#[cfg(not(feature = "bao1x"))]
pub mod {{$f.Name}};{{end}}
`
const fontmapTemplate = `#![cfg_attr(rustfmt, rustfmt_skip)]
// DO NOT MAKE EDITS HERE because this file is automatically generated.
// The order of these modules affects the link order in the loader, which is referred to in the graphics engine.
// To make changes, see <xous_root>/libs/blitstr2/codegen/main.go
#![allow(dead_code)]
#[cfg(not(feature = "bao1x"))]
pub const FONT_BASE: usize = 0x2053_0000;
// NOTE: this list must be in alphabetical order since Rust 1.91.0. If it is not alphabetized,
// the linker will re-order them into allphabetical order, messing up the offsets.
{{range $f := .FontDir}}#[cfg(not(feature = "bao1x"))]
pub const {{$f.Name}}: usize = 0x{{$f.Len}};
{{end}}
`