example: add macaw_cube_render_to_texture

This commit is contained in:
Zack Buhman 2023-12-18 02:10:52 +08:00
parent 88b6fa9aae
commit e2a6406a05
9 changed files with 333 additions and 17 deletions

View File

@ -82,6 +82,19 @@ MACAW_CUBE_OBJ = \
example/macaw_cube.elf: LDSCRIPT = $(LIB)/alt.lds example/macaw_cube.elf: LDSCRIPT = $(LIB)/alt.lds
example/macaw_cube.elf: $(START_OBJ) $(MACAW_CUBE_OBJ) 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 = \ MAPLE_DEVICE_REQUEST_OBJ = \
example/maple_device_request.o \ example/maple_device_request.o \
vga.o \ vga.o \

View File

@ -0,0 +1,272 @@
#include <cstdint>
#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<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;
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<float>(screen_height) * 0.7;
y *= static_cast<float>(screen_height) * 0.7;
x += static_cast<float>(screen_width / 2);
y += static_cast<float>(screen_height / 2);
z = 1 / z;
parameter.append<vertex_polygon_type_3>() =
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<const uint8_t *>(&_binary_macaw_data_start);
auto size = reinterpret_cast<const uint32_t>(&_binary_macaw_data_size);
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(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>() = 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<volatile texture_memory_alloc *>(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;
}
}

View File

@ -18,7 +18,7 @@ struct isp_tsp_parameter {
static_assert((sizeof (isp_tsp_parameter)) == (4 * 3 + 3) * 4); 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<volatile isp_tsp_parameter *>(buf); volatile isp_tsp_parameter * parameter = reinterpret_cast<volatile isp_tsp_parameter *>(buf);
@ -37,15 +37,15 @@ void background_parameter(volatile uint32_t * buf)
parameter->vertex[0].x = 0.f; parameter->vertex[0].x = 0.f;
parameter->vertex[0].y = 0.f; parameter->vertex[0].y = 0.f;
parameter->vertex[0].z = 1.f/100000; 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].x = 639.f;
parameter->vertex[1].y = 0.f; parameter->vertex[1].y = 0.f;
parameter->vertex[1].z = 1.f/100000; 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].x = 639.f;
parameter->vertex[2].y = 479.f; parameter->vertex[2].y = 479.f;
parameter->vertex[2].z = 1.f/100000; parameter->vertex[2].z = 1.f/100000;
parameter->vertex[2].base_color = 0xff0000ff; parameter->vertex[2].base_color = color;
} }

View File

@ -2,4 +2,4 @@
#include <cstdint> #include <cstdint>
void background_parameter(volatile uint32_t * buf); void background_parameter(volatile uint32_t * buf, uint32_t color);

View File

@ -50,7 +50,10 @@ void core_init()
| fpu_param_cfg::pointer_first_burst_size(7); // half of pointer burst size(?) | 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.REGION_BASE = (offsetof (struct texture_memory_alloc, region_array));
holly.PARAM_BASE = (offsetof (struct texture_memory_alloc, isp_tsp_parameters)); 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); | isp_backgnd_t::skip(1);
holly.ISP_BACKGND_D = _i(1.f/100000.f); 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_CTRL = fb_w_ctrl::fb_dither | fb_w_ctrl::fb_packmode::_565_rgb_16bit;
holly.FB_W_LINESTRIDE = (640 * 2) / 8; holly.FB_W_LINESTRIDE = (frame_linestride * 2) / 8;
uint32_t w_fb = ((frame_ix + 0) & num_frames) * 0x00096000; uint32_t w_fb = ((frame_ix + 0) & num_frames) * frame_size;
holly.FB_W_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + w_fb; holly.FB_W_SOF1 = frame_address + w_fb;
holly.STARTRENDER = 1; 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; static bool flycast_is_dumb = false;
#include "serial.hpp" void core_wait_end_of_render_video()
void core_wait_end_of_render_video(uint32_t frame_ix, uint32_t num_frames)
{ {
if (!flycast_is_dumb) { if (!flycast_is_dumb) {
flycast_is_dumb = true; 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); while ((system.ISTNRM & ISTNRM__END_OF_RENDER_TSP) == 0);
system.ISTNRM = ISTNRM__END_OF_RENDER_TSP; 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; uint32_t r_fb = ((frame_ix + 1) & num_frames) * 0x00096000;
holly.FB_R_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + r_fb; holly.FB_R_SOF1 = (offsetof (struct texture_memory_alloc, framebuffer)) + r_fb;
} }

View File

@ -1,5 +1,12 @@
#pragma once #pragma once
void core_init(); 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_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); void core_wait_end_of_render_video(uint32_t frame_ix, uint32_t num_frames);

View File

@ -13,13 +13,15 @@
#include "ta_fifo_polygon_converter.hpp" #include "ta_fifo_polygon_converter.hpp"
void ta_polygon_converter_init(uint32_t opb_total_size, // for all render passes 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 = softreset::ta_soft_reset;
holly.SOFTRESET = 0; holly.SOFTRESET = 0;
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num((480 / 32) - 1) holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num((height / 32) - 1)
| ta_glob_tile_clip::tile_x_num((640 / 32) - 1); | ta_glob_tile_clip::tile_x_num((width / 32) - 1);
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc; | ta_alloc;

View File

@ -3,7 +3,9 @@
#include <cstdint> #include <cstdint>
void ta_polygon_converter_init(uint32_t opb_total_size, // total OPB size for all render passes 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, void ta_polygon_converter_cont(uint32_t ol_base_offset,
uint32_t ta_alloc); uint32_t ta_alloc);
void ta_polygon_converter_transfer(volatile uint32_t * buf, uint32_t size); void ta_polygon_converter_transfer(volatile uint32_t * buf, uint32_t size);

View File

@ -10,6 +10,9 @@
TA/CORE drawings) TA/CORE drawings)
region-array[0x00004000 / 4] is enough space for 2 render passes. 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 { struct texture_memory_alloc {
@ -20,6 +23,7 @@ struct texture_memory_alloc {
uint32_t background[0x00000040 / 4]; // ISP_BACKGND_T uint32_t background[0x00000040 / 4]; // ISP_BACKGND_T
uint32_t framebuffer[2][0x00096000 / 4]; // FB_R_SOF1 / FB_W_SOF1 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) 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 uint16_t texture[128 * 128 * 2 / 2]; // texture_control_word::texture_address
}; };