font_outline_punch_through: implement punch through

This enables alpha blending for both font_outline and
font_outline_punch_through.

I have also experimented more with 16-gray vs 256-gray--I have not
decided which between monochrome, 16-gray, or 256-gray I like the
most.

Perhaps a better test might be to test hanzi.
This commit is contained in:
Zack Buhman 2023-12-24 01:12:08 +08:00
parent dc85cad8b0
commit 3373ea4c0c
8 changed files with 187 additions and 113 deletions

Binary file not shown.

Binary file not shown.

View File

@ -15,6 +15,7 @@
#include "holly/ta_bits.hpp" #include "holly/ta_bits.hpp"
#include "twiddle.hpp" #include "twiddle.hpp"
#include "serial.hpp" #include "serial.hpp"
#include "palette.hpp"
#include "font/font.hpp" #include "font/font.hpp"
#include "dejavusansmono.hpp" #include "dejavusansmono.hpp"
@ -59,17 +60,18 @@ uint32_t transform(ta_parameter_writer& parameter,
auto polygon = global_polygon_type_0(texture_address); auto polygon = global_polygon_type_0(texture_address);
polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| para_control::list_type::opaque | para_control::list_type::translucent
| obj_control::col_type::packed_color | obj_control::col_type::packed_color
| obj_control::texture; | obj_control::texture;
polygon.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one polygon.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::src_alpha
| tsp_instruction_word::dst_alpha_instr::zero | tsp_instruction_word::dst_alpha_instr::one
| tsp_instruction_word::fog_control::no_fog | tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::use_alpha
| tsp_instruction_word::texture_u_size::from_int(texture_width) | tsp_instruction_word::texture_u_size::from_int(texture_width)
| tsp_instruction_word::texture_v_size::from_int(texture_height); | tsp_instruction_word::texture_v_size::from_int(texture_height);
polygon.texture_control_word = texture_control_word::pixel_format::_8bpp_palette polygon.texture_control_word = texture_control_word::pixel_format::_4bpp_palette
| texture_control_word::scan_order::twiddled | texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8); | texture_control_word::texture_address(texture_address / 8);
parameter.append<global_polygon_type_0>() = polygon; parameter.append<global_polygon_type_0>() = polygon;
@ -117,17 +119,17 @@ uint32_t transform2(ta_parameter_writer& parameter,
auto polygon = global_polygon_type_0(texture_address); auto polygon = global_polygon_type_0(texture_address);
polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| para_control::list_type::opaque | para_control::list_type::translucent
| obj_control::col_type::packed_color | obj_control::col_type::packed_color
| obj_control::texture; | obj_control::texture;
polygon.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one polygon.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::src_alpha
| tsp_instruction_word::dst_alpha_instr::zero | tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog | tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_u_size::from_int(texture_width) | tsp_instruction_word::texture_u_size::from_int(texture_width)
| tsp_instruction_word::texture_v_size::from_int(texture_height); | tsp_instruction_word::texture_v_size::from_int(texture_height);
polygon.texture_control_word = texture_control_word::pixel_format::_8bpp_palette polygon.texture_control_word = texture_control_word::pixel_format::_4bpp_palette
| texture_control_word::scan_order::twiddled | texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8); | texture_control_word::texture_address(texture_address / 8);
parameter.append<global_polygon_type_0>() = polygon; parameter.append<global_polygon_type_0>() = polygon;
@ -139,8 +141,8 @@ uint32_t transform2(ta_parameter_writer& parameter,
float y = strip_vertices[i].y; float y = strip_vertices[i].y;
float z = strip_vertices[i].z; float z = strip_vertices[i].z;
x *= 128.f; x *= static_cast<float>(texture_width);
y *= 256.f; y *= static_cast<float>(texture_height);
x += 50.f; x += 50.f;
y += 50.f; y += 50.f;
z = 1.f / (z + 9.f); z = 1.f / (z + 9.f);
@ -179,28 +181,11 @@ void inflate_font(const uint32_t * src,
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64); auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64);
auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture); auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture);
twiddle::texture3<8, 8>(texture, reinterpret_cast<const uint8_t *>(src), twiddle::texture3<4, 8>(texture, reinterpret_cast<const uint8_t *>(src),
stride, stride,
curve_end_ix); curve_end_ix);
} }
template <int C>
void palette_data()
{
static_assert(C >= 2);
constexpr int increment = 256 / C;
holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::rgb565;
// generate a palette with `C` shades of grey,
// ranging in intensity from rgb565(0, 0, 0) to rgb565(31, 63, 31)
for (int i = 0; i < 256; i += increment) {
holly.PALETTE_RAM[i / increment] = ((i >> 3) << 11)
| ((i >> 2) << 5)
| ((i >> 3) << 0);
}
}
uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4]; uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4];
void main() void main()
@ -226,7 +211,7 @@ void main()
inflate_font(texture, inflate_font(texture,
font->texture_stride, font->texture_stride,
font->max_z_curve_ix); font->max_z_curve_ix);
palette_data<256>(); palette_data<16>();
// The address of `ta_parameter_buf` must be a multiple of 32 bytes. // 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. // This is mandatory for ch2-dma to the ta fifo polygon converter.
@ -234,13 +219,13 @@ void main()
constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list
| ta_alloc_ctrl::tm_opb::no_list | ta_alloc_ctrl::tm_opb::no_list
| ta_alloc_ctrl::t_opb::no_list | ta_alloc_ctrl::t_opb::_16x4byte
| ta_alloc_ctrl::om_opb::no_list | ta_alloc_ctrl::om_opb::no_list
| ta_alloc_ctrl::o_opb::_16x4byte; | ta_alloc_ctrl::o_opb::no_list;
constexpr struct opb_size opb_size = { .opaque = 16 * 4 constexpr struct opb_size opb_size = { .opaque = 0
, .opaque_modifier = 0 , .opaque_modifier = 0
, .translucent = 0 , .translucent = 16 * 4
, .translucent_modifier = 0 , .translucent_modifier = 0
, .punch_through = 0 , .punch_through = 0
}; };
@ -266,10 +251,8 @@ void main()
auto parameter = ta_parameter_writer(ta_parameter_buf); auto parameter = ta_parameter_writer(ta_parameter_buf);
/*
transform2(parameter, transform2(parameter,
font->texture_width, font->texture_height); font->texture_width, font->texture_height);
*/
transform(parameter, transform(parameter,
font->texture_width, font->texture_height, font->texture_width, font->texture_height,
@ -288,7 +271,7 @@ void main()
parameter.append<global_end_of_list>() = global_end_of_list(); parameter.append<global_end_of_list>() = global_end_of_list();
ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset);
ta_wait_opaque_list(); ta_wait_translucent_list();
core_start_render(frame_ix, num_frames); core_start_render(frame_ix, num_frames);

View File

@ -15,6 +15,7 @@
#include "holly/ta_bits.hpp" #include "holly/ta_bits.hpp"
#include "twiddle.hpp" #include "twiddle.hpp"
#include "serial.hpp" #include "serial.hpp"
#include "palette.hpp"
#include "font/font.hpp" #include "font/font.hpp"
#include "dejavusansmono_mono.hpp" #include "dejavusansmono_mono.hpp"
@ -39,11 +40,11 @@ const struct vertex strip_vertices[4] = {
constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex)); constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex));
uint32_t transform(ta_parameter_writer& parameter, uint32_t transform(ta_parameter_writer& parameter,
const uint32_t texture_width, uint32_t texture_height, const uint32_t texture_width, uint32_t texture_height,
const uint32_t first_char_code, const uint32_t first_char_code,
const glyph * glyphs, const glyph * glyphs,
const char * s, const uint32_t len, const char * s, const uint32_t len,
const uint32_t y_offset) const uint32_t y_offset)
{ {
uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture)); uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture));
@ -59,19 +60,20 @@ uint32_t transform(ta_parameter_writer& parameter,
auto polygon = global_polygon_type_0(texture_address); auto polygon = global_polygon_type_0(texture_address);
polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume polygon.parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| para_control::list_type::opaque | para_control::list_type::punch_through
| obj_control::col_type::packed_color | obj_control::col_type::packed_color
| obj_control::texture; | obj_control::texture;
polygon.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one polygon.tsp_instruction_word = tsp_instruction_word::src_alpha_instr::src_alpha
| tsp_instruction_word::dst_alpha_instr::zero | tsp_instruction_word::dst_alpha_instr::one
| tsp_instruction_word::fog_control::no_fog | tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_u_size::from_int(texture_width) //| tsp_instruction_word::use_alpha
| tsp_instruction_word::texture_v_size::from_int(texture_height); | tsp_instruction_word::texture_u_size::from_int(texture_width)
| tsp_instruction_word::texture_v_size::from_int(texture_height);
polygon.texture_control_word = texture_control_word::pixel_format::_4bpp_palette polygon.texture_control_word = texture_control_word::pixel_format::_4bpp_palette
| texture_control_word::scan_order::twiddled | texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8); | texture_control_word::texture_address(texture_address / 8);
parameter.append<global_polygon_type_0>() = polygon; parameter.append<global_polygon_type_0>() = polygon;
for (uint32_t i = 0; i < strip_length; i++) { for (uint32_t i = 0; i < strip_length; i++) {
@ -98,10 +100,10 @@ uint32_t transform(ta_parameter_writer& parameter,
v = v / static_cast<float>(texture_height); v = v / static_cast<float>(texture_height);
parameter.append<vertex_polygon_type_3>() = parameter.append<vertex_polygon_type_3>() =
vertex_polygon_type_3(x, y, z, vertex_polygon_type_3(x, y, z,
u, v, u, v,
0x00000000, // base_color 0x00000000, // base_color
end_of_strip); end_of_strip);
} }
advance += glyph.metrics.horiAdvance; advance += glyph.metrics.horiAdvance;
@ -110,6 +112,53 @@ uint32_t transform(ta_parameter_writer& parameter,
return parameter.offset; return parameter.offset;
} }
uint32_t transform2(ta_parameter_writer& parameter,
const uint32_t texture_width, uint32_t texture_height)
{
uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture));
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::src_alpha
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_u_size::from_int(texture_width)
| tsp_instruction_word::texture_v_size::from_int(texture_height);
polygon.texture_control_word = texture_control_word::pixel_format::_4bpp_palette
| texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 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 *= static_cast<float>(texture_width);
y *= static_cast<float>(texture_height);
x += 50.f;
y += 50.f;
z = 1.f / (z + 9.f);
float u = strip_vertices[i].u;
float v = strip_vertices[i].v;
parameter.append<vertex_polygon_type_3>() =
vertex_polygon_type_3(x, y, z,
u, v,
0x00000000, // base_color
end_of_strip);
}
return parameter.offset;
}
void init_texture_memory(const struct opb_size& opb_size) void init_texture_memory(const struct opb_size& opb_size)
{ {
@ -118,11 +167,11 @@ void init_texture_memory(const struct opb_size& opb_size)
background_parameter(mem->background, 0xff0000ff); background_parameter(mem->background, 0xff0000ff);
region_array2(mem->region_array, region_array2(mem->region_array,
(offsetof (struct texture_memory_alloc, object_list)), (offsetof (struct texture_memory_alloc, object_list)),
640 / 32, // width 640 / 32, // width
480 / 32, // height 480 / 32, // height
opb_size opb_size
); );
} }
constexpr inline uint32_t b(uint32_t v, uint32_t n) constexpr inline uint32_t b(uint32_t v, uint32_t n)
@ -131,38 +180,15 @@ constexpr inline uint32_t b(uint32_t v, uint32_t n)
} }
void inflate_font(const uint32_t * src, void inflate_font(const uint32_t * src,
const uint32_t stride, const uint32_t stride,
const uint32_t curve_end_ix) const uint32_t curve_end_ix)
{ {
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64); auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64);
auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture); auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture);
twiddle::texture3<4, 1>(texture, reinterpret_cast<const uint8_t *>(src), twiddle::texture3<4, 1>(texture, reinterpret_cast<const uint8_t *>(src),
stride, stride,
curve_end_ix); curve_end_ix);
}
template <int C>
void palette_data()
{
static_assert(C >= 2);
constexpr int increment = 256 / C;
holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::rgb565;
// generate a palette with `C` shades of grey,
// ranging in intensity from rgb565(0, 0, 0) to rgb565(31, 63, 31)
for (int i = 0; i < 256; i += increment) {
holly.PALETTE_RAM[i / increment] = ((i >> 3) << 11)
| ((i >> 2) << 5)
| ((i >> 3) << 0);
}
}
void palette_data_mono()
{
holly.PALETTE_RAM[0] = 0;
holly.PALETTE_RAM[1] = 0xffff;
} }
uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4]; uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4];
@ -187,33 +213,34 @@ void main()
*/ */
inflate_font(texture, inflate_font(texture,
font->texture_stride, font->texture_stride,
font->max_z_curve_ix); font->max_z_curve_ix);
palette_data_mono(); palette_data<2>();
// The address of `ta_parameter_buf` must be a multiple of 32 bytes. // 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. // This is mandatory for ch2-dma to the ta fifo polygon converter.
uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf); uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf);
constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::_16x4byte
| ta_alloc_ctrl::tm_opb::no_list | ta_alloc_ctrl::tm_opb::no_list
| ta_alloc_ctrl::t_opb::no_list | ta_alloc_ctrl::t_opb::no_list
| ta_alloc_ctrl::om_opb::no_list | ta_alloc_ctrl::om_opb::no_list
| ta_alloc_ctrl::o_opb::_16x4byte; | ta_alloc_ctrl::o_opb::_16x4byte;
constexpr struct opb_size opb_size = { .opaque = 16 * 4 constexpr struct opb_size opb_size = { .opaque = 16 * 4
, .opaque_modifier = 0 , .opaque_modifier = 0
, .translucent = 0 , .translucent = 0
, .translucent_modifier = 0 , .translucent_modifier = 0
, .punch_through = 0 , .punch_through = 16 * 4
}; };
constexpr uint32_t tiles = (640 / 32) * (320 / 32); constexpr uint32_t tiles = (640 / 32) * (320 / 32);
holly.SOFTRESET = softreset::pipeline_soft_reset holly.SOFTRESET = softreset::pipeline_soft_reset
| softreset::ta_soft_reset; | softreset::ta_soft_reset;
holly.SOFTRESET = 0; holly.SOFTRESET = 0;
holly.PT_ALPHA_REF = 0x1;
core_init(); core_init();
init_texture_memory(opb_size); init_texture_memory(opb_size);
@ -225,28 +252,33 @@ void main()
while (true) { while (true) {
ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc, ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc,
640, 480); 640, 480);
auto parameter = ta_parameter_writer(ta_parameter_buf); auto parameter = ta_parameter_writer(ta_parameter_buf);
transform(parameter, transform2(parameter,
font->texture_width, font->texture_height, font->texture_width, font->texture_height);
font->first_char_code,
glyphs, parameter.append<global_end_of_list>() = global_end_of_list();
ana, 17,
font->glyph_height * 0);
transform(parameter, transform(parameter,
font->texture_width, font->texture_height, font->texture_width, font->texture_height,
font->first_char_code, font->first_char_code,
glyphs, glyphs,
cabal, 26, ana, 17,
font->glyph_height * 1); font->glyph_height * 0);
transform(parameter,
font->texture_width, font->texture_height,
font->first_char_code,
glyphs,
cabal, 26,
font->glyph_height * 1);
parameter.append<global_end_of_list>() = global_end_of_list(); parameter.append<global_end_of_list>() = global_end_of_list();
ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset);
ta_wait_opaque_list(); ta_wait_punch_through_list();
core_start_render(frame_ix, num_frames); core_start_render(frame_ix, num_frames);

