From e2a6406a05a8e95af1182c877401e5c88b2e4a15 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 18 Dec 2023 02:10:52 +0800 Subject: [PATCH] example: add macaw_cube_render_to_texture --- example/example.mk | 13 ++ example/macaw_cube_render_to_texture.cpp | 272 +++++++++++++++++++++++ holly/background.cpp | 8 +- holly/background.hpp | 2 +- holly/core.cpp | 32 ++- holly/core.hpp | 7 + holly/ta_fifo_polygon_converter.cpp | 8 +- holly/ta_fifo_polygon_converter.hpp | 4 +- holly/texture_memory_alloc.hpp | 4 + 9 files changed, 333 insertions(+), 17 deletions(-) create mode 100644 example/macaw_cube_render_to_texture.cpp diff --git a/example/example.mk b/example/example.mk index 06a1b57..14118b8 100644 --- a/example/example.mk +++ b/example/example.mk @@ -82,6 +82,19 @@ MACAW_CUBE_OBJ = \ example/macaw_cube.elf: LDSCRIPT = $(LIB)/alt.lds example/macaw_cube.elf: $(START_OBJ) $(MACAW_CUBE_OBJ) +MACAW_CUBE_RENDER_TO_TEXTURE_OBJ = \ + example/macaw_cube_render_to_texture.o \ + vga.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + serial.o \ + macaw.data.o + +example/macaw_cube_render_to_texture.elf: LDSCRIPT = $(LIB)/alt.lds +example/macaw_cube_render_to_texture.elf: $(START_OBJ) $(MACAW_CUBE_RENDER_TO_TEXTURE_OBJ) + MAPLE_DEVICE_REQUEST_OBJ = \ example/maple_device_request.o \ vga.o \ diff --git a/example/macaw_cube_render_to_texture.cpp b/example/macaw_cube_render_to_texture.cpp new file mode 100644 index 0000000..785f0ea --- /dev/null +++ b/example/macaw_cube_render_to_texture.cpp @@ -0,0 +1,272 @@ +#include + +#include "align.hpp" + +#include "vga.hpp" +#include "holly.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_bits.hpp" +#include "holly/region_array.hpp" +#include "holly/background.hpp" +#include "holly/texture_memory_alloc.hpp" +#include "memorymap.hpp" + +#include "serial.hpp" + +#include "macaw.hpp" + +struct vertex { + float x; + float y; + float z; + float u; + float v; +}; + +vertex cube_faces[][4] = { + { // front + { -1.0f, -1.0f, 1.0f, 0.f, 0.f}, + { -1.0f, 1.0f, 1.0f, 0.f, 1.f}, + { 1.0f, -1.0f, 1.0f, 1.f, 0.f}, + { 1.0f, 1.0f, 1.0f, 1.f, 1.f}, + }, + { // back + { -1.0f, -1.0f, -1.0f, 1.f, 0.f}, + { -1.0f, 1.0f, -1.0f, 1.f, 1.f}, + { 1.0f, -1.0f, -1.0f, 0.f, 0.f}, + { 1.0f, 1.0f, -1.0f, 0.f, 1.f}, + }, + { // right side + { 1.0f, -1.0f, 1.0f, 0.f, 0.f}, + { 1.0f, 1.0f, 1.0f, 0.f, 1.f}, + { 1.0f, -1.0f, -1.0f, 1.f, 0.f}, + { 1.0f, 1.0f, -1.0f, 1.f, 1.f}, + }, + { // left side + { -1.0f, -1.0f, 1.0f, 1.f, 0.f}, + { -1.0f, 1.0f, 1.0f, 1.f, 1.f}, + { -1.0f, -1.0f, -1.0f, 0.f, 0.f}, + { -1.0f, 1.0f, -1.0f, 0.f, 1.f}, + }, +}; +constexpr uint32_t num_faces = (sizeof (cube_faces)) / (sizeof (cube_faces[0])); + +constexpr uint32_t color = 0xffff00ff; + +static float theta = 0; +constexpr float half_degree = 0.01745329f / 2.f; + +void transform(ta_parameter_writer& parameter, + const vertex * strip_vertices, + const uint32_t strip_length, + const uint32_t screen_width, + const uint32_t screen_height, + const uint32_t texture_address, + const uint32_t texture_width) +{ + auto polygon = global_polygon_type_0(texture_address); + switch (texture_width) { + case 32: + 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::_32 + | tsp_instruction_word::texture_v_size::_32 + | tsp_instruction_word::use_alpha; + break; + case 64: + 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::_64 + | tsp_instruction_word::texture_v_size::_64 + | tsp_instruction_word::use_alpha; + break; + case 128: + 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::_128 + | tsp_instruction_word::texture_v_size::_128 + | tsp_instruction_word::use_alpha; + break; + case 256: + 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::_256 + | tsp_instruction_word::texture_v_size::_256 + | tsp_instruction_word::use_alpha; + break; + case 512: + 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::_512 + | tsp_instruction_word::texture_v_size::_512 + | tsp_instruction_word::use_alpha; + break; + default: break; + } + parameter.append() = 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; + float t; + + t = y * __builtin_cosf(theta) - z * __builtin_sinf(theta); + z = y * __builtin_sinf(theta) + z * __builtin_cosf(theta); + y = t; + + float theta2 = 3.14 * __builtin_sinf(theta / 2); + + t = x * __builtin_cosf(theta2) - z * __builtin_sinf(theta2); + z = x * __builtin_sinf(theta2) + z * __builtin_cosf(theta2); + x = t; + + z += 3; + + // perspective + x = x / z; + y = y / z; + + x *= static_cast(screen_height) * 0.7; + y *= static_cast(screen_height) * 0.7; + x += static_cast(screen_width / 2); + y += static_cast(screen_height / 2); + + z = 1 / z; + + parameter.append() = + vertex_polygon_type_3(x, y, z, + strip_vertices[i].u, + strip_vertices[i].v, + color, + end_of_strip); + } +} + +void copy_macaw_texture() +{ + auto src = reinterpret_cast(&_binary_macaw_data_start); + auto size = reinterpret_cast(&_binary_macaw_data_size); + auto mem = reinterpret_cast(texture_memory64); + for (uint32_t px = 0; px < size / 3; px++) { + uint8_t r = src[px * 3 + 0]; + uint8_t g = src[px * 3 + 1]; + uint8_t b = src[px * 3 + 2]; + + uint16_t rgb565 = ((r / 8) << 11) | ((g / 4) << 5) | ((b / 8) << 0); + mem->texture[px] = rgb565; + } +} + +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 + }; + +void render(const uint32_t width, const uint32_t height, + const uint32_t texture_address, + const uint32_t texture_width, + uint32_t * ta_parameter_buf) +{ + const uint32_t tiles = (width / 32) * (height / 32); + ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc, + width, height); + + auto parameter = ta_parameter_writer(ta_parameter_buf); + for (uint32_t i = 0; i < num_faces; i++) { + transform(parameter, cube_faces[i], 4, + width, height, + texture_address, + texture_width); + } + parameter.append() = global_end_of_list(); + ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); + ta_wait_opaque_list(); +} + +uint32_t _ta_parameter_buf[((32 * (5 * 6 + 1)) + 32) / 4]; + +void main() +{ + vga(); + copy_macaw_texture(); + + // 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); + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + core_init(); + + auto mem = reinterpret_cast(texture_memory32); + + uint32_t frame_ix = 0; + constexpr uint32_t num_frames = 1; + + constexpr uint32_t texture_size = 256; + + while (1) { + region_array2(mem->region_array, + (offsetof (struct texture_memory_alloc, object_list)), + texture_size / 32, // width + texture_size / 32, // height + opb_size + ); + + background_parameter(mem->background, 0xffff00ff); + + render(texture_size, texture_size, + (offsetof (struct texture_memory_alloc, texture)), + 128, + ta_parameter_buf); + core_start_render(0x1000000 | (offsetof (struct texture_memory_alloc, texturebuffer)), // 64-bit area + texture_size, // linestride + 0, // framesize (dontcare) + 0, 0); + core_wait_end_of_render_video(); + + background_parameter(mem->background, 0xff0000ff); + + region_array2(mem->region_array, + (offsetof (struct texture_memory_alloc, object_list)), + 640 / 32, // width + 480 / 32, // height + opb_size + ); + + render(640, 480, + (offsetof (struct texture_memory_alloc, texturebuffer)), + texture_size, + ta_parameter_buf); + core_start_render(0x0000000 + (offsetof (struct texture_memory_alloc, framebuffer)), // 32-bit area + 640, // linestride + 0x00096000, // framesize + frame_ix, num_frames); + v_sync_in(); + core_wait_end_of_render_video(frame_ix, num_frames); + + theta += half_degree; + frame_ix += 1; + } +} diff --git a/holly/background.cpp b/holly/background.cpp index 5fd72a9..56167d9 100644 --- a/holly/background.cpp +++ b/holly/background.cpp @@ -18,7 +18,7 @@ struct isp_tsp_parameter { static_assert((sizeof (isp_tsp_parameter)) == (4 * 3 + 3) * 4); -void background_parameter(volatile uint32_t * buf) +void background_parameter(volatile uint32_t * buf, uint32_t color) { volatile isp_tsp_parameter * parameter = reinterpret_cast(buf); @@ -37,15 +37,15 @@ void background_parameter(volatile uint32_t * buf) parameter->vertex[0].x = 0.f; parameter->vertex[0].y = 0.f; parameter->vertex[0].z = 1.f/100000; - parameter->vertex[0].base_color = 0xff0000ff; + parameter->vertex[0].base_color = color; parameter->vertex[1].x = 639.f; parameter->vertex[1].y = 0.f; parameter->vertex[1].z = 1.f/100000; - parameter->vertex[1].base_color = 0xff0000ff; + parameter->vertex[1].base_color = color; parameter->vertex[2].x = 639.f; parameter->vertex[2].y = 479.f; parameter->vertex[2].z = 1.f/100000; - parameter->vertex[2].base_color = 0xff0000ff; + parameter->vertex[2].base_color = color; } diff --git a/holly/background.hpp b/holly/background.hpp index 266d44f..a567f81 100644 --- a/holly/background.hpp +++ b/holly/background.hpp @@ -2,4 +2,4 @@ #include -void background_parameter(volatile uint32_t * buf); +void background_parameter(volatile uint32_t * buf, uint32_t color); diff --git a/holly/core.cpp b/holly/core.cpp index 199fd9a..9c06e1c 100644 --- a/holly/core.cpp +++ b/holly/core.cpp @@ -50,7 +50,10 @@ void core_init() | fpu_param_cfg::pointer_first_burst_size(7); // half of pointer burst size(?) } -void core_start_render(uint32_t frame_ix, uint32_t num_frames) +void core_start_render(uint32_t frame_address, + uint32_t frame_linestride, // in pixels + uint32_t frame_size, // in bytes + uint32_t frame_ix, uint32_t num_frames) { holly.REGION_BASE = (offsetof (struct texture_memory_alloc, region_array)); holly.PARAM_BASE = (offsetof (struct texture_memory_alloc, isp_tsp_parameters)); @@ -60,20 +63,26 @@ void core_start_render(uint32_t frame_ix, uint32_t num_frames) | isp_backgnd_t::skip(1); holly.ISP_BACKGND_D = _i(1.f/100000.f); - holly.FB_W_CTRL = 1 << 3 | fb_w_ctrl::fb_packmode::_565_rgb_16bit; - holly.FB_W_LINESTRIDE = (640 * 2) / 8; + holly.FB_W_CTRL = fb_w_ctrl::fb_dither | fb_w_ctrl::fb_packmode::_565_rgb_16bit; + holly.FB_W_LINESTRIDE = (frame_linestride * 2) / 8; - uint32_t w_fb = ((frame_ix + 0) & num_frames) * 0x00096000; - holly.FB_W_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + w_fb; + uint32_t w_fb = ((frame_ix + 0) & num_frames) * frame_size; + holly.FB_W_SOF1 = frame_address + w_fb; holly.STARTRENDER = 1; } +void core_start_render(uint32_t frame_ix, uint32_t num_frames) +{ + core_start_render((offsetof (struct texture_memory_alloc, framebuffer)), + 640, // frame_linestride + 0x00096000, // frame_size + frame_ix, num_frames); +} + static bool flycast_is_dumb = false; -#include "serial.hpp" - -void core_wait_end_of_render_video(uint32_t frame_ix, uint32_t num_frames) +void core_wait_end_of_render_video() { if (!flycast_is_dumb) { flycast_is_dumb = true; @@ -81,6 +90,13 @@ void core_wait_end_of_render_video(uint32_t frame_ix, uint32_t num_frames) while ((system.ISTNRM & ISTNRM__END_OF_RENDER_TSP) == 0); system.ISTNRM = ISTNRM__END_OF_RENDER_TSP; } +} + +void core_wait_end_of_render_video(uint32_t frame_ix, uint32_t num_frames) +{ + core_wait_end_of_render_video(); + + // hmm hacky... uint32_t r_fb = ((frame_ix + 1) & num_frames) * 0x00096000; holly.FB_R_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + r_fb; } diff --git a/holly/core.hpp b/holly/core.hpp index 5714740..b9761dc 100644 --- a/holly/core.hpp +++ b/holly/core.hpp @@ -1,5 +1,12 @@ #pragma once void core_init(); + +void core_start_render(uint32_t frame_address, + uint32_t frame_linestride, // in pixels + uint32_t frame_size, // in bytes + uint32_t frame_ix, uint32_t num_frames); void core_start_render(uint32_t frame_ix, uint32_t num_frames); + +void core_wait_end_of_render_video(); void core_wait_end_of_render_video(uint32_t frame_ix, uint32_t num_frames); diff --git a/holly/ta_fifo_polygon_converter.cpp b/holly/ta_fifo_polygon_converter.cpp index a005072..eab3737 100644 --- a/holly/ta_fifo_polygon_converter.cpp +++ b/holly/ta_fifo_polygon_converter.cpp @@ -13,13 +13,15 @@ #include "ta_fifo_polygon_converter.hpp" void ta_polygon_converter_init(uint32_t opb_total_size, // for all render passes - uint32_t ta_alloc) + uint32_t ta_alloc, + uint32_t width, // in pixels + uint32_t height) // in pixels { holly.SOFTRESET = softreset::ta_soft_reset; holly.SOFTRESET = 0; - holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num((480 / 32) - 1) - | ta_glob_tile_clip::tile_x_num((640 / 32) - 1); + holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num((height / 32) - 1) + | ta_glob_tile_clip::tile_x_num((width / 32) - 1); holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses | ta_alloc; diff --git a/holly/ta_fifo_polygon_converter.hpp b/holly/ta_fifo_polygon_converter.hpp index b401192..52bbd01 100644 --- a/holly/ta_fifo_polygon_converter.hpp +++ b/holly/ta_fifo_polygon_converter.hpp @@ -3,7 +3,9 @@ #include void ta_polygon_converter_init(uint32_t opb_total_size, // total OPB size for all render passes - uint32_t ta_alloc); + uint32_t ta_alloc, + uint32_t width, // in pixels + uint32_t height); // in pixels void ta_polygon_converter_cont(uint32_t ol_base_offset, uint32_t ta_alloc); void ta_polygon_converter_transfer(volatile uint32_t * buf, uint32_t size); diff --git a/holly/texture_memory_alloc.hpp b/holly/texture_memory_alloc.hpp index bc280c2..f5f5f54 100644 --- a/holly/texture_memory_alloc.hpp +++ b/holly/texture_memory_alloc.hpp @@ -10,6 +10,9 @@ TA/CORE drawings) region-array[0x00004000 / 4] is enough space for 2 render passes. + (640 // 32) * (480 // 32) * 6 * 4 * 2 == 0x3840 + (640 // 32) * (512 // 32) * 6 * 4 * 2 == 0x3c00 + (512 // 32) * (512 // 32) * 6 * 4 * 2 == 0x3000 */ struct texture_memory_alloc { @@ -20,6 +23,7 @@ struct texture_memory_alloc { uint32_t background[0x00000040 / 4]; // ISP_BACKGND_T uint32_t framebuffer[2][0x00096000 / 4]; // FB_R_SOF1 / FB_W_SOF1 uint32_t _res1[ 0x20 / 4]; // (re-align texture to a 64-byte boundary) + uint16_t texturebuffer[512 * 512 * 2 / 2]; uint16_t texture[128 * 128 * 2 / 2]; // texture_control_word::texture_address };