fonts and stuff work

This commit is contained in:
water
2021-08-08 20:46:14 -04:00
parent 124003f5f2
commit 0dfe6a169d
17 changed files with 353 additions and 40 deletions
+15
View File
@@ -333,4 +333,19 @@ std::string GsAlpha::print() const {
}
return result;
}
std::string GsTex1::print() const {
return fmt::format("lcm: {} mxl: {} mmag: {} mmin: {} mtba: {} l: {} k: {}\n", lcm(), mxl(),
mmag(), mmin(), mtba(), l(), k());
}
std::string GsTexa::print() const {
return fmt::format("ta0: {} aem: {} ta1: {}\n", ta0(), aem(), ta1());
}
std::string GsTex0::print() const {
return fmt::format(
"tbp0: {} tbw: {} psm: {} tw: {} th: {} tcc: {} tfx: {} cbp: {} cpsm: {} csm: {}\n", tbp0(),
tbw(), psm(), tw(), th(), tcc(), tfx(), cbp(), cpsm(), csm());
}
+63
View File
@@ -242,4 +242,67 @@ struct GsPrim {
bool operator==(const GsPrim& other) const { return data == other.data; }
bool operator!=(const GsPrim& other) const { return data != other.data; }
};
struct GsTex0 {
GsTex0() = default;
GsTex0(u64 val) : data(val) {}
u32 tbp0() const { return data & 0b11'1111'1111'1111; }
u32 tbw() const { return (data >> 14) & 0b111111; }
u32 psm() const { return (data >> 20) & 0b111111; }
u32 tw() const { return (data >> 26) & 0b1111; }
u32 th() const { return (data >> 30) & 0b1111; }
enum class TextureFunction : u8 {
MODULATE = 0,
DECAL = 1,
HIGHLIGHT = 2,
HIGHLIGHT2 = 3,
};
u32 tcc() const { return ((data >> 34) & 0b1); }
TextureFunction tfx() const { return (TextureFunction)((data >> 35) & 0b11); }
u32 cbp() const { return (data >> 37) & 0b11'1111'1111'1111; }
u32 cpsm() const { return (data >> 51) & 0b1111; }
u32 csm() const { return (data >> 55) & 1; }
std::string print() const;
bool operator==(const GsTex0& other) const { return data == other.data; }
bool operator!=(const GsTex0& other) const { return data != other.data; }
u64 data = 0;
};
struct GsTex1 { // tex1_1 and tex1_2
GsTex1() = default;
GsTex1(u64 val) : data(val) {}
bool lcm() const {
// 1 = fixed
return data & 1;
}
u32 mxl() const { return (data >> 2) & 0b111; }
bool mmag() const { return data & (1 << 5); }
u32 mmin() const { return (data >> 6) & 0b111; }
bool mtba() const { return data & (1 << 9); }
u32 l() const { return (data >> 19) & 0b11; }
u32 k() const { return (data >> 32) & 0b1111'1111'1111; }
std::string print() const;
u64 data = 0;
};
struct GsTexa {
GsTexa() = default;
GsTexa(u64 val) : data(val) {}
u8 ta0() const { return data; }
bool aem() const { return data & (1 << 15); }
u8 ta1() const { return (data >> 32); }
std::string print() const;
u64 data = 0;
};
+6
View File
@@ -202,4 +202,10 @@ void texture_upload_now(const u8* tpage, int mode, u32 s7_ptr) {
}
}
void texture_relocate(u32 destination, u32 source) {
if (g_gfx_data) {
g_gfx_data->texture_pool->relocate(destination, source);
}
}
} // namespace Gfx
+1
View File
@@ -22,6 +22,7 @@ u32 Exit();
u32 vsync();
void send_chain(const void* data, u32 offset);
void texture_upload_now(const u8* tpage, int mode, u32 s7_ptr);
void texture_relocate(u32 destination, u32 source);
} // namespace Gfx
+153 -30
View File
@@ -16,12 +16,17 @@ DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batc
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.color_buffer);
m_ogl.color_buffer_bytes = batch_size * 3 * 4 * sizeof(u8);
glBufferData(GL_ARRAY_BUFFER, m_ogl.color_buffer_bytes, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer);
m_ogl.st_buffer_bytes = batch_size * 3 * 2 * sizeof(float);
glBufferData(GL_ARRAY_BUFFER, m_ogl.st_buffer_bytes, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
DirectRenderer::~DirectRenderer() {
glDeleteBuffers(1, &m_ogl.color_buffer);
glDeleteBuffers(1, &m_ogl.vertex_buffer);
glDeleteBuffers(1, &m_ogl.st_buffer);
}
/*!
@@ -41,13 +46,14 @@ void DirectRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
}
if (dma.current_tag_offset() == render_state->default_regs_buffer) {
reset_state();
// reset_state();
dma.read_and_advance(); // cnt
assert(dma.current_tag().kind == DmaTag::Kind::RET);
dma.read_and_advance(); // ret
}
}
fmt::print("update from end {}\n", m_prim_gl_state.texture_enable);
flush_pending(render_state);
}
@@ -59,7 +65,7 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
lg::warn("DirectRenderer flush with {} triangles.\n", m_prim_buffer.vert_count / 3);
// update opengl state
if (m_prim_gl_state_needs_gl_update) {
update_gl_prim();
update_gl_prim(render_state);
m_prim_gl_state_needs_gl_update = false;
}
@@ -83,6 +89,13 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
glBufferSubData(GL_ARRAY_BUFFER, 0, m_ogl.vertex_buffer_bytes, m_prim_buffer.verts.data());
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.color_buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_ogl.color_buffer_bytes, m_prim_buffer.rgba_u8.data());
if (m_prim_gl_state.texture_enable) {
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_ogl.st_buffer_bytes, m_prim_buffer.sts.data());
for (int i = 0; i < 10; i++) {
fmt::print("{}: {} {}\n", i, m_prim_buffer.sts[i].x(), m_prim_buffer.sts[i].y());
}
}
// setup attributes:
@@ -104,16 +117,32 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
GL_TRUE, // normalized, ignored,
0, // tightly packed
0);
if (m_prim_gl_state.texture_enable) {
fmt::print("DO TEXTURE!\n");
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, // location 0 in the shader
2, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
0, // tightly packed
0);
glActiveTexture(GL_TEXTURE0);
}
// assert(false);
glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count);
m_prim_buffer.vert_count = 0;
}
void DirectRenderer::update_gl_prim() {
void DirectRenderer::update_gl_prim(SharedRenderState* render_state) {
// currently gouraud is handled in setup.
const auto& state = m_prim_gl_state;
if (state.texture_enable) {
// assert(false); TODO
render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].activate();
update_gl_texture(render_state);
} else {
render_state->shaders[ShaderId::DIRECT_BASIC].activate();
}
if (state.fogging_enable) {
assert(false);
@@ -132,6 +161,38 @@ void DirectRenderer::update_gl_prim() {
}
}
void DirectRenderer::upload_texture(TextureRecord* tex) {
assert(!tex->on_gpu);
GLuint tex_id;
glGenTextures(1, &tex_id);
tex->gpu_texture = tex_id;
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->w, tex->h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
tex->data.data());
glBindTexture(GL_TEXTURE_2D, 0);
tex->on_gpu = true;
}
void DirectRenderer::update_gl_texture(SharedRenderState* render_state) {
auto tex = render_state->texture_pool->lookup(m_texture_state.texture_base_ptr);
assert(tex);
fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name);
// first: do we need to load the texture?
if (!tex->on_gpu) {
upload_texture(tex);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->gpu_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glUniform1i(
glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(), "T0"), 0);
}
void DirectRenderer::update_gl_blend() {
const auto& state = m_blend_state;
if (state.a == GsAlpha::BlendMode::SOURCE && state.b == GsAlpha::BlendMode::DEST &&
@@ -181,7 +242,6 @@ void DirectRenderer::update_gl_test() {
void DirectRenderer::setup_common_state(SharedRenderState* render_state) {
// todo texture clamp.
render_state->shaders[ShaderId::DIRECT_BASIC].activate();
}
namespace {
@@ -255,7 +315,6 @@ void DirectRenderer::render_vif(u32 vif0,
* Render GIF data.
*/
void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* render_state) {
fmt::print("Render GIF: {}\n", size);
assert(size >= 16);
bool eop = false;
@@ -263,7 +322,7 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren
while (!eop) {
GifTag tag(data + offset);
offset += 16;
fmt::print("Tag: {}\n", tag.print());
// fmt::print("Tag: {}\n", tag.print());
// unpack registers.
// faster to do it once outside of the nloop loop.
@@ -306,7 +365,7 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren
for (u32 reg = 0; reg < nreg; reg++) {
u64 register_data;
memcpy(&register_data, data + offset, 8);
fmt::print("loop: {} reg: {} {}\n", loop, reg, reg_descriptor_name(reg_desc[reg]));
// fmt::print("loop: {} reg: {} {}\n", loop, reg, reg_descriptor_name(reg_desc[reg]));
switch (reg_desc[reg]) {
case GifTag::RegisterDescriptor::PRIM:
handle_prim(register_data, render_state);
@@ -334,7 +393,7 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren
assert(offset == size);
fmt::print("{}\n", GifTag(data).print());
// fmt::print("{}\n", GifTag(data).print());
}
void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state) {
@@ -363,13 +422,23 @@ void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state)
handle_prim(value, render_state);
break;
// for now, ignore textures/fog.
// TODO
case GsRegisterAddress::TEX1_1:
handle_tex1_1(value);
break;
case GsRegisterAddress::TEXA:
handle_texa(value);
break;
case GsRegisterAddress::TEXCLUT:
// TODO
// the only thing the direct renderer does with texture is font, which does no tricks with
// CLUT. The texture upload process will do all of the lookups with the default CLUT.
// So we'll just assume that the TEXCLUT is set properly and ignore this.
break;
case GsRegisterAddress::FOGCOL:
// TODO
break;
case GsRegisterAddress::TEX0_1:
handle_tex0_1(value, render_state);
break;
default:
fmt::print("Address {} is not supported\n", register_address_name(addr));
@@ -377,8 +446,60 @@ void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state)
}
}
void DirectRenderer::handle_tex1_1(u64 val) {
GsTex1 reg(val);
// for now, we aren't going to handle mipmapping. I don't think it's used with direct.
assert(reg.mxl() == 0);
// if that's true, we can ignore LCM, MTBA, L, K
// MMAG/MMIN specify texture filtering. For now, assume always linear
assert(reg.mmag() == true);
assert(reg.mmin() == 1);
// fmt::print("{}\n", reg.print());
}
void DirectRenderer::handle_tex0_1(u64 val, SharedRenderState* render_state) {
GsTex0 reg(val);
// fmt::print("{}\n", reg.print());
// update tbp
if (m_texture_state.current_register != reg) {
flush_pending(render_state);
m_texture_state.texture_base_ptr = reg.tbp0();
m_texture_state_needs_gl_update = true;
m_texture_state.current_register = reg;
}
// tbw: assume they got it right
// psm: assume they got it right
// tw: assume they got it right
// th: assume they got it right
// these mean that the texture is multiplied, and uses the alpha from the clut.
assert(reg.tcc() == 1);
assert(reg.tfx() == GsTex0::TextureFunction::MODULATE);
// cbp: assume they got it right
// cpsm: assume they got it right
// csm: assume they got it right
}
void DirectRenderer::handle_texa(u64 val) {
GsTexa reg(val);
// rgba16 isn't used so this doesn't matter?
// but they use sane defaults anyway
assert(reg.ta0() == 0);
assert(reg.ta1() == 0x80);
assert(reg.aem() == false);
}
void DirectRenderer::handle_st_packed(const u8* data) {
// TODO
memcpy(&m_prim_building.st_reg.x(), data + 0, 4);
memcpy(&m_prim_building.st_reg.y(), data + 4, 4);
memcpy(&m_prim_building.Q, data + 8, 4);
}
void DirectRenderer::handle_rgbaq_packed(const u8* data) {
@@ -406,9 +527,6 @@ void DirectRenderer::handle_xyzf2_packed(const u8* data) {
bool adc = upper & (1ull << 47);
assert(!adc);
assert(!f);
// TODO (not this)
fmt::print("font vert at {} {}\n", u32_to_float(x), u32_to_float(y));
handle_xyzf2_common(x, y, z, f);
}
@@ -427,7 +545,6 @@ void DirectRenderer::handle_zbuf1(u64 val) {
void DirectRenderer::handle_test1(u64 val, SharedRenderState* render_state) {
GsTest reg(val);
fmt::print("test: {}\n", reg.print());
if (m_test_state.current_register != reg) {
flush_pending(render_state);
m_test_state.from_register(reg);
@@ -437,7 +554,6 @@ void DirectRenderer::handle_test1(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_alpha1(u64 val, SharedRenderState* render_state) {
GsAlpha reg(val);
fmt::print("alpha: {}\n", reg.print());
if (m_blend_state.current_register != reg) {
flush_pending(render_state);
m_blend_state.from_register(reg);
@@ -454,8 +570,6 @@ void DirectRenderer::handle_clamp1(u64 val) {
}
void DirectRenderer::handle_prim(u64 val, SharedRenderState* render_state) {
fmt::print("got prim: 0x{:x}\n", val);
if (m_prim_building.tri_strip_startup) {
m_prim_building.tri_strip_startup = 0;
m_prim_building.building_idx = 0;
@@ -481,11 +595,11 @@ void DirectRenderer::handle_prim(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_rgbaq(u64 val) {
assert((val >> 32) == 0); // q = 0
memcpy(m_prim_building.rgba_reg.data(), &val, 4);
fmt::print("a = 0x{:x}\n", m_prim_building.rgba_reg[3]);
}
void DirectRenderer::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f) {
assert(f == 0);
m_prim_building.building_st.at(m_prim_building.building_idx) = m_prim_building.st_reg;
m_prim_building.building_rgba.at(m_prim_building.building_idx) = m_prim_building.rgba_reg;
m_prim_building.building_vert.at(m_prim_building.building_idx) = {x << 16, y << 16, z};
m_prim_building.building_idx++;
@@ -509,12 +623,12 @@ void DirectRenderer::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f) {
auto& corner3_rgba = corner2_rgba;
auto& corner4_rgba = corner2_rgba;
m_prim_buffer.push(corner1_rgba, corner1_vert);
m_prim_buffer.push(corner3_rgba, corner3_vert);
m_prim_buffer.push(corner2_rgba, corner2_vert);
m_prim_buffer.push(corner2_rgba, corner2_vert);
m_prim_buffer.push(corner4_rgba, corner4_vert);
m_prim_buffer.push(corner1_rgba, corner1_vert);
m_prim_buffer.push(corner1_rgba, corner1_vert, {});
m_prim_buffer.push(corner3_rgba, corner3_vert, {});
m_prim_buffer.push(corner2_rgba, corner2_vert, {});
m_prim_buffer.push(corner2_rgba, corner2_vert, {});
m_prim_buffer.push(corner4_rgba, corner4_vert, {});
m_prim_buffer.push(corner1_rgba, corner1_vert, {});
m_prim_building.building_idx = 0;
}
} break;
@@ -527,9 +641,10 @@ void DirectRenderer::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f) {
m_prim_building.tri_strip_startup++;
}
if (m_prim_building.tri_strip_startup >= 3) {
m_prim_buffer.push(m_prim_building.building_rgba[0], m_prim_building.building_vert[0]);
m_prim_buffer.push(m_prim_building.building_rgba[1], m_prim_building.building_vert[1]);
m_prim_buffer.push(m_prim_building.building_rgba[2], m_prim_building.building_vert[2]);
for (int i = 0; i < 3; i++) {
m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i],
m_prim_building.building_st[i]);
}
}
} break;
@@ -541,6 +656,7 @@ void DirectRenderer::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f) {
void DirectRenderer::handle_xyzf2(u64 val, SharedRenderState* render_state) {
if (m_prim_buffer.is_full()) {
fmt::print("update from full\n");
flush_pending(render_state);
}
@@ -564,6 +680,9 @@ void DirectRenderer::reset_state() {
m_prim_gl_state_needs_gl_update = true;
m_prim_gl_state = PrimGlState();
m_texture_state_needs_gl_update = true;
m_texture_state = TextureState();
m_prim_building = PrimBuildState();
}
@@ -600,6 +719,7 @@ void DirectRenderer::PrimGlState::from_register(GsPrim reg) {
current_register = reg;
gouraud_enable = reg.gouraud();
texture_enable = reg.tme();
fmt::print("set tex en: {}\n", texture_enable);
fogging_enable = reg.fge();
aa_enable = reg.aa1();
use_uv = reg.fst();
@@ -610,12 +730,15 @@ void DirectRenderer::PrimGlState::from_register(GsPrim reg) {
DirectRenderer::PrimitiveBuffer::PrimitiveBuffer(int max_triangles) {
rgba_u8.resize(max_triangles * 3);
verts.resize(max_triangles * 3);
sts.resize(max_triangles * 3);
max_verts = max_triangles * 3;
}
void DirectRenderer::PrimitiveBuffer::push(const math::Vector<u8, 4>& rgba,
const math::Vector<u32, 3>& vert) {
const math::Vector<u32, 3>& vert,
const math::Vector<float, 2>& st) {
rgba_u8[vert_count] = rgba;
verts[vert_count] = vert;
sts[vert_count] = st;
vert_count++;
}
+23 -3
View File
@@ -60,12 +60,18 @@ class DirectRenderer : public BucketRenderer {
void handle_st_packed(const u8* data);
void handle_rgbaq_packed(const u8* data);
void handle_xyzf2_packed(const u8* data);
void handle_tex0_1(u64 val, SharedRenderState* render_state);
void handle_tex1_1(u64 val);
void handle_texa(u64 val);
void handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f);
void update_gl_prim();
void update_gl_prim(SharedRenderState* render_state);
void update_gl_blend();
void update_gl_test();
void update_gl_texture(SharedRenderState* render_state);
void upload_texture(TextureRecord* tex);
struct TestState {
void from_register(GsTest reg);
@@ -111,37 +117,51 @@ class DirectRenderer : public BucketRenderer {
bool fix = false; // what does this even do?
} m_prim_gl_state;
struct TextureState {
GsTex0 current_register;
u32 texture_base_ptr = 0;
} m_texture_state;
// state set through the prim/rgbaq register that doesn't require changing GL stuff
struct PrimBuildState {
GsPrim::Kind kind = GsPrim::Kind::PRIM_7;
math::Vector<u8, 4> rgba_reg = {0, 0, 0, 0};
math::Vector<float, 2> st_reg;
std::array<math::Vector<u8, 4>, 3> building_rgba;
std::array<math::Vector<u32, 3>, 3> building_vert;
std::array<math::Vector<float, 2>, 3> building_st;
int building_idx = 0;
int tri_strip_startup = 0;
float Q = 0;
} m_prim_building;
struct PrimitiveBuffer {
PrimitiveBuffer(int max_triangles);
std::vector<math::Vector<u8, 4>> rgba_u8;
std::vector<math::Vector<u32, 3>> verts;
std::vector<math::Vector<float, 2>> sts;
int vert_count = 0;
int max_verts = 0;
// leave 6 free on the end so we always have room to flush one last primitive.
bool is_full() { return max_verts < (vert_count - 6); }
void push(const math::Vector<u8, 4>& rgba, const math::Vector<u32, 3>& vert);
void push(const math::Vector<u8, 4>& rgba,
const math::Vector<u32, 3>& vert,
const math::Vector<float, 2>& st);
} m_prim_buffer;
struct {
GLuint vertex_buffer, color_buffer;
GLuint vertex_buffer, color_buffer, st_buffer;
u32 vertex_buffer_bytes = 0;
u32 color_buffer_bytes = 0;
u32 st_buffer_bytes = 0;
} m_ogl;
bool m_prim_gl_state_needs_gl_update = true;
bool m_test_state_needs_gl_update = true;
bool m_blend_state_needs_gl_update = true;
bool m_texture_state_needs_gl_update = true;
};
@@ -38,8 +38,8 @@ void OpenGLRenderer::init_bucket_renderers() {
init_bucket_renderer<EmptyBucketRenderer>("bucket0", BucketId::BUCKET0);
// TODO what the heck is drawing to debug-draw-0 on init?
init_bucket_renderer<DirectRenderer>("debug-draw-0", BucketId::DEBUG_DRAW_0, 1024);
init_bucket_renderer<DirectRenderer>("debug-draw-1", BucketId::DEBUG_DRAW_1, 1024);
init_bucket_renderer<DirectRenderer>("debug-draw-0", BucketId::DEBUG_DRAW_0, 1024 * 8);
init_bucket_renderer<DirectRenderer>("debug-draw-1", BucketId::DEBUG_DRAW_1, 1024 * 8);
// for now, for any unset renderers, just set them to an EmptyBucketRenderer.
for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
+1
View File
@@ -66,4 +66,5 @@ void Shader::activate() {
ShaderLibrary::ShaderLibrary() {
at(ShaderId::TEST_SHADER) = {"test_shader"};
at(ShaderId::DIRECT_BASIC) = {"direct_basic"};
at(ShaderId::DIRECT_BASIC_TEXTURED) = {"direct_basic_textured"};
}
+2 -1
View File
@@ -9,6 +9,7 @@ class Shader {
Shader() = default;
void activate();
bool okay() const { return m_is_okay; }
uint id() const { return m_program; }
private:
uint m_frag_shader = 0;
@@ -18,7 +19,7 @@ class Shader {
};
// note: update the constructor in Shader.cpp
enum class ShaderId { TEST_SHADER = 0, DIRECT_BASIC = 1, MAX_SHADERS };
enum class ShaderId { TEST_SHADER = 0, DIRECT_BASIC = 1, DIRECT_BASIC_TEXTURED = 2, MAX_SHADERS };
class ShaderLibrary {
public:
@@ -0,0 +1,12 @@
#version 330 core
out vec4 color;
in vec4 fragment_color;
in vec2 tex_coord;
uniform sampler2D tex_T0;
void main() {
vec4 T0 = texture(tex_T0, tex_coord);
color = fragment_color * T0 * 2.0;
}
@@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec2 tex_coord_in;
out vec4 fragment_color;
out vec2 tex_coord;
void main() {
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z, 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w + 0.5);
tex_coord = tex_coord_in;
}
+30 -3
View File
@@ -4,6 +4,7 @@
#include "common/util/assert.h"
#include "common/util/FileUtil.h"
#include "common/util/Timer.h"
#include "common/log/log.h"
////////////////////////////////
// Extraction of textures
@@ -118,8 +119,9 @@ void TexturePool::handle_upload_now(const u8* tpage, int mode, const u8* memory_
m_tex_converter.upload(memory_base + texture_page.segment[0].block_data_ptr,
texture_page.segment[0].dest, size);
} else {
assert(false);
// return;
// no reason to skip this, other than
lg::error("TexturePool skipping upload now with mode {}.", mode);
return;
}
// loop over all texture in the tpage and download them.
@@ -144,7 +146,7 @@ void TexturePool::handle_upload_now(const u8* tpage, int mode, const u8* memory_
m_tex_converter.download_rgba8888(texture_record->data.data(), tex.dest[mip_idx],
tex.width[mip_idx], ww, hh, tex.psm, tex.clutpsm,
tex.clut_dest, size_bytes);
m_textures.at(tex.dest[mip_idx]) = std::move(texture_record);
set_texture(tex.dest[mip_idx], std::move(texture_record));
// Debug output.
if (dump_textures_to_file) {
@@ -165,4 +167,29 @@ void TexturePool::handle_upload_now(const u8* tpage, int mode, const u8* memory_
}
fmt::print("upload now took {:.2f} ms\n", timer.getMs());
}
/*!
* Store a texture in the pool. Location is specified like TBP.
*/
void TexturePool::set_texture(u32 location, std::unique_ptr<TextureRecord>&& record) {
if (m_textures.at(location)) {
m_garbage_textures.push_back(std::move(m_textures[location]));
}
m_textures[location] = std::move(record);
}
/*!
* Move a texture.
*/
void TexturePool::relocate(u32 destination, u32 source) {
if (m_textures.at(source)) {
if (m_textures.at(destination)) {
return; // HACK
}
m_textures.at(destination) = std::move(m_textures.at(source));
fmt::print("Relocated a texture: {}\n", m_textures[destination]->name);
} else {
assert(false);
}
}
+16
View File
@@ -13,15 +13,31 @@ struct TextureRecord {
u16 w, h;
std::vector<u8> data;
u8 data_segment;
u64 gpu_texture = 0;
bool on_gpu = false;
};
class TexturePool {
public:
void handle_upload_now(const u8* tpage, int mode, const u8* memory_base, u32 s7_ptr);
void set_texture(u32 location, std::unique_ptr<TextureRecord>&& record);
TextureRecord* lookup(u32 location) {
if (m_textures.at(location)) {
return m_textures[location].get();
} else {
return nullptr;
}
}
void relocate(u32 destination, u32 source);
private:
TextureConverter m_tex_converter;
// uses tex.dest[mip] indexing. (bytes / 256). Currently only sets the base of a texture.
std::array<std::unique_ptr<TextureRecord>, 1024 * 1024 * 4 / 256> m_textures;
// textures that the game overwrote, but may be still allocated on the GPU.
// TODO: free these periodically.
std::vector<std::unique_ptr<TextureRecord>> m_garbage_textures;
};
+4 -1
View File
@@ -181,7 +181,10 @@ void KernelCheckAndDispatch() {
SendAck();
}
std::this_thread::sleep_for(std::chrono::microseconds(1000));
if (time_ms < 4) {
std::this_thread::sleep_for(std::chrono::microseconds(1000));
}
}
}
+5
View File
@@ -445,6 +445,10 @@ void pc_texture_upload_now(u32 page, u32 mode) {
Gfx::texture_upload_now(Ptr<u8>(page).c(), mode, s7.offset);
}
void pc_texture_relocate(u32 dst, u32 src) {
Gfx::texture_relocate(dst, src);
}
/*!
* Open a file-stream. Name is a GOAL string. Mode is a GOAL symbol. Use 'read for readonly
* and anything else for write only.
@@ -605,6 +609,7 @@ void InitMachine_PCPort() {
make_function_symbol_from_c("__mem-move", (void*)c_memmove);
make_function_symbol_from_c("__send-gfx-dma-chain", (void*)send_gfx_dma_chain);
make_function_symbol_from_c("__pc-texture-upload-now", (void*)pc_texture_upload_now);
make_function_symbol_from_c("__pc-texture-relocate", (void*)pc_texture_relocate);
}
/*!
+5
View File
@@ -1807,6 +1807,11 @@
Will try to move the whole thing, including the clut, assuming you provide a destination for it.
Note that this uses the format/width stuff properly, so it will be slower, but won't scramble your texture."
(#when PC_PORT
;; as far as I know this is only used for fonts which have 1 mip level.
(__pc-texture-relocate (/ dest-loc 64) (-> tex dest 0))
)
;; loop over mips
(dotimes (mip-level (the-as int (-> tex num-mips)))
;; size of the current mip.
+1
View File
@@ -183,6 +183,7 @@
(define-extern __mem-move (function pointer pointer uint none))
(define-extern __send-gfx-dma-chain (function object object none))
(define-extern __pc-texture-upload-now (function object object none))
(define-extern __pc-texture-relocate (function object object none))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; ksound - InitSoundScheme