[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
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 14 KiB |
@@ -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(®ister_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++;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"};
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||