diff --git a/example/example.mk b/example/example.mk index 0f2d86e..a15ae15 100644 --- a/example/example.mk +++ b/example/example.mk @@ -701,3 +701,15 @@ MEMORY_MAP_OBJ = \ example/memory_map.elf: LDSCRIPT = $(LIB)/main.lds example/memory_map.elf: $(START_OBJ) $(MEMORY_MAP_OBJ) + +TRIANGLE_GOURAUD_OBJ = \ + example/triangle_gouraud.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + holly/video_output.o \ + sh7091/serial.o + +example/triangle_gouraud.elf: LDSCRIPT = $(LIB)/main.lds +example/triangle_gouraud.elf: $(START_OBJ) $(TRIANGLE_GOURAUD_OBJ) diff --git a/example/triangle_gouraud.cpp b/example/triangle_gouraud.cpp new file mode 100644 index 0000000..9ff06bc --- /dev/null +++ b/example/triangle_gouraud.cpp @@ -0,0 +1,149 @@ +#include + +#include "holly/background.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/holly.hpp" +#include "holly/isp_tsp.hpp" +#include "holly/region_array.hpp" +#include "holly/ta_bits.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/ta_global_parameter.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/texture_memory_alloc2.hpp" +#include "holly/video_output.hpp" + +#include "sh7091/store_queue.hpp" +#include "sh7091/serial.hpp" + +#include "memorymap.hpp" + +struct vertex { + float x; + float y; + float z; + unsigned int base_color; +}; + +// screen space coordinates +const struct vertex triangle_vertices[] = { + { 320.000f, 50.f, 0.1f, 0xffff0000 }, + { 539.393f, 430.f, 0.1f, 0xff00ff00 }, + { 100.607f, 430.f, 0.1f, 0xff0000ff }, +}; + +void transfer_triangle() +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::packed_color + | obj_control::gouraud; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + | isp_tsp_instruction_word::culling_mode::no_culling; + + const uint32_t tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog; + + *reinterpret_cast(store_queue) = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + 0, + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + sq_transfer_32byte(ta_fifo_polygon_converter); + + for (int i = 0; i < 3; i++) { + float x = triangle_vertices[i].x; + float y = triangle_vertices[i].y; + float z = triangle_vertices[i].z; + int base_color = triangle_vertices[i].base_color; + + bool end_of_strip = i == 2; + + *reinterpret_cast(store_queue) = + ta_vertex_parameter::polygon_type_0(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + base_color); + sq_transfer_32byte(ta_fifo_polygon_converter); + } + + *reinterpret_cast(store_queue) = + ta_global_parameter::end_of_list(para_control::para_type::end_of_list); + sq_transfer_32byte(ta_fifo_polygon_converter); +} + +void main() +{ + const 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; + + const int render_passes = 1; + const struct opb_size opb_size[render_passes] = { + { + .opaque = 16 * 4, + .opaque_modifier = 0, + .translucent = 0, + .translucent_modifier = 0, + .punch_through = 0 + } + }; + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + core_init(); + + video_output::set_mode_vga(); + + const int framebuffer_width = 640; + const int framebuffer_height = 480; + const int tile_width = framebuffer_width / 32; + const int tile_height = framebuffer_height / 32; + + region_array_multipass(tile_width, + tile_height, + opb_size, + render_passes, + texture_memory_alloc::region_array[0].start, + texture_memory_alloc::object_list[0].start); + + background_parameter2(texture_memory_alloc::background[0].start, + 0xff220033); + + + while (1) { + ta_polygon_converter_init2(texture_memory_alloc::isp_tsp_parameters[0].start, + texture_memory_alloc::isp_tsp_parameters[0].end, + texture_memory_alloc::object_list[0].start, + texture_memory_alloc::object_list[0].end, + opb_size[0].total(), + ta_alloc, + tile_width, + tile_height); + transfer_triangle(); + ta_wait_opaque_list(); + + core_start_render2(texture_memory_alloc::region_array[0].start, + texture_memory_alloc::isp_tsp_parameters[0].start, + texture_memory_alloc::background[0].start, + texture_memory_alloc::framebuffer[0].start, + framebuffer_width); + + core_wait_end_of_render_video(); + + while (!spg_status::vsync(holly.SPG_STATUS)); + holly.FB_R_SOF1 = texture_memory_alloc::framebuffer[0].start; + while (spg_status::vsync(holly.SPG_STATUS)); + break; + } + serial::string("return\nreturn\nreturn\n"); +} diff --git a/parse_texture_memory.py b/parse_texture_memory.py new file mode 100644 index 0000000..b4ab748 --- /dev/null +++ b/parse_texture_memory.py @@ -0,0 +1,218 @@ +from dataclasses import dataclass +import sys +import struct +from pprint import pprint, pformat +import textwrap + +with open(sys.argv[1], "rb") as f: + mem = memoryview(f.read()) + +@dataclass +class buf_parser: + mem: memoryview + address: int + +def u32(buf): + value, = struct.unpack("> 31) & 1 + z_clear = (value >> 30) & 1 + pre_sort = (value >> 29) & 1 + flush_accumulate = (value >> 28) & 1 + tile_y_position = (value >> 8) & 0x3f + tile_x_position = (value >> 2) & 0x3f + + flags = set() + if last_region: + flags.add("last_region") + if z_clear: + flags.add("z_clear") + if pre_sort: + flags.add("pre_sort") + if flush_accumulate: + flags.add("flush_accumulate") + return tile(flags, tile_x_position, tile_y_position) + +@dataclass +class region_array_entry: + tile: int + opaque_list_pointer: int + modifier_volume_list_pointer: int + translucent_list_pointer: int + translucent_modifier_volume_list_pointer: int + punch_through_list_pointer: int + + def __init__(self): + pass + +def parse_region_array_entry(buf): + entry = region_array_entry() + entry.tile = region_array_tile(u32(buf)) + entry.opaque_list_pointer = u32(buf) + entry.modifier_volume_list_pointer = u32(buf) + entry.translucent_list_pointer = u32(buf) + entry.translucent_modifier_volume_list_pointer = u32(buf) + entry.punch_through_list_pointer = u32(buf) + return entry + +def parse_region_array(mem, address): + buf = buf_parser(mem, address) + while True: + entry = parse_region_array_entry(buf) + yield entry + if "last_region" in entry.tile.flags: + break + +@dataclass +class object_list_array: + number: int + shadow: int + skip: int + start: int + +def print_array(value): + number = (value >> 25) & 0b1111 + shadow = (value >> 24) & 1 + skip = (value >> 21) & 0b111 + start = value & ((1 << 21) - 1) + print(f' number: {number}') + print(f' shadow: {shadow}') + print(f' skip: {skip}') + print(f' start: {start}') + return object_list_array(number, shadow, skip, start) + +@dataclass +class isp_tsp_instruction_word: + depth_compare_mode: str + culling_mode: str + z_write_disable: int + texture: int + offset: int + gouraud_shading: int + _16bit_uv: int + cache_bypass: int + dcalc_ctrl: int + +def parse_isp_tsp_instruction_word(value): + def depth_compare_mode(value): + value = (value >> 29) & 0b111 + if value == 0: return "never" + if value == 1: return "less" + if value == 2: return "equal" + if value == 3: return "less_or_equal" + if value == 4: return "greater" + if value == 5: return "not_equal" + if value == 6: return "greater_or_equal" + if value == 7: return "always" + + def culling_mode(value): + value = (value >> 27) & 0b11 + if value == 0: return "no_culling" + if value == 1: return "cull_if_small" + if value == 2: return "cull_if_negative" + if value == 3: return "cull_if_positive" + + z_write_disable = (value >> 26) & 1 + texture = (value >> 25) & 1 + offset = (value >> 24) & 1 + gouraud_shading = (value >> 23) & 1 + _16bit_uv = (value >> 22) & 1 + cache_bypass = (value >> 21) & 1 + dcalc_ctrl = (value >> 20) & 1 + + return isp_tsp_instruction_word( + depth_compare_mode(value), + culling_mode(value), + z_write_disable, + texture, + offset, + gouraud_shading, + _16bit_uv, + cache_bypass, + dcalc_ctrl, + ) + +def print_params(mem, ol_array, num_vertices): + # skip + + # This field specifies the data size (* 32 bits) for one vertex in the + # ISP/TSP Parameters. Normally, the actual data size is "skip + 3," + + buf = buf_parser(mem, ol_array.start) + isp_tsp = u32(buf) + tsp = u32(buf) + texture = u32(buf) + print(textwrap.indent(pformat(parse_isp_tsp_instruction_word(isp_tsp)), ' ')) + + vertex_size = (ol_array.skip + 3) * 4 + while num_vertices > 0: + start = buf.address + x = f32(buf) + y = f32(buf) + z = f32(buf) + base_color = u32(buf) + print(f"{x:7.3f} {y:7.3f} {z:7.3f} {base_color:x}") + buf.address = start + vertex_size + num_vertices -= 1 + +def parse_object_list_data(mem, value): + if ((value >> 31) & 1) == 0: + print(' triangle:') + elif ((value >> 29) & 0b111) == 0b100: + print(' triangle array:') + ol_array = print_array(value) + print_params(mem, ol_array, 3) + elif ((value >> 29) & 0b111) == 0b101: + print(' quad array:') + ol_array = print_array(value) + print_params(mem, ol_array, 4) + elif ((value >> 29) & 0b111) == 0b111: + print(' block link:') + end_of_list = (value >> 28) & 1 + if end_of_list: + print(' [end of list]') + return end_of_list + else: + assert False, value + +def parse_object_list(mem, address): + if (address & (1 << 31)) != 0: + return + buf = buf_parser(mem, address) + while True: + end_of_list = parse_object_list_data(mem, u32(buf)) + if end_of_list: + break + +def parse_object_lists(mem, region_array_entry): + print(region_array_entry.tile) + parse_object_list(mem, region_array_entry.opaque_list_pointer) + parse_object_list(mem, region_array_entry.modifier_volume_list_pointer) + parse_object_list(mem, region_array_entry.translucent_list_pointer) + parse_object_list(mem, region_array_entry.translucent_modifier_volume_list_pointer) + parse_object_list(mem, region_array_entry.punch_through_list_pointer) + + +region_array = 0x296000 +framebuffer = 0x200000 +region_array_entries = list(parse_region_array(mem, region_array)) + +for region_array_entry in region_array_entries: + parse_object_lists(mem, region_array_entry) + +#with open('framebuffer.data', 'wb') as f: +# f.write(mem[framebuffer:framebuffer + 640 * 480 * 2])