fix merge issues

This commit is contained in:
water
2021-08-09 21:42:05 -04:00
parent 40ecd92272
commit f700438d01
9 changed files with 251 additions and 106 deletions
+2 -1
View File
@@ -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<GfxDisplay> display) {
@@ -117,7 +118,7 @@ void KillDisplay(std::shared_ptr<GfxDisplay> 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));
}
}
+62 -76
View File
@@ -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;
}
+16
View File
@@ -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
+4
View File
@@ -25,6 +25,10 @@ struct GfxRendererModule {
std::function<void(GfxDisplay* display)> kill_display;
std::function<void(GfxDisplay* display)> render_display;
std::function<void()> exit;
std::function<u32()> vsync;
std::function<void(const void*, u32)> send_chain;
std::function<void(const u8*, int, u32)> texture_upload_now;
std::function<void(u32, u32)> texture_relocate;
GfxPipeline pipeline;
const char* name;
@@ -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<u32, 3>& 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() {
@@ -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();
@@ -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
+1 -1
View File
@@ -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
+148 -12
View File
@@ -3,18 +3,51 @@
* Lower-level OpenGL implementation.
*/
#include <memory>
#include <mutex>
#include <condition_variable>
#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 <memory>
#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<TexturePool> texture_pool;
// temporary opengl renderer
OpenGLRenderer ogl_renderer;
GraphicsData()
: dma_copier(EE_MAIN_MEM_SIZE),
texture_pool(std::make_shared<TexturePool>()),
ogl_renderer(texture_pool) {}
};
std::unique_ptr<GraphicsData> 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<GfxDisplay> gl_make_main_display(int width,
@@ -73,6 +108,7 @@ static std::shared_ptr<GfxDisplay> gl_make_main_display(int width,
lg::error("GL init fail");
return NULL;
}
g_gfx_data = std::make_unique<GraphicsData>();
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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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
};