example: add triangle_gouraud

This commit is contained in:
Zack Buhman 2025-01-22 22:54:57 -06:00
parent c0d424c745
commit 8b4b79a705
3 changed files with 379 additions and 0 deletions

View File

@ -701,3 +701,15 @@ MEMORY_MAP_OBJ = \
example/memory_map.elf: LDSCRIPT = $(LIB)/main.lds example/memory_map.elf: LDSCRIPT = $(LIB)/main.lds
example/memory_map.elf: $(START_OBJ) $(MEMORY_MAP_OBJ) 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)

View File

@ -0,0 +1,149 @@
#include <stdint.h>
#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<ta_global_parameter::polygon_type_0 *>(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<ta_vertex_parameter::polygon_type_0 *>(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<ta_global_parameter::end_of_list *>(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");
}

218
parse_texture_memory.py Normal file
View File

@ -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("<I", buf.mem[buf.address:buf.address+4])
buf.address += 4
return value
def f32(buf):
value, = struct.unpack("<f", buf.mem[buf.address:buf.address+4])
buf.address += 4
return value
@dataclass
class tile:
flags: set[str]
x: int
y: int
def region_array_tile(value):
last_region = (value >> 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])