dreamcast/example/texture_filtering.cpp

378 lines
14 KiB
C++

#include <cstdint>
#include "align.hpp"
#include "holly/texture_memory_alloc.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/ta_bits.hpp"
#include "holly/isp_tsp.hpp"
#include "holly/region_array.hpp"
#include "holly/background.hpp"
#include "holly/video_output.hpp"
#include "memorymap.hpp"
#include "twiddle.hpp"
#include "sh7091/serial.hpp"
#include "texture/bbb/bbb1024.data.h"
#include "texture/bbb/bbb128.data.h"
#include "texture/bbb/bbb16.data.h"
#include "texture/bbb/bbb1.data.h"
#include "texture/bbb/bbb256.data.h"
#include "texture/bbb/bbb2.data.h"
#include "texture/bbb/bbb32.data.h"
#include "texture/bbb/bbb4.data.h"
#include "texture/bbb/bbb512.data.h"
#include "texture/bbb/bbb64.data.h"
#include "texture/bbb/bbb8.data.h"
#include "texture/bbb/bbb.data.h"
struct vertex {
float x;
float y;
float z;
float u;
float v;
uint32_t color;
};
const struct vertex strip_vertices[4] = {
// [ position ] [ uv coordinates ] [color ]
{ -0.5f, -0.5f, 0.f, 0.f, 0.f, 0xffffffff},
{ 0.5f, -0.5f, 0.f, 1.f, 0.f, 0xffffffff},
{ -0.5f, 0.5f, 0.f, 0.f, 1.f, 0xffffffff},
{ 0.5f, 0.5f, 0.f, 1.f, 1.f, 0xffffffff},
};
constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex));
static float theta = 0;
constexpr float half_degree = 0.01745329f / 2.f;
namespace defaults {
//constexpr uint32_t parameter_control_word = para_control::para_type::sprite
constexpr uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| obj_control::col_type::packed_color
| obj_control::texture
;
//| obj_control::_16bit_uv;
constexpr uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling;
constexpr uint32_t tsp_instruction_word = tsp_instruction_word::src_select::primary_accumulation_buffer
| tsp_instruction_word::dst_select::primary_accumulation_buffer
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_u_size::_1024
| tsp_instruction_word::texture_v_size::_1024;
constexpr uint32_t texture_address = texture_memory_alloc::texture.start;
constexpr uint32_t texture_control_word = texture_control_word::mip_mapped
| texture_control_word::pixel_format::_565
| texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8);
}
void append_parameter(ta_parameter_writer& parameter,
const uint32_t parameter_control_word,
const uint32_t isp_tsp_instruction_word,
const uint32_t tsp_instruction_word,
const uint32_t texture_control_word)
{
parameter.append<ta_global_parameter::polygon_type_0>() =
ta_global_parameter::polygon_type_0(parameter_control_word,
isp_tsp_instruction_word,
tsp_instruction_word,
texture_control_word,
0, // data_size_for_sort_dma
0 // next_address_for_sort_dma
);
/*
constexpr uint32_t base_color = 0xffff0000;
parameter.append<ta_global_parameter::sprite>() =
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
*/
}
void append_point_sampled(ta_parameter_writer& parameter)
{
const uint32_t parameter_control_word = defaults::parameter_control_word
| para_control::list_type::opaque;
const uint32_t isp_tsp_instruction_word = defaults::isp_tsp_instruction_word;
const uint32_t tsp_instruction_word = defaults::tsp_instruction_word
| tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::filter_mode::point_sampled;
const uint32_t texture_control_word = defaults::texture_control_word;
append_parameter(parameter, parameter_control_word, isp_tsp_instruction_word, tsp_instruction_word, texture_control_word);
}
void append_bilinear(ta_parameter_writer& parameter)
{
const uint32_t parameter_control_word = defaults::parameter_control_word
| para_control::list_type::opaque;
const uint32_t isp_tsp_instruction_word = defaults::isp_tsp_instruction_word;
const uint32_t tsp_instruction_word = defaults::tsp_instruction_word
| tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::filter_mode::bilinear_filter;
const uint32_t texture_control_word = defaults::texture_control_word;
append_parameter(parameter, parameter_control_word, isp_tsp_instruction_word, tsp_instruction_word, texture_control_word);
}
void append_trilinear_pass_a(ta_parameter_writer& parameter)
{
const uint32_t parameter_control_word = defaults::parameter_control_word
| para_control::list_type::opaque;
const uint32_t isp_tsp_instruction_word = defaults::isp_tsp_instruction_word;
const uint32_t tsp_instruction_word = defaults::tsp_instruction_word
| tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::filter_mode::trilinear_pass_a;
const uint32_t texture_control_word = defaults::texture_control_word;
append_parameter(parameter, parameter_control_word, isp_tsp_instruction_word, tsp_instruction_word, texture_control_word);
}
void append_trilinear_pass_b(ta_parameter_writer& parameter)
{
const uint32_t parameter_control_word = defaults::parameter_control_word
| para_control::list_type::translucent;
const uint32_t isp_tsp_instruction_word = defaults::isp_tsp_instruction_word;
const uint32_t tsp_instruction_word = defaults::tsp_instruction_word
| tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::one
| tsp_instruction_word::filter_mode::trilinear_pass_b;
const uint32_t texture_control_word = defaults::texture_control_word;
append_parameter(parameter, parameter_control_word, isp_tsp_instruction_word, tsp_instruction_word, texture_control_word);
}
enum class filter_type {
point_sampled,
bilinear,
trilinear_pass_a,
trilinear_pass_b,
};
void transform(ta_parameter_writer& parameter,
const vertex * strip_vertices,
const uint32_t strip_length,
enum filter_type filter
)
{
switch (filter) {
case filter_type::point_sampled: append_point_sampled(parameter); break;
case filter_type::bilinear: append_bilinear(parameter); break;
case filter_type::trilinear_pass_a: append_trilinear_pass_a(parameter); break;
case filter_type::trilinear_pass_b: append_trilinear_pass_b(parameter); break;
}
//struct vertex v[strip_length];
for (uint32_t i = 0; i < strip_length; i++) {
float x = strip_vertices[i].x;
float y = strip_vertices[i].y;
float z = strip_vertices[i].z;
float x1;
x1 = x * __builtin_cosf(theta / 5.f) - z * __builtin_sinf(theta / 5.f);
z = x * __builtin_sinf(theta / 5.f) + z * __builtin_cosf(theta / 5.f);
x = x1;
x *= 1024.f * (__builtin_cosf(theta / 10.f) + 1.0f);
y *= 1024.f * (__builtin_cosf(theta / 10.f) + 1.0f);
x += 320.f;
y += 240.f;
z = 1.f / (z + 10.f);
bool end_of_strip = i == strip_length - 1;
parameter.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(end_of_strip),
x, y, z,
strip_vertices[i].u,
strip_vertices[i].v,
strip_vertices[i].color,
0 // offset_color
);
/*
v[i].x = x;
v[i].y = y;
v[i].z = z;
v[i].u = strip_vertices[i].u;
v[i].v = strip_vertices[i].v;
*/
}
/*
parameter.append<ta_vertex_parameter::sprite_type_1>() =
ta_vertex_parameter::sprite_type_1(para_control::para_type::vertex_parameter,
v[0].x,
v[0].y,
v[0].z,
v[1].x,
v[1].y,
v[1].z,
v[2].x,
v[2].y,
v[2].z,
v[3].x,
v[3].y,
uv_16bit(v[0].u, v[0].v),
uv_16bit(v[1].u, v[1].v),
uv_16bit(v[2].u, v[2].v));
*/
parameter.append<ta_global_parameter::end_of_list>() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list);
}
void init_texture_memory(const struct opb_size& opb_size)
{
region_array2(640 / 32, // width
480 / 32, // height
opb_size
);
background_parameter(0xff00ff00);
}
uint8_t const * const mips[] = {
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb1_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb2_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb4_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb8_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb16_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb32_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb64_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb128_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb256_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb512_data_start),
reinterpret_cast<uint8_t *>(&_binary_texture_bbb_bbb1024_data_start)
};
void _copy_bbb_texture(uint32_t dst_offset, uint8_t const * const src, uint32_t mip)
{
auto area = mip * mip;
uint16_t temp[area];
for (uint32_t px = 0; px < area; 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);
temp[px] = rgb565;
}
auto texture = reinterpret_cast<volatile uint16_t *>(&texture_memory64[texture_memory_alloc::texture.start / 4]);
auto dst = &texture[dst_offset / 2];
twiddle::texture(dst, temp, mip, mip);
}
void copy_bbb_texture()
{
uint32_t dst_offset = 6;
uint32_t ix = 0;
for (uint32_t mip = 1; mip <= 1024; mip *= 2) {
_copy_bbb_texture(dst_offset, mips[ix], mip);
ix += 1;
dst_offset += mip * mip * 2;
}
}
uint32_t _ta_parameter_buf[((32 * (strip_length + 2)) + 32) / 4];
void main()
{
video_output::set_mode_vga();
holly.TEXT_CONTROL = text_control::bank_bit(0);
// 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::_16x4byte
| 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 = 16 * 4
, .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);
copy_bbb_texture();
uint32_t frame_ix = 0;
while (true) {
ta_polygon_converter_init(opb_size.total(),
ta_alloc,
640 / 32,
480 / 32);
{
auto parameter = ta_parameter_writer(ta_parameter_buf);
transform(parameter, strip_vertices, strip_length, filter_type::trilinear_pass_a);
ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset);
ta_wait_opaque_list();
}
/*
{
auto parameter = ta_parameter_writer(ta_parameter_buf);
parameter.append<ta_global_parameter::end_of_list>() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list);
//transform(parameter, strip_vertices, strip_length, filter_type::trilinear_pass_b);
ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset);
ta_wait_translucent_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;
}
}