View File

@ -13,7 +13,8 @@
void core_init() void core_init()
{ {
holly.ISP_FEED_CFG = isp_feed_cfg::cache_size_for_translucency(0x200); holly.ISP_FEED_CFG = isp_feed_cfg::cache_size_for_translucency(0x200)
| isp_feed_cfg::punch_through_chunk_size(0x200);
holly.FPU_SHAD_SCALE = fpu_shad_scale::scale_factor_for_shadows(1); holly.FPU_SHAD_SCALE = fpu_shad_scale::scale_factor_for_shadows(1);
holly.FPU_CULL_VAL = _i(1.f); holly.FPU_CULL_VAL = _i(1.f);

View File

@ -114,3 +114,10 @@ void ta_wait_translucent_list()
system.ISTNRM = ISTNRM__END_OF_TRANSFERRING_TRANSLUCENT_LIST; system.ISTNRM = ISTNRM__END_OF_TRANSFERRING_TRANSLUCENT_LIST;
} }
void ta_wait_punch_through_list()
{
while ((system.ISTNRM & ISTNRM__END_OF_TRANSFERRING_PUNCH_THROUGH_LIST) == 0);
system.ISTNRM = ISTNRM__END_OF_TRANSFERRING_PUNCH_THROUGH_LIST;
}

