From f700438d01eb5442cc85e346eb2232d49372309e Mon Sep 17 00:00:00 2001 From: water Date: Mon, 9 Aug 2021 21:42:05 -0400 Subject: [PATCH] fix merge issues --- game/graphics/display.cpp | 3 +- game/graphics/dma/dma.cpp | 138 +++++++-------- game/graphics/gfx.cpp | 16 ++ game/graphics/gfx.h | 4 + .../opengl_renderer/DirectRenderer.cpp | 26 +-- .../graphics/opengl_renderer/DirectRenderer.h | 6 +- .../opengl_renderer/OpenGLRenderer.cpp | 2 +- game/graphics/opengl_renderer/Shader.cpp | 2 +- game/graphics/pipelines/opengl.cpp | 160 ++++++++++++++++-- 9 files changed, 251 insertions(+), 106 deletions(-) diff --git a/game/graphics/display.cpp b/game/graphics/display.cpp index 6a72b0bf24..273641e2d1 100644 --- a/game/graphics/display.cpp +++ b/game/graphics/display.cpp @@ -106,6 +106,7 @@ int InitMainDisplay(int width, int height, const char* title, GfxSettings& setti return 1; } set_main_display(display); + return 0; } void KillDisplay(std::shared_ptr display) { @@ -117,7 +118,7 @@ void KillDisplay(std::shared_ptr display) { if (GetMainDisplay() == display) { // killing the main display, kill all children displays too! - for (int i = 1; i < g_displays.size(); ++i) { + for (size_t i = 1; i < g_displays.size(); ++i) { KillDisplay(g_displays.at(i)); } } diff --git a/game/graphics/dma/dma.cpp b/game/graphics/dma/dma.cpp index 6f65606c4c..2094a0e39a 100644 --- a/game/graphics/dma/dma.cpp +++ b/game/graphics/dma/dma.cpp @@ -17,88 +17,74 @@ std::string DmaTag::print() { std::string VifCode::print() { std::string result; - bool special_kind = false; switch (kind) { - // case Kind::NOP: - // result = "NOP"; - // break; - // case Kind::STCYCL: - // result = "STCYCL"; - // break; - // case Kind::OFFSET: - // result = "OFFSET"; - // break; - // case Kind::BASE: - // result = "BASE"; - // break; - // case Kind::ITOP: - // result = "ITOP"; - // break; - // case Kind::STMOD: - // result = "STMOD"; - // break; - // case Kind::MSK3PATH: - // result = "MSK3PATH"; - // break; - // case Kind::MARK: - // result = "MARK"; - // break; - // case Kind::FLUSHE: - // result = "FLUSHE"; - // break; - // case Kind::FLUSH: - // result = "FLUSH"; - // break; - // - // case Kind::FLUSHA: - // result = "FLUSHA"; - // break; - // case Kind::MSCAL: - // result = "MSCAL"; - // break; - // case Kind::MSCNT: - // result = "MSCNT"; - // break; - // case Kind::MSCALF: - // result = "MSCALF"; - // break; - // case Kind::STMASK: - // result = "STMASK"; - // break; - // case Kind::STROW: - // result = "STROW"; - // break; - // case Kind::STCOL: - // result = "STCOL"; - // break; - // case Kind::MPG: - // result = "MPG"; - // break; - // case Kind::DIRECT: - // result = "DIRECT"; - // break; - // case Kind::DIRECTHL: - // result = "DIRECTHL"; - // break; + case Kind::NOP: + result = "NOP"; + break; + case Kind::STCYCL: + result = "STCYCL"; + break; + case Kind::OFFSET: + result = "OFFSET"; + break; + case Kind::BASE: + result = "BASE"; + break; + case Kind::ITOP: + result = "ITOP"; + break; + case Kind::STMOD: + result = "STMOD"; + break; + case Kind::MSK3PATH: + result = "MSK3PATH"; + break; + case Kind::MARK: + result = "MARK"; + break; + case Kind::FLUSHE: + result = "FLUSHE"; + break; + case Kind::FLUSH: + result = "FLUSH"; + break; + + case Kind::FLUSHA: + result = "FLUSHA"; + break; + case Kind::MSCAL: + result = "MSCAL"; + break; + case Kind::MSCNT: + result = "MSCNT"; + break; + case Kind::MSCALF: + result = "MSCALF"; + break; + case Kind::STMASK: + result = "STMASK"; + break; + case Kind::STROW: + result = "STROW"; + break; + case Kind::STCOL: + result = "STCOL"; + break; + case Kind::MPG: + result = "MPG"; + break; + case Kind::DIRECT: + result = "DIRECT"; + break; + case Kind::DIRECTHL: + result = "DIRECTHL"; + break; default: fmt::print("Unhandled vif code {}", (int)kind); assert(false); - // special_kind = true; break; } - // - // if (special_kind) { - // if (((u32)kind & (u32)Kind::UNPACK_MASK) == (u32)Kind::UNPACK_MASK) { - // result = "UNPACK"; - // assert(false); - // } else { - // assert(false); - // } - // } - // - // result += ' '; - // + // TODO: the rest of the VIF code. return result; } - diff --git a/game/graphics/gfx.cpp b/game/graphics/gfx.cpp index 07f6b86b52..4a1eec01c4 100644 --- a/game/graphics/gfx.cpp +++ b/game/graphics/gfx.cpp @@ -85,4 +85,20 @@ u32 Exit() { return 0; } +u32 vsync() { + return g_settings.renderer->vsync(); +} + +void send_chain(const void* data, u32 offset) { + g_settings.renderer->send_chain(data, offset); +} + +void texture_upload_now(const u8* tpage, int mode, u32 s7_ptr) { + g_settings.renderer->texture_upload_now(tpage, mode, s7_ptr); +} + +void texture_relocate(u32 destination, u32 source) { + g_settings.renderer->texture_relocate(destination, source); +} + } // namespace Gfx diff --git a/game/graphics/gfx.h b/game/graphics/gfx.h index 9f988e1aa7..56be772274 100644 --- a/game/graphics/gfx.h +++ b/game/graphics/gfx.h @@ -25,6 +25,10 @@ struct GfxRendererModule { std::function kill_display; std::function render_display; std::function exit; + std::function vsync; + std::function send_chain; + std::function texture_upload_now; + std::function texture_relocate; GfxPipeline pipeline; const char* name; diff --git a/game/graphics/opengl_renderer/DirectRenderer.cpp b/game/graphics/opengl_renderer/DirectRenderer.cpp index 2443a27555..315a3d22d5 100644 --- a/game/graphics/opengl_renderer/DirectRenderer.cpp +++ b/game/graphics/opengl_renderer/DirectRenderer.cpp @@ -2,7 +2,7 @@ #include "game/graphics/dma/gs.h" #include "common/log/log.h" #include "third-party/fmt/core.h" -#include "game/graphics/opengl.h" +#include "game/graphics/pipelines/opengl.h" DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batch_size) : BucketRenderer(name, my_id), m_prim_buffer(batch_size) { @@ -236,7 +236,7 @@ void DirectRenderer::update_gl_test() { } } -void DirectRenderer::setup_common_state(SharedRenderState* render_state) { +void DirectRenderer::setup_common_state(SharedRenderState* /*render_state*/) { // todo texture clamp. } @@ -346,7 +346,7 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren handle_rgbaq_packed(data + offset); break; case GifTag::RegisterDescriptor::XYZF2: - handle_xyzf2_packed(data + offset); + handle_xyzf2_packed(data + offset, render_state); break; default: fmt::print("Register {} is not supported in packed mode yet\n", @@ -512,7 +512,7 @@ float u32_to_float(u32 in) { return x * 2 - 1; } -void DirectRenderer::handle_xyzf2_packed(const u8* data) { +void DirectRenderer::handle_xyzf2_packed(const u8* data, SharedRenderState* render_state) { u32 x, y; memcpy(&x, data, 4); memcpy(&y, data + 4, 4); @@ -524,7 +524,7 @@ void DirectRenderer::handle_xyzf2_packed(const u8* data) { bool adc = upper & (1ull << 47); assert(!adc); assert(!f); - handle_xyzf2_common(x, y, z, f); + handle_xyzf2_common(x, y, z, f, render_state); } void debug_print_vtx(const math::Vector& vtx) { @@ -594,7 +594,14 @@ void DirectRenderer::handle_rgbaq(u64 val) { memcpy(m_prim_building.rgba_reg.data(), &val, 4); } -void DirectRenderer::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f) { +void DirectRenderer::handle_xyzf2_common(u32 x, + u32 y, + u32 z, + u8 f, + SharedRenderState* render_state) { + if (m_prim_buffer.is_full()) { + flush_pending(render_state); + } 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; @@ -685,11 +692,6 @@ 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); - } - // m_prim_buffer.rgba_u8[m_prim_buffer.vert_count] = m_prim_building.rgba; u32 x = val & 0xffff; @@ -697,7 +699,7 @@ void DirectRenderer::handle_xyzf2(u64 val, SharedRenderState* render_state) { u32 z = (val >> 32) & 0xfffff; u32 f = (val >> 56) & 0xff; - handle_xyzf2_common(x, y, z, f); + handle_xyzf2_common(x, y, z, f, render_state); } void DirectRenderer::reset_state() { diff --git a/game/graphics/opengl_renderer/DirectRenderer.h b/game/graphics/opengl_renderer/DirectRenderer.h index 0069412fa0..b400e12362 100644 --- a/game/graphics/opengl_renderer/DirectRenderer.h +++ b/game/graphics/opengl_renderer/DirectRenderer.h @@ -6,7 +6,7 @@ #include "game/graphics/types.h" #include "common/math/Vector.h" #include "common/util/SmallVector.h" -#include "game/graphics/opengl.h" +#include "game/graphics/pipelines/opengl.h" /*! * The direct renderer will handle rendering GIFtags directly. @@ -59,12 +59,12 @@ class DirectRenderer : public BucketRenderer { void handle_xyzf2(u64 val, SharedRenderState* render_state); void handle_st_packed(const u8* data); void handle_rgbaq_packed(const u8* data); - void handle_xyzf2_packed(const u8* data); + void handle_xyzf2_packed(const u8* data, SharedRenderState* render_state); 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 handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f, SharedRenderState* render_state); void update_gl_prim(SharedRenderState* render_state); void update_gl_blend(); diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 474ddcb7a7..81b91e7a11 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -1,7 +1,7 @@ #include "OpenGLRenderer.h" #include "common/log/log.h" -#include "game/graphics/opengl.h" +#include "game/graphics/pipelines/opengl.h" #include "game/graphics/opengl_renderer/DirectRenderer.h" // for the vif callback diff --git a/game/graphics/opengl_renderer/Shader.cpp b/game/graphics/opengl_renderer/Shader.cpp index 67763d1f56..a8d73fa858 100644 --- a/game/graphics/opengl_renderer/Shader.cpp +++ b/game/graphics/opengl_renderer/Shader.cpp @@ -1,7 +1,7 @@ #include "Shader.h" #include "common/util/assert.h" #include "common/util/FileUtil.h" -#include "game/graphics/opengl.h" +#include "game/graphics/pipelines/opengl.h" Shader::Shader(const std::string& shader_name) { // read the shader source diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index 9cc6b26c09..37aecc9c70 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -3,18 +3,51 @@ * Lower-level OpenGL implementation. */ +#include +#include +#include + #include "opengl.h" #include "game/graphics/gfx.h" #include "game/graphics/display.h" - +#include "game/graphics/opengl_renderer/OpenGLRenderer.h" +#include "game/graphics/texture/TexturePool.h" +#include "game/graphics/dma/dma_copy.h" #include "common/log/log.h" -#include +#include "common/goal_constants.h" +#include "game/runtime.h" namespace { +struct GraphicsData { + // vsync + std::mutex sync_mutex; + std::condition_variable sync_cv; + + // dma chain transfer + std::mutex dma_mutex; + std::condition_variable dma_cv; + u64 frame_idx = 0; + bool has_data_to_render = false; + FixedChunkDmaCopier dma_copier; + + // texture pool + std::shared_ptr texture_pool; + + // temporary opengl renderer + OpenGLRenderer ogl_renderer; + + GraphicsData() + : dma_copier(EE_MAIN_MEM_SIZE), + texture_pool(std::make_shared()), + ogl_renderer(texture_pool) {} +}; + +std::unique_ptr g_gfx_data; + void SetDisplayCallbacks(GLFWwindow* d) { - glfwSetKeyCallback(d, [](GLFWwindow* window, int key, int scancode, int action, int mods) { + glfwSetKeyCallback(d, [](GLFWwindow* /*window*/, int key, int scancode, int action, int mods) { if (action == GlfwKeyAction::Press) { lg::debug("KEY PRESS: key: {} scancode: {} mods: {:X}", key, scancode, mods); } else if (action == GlfwKeyAction::Release) { @@ -52,8 +85,10 @@ static int gl_init() { } static void gl_exit() { + g_gfx_data.reset(); glfwTerminate(); glfwSetErrorCallback(NULL); + gl_inited = false; } static std::shared_ptr gl_make_main_display(int width, @@ -73,6 +108,7 @@ static std::shared_ptr gl_make_main_display(int width, lg::error("GL init fail"); return NULL; } + g_gfx_data = std::make_unique(); gl_inited = true; // enable vsync by default @@ -101,11 +137,42 @@ static void gl_render_display(GfxDisplay* display) { glfwMakeContextCurrent(window); - // render graphics - glClear(GL_COLOR_BUFFER_BIT); + // wait for a copied chain. + bool got_chain = false; + { + std::unique_lock lock(g_gfx_data->dma_mutex); + // note: there's a timeout here. If the engine is messed up and not sending us frames, + // we still want to run the glfw loop. + got_chain = g_gfx_data->dma_cv.wait_for(lock, std::chrono::milliseconds(20), + [=] { return g_gfx_data->has_data_to_render; }); + } + // render that chain. + if (got_chain) { + auto& chain = g_gfx_data->dma_copier.get_last_result(); + int width, height; + glfwGetFramebufferSize(window, &width, &height); + g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), width, + height); + } + + // before vsync, mark the chain as rendered. + { + // should be fine to remove this mutex if the game actually waits for vsync to call + // send_chain again. but let's be safe for now. + std::unique_lock lock(g_gfx_data->dma_mutex); + g_gfx_data->has_data_to_render = false; + } + + // actual vsync glfwSwapBuffers(window); + // toggle even odd and wake up engine waiting on vsync. + { + std::unique_lock lock(g_gfx_data->sync_mutex); + g_gfx_data->frame_idx++; + g_gfx_data->sync_cv.notify_all(); + } // poll events TODO integrate input with cpad glfwPollEvents(); @@ -116,12 +183,81 @@ static void gl_render_display(GfxDisplay* display) { } } +/*! + * Wait for the next vsync. Returns 0 or 1 depending on if frame is even or odd. + * Called from the game thread, on a GOAL stack. + */ +u32 gl_vsync() { + if (!g_gfx_data) { + return 0; + } + + std::unique_lock lock(g_gfx_data->sync_mutex); + auto init_frame = g_gfx_data->frame_idx; + g_gfx_data->sync_cv.wait(lock, [=] { return g_gfx_data->frame_idx > init_frame; }); + + return g_gfx_data->frame_idx & 1; +} + +/*! + * Send DMA to the renderer. + * Called from the game thread, on a GOAL stack. + */ +void gl_send_chain(const void* data, u32 offset) { + if (g_gfx_data) { + std::unique_lock lock(g_gfx_data->dma_mutex); + if (g_gfx_data->has_data_to_render) { + lg::error( + "Gfx::send_chain called when the graphics renderer has pending data. Was this called " + "multiple times per frame?"); + return; + } + + // we copy the dma data and give a copy of it to the render. + // the copy has a few advantages: + // - if the game code has a bug and corrupts the DMA buffer, the renderer won't see it. + // - the copied DMA is much smaller than the entire game memory, so it can be dumped to a file + // separate of the entire RAM. + // - it verifies the DMA data is valid early on. + // but it may also be pretty expensive. Both the renderer and the game wait on this to complete. + + // The renderers should just operate on DMA chains, so eliminating this step in the future may + // be easy. + + // Timer copy_timer; + g_gfx_data->dma_copier.run(data, offset); + // fmt::print("copy took {:.3f}ms\n", copy_timer.getMs()); + + g_gfx_data->has_data_to_render = true; + g_gfx_data->dma_cv.notify_all(); + } +} + +void gl_texture_upload_now(const u8* tpage, int mode, u32 s7_ptr) { + if (g_gfx_data) { + // just pass it to the texture pool. + // the texture pool will take care of locking. + // we don't want to lock here for the entire duration of the conversion. + g_gfx_data->texture_pool->handle_upload_now(tpage, mode, g_ee_main_mem, s7_ptr); + } +} + +void gl_texture_relocate(u32 destination, u32 source) { + if (g_gfx_data) { + g_gfx_data->texture_pool->relocate(destination, source); + } +} + const GfxRendererModule moduleOpenGL = { - gl_init, // init - gl_make_main_display, // make_main_display - gl_kill_display, // kill_display - gl_render_display, // render_display - gl_exit, // exit - GfxPipeline::OpenGL, // pipeline - "OpenGL 3.0" // name + gl_init, // init + gl_make_main_display, // make_main_display + gl_kill_display, // kill_display + gl_render_display, // render_display + gl_exit, // exit + gl_vsync, // vsync + gl_send_chain, // send_chain + gl_texture_upload_now, // texture_upload_now + gl_texture_relocate, // texture_relocate + GfxPipeline::OpenGL, // pipeline + "OpenGL 3.0" // name };