From c7c0ce277ae520393d388802c0d60c6f82613b58 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Fri, 24 Jan 2025 22:47:28 -0600 Subject: [PATCH] add sprite_gouraud/texture_memory_alloc3 --- example/example.mk | 31 +++ example/sprite_gouraud.cpp | 180 ++++++++++++++++++ example/wiffle_screen_space.cpp | 325 ++++++++++++++++++++++++++++++++ holly/texture_memory_alloc3.hpp | 37 ++++ 4 files changed, 573 insertions(+) create mode 100644 example/sprite_gouraud.cpp create mode 100644 example/wiffle_screen_space.cpp create mode 100644 holly/texture_memory_alloc3.hpp diff --git a/example/example.mk b/example/example.mk index a15ae15..05f3985 100644 --- a/example/example.mk +++ b/example/example.mk @@ -209,6 +209,18 @@ WIFFLE_ATTENUATION_OBJ = \ example/wiffle_attenuation.elf: LDSCRIPT = $(LIB)/main.lds example/wiffle_attenuation.elf: $(START_OBJ) $(WIFFLE_ATTENUATION_OBJ) +WIFFLE_SCREEN_SPACE_OBJ = \ + example/wiffle_screen_space.o \ + holly/video_output.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + sh7091/serial.o + +example/wiffle_screen_space.elf: LDSCRIPT = $(LIB)/main.lds +example/wiffle_screen_space.elf: $(START_OBJ) $(WIFFLE_SCREEN_SPACE_OBJ) + MODIFIER_VOLUME_OBJ = \ example/modifier_volume.o \ holly/video_output.o \ @@ -713,3 +725,22 @@ TRIANGLE_GOURAUD_OBJ = \ example/triangle_gouraud.elf: LDSCRIPT = $(LIB)/main.lds example/triangle_gouraud.elf: $(START_OBJ) $(TRIANGLE_GOURAUD_OBJ) + +SPRITE_GOURAUD_OBJ = \ + example/sprite_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/sprite_gouraud.elf: LDSCRIPT = $(LIB)/main.lds +example/sprite_gouraud.elf: $(START_OBJ) $(SPRITE_GOURAUD_OBJ) + +TEXTURE_MEMORY_OBJ = \ + example/texture_memory.o \ + sh7091/serial.o + +example/texture_memory.elf: LDSCRIPT = $(LIB)/main.lds +example/texture_memory.elf: $(START_OBJ) $(TEXTURE_MEMORY_OBJ) diff --git a/example/sprite_gouraud.cpp b/example/sprite_gouraud.cpp new file mode 100644 index 0000000..61f84b4 --- /dev/null +++ b/example/sprite_gouraud.cpp @@ -0,0 +1,180 @@ +#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 "systembus.hpp" + +#include "memorymap.hpp" + +struct vertex { + float x; + float y; + float z; + unsigned int base_color; +}; + +// screen space coordinates +const struct vertex quad_vertices[] = { + { 100.607f, 50.f, 0.1f, 0xff0000ff }, + { 539.393f, 50.f, 0.1f, 0xff00ff00 }, + { 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::sprite + | 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; + + const uint32_t texture_control_word = 0; + + const uint32_t base_color = 0xffff0000; + *reinterpret_cast(store_queue) = + ta_global_parameter::sprite(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + texture_control_word, + base_color, + 0, // offset_color + 0, // data_size_for_sort_dma + 0); // next_address_for_sort_dma + sq_transfer_32byte(ta_fifo_polygon_converter); + + *reinterpret_cast(store_queue) = + ta_vertex_parameter::sprite_type_0(para_control::para_type::vertex_parameter, + quad_vertices[0].x, + quad_vertices[0].y, + quad_vertices[0].z, + quad_vertices[1].x, + quad_vertices[1].y, + quad_vertices[1].z, + quad_vertices[2].x, + quad_vertices[2].y, + quad_vertices[2].z, + quad_vertices[3].x, + quad_vertices[3].y); + sq_transfer_64byte(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(); + + //0x80400000 + volatile uint32_t * param_base = &texture_memory32[texture_memory_alloc::isp_tsp_parameters[0].start / 4]; + param_base[0] |= isp_tsp_instruction_word::gouraud_shading; + //param_base[1]; // tsp + //param_base[2]; // texture + //param_base[3]; // x + //param_base[4]; // y + //param_base[5]; // z + param_base[6] = quad_vertices[0].base_color; // base_color + //param_base[7]; // x + //param_base[8]; // y + //param_base[9]; // z + param_base[10] = quad_vertices[1].base_color; // base_color + //param_base[11]; // x + //param_base[12]; // y + //param_base[13]; // z + //param_base[14] = quad_vertices[2].base_color; // base_color + //param_base[15]; // x + //param_base[16]; // y + //param_base[17]; // z + //param_base[18] = quad_vertices[3].base_color; // base_color + + 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::integer(system.ISTNRM); + serial::integer(system.ISTERR); + serial::string("return\nreturn\nreturn\n"); +} diff --git a/example/wiffle_screen_space.cpp b/example/wiffle_screen_space.cpp new file mode 100644 index 0000000..b25895d --- /dev/null +++ b/example/wiffle_screen_space.cpp @@ -0,0 +1,325 @@ +#include + +#include "align.hpp" +#include "holly/video_output.hpp" + +#include "holly/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_global_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/isp_tsp.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 "geometry/wiffle.hpp" +#include "math/vec4.hpp" + +constexpr float half_degree = 0.01745329f / 2; + +#define MODEL wiffle + +vec3 rotate(const vec3& vertex, float theta) +{ + float x = vertex.x; + float y = vertex.y; + float z = vertex.z; + float t; + + t = y * cos(theta) - z * sin(theta); + z = y * sin(theta) + z * cos(theta); + y = t; + + float theta2 = 3.14 * sin(theta / 2); + + t = x * cos(theta2) - z * sin(theta2); + z = x * sin(theta2) + z * cos(theta2); + x = t; + + return vec3(x, y, z); +} + +void transform(ta_parameter_writer& parameter, + const uint32_t face_ix, + const float theta, + const vec3 lights[3]) +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::floating_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::cull_if_positive; + + 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; + + parameter.append() = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + 0, // texture_control_word + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + + auto& face = MODEL::faces[face_ix]; + + constexpr uint32_t strip_length = 3; + for (uint32_t i = 0; i < strip_length; i++) { + // world transform + uint32_t vertex_ix = face[i].vertex; + auto& vertex = MODEL::vertices[vertex_ix]; + auto point = rotate(vertex, theta); + + // lighting transform + uint32_t normal_ix = face[i].normal; + auto& normal = MODEL::normals[normal_ix]; + auto n = rotate(normal, theta); + + /* + vec4 color = {0.0, 0.0, 0.0, 1.0}; + + // intensity calculation + { + auto l = lights[0] - point; + auto n_dot_l = dot(n, l); + if (n_dot_l > 0) { + float distance = magnitude(lights[0] - point); + float attenuation = 1.0 / (1.0f + + 0.07f * distance + + 0.007f * (distance * distance)); + color.x += 5.0 * attenuation; + } + } + + { + auto l = lights[1] - point; + auto n_dot_l = dot(n, l); + if (n_dot_l > 0) { + float distance = magnitude(lights[1] - point); + float attenuation = 1.0 / (1.0f + + 0.07f * distance + + 0.007f * (distance * distance)); + color.y += 5.0 * attenuation; + } + } + + { + auto l = lights[2] - point; + auto n_dot_l = dot(n, l); + if (n_dot_l > 0) { + float distance = magnitude(lights[2] - point); + float attenuation = 1.0 / (1.0f + + 0.07f * distance + + 0.007f * (distance * distance)); + color.z += 9.0 * attenuation; + } + } + */ + + float x = point.x; + float y = point.y; + float z = point.z; + + x *= 1; + y *= 1; + z *= 1; + + // camera transform + z += 90; + + // perspective + x = x / z; + y = y / z; + + // screen space transform + x *= 240.f; + y *= 240.f; + x += 320.f; + y += 240.f; + z = 1 / z; + + float scale_z = ((point.z - -46) / (46 - -46)) * (1 - 0); + + bool end_of_strip = i == strip_length - 1; + parameter.append() = + ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + 1.0, + //(point.z + 1) * 90, // alpha + //__builtin_fabs(n.x), // r + //__builtin_fabs(n.y), // g + //__builtin_fabs(n.z) // b + 1 - scale_z, + 1 - scale_z, + 1 - scale_z + ); + } +} + +void transform2(ta_parameter_writer& parameter, + const vec3& pos, + const vec4& color) +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::floating_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; + + parameter.append() = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + 0, // texture_control_word + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + + constexpr vec3 triangle[] = { + { 0.f, -1.f, 0.f}, + {-1.f, 1.f, 0.f}, + { 1.f, 1.f, 0.f}, + }; + + constexpr uint32_t strip_length = 3; + for (uint32_t i = 0; i < strip_length; i++) { + float x = triangle[i].x; + float y = triangle[i].y; + float z = triangle[i].z; + + x *= 0.2; + y *= 0.2; + z *= 0.2; + + x += pos.x; + y += pos.y; + z += pos.z; + + // camera transform + z += 40; + + // perspective + x = x / z; + y = y / z; + + // screen space transform + x *= 240.f; + y *= 240.f; + x += 320.f; + y += 240.f; + z = 1 / z; + + bool end_of_strip = i == strip_length - 1; + parameter.append() = + ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + color.w, // alpha + color.x, // r + color.y, // g + color.z // b + ); + } +} + +void init_texture_memory(const struct opb_size& opb_size) +{ + region_array2(640 / 32, // width + 480 / 32, // height + opb_size + ); + background_parameter(0xffc0c0c0); +} + +uint32_t _ta_parameter_buf[((32 * 8192) + 32) / 4]; + +void main() +{ + video_output::set_mode_vga(); + + // 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 + }; + + 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; + + float theta = 0; + vec3 lights[3] = { + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + }; + + while (1) { + ta_polygon_converter_init(opb_size.total(), + ta_alloc, + 640 / 32, + 480 / 32); + + float theta2 = 3.14 * 2 * sin(theta / 7); + + lights[0].x = cos(theta) * 20; + lights[0].z = sin(theta) * 20; + + lights[1].x = cos(theta2 + half_degree * 180.f) * 20; + lights[1].z = sin(theta2 + half_degree * 180.f) * 20; + + lights[2].x = cos(theta + half_degree * 360.f) * 20; + lights[2].z = sin(theta + half_degree * 360.f) * 20; + + auto parameter = ta_parameter_writer(ta_parameter_buf); + for (uint32_t i = 0; i < MODEL::num_faces; i++) { + transform(parameter, i, theta, lights); + } + transform2(parameter, lights[0], {1.f, 0.f, 0.f, 1.f}); + transform2(parameter, lights[1], {0.f, 1.f, 0.f, 1.f}); + transform2(parameter, lights[2], {0.f, 0.f, 1.f, 1.f}); + + parameter.append() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list); + ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); + ta_wait_opaque_list(); + core_start_render(frame_ix); + core_wait_end_of_render_video(); + + while (!spg_status::vsync(holly.SPG_STATUS)); + core_flip(frame_ix); + while (spg_status::vsync(holly.SPG_STATUS)); + + theta += half_degree; + frame_ix = (frame_ix + 1) & 1; + } +} diff --git a/holly/texture_memory_alloc3.hpp b/holly/texture_memory_alloc3.hpp new file mode 100644 index 0000000..7479140 --- /dev/null +++ b/holly/texture_memory_alloc3.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +/* + * A 0x10000-byte region array is sufficient for 9 render passes: + * + * ((640 / 32) * (480 / 32) * 6 * 4) * 9 == 0xfd20 + */ + +struct texture_memory_alloc__start_end { + uint32_t start; + uint32_t end; +}; + +struct texture_memory_alloc { + struct texture_memory_alloc__start_end isp_tsp_parameters[2]; + struct texture_memory_alloc__start_end background[2]; + struct texture_memory_alloc__start_end object_list[2]; + struct texture_memory_alloc__start_end region_array[2]; + struct texture_memory_alloc__start_end framebuffer[2]; + struct texture_memory_alloc__start_end texture; +}; + +constexpr texture_memory_alloc texture_memory_alloc = { + // bus a bus b + // 32-bit addresses start end start end + .isp_tsp_parameters = {{0x00'0000, 0x07'ffe0}, {0x40'0000, 0x47'ffe0}}, // 5461 textured triangles + .background = {{0x07'ffe0, 0x08'0000}, {0x47'ffe0, 0x48'0000}}, + .object_list = {{0x08'0000, 0x0f'ffe0}, {0x48'0000, 0x4f'ffe0}}, // ~122880 object list pointers + .region_array = {{0x10'0000, 0x11'0000}, {0x50'0000, 0x51'0000}}, // ~9 render passes + .framebuffer = {{0x11'0000, 0x1b'8c00}, {0x51'0000, 0x5b'8c00}}, // 720x480*2bpp + + // 64-bit addresses + .texture = {0x37'1800, 0x80'0000} +};