View File

@ -11,3 +11,4 @@ void ta_polygon_converter_cont(uint32_t ol_base_offset,
void ta_polygon_converter_transfer(volatile uint32_t * buf, uint32_t size); void ta_polygon_converter_transfer(volatile uint32_t * buf, uint32_t size);
void ta_wait_opaque_list(); void ta_wait_opaque_list();
void ta_wait_translucent_list(); void ta_wait_translucent_list();
void ta_wait_punch_through_list();

50
palette.hpp Normal file
View File

@ -0,0 +1,50 @@
#pragma once
constexpr inline uint16_t rgb565(uint8_t r, uint8_t g, uint8_t b)
{
return ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0);
}
constexpr inline uint16_t grey565(uint8_t i)
{
return ((i >> 3) << 11) | ((i >> 2) << 5) | ((i >> 3) << 0);
}
constexpr inline uint16_t argb4444(uint8_t i)
{
return (i << 12) | (15 << 8) | (15 << 4) | (15 << 0);
}
template <int C>
void palette_data();
template <>
void palette_data<255>()
{
holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::rgb565;
// ranging in intensity from rgb565(0, 0, 0) to rgb565(31, 63, 31)
for (int i = 0; i < 256; i += 1) {
holly.PALETTE_RAM[i] = grey565(i);
}
}
template <>
void palette_data<16>()
{
holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::argb4444;
// ranging in intensity from rgb565(0, 0, 0) to rgb565(31, 63, 31)
for (uint32_t i = 0; i < 16; i++) {
holly.PALETTE_RAM[i] = argb4444(i);
}
}
template <>
void palette_data<2>()
{
holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::argb1555;
holly.PALETTE_RAM[0] = 0x0000;
holly.PALETTE_RAM[1] = 0xffff;
}