examples: add font example

This commit is contained in:
Zack Buhman 2023-12-17 02:03:42 +08:00
parent 7daff7e3ca
commit 5a9790daf1
9 changed files with 427 additions and 7 deletions

View File

@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
DIR := $(dir $(MAKEFILE_PATH))
LIB ?= .
OPT ?= -Os
OPT ?= -O3
DEBUG ?= -g -gdwarf-4
GENERATED ?=

View File

@ -33,6 +33,19 @@ MACAW_TWIDDLE_OBJ = \
example/macaw_twiddle.elf: LDSCRIPT = $(LIB)/alt.lds
example/macaw_twiddle.elf: $(START_OBJ) $(MACAW_TWIDDLE_OBJ)
FONT_OBJ = \
example/font.o \
vga.o \
holly/core.o \
holly/region_array.o \
holly/background.o \
holly/ta_fifo_polygon_converter.o \
serial.o \
sperrypc.data.o
example/font.elf: LDSCRIPT = $(LIB)/alt.lds
example/font.elf: $(START_OBJ) $(FONT_OBJ)
MACAW_MULTIPASS_OBJ = \
example/macaw_multipass.o \
vga.o \

261
example/font.cpp Normal file
View File

@ -0,0 +1,261 @@
#include <cstdint>
#include "align.hpp"
#include "vga.hpp"
#include "holly.hpp"
#include "holly/core.hpp"
#include "holly/core_bits.hpp"
#include "holly/ta_parameter.hpp"
#include "holly/ta_fifo_polygon_converter.hpp"
#include "holly/texture_memory_alloc.hpp"
#include "memorymap.hpp"
#include "holly/background.hpp"
#include "holly/region_array.hpp"
#include "holly/ta_bits.hpp"
#include "twiddle.hpp"
#include "serial.hpp"
#include "sperrypc.hpp"
struct vertex {
float x;
float y;
float z;
float u;
float v;
};
/*
// screen space coordinates
const struct vertex quad_verticies[4] = {
{ 0.f, 64.f, 0.01f, 0.f, 1.f },
{ 0.f, 0.f, 0.01f, 0.f, 0.f },
{ 64.f, 0.f, 0.01f, 1.f, 0.f },
{ 64.f, 64.f, 0.01f, 1.f, 1.f, },
};
uint32_t transform(uint32_t * ta_parameter_buf)
{
auto parameter = ta_parameter_writer(ta_parameter_buf);
uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture));
constexpr uint32_t base_color = 0xffffffff;
auto sprite = global_sprite(base_color);
sprite.parameter_control_word = para_control::para_type::sprite
| para_control::list_type::opaque
| obj_control::col_type::packed_color
| obj_control::texture
| obj_control::_16bit_uv;
sprite.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_u_size::_8 // 8px
| tsp_instruction_word::texture_v_size::_8; // 8px
sprite.texture_control_word = texture_control_word::pixel_format::_565
| texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8);
parameter.append<global_sprite>() = sprite;
parameter.append<vertex_sprite_type_1>() =
vertex_sprite_type_1(quad_verticies[0].x,
quad_verticies[0].y,
quad_verticies[0].z,
quad_verticies[1].x,
quad_verticies[1].y,
quad_verticies[1].z,
quad_verticies[2].x,
quad_verticies[2].y,
quad_verticies[2].z,
quad_verticies[3].x,
quad_verticies[3].y,
uv_16bit(quad_verticies[0].u, quad_verticies[0].v),
uv_16bit(quad_verticies[1].u, quad_verticies[1].v),
uv_16bit(quad_verticies[2].u, quad_verticies[2].v));
// curiously, there is no `dz` in vertex_sprite_type_1
// curiously, there is no `du_dv` in vertex_sprite_type_1
parameter.append<global_end_of_list>() = global_end_of_list();
return parameter.offset;
}
*/
const struct vertex strip_vertices[4] = {
// [ position ] [ uv coordinates ]
{ -0.5f, 0.5f, 0.f, 0.f, 1.f, },
{ -0.5f, -0.5f, 0.f, 0.f, 0.f, },
{ 0.5f, 0.5f, 0.f, 1.f, 1.f, },
{ 0.5f, -0.5f, 0.f, 1.f, 0.f, },
};
constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex));
uint32_t transform(uint32_t * ta_parameter_buf, const char * s, const uint32_t len)
{
auto parameter = ta_parameter_writer(ta_parameter_buf);
uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture));
for (uint32_t string_ix = 0; string_ix < len; string_ix++) {
auto polygon = global_polygon_type_0(texture_address);
polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| para_control::list_type::opaque
| obj_control::col_type::packed_color
| obj_control::texture;
polygon.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_u_size::_8 // 8px
| tsp_instruction_word::texture_v_size::_8; // 8px
polygon.texture_control_word = texture_control_word::pixel_format::_8bpp_palette
| texture_control_word::scan_order::twiddled
| texture_control_word::texture_address((texture_address + 8 * 8 * (s[string_ix] - ' ')) / 8);
parameter.append<global_polygon_type_0>() = polygon;
for (uint32_t i = 0; i < strip_length; i++) {
bool end_of_strip = i == strip_length - 1;
float x = strip_vertices[i].x;
float y = strip_vertices[i].y;
float z = strip_vertices[i].z;
x *= 32.f;
y *= 32.f;
x += 64.f + 32 * string_ix;
y += 240.f;
z = 1.f / (z + 10.f);
parameter.append<vertex_polygon_type_3>() =
vertex_polygon_type_3(x, y, z,
strip_vertices[i].u,
strip_vertices[i].v,
0x00000000, // base_color
end_of_strip);
}
}
parameter.append<global_end_of_list>() = global_end_of_list();
return parameter.offset;
}
void init_texture_memory(const struct opb_size& opb_size)
{
volatile texture_memory_alloc * mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory);
background_parameter(mem->background);
region_array2(mem->region_array,
(offsetof (struct texture_memory_alloc, object_list)),
640 / 32, // width
480 / 32, // height
opb_size
);
}
inline void inflate_character(const uint8_t * src, const uint8_t c)
{
uint8_t character_index = c - ' ';
uint8_t temp[8 * 8];
for (uint32_t y = 0; y < 8; y++) {
uint8_t row = src[y + 8 * character_index];
for (uint32_t x = 0; x < 8; x++) {
uint8_t px = (row >> (7 - x)) & 1;
//serial::character((px == 1) ? 'X' : '_');
//uint16_t rgb565 = px ? 0xffff : 0;
uint16_t palette_index = px ? 2 : 1;
temp[y * 8 + x] = palette_index;
}
//serial::character('\n');
}
auto mem = reinterpret_cast<texture_memory_alloc *>(0xa400'0000);
auto texture = reinterpret_cast<uint32_t *>(mem->texture);
uint32_t offset = 8 * 8 * character_index;
union {
uint8_t u8[8 * 8];
uint32_t u32[8 * 8 / 4];
} temp2;
//twiddle::texture(&texture[offset], temp, 8, 8);
twiddle::texture(temp2.u8, temp, 8, 8);
for (uint32_t i = 0; i < 8 * 8 / 4; i++) {
texture[(offset / 4) + i] = temp2.u32[i];
}
}
void inflate_font(const uint8_t * src)
{
for (uint8_t ix = 0x20; ix < 0x7f; ix++) {
inflate_character(src, ix);
}
}
void palette_data()
{
holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::rgb565;
holly.PALETTE_RAM[1] = (15) << 11;
holly.PALETTE_RAM[2] = (15 << 11) | (30 << 5);
}
uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4];
void main()
{
vga();
auto src = reinterpret_cast<const uint8_t *>(&_binary_sperrypc_data_start);
inflate_font(src);
palette_data();
// The address of `ta_parameter_buf` must be a multiple of 32 bytes.
// This is mandatory for ch2-dma to the ta fifo polygon converter.
uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf);
constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list
| ta_alloc_ctrl::tm_opb::no_list
| ta_alloc_ctrl::t_opb::no_list
| ta_alloc_ctrl::om_opb::no_list
| ta_alloc_ctrl::o_opb::_16x4byte;
constexpr struct opb_size opb_size = { .opaque = 16 * 4
, .opaque_modifier = 0
, .translucent = 0
, .translucent_modifier = 0
, .punch_through = 0
};
constexpr uint32_t tiles = (640 / 32) * (320 / 32);
holly.SOFTRESET = softreset::pipeline_soft_reset
| softreset::ta_soft_reset;
holly.SOFTRESET = 0;
core_init();
init_texture_memory(opb_size);
uint32_t frame_ix = 0;
constexpr uint32_t num_frames = 1;
const char ana[18] = "A from ana i know";
while (true) {
ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc);
uint32_t ta_parameter_size = transform(ta_parameter_buf, ana, 17);
ta_polygon_converter_transfer(ta_parameter_buf, ta_parameter_size);
ta_wait_opaque_list();
core_start_render(frame_ix, num_frames);
v_sync_out();
v_sync_in();
core_wait_end_of_render_video(frame_ix, num_frames);
frame_ix++;
}
}

