[graphics] merc2 fix, texture crash bug fix (#1385)

* [graphics] merc2 fix, texture crash bug fix

* still boot if deci2 fails to init
This commit is contained in:
water111 2022-05-30 11:06:11 -04:00 committed by GitHub
parent 750255e5b2
commit dad84ec249
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 102 additions and 68 deletions

View file

@ -249,7 +249,7 @@ std::vector<EyeRenderer::SingleEyeDraws> EyeRenderer::get_draws(DmaFollower& dma
pair_idx = y0 / SINGLE_EYE_SIZE;
l_draw.pair = pair_idx;
r_draw.pair = pair_idx;
if (tex0->get_data_ptr()) {
if (tex0 && tex0->get_data_ptr()) {
u32 tex_val;
memcpy(&tex_val, tex0->get_data_ptr(), 4);
l_draw.clear_color = tex_val;
@ -280,7 +280,7 @@ std::vector<EyeRenderer::SingleEyeDraws> EyeRenderer::get_draws(DmaFollower& dma
AdgifHelper adgif1(adgif1_dma.data + 16);
auto tex1 = render_state->texture_pool->lookup_gpu_texture(adgif1.tex0().tbp0());
{
if (tex1 && tex1->get_data_ptr()) {
l_draw.pupil = read_eye_draw(dma);
r_draw.pupil = read_eye_draw(dma);
l_draw.pupil_tex = tex1;

View file

@ -151,13 +151,16 @@ SkyBlendStats SkyBlendCPU::do_sky_blends(DmaFollower& dma,
}
*/
if (tex->get_data_ptr()) {
if (is_first_draw) {
blend_sky_initial_fast(intensity, m_texture_data[buffer_idx].data(), tex->get_data_ptr(),
tex->data_size());
} else {
blend_sky_fast(intensity, m_texture_data[buffer_idx].data(), tex->get_data_ptr(),
tex->data_size());
if (m_texture_data[buffer_idx].size() == tex->data_size()) {
if (is_first_draw) {
blend_sky_initial_fast(intensity, m_texture_data[buffer_idx].data(), tex->get_data_ptr(),
m_texture_data[buffer_idx].size());
} else {
blend_sky_fast(intensity, m_texture_data[buffer_idx].data(), tex->get_data_ptr(),
m_texture_data[buffer_idx].size());
}
}
if (buffer_idx == 0) {
if (is_first_draw) {
stats.sky_draws++;

View file

@ -8,9 +8,23 @@ Merc2::Merc2(const std::string& name, BucketId my_id) : BucketRenderer(name, my_
glGenBuffers(1, &m_bones_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, m_bones_buffer);
glBufferData(GL_UNIFORM_BUFFER, MAX_SHADER_BONES * sizeof(MercMat), nullptr, GL_DYNAMIC_DRAW);
glBufferData(GL_UNIFORM_BUFFER, MAX_SHADER_BONE_VECTORS * sizeof(math::Vector4f), nullptr,
GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
GLint val;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &val);
if (val <= 16) {
// somehow doubt this can happen, but just in case
m_opengl_buffer_alignment = 1;
} else {
m_opengl_buffer_alignment = val / 16; // number of bone vectors
if (m_opengl_buffer_alignment * 16 != (u32)val) {
ASSERT_MSG(false,
fmt::format("opengl uniform buffer alignment is {}, which is strange\n", val));
}
}
for (int i = 0; i < MAX_LEVELS; i++) {
auto& draws = m_level_draw_buckets.emplace_back();
draws.draws.resize(MAX_DRAWS_PER_LEVEL);
@ -115,48 +129,6 @@ void Merc2::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProf
flush_draw_buckets(render_state, prof);
}
/*!
* Queue up some bones to be included in the bone buffer.
* Returns the index of the first bone.
*/
u32 Merc2::alloc_bones(int count, float scale) {
ASSERT(count + m_next_free_bone <= MAX_SHADER_BONES);
u32 first_bone = m_next_free_bone;
// model should have under 128 bones.
ASSERT(count <= MAX_SKEL_BONES);
// iterate over each bone we need
for (int i = 0; i < count; i++) {
auto& skel_mat = m_skel_matrix_buffer[i];
auto& shader_mat = m_shader_matrix_buffer[m_next_free_bone++];
// scale the transformation matrix (todo: can we move this to the extraction)
// and copy to the large bone buffer.
for (int j = 0; j < 3; j++) {
shader_mat.tmat[j] = skel_mat.tmat[j] * scale;
}
shader_mat.tmat[3] = skel_mat.tmat[3];
for (int j = 0; j < 3; j++) {
shader_mat.nmat[j] = skel_mat.nmat[j];
}
// we could include the effect of the perspective matrix here.
// for (int j = 0; j < 3; j++) {
// tbone_buffer[i][j] = vf15.elementwise_multiply(bone_mat[j]);
// tbone_buffer[i][j].w() += p.w() * bone_mat[j].z();
// tbone_buffer[i][j] *= scale;
// }
//
// tbone_buffer[i][3] = vf15.elementwise_multiply(bone_mat[3]) +
// m_low_memory.perspective[3]; tbone_buffer[i][3].w() += p.w() * bone_mat[3].z();
}
return first_bone;
}
u32 Merc2::alloc_lights(const VuLights& lights) {
ASSERT(m_next_free_light < MAX_LIGHTS);
m_stats.num_lights++;
@ -404,6 +376,55 @@ void Merc2::handle_merc_chain(DmaFollower& dma,
}
}
/*!
* Queue up some bones to be included in the bone buffer.
* Returns the index of the first bone vector.
*/
u32 Merc2::alloc_bones(int count, float scale) {
u32 first_bone_vector = m_next_free_bone_vector;
ASSERT(count * 8 + first_bone_vector <= MAX_SHADER_BONE_VECTORS);
// model should have under 128 bones.
ASSERT(count <= MAX_SKEL_BONES);
// iterate over each bone we need
for (int i = 0; i < count; i++) {
auto& skel_mat = m_skel_matrix_buffer[i];
auto* shader_mat = &m_shader_bone_vector_buffer[m_next_free_bone_vector];
int bv = 0;
// scale the transformation matrix (todo: can we move this to the extraction)
// and copy to the large bone buffer.
for (int j = 0; j < 3; j++) {
shader_mat[bv++] = skel_mat.tmat[j] * scale;
}
shader_mat[bv++] = skel_mat.tmat[3];
for (int j = 0; j < 3; j++) {
shader_mat[bv++] = skel_mat.nmat[j];
}
// we could include the effect of the perspective matrix here.
// for (int j = 0; j < 3; j++) {
// tbone_buffer[i][j] = vf15.elementwise_multiply(bone_mat[j]);
// tbone_buffer[i][j].w() += p.w() * bone_mat[j].z();
// tbone_buffer[i][j] *= scale;
// }
//
// tbone_buffer[i][3] = vf15.elementwise_multiply(bone_mat[3]) +
// m_low_memory.perspective[3]; tbone_buffer[i][3].w() += p.w() * bone_mat[3].z();
m_next_free_bone_vector += 8;
}
auto b0 = m_next_free_bone_vector;
m_next_free_bone_vector += m_opengl_buffer_alignment - 1;
m_next_free_bone_vector /= m_opengl_buffer_alignment;
m_next_free_bone_vector *= m_opengl_buffer_alignment;
ASSERT(b0 <= m_next_free_bone_vector);
ASSERT(first_bone_vector + count * 8 <= m_next_free_bone_vector);
return first_bone_vector;
}
/*!
* Flush a model to draw buckets
*/
@ -415,16 +436,16 @@ void Merc2::flush_pending_model(SharedRenderState* render_state, ScopedProfilerN
const LevelData* lev = m_current_model->level;
const tfrag3::MercModel* model = m_current_model->model;
int bone_count = (model->max_bones + 31) & (~31); // todo
// int bone_count = 128;
int bone_count = model->max_bones + 1;
if (m_next_free_light >= MAX_LIGHTS) {
fmt::print("MERC2 out of lights, consider increasing MAX_LIGHTS\n");
flush_draw_buckets(render_state, prof);
}
if (m_next_free_bone + bone_count > MAX_SHADER_BONES) {
fmt::print("MERC2 out of bones, consider increasing MAX_SHADER_BONES\n");
if (m_next_free_bone_vector + m_opengl_buffer_alignment + bone_count * 8 >
MAX_SHADER_BONE_VECTORS) {
fmt::print("MERC2 out of bones, consider increasing MAX_SHADER_BONE_VECTORS\n");
flush_draw_buckets(render_state, prof);
}
@ -560,11 +581,11 @@ void Merc2::flush_draw_buckets(SharedRenderState* /*render_state*/, ScopedProfil
int last_tex = -1;
int last_light = -1;
m_stats.num_bones_uploaded += m_next_free_bone;
m_stats.num_bones_uploaded += m_next_free_bone_vector;
glBindBuffer(GL_UNIFORM_BUFFER, m_bones_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, m_next_free_bone * sizeof(MercMat),
m_shader_matrix_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, m_next_free_bone_vector * sizeof(math::Vector4f),
m_shader_bone_vector_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
for (u32 di = 0; di < lev_bucket.next_free_draw; di++) {
@ -591,14 +612,14 @@ void Merc2::flush_draw_buckets(SharedRenderState* /*render_state*/, ScopedProfil
prof.add_draw_call();
prof.add_tri(draw.num_triangles);
glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_bones_buffer, sizeof(MercMat) * draw.first_bone,
128 * sizeof(MercMat));
glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_bones_buffer,
sizeof(math::Vector4f) * draw.first_bone, 128 * sizeof(ShaderMercMat));
glDrawElements(GL_TRIANGLE_STRIP, draw.index_count, GL_UNSIGNED_INT,
(void*)(sizeof(u32) * draw.first_index));
}
}
m_next_free_light = 0;
m_next_free_bone = 0;
m_next_free_bone_vector = 0;
m_next_free_level_bucket = 0;
}

View file

@ -65,14 +65,21 @@ class Merc2 : public BucketRenderer {
math::Vector4f nmat[3];
};
struct ShaderMercMat {
math::Vector4f tmat[4];
math::Vector4f nmat[3];
math::Vector4f pad;
};
static constexpr int MAX_SKEL_BONES = 128;
static constexpr int MAX_SHADER_BONES = 8192;
static constexpr int BONE_VECTORS_PER_BONE = 7;
static constexpr int MAX_SHADER_BONE_VECTORS = 8192; // ??
static constexpr int MAX_LEVELS = 3;
static constexpr int MAX_DRAWS_PER_LEVEL = 1024;
MercMat m_shader_matrix_buffer[MAX_SHADER_BONES];
MercMat m_skel_matrix_buffer[MAX_SKEL_BONES];
math::Vector4f m_shader_bone_vector_buffer[MAX_SHADER_BONE_VECTORS];
ShaderMercMat m_skel_matrix_buffer[MAX_SKEL_BONES];
struct {
GLuint light_direction[3];
@ -137,7 +144,8 @@ class Merc2 : public BucketRenderer {
std::vector<LevelDrawBucket> m_level_draw_buckets;
u32 m_next_free_level_bucket = 0;
u32 m_next_free_bone = 0;
u32 m_next_free_bone_vector = 0;
size_t m_opengl_buffer_alignment = 0;
void flush_draw_buckets(SharedRenderState* render_state, ScopedProfilerNode& prof);
};

View file

@ -36,6 +36,7 @@ out float fog;
struct MercMatrixData {
mat4 X;
mat3 R;
vec4 pad;
};
layout (std140, binding = 1) uniform ub_bones {

View file

@ -86,14 +86,15 @@ void deci2_runner(SystemThreadInterface& iface) {
lg::debug("[DECI2] Waiting for EE to register protos");
server.wait_for_protos_ready();
// then allow the server to accept connections
if (!server.init_server()) {
ASSERT_MSG(false, "[DECI2] Server not initialized even if protocols are ready, aborting");
bool server_ok = server.init_server();
if (!server_ok) {
lg::error("[DECI2] failed to initialize, REPL will not work.\n");
}
lg::debug("[DECI2] Waiting for listener...");
bool saw_listener = false;
while (!iface.get_want_exit()) {
if (server.is_client_connected()) {
if (server_ok && server.is_client_connected()) {
if (!saw_listener) {
lg::debug("[DECI2] Connected!");
}