[runtime] optimize DirectRenderer for multiple textures + optimize sprite renderer (#1054)

* optimize sprite texture flush + update shaders

* fix bugs

* change logic a bit

* crunch PNGs

* hud size fix

* clang

* remove shaders from list

* use really small alpha cut-off point for sprites

* ad `flat` to vertex shaders too

* increase cut-off very slightly

* take *2 into account

* ok for real this should be good enough
This commit is contained in:
ManDude
2022-01-06 23:47:20 +00:00
committed by GitHub
parent 74a791c67f
commit 2e18cb605a
46 changed files with 300 additions and 234 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+145 -112
View File
@@ -4,6 +4,7 @@
#include "third-party/fmt/core.h"
#include "game/graphics/pipelines/opengl.h"
#include "third-party/imgui/imgui.h"
#include "common/util/assert.h"
DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batch_size, Mode mode)
: BucketRenderer(name, my_id), m_prim_buffer(batch_size), m_mode(mode) {
@@ -16,33 +17,38 @@ DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batc
glBufferData(GL_ARRAY_BUFFER, m_ogl.vertex_buffer_bytes, nullptr,
GL_STREAM_DRAW); // todo stream?
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0, // location 0 in the shader
4, // 3 floats per vert
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, xyz) // offset in array (why is is this a pointer...)
glVertexAttribPointer(0, // location 0 in the shader
4, // 4 floats per vert (w unused)
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, xyz) // offset in array (why is this a pointer...)
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1, // location 0 in the shader
4, // 4 floats per vert (w unused)
GL_UNSIGNED_BYTE, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, rgba) // offset in array (why is is this a pointer...)
glVertexAttribPointer(1, // location 0 in the shader
4, // 4 color components
GL_UNSIGNED_BYTE, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, rgba) // offset in array (why is this a pointer...)
);
glEnableVertexAttribArray(2);
glVertexAttribPointer(
2, // location 0 in the shader
3, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, stq) // offset in array (why is is this a pointer...)
glVertexAttribPointer(2, // location 0 in the shader
3, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, stq) // offset in array (why is this a pointer...)
);
glEnableVertexAttribArray(3);
glVertexAttribIPointer(3, // location 0 in the shader
4, // 3 floats per vert
GL_UNSIGNED_BYTE, // floats
sizeof(Vertex), //
(void*)offsetof(Vertex, tex) // offset in array (why is this a pointer...)
);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
@@ -96,8 +102,6 @@ void DirectRenderer::draw_debug_window() {
if (m_mode == Mode::SPRITE_CPU) {
ImGui::Checkbox("draw1", &m_sprite_mode.do_first_draw);
ImGui::SameLine();
ImGui::Checkbox("draw2", &m_sprite_mode.do_second_draw);
}
ImGui::Text("Triangles: %d", m_stats.triangles);
@@ -112,10 +116,11 @@ void DirectRenderer::draw_debug_window() {
ImGui::Text(" alph: %d", m_stats.flush_from_alpha);
ImGui::Text(" clmp: %d", m_stats.flush_from_clamp);
ImGui::Text(" prim: %d", m_stats.flush_from_prim);
ImGui::Text(" texstate: %d", m_stats.flush_from_state_exhaust);
ImGui::Text(" Total: %d/%d",
m_stats.flush_from_prim + m_stats.flush_from_clamp + m_stats.flush_from_alpha +
m_stats.flush_from_test + m_stats.flush_from_zbuf + m_stats.flush_from_tex_1 +
m_stats.flush_from_tex_0,
m_stats.flush_from_tex_0 + m_stats.flush_from_state_exhaust,
m_stats.draw_calls);
}
@@ -130,10 +135,6 @@ float u32_to_sc(u32 in) {
}
void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfilerNode& prof) {
if (m_prim_buffer.vert_count == 0) {
return;
}
// update opengl state
if (m_prim_gl_state_needs_gl_update) {
update_gl_prim(render_state);
@@ -151,9 +152,19 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil
}
// I think it's important that this comes last.
if (m_texture_state.needs_gl_update) {
update_gl_texture(render_state);
m_texture_state.needs_gl_update = false;
if (m_global_texture_state.needs_gl_update) {
// fmt::print("flushing with {} states\n", m_current_texture_state + 1);
for (int i = 0; i <= m_current_texture_state; ++i) {
update_gl_texture(render_state, i);
}
m_global_texture_state.needs_gl_update = false;
// fmt::print("tex state flush\n");
}
// NOTE: sometimes we want to update the GL state without actually rendering anything, such as sky
// textures, so we only return after we've updated the full state
if (m_prim_buffer.vert_count == 0) {
return;
}
if (m_debug_state.disable_texture) {
@@ -195,7 +206,7 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil
if (!m_prim_gl_state.texture_enable) {
render_state->shaders[ShaderId::DIRECT_BASIC].activate();
} else {
assert(m_texture_state.tcc);
// assert(m_global_texture_state.tcc);
assert(m_prim_gl_state.texture_enable);
render_state->shaders[ShaderId::SPRITE_CPU].activate();
}
@@ -204,18 +215,6 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfil
glDrawArrays(GL_TRIANGLES, vertex_offset, m_prim_buffer.vert_count);
draw_count++;
}
if (m_sprite_mode.do_second_draw) {
render_state->shaders[ShaderId::SPRITE_CPU_AFAIL].activate();
glDepthMask(GL_FALSE);
glDrawArrays(GL_TRIANGLES, vertex_offset, m_prim_buffer.vert_count);
if (m_test_state.depth_writes) {
glDepthMask(GL_TRUE);
}
m_prim_gl_state_needs_gl_update = true;
m_blend_state_needs_gl_update = true;
draw_count++;
}
} else {
glDrawArrays(GL_TRIANGLES, vertex_offset, m_prim_buffer.vert_count);
draw_count++;
@@ -260,27 +259,18 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) {
assert(false);
}
}
if (m_texture_state.tcc) {
if (m_mode == Mode::SPRITE_CPU) {
render_state->shaders[ShaderId::SPRITE_CPU].activate();
} else if (m_mode == Mode::SKY) {
assert(false);
} else {
render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].activate();
glUniform1f(
glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(),
"alpha_reject"),
alpha_reject);
}
if (m_mode == Mode::SPRITE_CPU) {
render_state->shaders[ShaderId::SPRITE_CPU].activate();
} else if (m_mode == Mode::SKY) {
assert(false);
} else {
render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED_TCC0].activate();
glUniform1f(
glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED_TCC0].id(),
"alpha_reject"),
alpha_reject);
render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].activate();
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].id(),
"alpha_reject"),
alpha_reject);
}
// update_gl_texture(render_state);
m_texture_state.needs_gl_update = true;
m_global_texture_state.needs_gl_update = true;
} else {
if (m_mode == Mode::SKY) {
render_state->shaders[ShaderId::SKY].activate();
@@ -305,17 +295,18 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) {
}
}
void DirectRenderer::update_gl_texture(SharedRenderState* render_state) {
void DirectRenderer::update_gl_texture(SharedRenderState* render_state, int unit) {
TextureRecord* tex = nullptr;
if (m_texture_state.using_mt4hh) {
tex = render_state->texture_pool->lookup_mt4hh(m_texture_state.texture_base_ptr);
auto& state = m_texture_state[unit];
if (state.using_mt4hh) {
tex = render_state->texture_pool->lookup_mt4hh(state.texture_base_ptr);
} else {
tex = render_state->texture_pool->lookup(m_texture_state.texture_base_ptr);
tex = render_state->texture_pool->lookup(state.texture_base_ptr);
}
if (!tex) {
// TODO Add back
fmt::print("Failed to find texture at {}, using random\n", m_texture_state.texture_base_ptr);
fmt::print("Failed to find texture at {}, using random\n", state.texture_base_ptr);
tex = render_state->texture_pool->get_random_texture();
if (tex) {
// fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name);
@@ -328,22 +319,22 @@ void DirectRenderer::update_gl_texture(SharedRenderState* render_state) {
render_state->texture_pool->upload_to_gpu(tex);
}
glActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE20 + unit);
glBindTexture(GL_TEXTURE_2D, tex->gpu_texture);
// Note: CLAMP and CLAMP_TO_EDGE are different...
if (m_clamp_state.clamp_s) {
if (state.m_clamp_state.clamp_s) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
}
if (m_clamp_state.clamp_t) {
if (state.m_clamp_state.clamp_t) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
if (m_texture_state.enable_tex_filt) {
if (state.enable_tex_filt) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
m_debug_state.disable_mipmap ? GL_LINEAR : GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -529,6 +520,7 @@ void DirectRenderer::render_gif(const u8* data,
}
for (u32 loop = 0; loop < tag.nloop(); loop++) {
for (u32 reg = 0; reg < nreg; reg++) {
// fmt::print("{}\n", reg_descriptor_name(reg_desc[reg]));
switch (reg_desc[reg]) {
case GifTag::RegisterDescriptor::AD:
handle_ad(data + offset, render_state, prof);
@@ -561,8 +553,7 @@ void DirectRenderer::render_gif(const u8* data,
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, prof);
@@ -603,6 +594,7 @@ void DirectRenderer::handle_ad(const u8* data,
memcpy(&value, data, sizeof(u64));
memcpy(&addr, data + 8, sizeof(GsRegisterAddress));
// fmt::print("{}\n", register_address_name(addr));
switch (addr) {
case GsRegisterAddress::ZBUF_1:
handle_zbuf1(value, render_state, prof);
@@ -662,11 +654,21 @@ void DirectRenderer::handle_tex1_1(u64 val,
// if that's true, we can ignore LCM, MTBA, L, K
bool want_tex_filt = reg.mmag();
if (want_tex_filt != current_texture_state()->enable_tex_filt) {
if (current_texture_state()->used) {
if (needs_state_flush()) {
flush_pending(render_state, prof);
m_texture_state[0] = *current_texture_state();
m_texture_state[0].used = false;
m_current_texture_state = 0;
m_stats.flush_from_state_exhaust++;
} else {
push_texture_state();
}
}
m_global_texture_state.needs_gl_update = true;
if (want_tex_filt != m_texture_state.enable_tex_filt) {
flush_pending(render_state, prof);
m_stats.flush_from_tex_1++;
m_texture_state.enable_tex_filt = want_tex_filt;
current_texture_state()->enable_tex_filt = want_tex_filt;
}
// MMAG/MMIN specify texture filtering. For now, assume always linear
@@ -690,18 +692,25 @@ void DirectRenderer::handle_tex0_1(u64 val,
GsTex0 reg(val);
// update tbp
if (m_texture_state.current_register != reg) {
flush_pending(render_state, prof);
m_stats.flush_from_tex_0++;
m_texture_state.texture_base_ptr = reg.tbp0();
m_texture_state.using_mt4hh = reg.psm() == GsTex0::PSM::PSMT4HH;
m_prim_gl_state_needs_gl_update = true;
m_texture_state.current_register = reg;
if (m_texture_state.tcc != reg.tcc()) {
m_texture_state.needs_gl_update = true;
if (current_texture_state()->current_register != reg) {
if (current_texture_state()->used) {
if (needs_state_flush()) {
flush_pending(render_state, prof);
m_texture_state[0] = *current_texture_state();
m_texture_state[0].used = false;
m_current_texture_state = 0;
m_stats.flush_from_state_exhaust++;
} else {
push_texture_state();
}
}
m_texture_state.tcc = reg.tcc();
m_global_texture_state.needs_gl_update = true;
current_texture_state()->texture_base_ptr = reg.tbp0();
current_texture_state()->using_mt4hh = reg.psm() == GsTex0::PSM::PSMT4HH;
current_texture_state()->current_register = reg;
current_texture_state()->tcc = reg.tcc();
}
// tbw: assume they got it right
@@ -819,13 +828,23 @@ void DirectRenderer::handle_clamp1(u64 val,
assert(false);
}
if (m_clamp_state.current_register != val) {
m_stats.flush_from_clamp++;
flush_pending(render_state, prof);
m_clamp_state.current_register = val;
m_clamp_state.clamp_s = val & 0b001;
m_clamp_state.clamp_t = val & 0b100;
m_texture_state.needs_gl_update = true;
if (current_texture_state()->m_clamp_state.current_register != val) {
if (current_texture_state()->used) {
if (needs_state_flush()) {
flush_pending(render_state, prof);
m_texture_state[0] = *current_texture_state();
m_texture_state[0].used = false;
m_current_texture_state = 0;
m_stats.flush_from_state_exhaust++;
} else {
push_texture_state();
}
}
m_global_texture_state.needs_gl_update = true;
current_texture_state()->m_clamp_state.current_register = val;
current_texture_state()->m_clamp_state.clamp_s = val & 0b001;
current_texture_state()->m_clamp_state.clamp_t = val & 0b100;
}
}
@@ -909,12 +928,12 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
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, {}, 0, false);
m_prim_buffer.push(corner3_rgba, corner3_vert, {}, 0, false);
m_prim_buffer.push(corner2_rgba, corner2_vert, {}, 0, false);
m_prim_buffer.push(corner2_rgba, corner2_vert, {}, 0, false);
m_prim_buffer.push(corner4_rgba, corner4_vert, {}, 0, false);
m_prim_buffer.push(corner1_rgba, corner1_vert, {}, 0, false);
m_prim_building.building_idx = 0;
}
} break;
@@ -930,7 +949,8 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
if (advance) {
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_stq[i]);
m_prim_building.building_stq[i], m_current_texture_state,
current_texture_state()->tcc);
}
}
}
@@ -942,7 +962,8 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
m_prim_building.building_idx = 0;
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_stq[i]);
m_prim_building.building_stq[i], m_current_texture_state,
current_texture_state()->tcc);
}
}
break;
@@ -958,7 +979,8 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
}
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_stq[i]);
m_prim_building.building_stq[i], m_current_texture_state,
current_texture_state()->tcc);
}
}
} break;
@@ -979,13 +1001,13 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
math::Vector<double, 3> d = pt1 - normal * line_width;
// ACB:
m_prim_buffer.push(m_prim_building.building_rgba[0], a.cast<u32>(), {});
m_prim_buffer.push(m_prim_building.building_rgba[0], c.cast<u32>(), {});
m_prim_buffer.push(m_prim_building.building_rgba[1], b.cast<u32>(), {});
m_prim_buffer.push(m_prim_building.building_rgba[0], a.cast<u32>(), {}, 0, false);
m_prim_buffer.push(m_prim_building.building_rgba[0], c.cast<u32>(), {}, 0, false);
m_prim_buffer.push(m_prim_building.building_rgba[1], b.cast<u32>(), {}, 0, false);
// b c d
m_prim_buffer.push(m_prim_building.building_rgba[1], b.cast<u32>(), {});
m_prim_buffer.push(m_prim_building.building_rgba[0], c.cast<u32>(), {});
m_prim_buffer.push(m_prim_building.building_rgba[1], d.cast<u32>(), {});
m_prim_buffer.push(m_prim_building.building_rgba[1], b.cast<u32>(), {}, 0, false);
m_prim_buffer.push(m_prim_building.building_rgba[0], c.cast<u32>(), {}, 0, false);
m_prim_buffer.push(m_prim_building.building_rgba[1], d.cast<u32>(), {}, 0, false);
//
m_prim_building.building_idx = 0;
@@ -995,6 +1017,8 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
fmt::print("prim type {} is unsupported.\n", (int)m_prim_building.kind);
assert(false);
}
current_texture_state()->used = true;
}
void DirectRenderer::handle_xyzf2(u64 val,
@@ -1018,7 +1042,10 @@ void DirectRenderer::reset_state() {
m_prim_gl_state_needs_gl_update = true;
m_prim_gl_state = PrimGlState();
m_texture_state = TextureState();
for (int i = 0; i < TEXTURE_STATE_COUNT; ++i) {
m_texture_state[i] = TextureState();
}
m_global_texture_state = TextureGlobalState();
m_prim_building = PrimBuildState();
@@ -1052,6 +1079,8 @@ void DirectRenderer::BlendState::from_register(GsAlpha reg) {
c = reg.c_mode();
d = reg.d_mode();
fix = reg.fix();
assert(fix == 0);
}
void DirectRenderer::PrimGlState::from_register(GsPrim reg) {
@@ -1072,12 +1101,16 @@ DirectRenderer::PrimitiveBuffer::PrimitiveBuffer(int max_triangles) {
void DirectRenderer::PrimitiveBuffer::push(const math::Vector<u8, 4>& rgba,
const math::Vector<u32, 3>& vert,
const math::Vector<float, 3>& st) {
const math::Vector<float, 3>& st,
int unit,
bool tcc) {
auto& v = vertices[vert_count];
v.rgba = rgba;
v.xyz[0] = (float)vert[0] / (float)UINT32_MAX;
v.xyz[1] = (float)vert[1] / (float)UINT32_MAX;
v.xyz[2] = (float)vert[2] / (float)UINT32_MAX;
v.stq = st;
v.tex[0] = unit;
v.tex[1] = tcc;
vert_count++;
}
+40 -13
View File
@@ -6,6 +6,7 @@
#include "common/math/Vector.h"
#include "common/util/SmallVector.h"
#include "game/graphics/pipelines/opengl.h"
#include "common/log/log.h"
/*!
* The direct renderer will handle rendering GIFtags directly.
@@ -98,7 +99,7 @@ class DirectRenderer : public BucketRenderer {
void update_gl_prim(SharedRenderState* render_state);
void update_gl_blend();
void update_gl_test();
void update_gl_texture(SharedRenderState* render_state);
void update_gl_texture(SharedRenderState* render_state, int unit);
struct TestState {
void from_register(GsTest reg);
@@ -131,13 +132,6 @@ class DirectRenderer : public BucketRenderer {
} m_blend_state;
struct ClampState {
void from_register(u64 value);
u64 current_register = 0b101;
bool clamp_s = true;
bool clamp_t = true;
} m_clamp_state;
// state set through the prim register that requires changing GL stuff.
struct PrimGlState {
void from_register(GsPrim reg);
@@ -153,15 +147,43 @@ class DirectRenderer : public BucketRenderer {
bool fix = false; // what does this even do?
} m_prim_gl_state;
static constexpr int TEXTURE_STATE_COUNT = 10;
struct TextureState {
GsTex0 current_register;
u32 texture_base_ptr = 0;
bool using_mt4hh = false;
bool tcc = false;
bool needs_gl_update = true;
bool enable_tex_filt = true;
} m_texture_state;
struct ClampState {
void from_register(u64 value) { current_register = value; }
u64 current_register = 0b101;
bool clamp_s = true;
bool clamp_t = true;
} m_clamp_state;
bool used = false;
} m_texture_state[TEXTURE_STATE_COUNT];
struct TextureGlobalState {
bool needs_gl_update = true;
} m_global_texture_state;
int m_current_texture_state = 0;
TextureState* current_texture_state() { return &m_texture_state[m_current_texture_state]; }
bool needs_state_flush() { return m_current_texture_state + 1 >= TEXTURE_STATE_COUNT; }
void push_texture_state() {
++m_current_texture_state;
if (m_current_texture_state >= TEXTURE_STATE_COUNT) {
lg::error("fatal tex push {}!!!!", m_current_texture_state);
}
if (m_current_texture_state > 0) {
m_texture_state[m_current_texture_state] = m_texture_state[m_current_texture_state - 1];
}
}
// state set through the prim/rgbaq register that doesn't require changing GL stuff
struct PrimBuildState {
@@ -183,8 +205,11 @@ class DirectRenderer : public BucketRenderer {
math::Vector<float, 4> xyz;
math::Vector<float, 3> stq;
math::Vector<u8, 4> rgba;
math::Vector<u8, 2> tex; // texture unit to use + tcc
math::Vector<u8, 30> pad;
};
static_assert(sizeof(Vertex) == 32);
static_assert(sizeof(Vertex) == 64);
static_assert(offsetof(Vertex, tex) == 32);
struct PrimitiveBuffer {
PrimitiveBuffer(int max_triangles);
@@ -196,7 +221,9 @@ class DirectRenderer : public BucketRenderer {
bool is_full() { return max_verts < (vert_count + 18); }
void push(const math::Vector<u8, 4>& rgba,
const math::Vector<u32, 3>& vert,
const math::Vector<float, 3>& stq);
const math::Vector<float, 3>& stq,
int unit,
bool tcc);
} m_prim_buffer;
struct {
@@ -226,6 +253,7 @@ class DirectRenderer : public BucketRenderer {
int flush_from_alpha = 0;
int flush_from_clamp = 0;
int flush_from_prim = 0;
int flush_from_state_exhaust = 0;
} m_stats;
bool m_prim_gl_state_needs_gl_update = true;
@@ -234,7 +262,6 @@ class DirectRenderer : public BucketRenderer {
struct SpriteMode {
bool do_first_draw = true;
bool do_second_draw = true;
} m_sprite_mode;
Mode m_mode;
@@ -242,10 +242,10 @@ void OpenGLRenderer::dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof)
for (int bucket_id = 0; bucket_id < (int)BucketId::MAX_BUCKETS; bucket_id++) {
auto& renderer = m_bucket_renderers[bucket_id];
auto bucket_prof = prof.make_scoped_child(renderer->name_and_id());
// lg::info("Render: {} start\n", renderer->name_and_id());
g_current_render = renderer->name_and_id();
// lg::info("Render: {} start", g_current_render);
renderer->render(dma, &m_render_state, bucket_prof);
// lg::info("Render: {} end\n", renderer->name_and_id());
// lg::info("Render: {} end", g_current_render);
// should have ended at the start of the next chain
assert(dma.current_tag_offset() == m_render_state.next_bucket);
m_render_state.next_bucket += 16;
-2
View File
@@ -67,11 +67,9 @@ void Shader::activate() {
ShaderLibrary::ShaderLibrary() {
at(ShaderId::TEST_SHADER) = {"test_shader"};
at(ShaderId::DIRECT_BASIC) = {"direct_basic"};
at(ShaderId::DIRECT_BASIC_TEXTURED_TCC0) = {"direct_basic_textured_tcc0"};
at(ShaderId::DIRECT_BASIC_TEXTURED) = {"direct_basic_textured"};
at(ShaderId::DEBUG_RED) = {"debug_red"};
at(ShaderId::SPRITE_CPU) = {"sprite_cpu"};
at(ShaderId::SPRITE_CPU_AFAIL) = {"sprite_cpu_afail"};
at(ShaderId::SKY) = {"sky"};
at(ShaderId::SKY_BLEND) = {"sky_blend"};
at(ShaderId::DEBUG_BUFFERED) = {"debug_buffered"};
+3 -3
View File
@@ -25,10 +25,10 @@ enum class ShaderId {
TEST_SHADER = 0,
DIRECT_BASIC = 1,
DIRECT_BASIC_TEXTURED = 2,
DIRECT_BASIC_TEXTURED_TCC0 = 3,
// DIRECT_BASIC_TEXTURED_TCC0 = 3,
DEBUG_RED = 4,
SPRITE_CPU = 5,
SPRITE_CPU_AFAIL = 6,
// SPRITE_CPU_AFAIL = 6,
SKY = 7,
SKY_BLEND = 8,
DEBUG_BUFFERED = 9,
@@ -48,4 +48,4 @@ class ShaderLibrary {
private:
Shader m_shaders[(int)ShaderId::MAX_SHADERS];
};
};
@@ -133,7 +133,6 @@ void SpriteRenderer::render_3d(DmaFollower& dma) {
void SpriteRenderer::render_2d_group0(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
(void)dma;
while (looks_like_2d_chunk_start(dma)) {
m_debug_stats.blocks_2d_grp0++;
// 4 packets per chunk
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec4 color;
@@ -8,8 +8,8 @@ uniform sampler2D tex_T0;
uniform float alpha_reject;
void main() {
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
//vec4 T0 = textureProj(tex_T0, vec3(tex_coord.xy, 1.0));
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
T0.w = 1.0;
color = fragment_color * T0 * 2.0;
if (color.a <= alpha_reject) {
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec4 color;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec4 color;
@@ -1,7 +1,7 @@
// Shader for debugging the buffered renderer.
// no texture
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -1,6 +1,6 @@
// Debug shader for drawing things in red. Uses the same conventions as direct_basic, see there for more details
#version 330 core
#version 430 core
out vec4 color;
@@ -1,6 +1,6 @@
// Debug shader for drawing things in red. Uses the same conventions as direct_basic, see there for more details
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec4 color;
@@ -1,6 +1,6 @@
// Shader for the DirectRenderer. Inputs are RGBA + position.
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -1,15 +1,45 @@
#version 330 core
#version 430 core
out vec4 color;
in vec4 fragment_color;
in vec3 tex_coord;
uniform sampler2D tex_T0;
uniform float alpha_reject;
in flat uvec2 tex_info;
layout (binding = 20) uniform sampler2D tex_T0;
layout (binding = 21) uniform sampler2D tex_T1;
layout (binding = 22) uniform sampler2D tex_T2;
layout (binding = 23) uniform sampler2D tex_T3;
layout (binding = 24) uniform sampler2D tex_T4;
layout (binding = 25) uniform sampler2D tex_T5;
layout (binding = 26) uniform sampler2D tex_T6;
layout (binding = 27) uniform sampler2D tex_T7;
layout (binding = 28) uniform sampler2D tex_T8;
layout (binding = 29) uniform sampler2D tex_T9;
vec4 sample_tex(vec2 coord, uint unit) {
switch (unit) {
case 0: return texture(tex_T0, coord);
case 1: return texture(tex_T1, coord);
case 2: return texture(tex_T2, coord);
case 3: return texture(tex_T3, coord);
case 4: return texture(tex_T4, coord);
case 5: return texture(tex_T5, coord);
case 6: return texture(tex_T6, coord);
case 7: return texture(tex_T7, coord);
case 8: return texture(tex_T8, coord);
case 9: return texture(tex_T9, coord);
default: return vec4(1.0, 0, 1.0, 1.0);
}
}
void main() {
//vec4 T0 = texture(tex_T0, tex_coord);
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
vec4 T0 = sample_tex(tex_coord.xy / tex_coord.z, tex_info.x);
if (tex_info.y == 0) {
T0.w = 1.0;
}
color = fragment_color * T0 * 2.0;
if (color.a <= alpha_reject) {
discard;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -7,8 +7,13 @@ layout (location = 2) in vec3 tex_coord_in;
out vec4 fragment_color;
out vec3 tex_coord;
// putting all texture info stuff here so it's easier to copy-paste
layout (location = 3) in uvec2 tex_info_in;
out flat uvec2 tex_info;
void main() {
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z * 2 - 1., 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.);
tex_coord = tex_coord_in;
}
tex_info = tex_info_in;
}
@@ -1,18 +0,0 @@
#version 330 core
out vec4 color;
in vec4 fragment_color;
in vec3 tex_coord;
uniform sampler2D tex_T0;
uniform float alpha_reject;
void main() {
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
//vec4 T0 = textureProj(tex_T0, vec3(tex_coord.xy, 1.0));
T0.w = 1.0;
color = fragment_color * T0 * 2.0;
if (color.a <= alpha_reject) {
discard;
}
}
@@ -1,14 +0,0 @@
#version 330 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec3 tex_coord_in;
out vec4 fragment_color;
out vec3 tex_coord;
void main() {
gl_Position = vec4((position_in.x - 0.5) * 16. , -(position_in.y - 0.5) * 32, position_in.z * 2 - 1., 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.a * 2);
tex_coord = tex_coord_in;
}
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec4 color;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout(location = 0) out vec4 color;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
@@ -1,15 +1,46 @@
#version 330 core
#version 430 core
out vec4 color;
in vec4 fragment_color;
in vec2 tex_coord;
uniform sampler2D tex_T0;
in flat uvec2 tex_info;
layout (binding = 20) uniform sampler2D tex_T0;
layout (binding = 21) uniform sampler2D tex_T1;
layout (binding = 22) uniform sampler2D tex_T2;
layout (binding = 23) uniform sampler2D tex_T3;
layout (binding = 24) uniform sampler2D tex_T4;
layout (binding = 25) uniform sampler2D tex_T5;
layout (binding = 26) uniform sampler2D tex_T6;
layout (binding = 27) uniform sampler2D tex_T7;
layout (binding = 28) uniform sampler2D tex_T8;
layout (binding = 29) uniform sampler2D tex_T9;
vec4 sample_tex(vec2 coord, uint unit) {
switch (unit) {
case 0: return texture(tex_T0, coord);
case 1: return texture(tex_T1, coord);
case 2: return texture(tex_T2, coord);
case 3: return texture(tex_T3, coord);
case 4: return texture(tex_T4, coord);
case 5: return texture(tex_T5, coord);
case 6: return texture(tex_T6, coord);
case 7: return texture(tex_T7, coord);
case 8: return texture(tex_T8, coord);
case 9: return texture(tex_T9, coord);
default: return vec4(1.0, 0, 1.0, 1.0);
}
}
void main() {
vec4 T0 = texture(tex_T0, tex_coord);
vec4 T0 = sample_tex(tex_coord, tex_info.x);
if (tex_info.y == 0) {
T0.w = 1.0;
}
vec4 tex_color = fragment_color * T0 * 2.0;
if (tex_color.a <= 38./255.) {
if (tex_color.a < 0.016) {
discard;
}
color = tex_color;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -7,8 +7,13 @@ layout (location = 2) in vec2 tex_coord_in;
out vec4 fragment_color;
out vec2 tex_coord;
// putting all texture info stuff here so it's easier to copy-paste
layout (location = 3) in uvec2 tex_info_in;
out flat uvec2 tex_info;
void main() {
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z * 2 - 1., 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.);
tex_coord = tex_coord_in;
}
tex_info = tex_info_in;
}
@@ -1,16 +0,0 @@
#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);
vec4 tex_color = fragment_color * T0 * 2.0;
if (tex_color.a > 38./255.) {
discard;
}
color = tex_color;
}
@@ -1,14 +0,0 @@
#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 * 2 - 1., 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.);
tex_coord = tex_coord_in;
}
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec3 color;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec4 color;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec3 tex_coord_in;
@@ -7,7 +7,7 @@ layout (location = 2) in int time_of_day_index;
uniform vec4 hvdf_offset;
uniform mat4 camera;
uniform float fog_constant;
uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose.
layout (binding = 10) uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose.
out vec4 fragment_color;
out vec3 tex_coord;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
out vec4 color;
@@ -1,4 +1,4 @@
#version 330 core
#version 430 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
@@ -178,7 +178,7 @@ void Tfrag3::render_tree(const TfragRenderSettings& settings,
} else {
interp_time_of_day_slow(settings.time_of_day_weights, *tree.colors, m_color_result.data());
}
glActiveTexture(GL_TEXTURE1);
glActiveTexture(GL_TEXTURE10);
glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, tree.colors->size(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
m_color_result.data());
+2 -2
View File
@@ -127,7 +127,7 @@ void Tie3::setup_for_level(const std::string& level, SharedRenderState* render_s
GL_STATIC_DRAW);
}
glActiveTexture(GL_TEXTURE1);
glActiveTexture(GL_TEXTURE10);
glGenTextures(1, &m_trees[tree_idx].time_of_day_texture);
glBindTexture(GL_TEXTURE_1D, m_trees[tree_idx].time_of_day_texture);
// just fill with zeros. this lets use use the faster texsubimage later
@@ -539,7 +539,7 @@ void Tie3::render_tree(int idx,
tree.perf.tod_time.add(interp_timer.getSeconds());
Timer setup_timer;
glActiveTexture(GL_TEXTURE1);
glActiveTexture(GL_TEXTURE10);
glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, tree.colors->size(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
m_color_result.data());
@@ -132,7 +132,6 @@ DoubleDraw setup_tfrag_shader(const TfragRenderSettings& /*settings*/,
void first_tfrag_draw_setup(const TfragRenderSettings& settings, SharedRenderState* render_state) {
render_state->shaders[ShaderId::TFRAG3].activate();
glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "tex_T0"), 0);
glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "tex_T1"), 1);
glUniformMatrix4fv(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "camera"),
1, GL_FALSE, settings.math_camera.data());
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::TFRAG3].id(), "hvdf_offset"),
@@ -368,4 +367,4 @@ u32 make_index_list_from_vis_string(std::pair<int, int>* group_out,
group_out[i] = ds;
}
return idx_buffer_ptr;
}
}
+1
View File
@@ -22,6 +22,7 @@
;; discard scissoring area
(set! (-> *math-camera* y-pix) 128.0)
(set! (-> *math-camera* y-clip) 512.0)
;(set! (-> *video-parms* relative-y-scale) (/ 448.0 512.0))
)
(#t
(set! (-> *math-camera* y-pix) 112.0)