View File

@ -51,6 +51,8 @@ namespace fb_r_ctrl {
namespace vclk_div {
constexpr uint32_t pclk_vclk_2 = 0 << 23;
constexpr uint32_t pclk_vclk_1 = 1 << 23;
constexpr uint32_t bit_mask = 0x1 << 23;
}
constexpr uint32_t fb_strip_buf_en = 1 << 22;
@ -63,6 +65,8 @@ namespace fb_r_ctrl {
constexpr uint32_t _0565_rgb_16bit = 1 << 2;
constexpr uint32_t _888_rgb_24bit_packed = 2 << 2;
constexpr uint32_t _0888_rgb_32bit = 3 << 2;
constexpr uint32_t bit_mask = 0x3 << 2;
}
constexpr uint32_t fb_line_double = 1 << 1;
@ -82,6 +86,8 @@ namespace fb_w_ctrl {
constexpr uint32_t _888_rgb_24bit_packed = 4 << 0;
constexpr uint32_t _0888_krgb_32bit = 5 << 0;
constexpr uint32_t _8888_argb_32bit = 6 << 0;
constexpr uint32_t bit_mask = 0x7 << 0;
}
}
@ -125,6 +131,8 @@ namespace fpu_shad_scale {
namespace simple_shadow_enable {
constexpr uint32_t parameter_selection_volume_mode = 0 << 8;
constexpr uint32_t intensity_volume_mode = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
constexpr uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; }
@ -138,6 +146,8 @@ namespace fpu_param_cfg {
namespace region_header_type {
constexpr uint32_t type_1 = 0 << 21;
constexpr uint32_t type_2 = 1 << 21;
constexpr uint32_t bit_mask = 0x1 << 21;
}
constexpr uint32_t tsp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 14; }
@ -150,16 +160,22 @@ namespace half_offset {
namespace tsp_texel_sampling_position {
constexpr uint32_t top_left = 1 << 2;
constexpr uint32_t center = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace tsp_pixel_sampling_position {
constexpr uint32_t top_left = 1 << 1;
constexpr uint32_t center = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace fpu_pixel_sampling_position {
constexpr uint32_t top_left = 1 << 0;
constexpr uint32_t center = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
@ -204,12 +220,16 @@ namespace sdram_arb_cfg {
constexpr uint32_t isp_pointer_data = 0x9 << 18;
constexpr uint32_t isp_parameters = 0xa << 18;
constexpr uint32_t crt_controller = 0xb << 18;
constexpr uint32_t bit_mask = 0xf << 18;
}
namespace arbiter_priority_control {
constexpr uint32_t priority_arbitration_only = 0x0 << 16;
constexpr uint32_t override_value_field = 0x1 << 16;
constexpr uint32_t round_robin_counter = 0x2 << 16;
constexpr uint32_t bit_mask = 0x3 << 16;
}
constexpr uint32_t arbiter_crt_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 8; }
@ -272,6 +292,8 @@ namespace spg_hblank_int {
constexpr uint32_t output_equal_line_comp_val = 0x0 << 12;
constexpr uint32_t output_every_line_comp_val = 0x1 << 12;
constexpr uint32_t output_every_line = 0x2 << 12;
constexpr uint32_t bit_mask = 0x3 << 12;
}
constexpr uint32_t line_comp_val(uint32_t num) { return (num & 0x3ff) << 0; }
@ -286,11 +308,15 @@ namespace spg_control {
namespace csync_on_h {
constexpr uint32_t hsync = 0 << 9;
constexpr uint32_t csync = 1 << 9;
constexpr uint32_t bit_mask = 0x1 << 9;
}
namespace sync_direction {
constexpr uint32_t input = 0 << 8;
constexpr uint32_t output = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
constexpr uint32_t pal = 1 << 7;
@ -302,16 +328,22 @@ namespace spg_control {
namespace mcsync_pol {
constexpr uint32_t active_low = 0 << 2;
constexpr uint32_t active_high = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace mvsync_pol {
constexpr uint32_t active_low = 0 << 1;
constexpr uint32_t active_high = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace mhsync_pol {
constexpr uint32_t active_low = 0 << 0;
constexpr uint32_t active_high = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
@ -341,11 +373,15 @@ namespace text_control {
namespace code_book_endian {
constexpr uint32_t little_endian = 0 << 17;
constexpr uint32_t big_endian = 1 << 17;
constexpr uint32_t bit_mask = 0x1 << 17;
}
namespace index_endian {
constexpr uint32_t little_endian = 0 << 16;
constexpr uint32_t big_endian = 1 << 16;
constexpr uint32_t bit_mask = 0x1 << 16;
}
constexpr uint32_t bank_bit(uint32_t num) { return (num & 0x1f) << 8; }
@ -367,6 +403,8 @@ namespace vo_control {
constexpr uint32_t field_1_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x6 << 4;
constexpr uint32_t field_2_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x7 << 4;
constexpr uint32_t inverted_at_the_active_edge_of_vsync = 0x8 << 4;
constexpr uint32_t bit_mask = 0xf << 4;
}
constexpr uint32_t blank_video = 1 << 3;
@ -374,16 +412,22 @@ namespace vo_control {
namespace blank_pol {
constexpr uint32_t active_low = 0 << 2;
constexpr uint32_t active_high = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace vsync_pol {
constexpr uint32_t active_low = 0 << 1;
constexpr uint32_t active_high = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace hsync_pol {
constexpr uint32_t active_low = 0 << 0;
constexpr uint32_t active_high = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
@ -400,6 +444,8 @@ namespace scaler_ctl {
namespace field_select {
constexpr uint32_t field_1 = 0 << 18;
constexpr uint32_t field_2 = 1 << 18;
constexpr uint32_t bit_mask = 0x1 << 18;
}
constexpr uint32_t interlace = 1 << 17;
@ -407,12 +453,14 @@ namespace scaler_ctl {
constexpr uint32_t vertical_scale_factor(uint32_t num) { return (num & 0xffff) << 0; }
}
namespace pal_ram_ctl {
namespace pal_ram_ctrl {
namespace pixel_format {
constexpr uint32_t argb1555 = 0 << 0;
constexpr uint32_t rgb565 = 1 << 0;
constexpr uint32_t argb4444 = 2 << 0;
constexpr uint32_t argb8888 = 3 << 0;
constexpr uint32_t bit_mask = 0x3 << 0;
}
}

View File

@ -131,6 +131,36 @@ static_assert((offsetof (struct vertex_polygon_type_0, _res1)) == 0x14);
static_assert((offsetof (struct vertex_polygon_type_0, base_color)) == 0x18);
static_assert((offsetof (struct vertex_polygon_type_0, _res2)) == 0x1c);
struct vertex_polygon_type_4 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t uv;
uint32_t _res0;
uint32_t base_color;
uint32_t offset_color;
vertex_polygon_type_4(const float x,
const float y,
const float z,
const uint32_t uv,
const uint32_t base_color,
const bool end_of_strip
)
: parameter_control_word( para_control::para_type::vertex_parameter
| (end_of_strip ? para_control::end_of_strip : 0)
)
, x(x)
, y(y)
, z(z)
, uv(uv)
, _res0(0)
, base_color(base_color)
, offset_color(0)
{ }
};
struct global_polygon_type_0 {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
@ -218,7 +248,8 @@ struct global_sprite {
global_sprite(const uint32_t base_color)
: parameter_control_word( para_control::para_type::sprite
| para_control::list_type::opaque )
| para_control::list_type::opaque
| obj_control::col_type::packed_color )
, isp_tsp_instruction_word( isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling )
, tsp_instruction_word( tsp_instruction_word::src_alpha_instr::one
@ -284,6 +315,59 @@ struct vertex_sprite_type_0 {
static_assert((sizeof (vertex_sprite_type_0)) == 64);
struct vertex_sprite_type_1 {
uint32_t parameter_control_word;
float ax;
float ay;
float az;
float bx;
float by;
float bz;
float cx;
float cy;
float cz;
float dx;
float dy;
float _res0;
uint32_t au_av;
uint32_t bu_bv;
uint32_t cu_cv;
vertex_sprite_type_1(const float ax,
const float ay,
const float az,
const float bx,
const float by,
const float bz,
const float cx,
const float cy,
const float cz,
const float dx,
const float dy,
const uint32_t au_av,
const uint32_t bu_bv,
const uint32_t cu_cv)
: parameter_control_word(para_control::para_type::vertex_parameter)
, ax(ax)
, ay(ay)
, az(az)
, bx(bx)
, by(by)
, bz(bz)
, cx(cx)
, cy(cy)
, dx(dx)
, dy(dy)
, _res0(0)
, au_av(au_av)
, bu_bv(bu_bv)
, cu_cv(cu_cv)
{}
};
static_assert((sizeof (vertex_sprite_type_1)) == 64);
struct global_end_of_list {
uint32_t parameter_control_word;
uint32_t _res0;
@ -347,3 +431,12 @@ union ta_parameter {
};
static_assert((sizeof (ta_parameter)) == 32);
*/
uint32_t uv_16bit(float u, float v)
{
uint32_t * ui = (reinterpret_cast<uint32_t *>(&u));
uint32_t * vi = (reinterpret_cast<uint32_t *>(&v));
uint32_t u_half = ((*ui) >> 16) & 0xffff;
uint32_t v_half = ((*vi) >> 16) & 0xffff;
return (u_half << 16) | (v_half << 0);
}

View File

@ -237,10 +237,10 @@
"SCALER_CTL",,16,"horizontal_scaling_enable",1,,,,,,,
"SCALER_CTL",,"15-0","vertical_scale_factor",,"0xffff",,,,,,
,,,,,,,,,,,
"PAL_RAM_CTL","pixel_format","1-0","argb1555",0,,,,,,,
"PAL_RAM_CTL","pixel_format","1-0","rgb565",1,,,,,,,
"PAL_RAM_CTL","pixel_format","1-0","argb4444",2,,,,,,,
"PAL_RAM_CTL","pixel_format","1-0","argb8888",3,,,,,,,
"PAL_RAM_CTRL","pixel_format","1-0","argb1555",0,,,,,,,
"PAL_RAM_CTRL","pixel_format","1-0","rgb565",1,,,,,,,
"PAL_RAM_CTRL","pixel_format","1-0","argb4444",2,,,,,,,
"PAL_RAM_CTRL","pixel_format","1-0","argb8888",3,,,,,,,
,,,,,,,,,,,
"SPG_STATUS",,13,"vsync",,,,,,,,
"SPG_STATUS",,12,"hsync",,,,,,,,

1 register_name enum_name bits bit_name value mask description
237 SCALER_CTL 16 horizontal_scaling_enable 1
238 SCALER_CTL 15-0 vertical_scale_factor 0xffff
239
240 PAL_RAM_CTL PAL_RAM_CTRL pixel_format 1-0 argb1555 0
241 PAL_RAM_CTL PAL_RAM_CTRL pixel_format 1-0 rgb565 1
242 PAL_RAM_CTL PAL_RAM_CTRL pixel_format 1-0 argb4444 2
243 PAL_RAM_CTL PAL_RAM_CTRL pixel_format 1-0 argb8888 3
244
245 SPG_STATUS 13 vsync
246 SPG_STATUS 12 hsync

Binary file not shown.

BIN
sperrypc.data Normal file

Binary file not shown.

5
sperrypc.hpp Normal file
View File

@ -0,0 +1,5 @@
#include <cstdint>
extern uint32_t _binary_sperrypc_data_start __asm("_binary_sperrypc_data_start");
extern uint32_t _binary_sperrypc_data_end __asm("_binary_sperrypc_data_end");
extern uint32_t _binary_sperrypc_data_size __asm("_binary_sperrypc_data_size");