From bb323c2ebe960c759108389c189854c2587a34ac Mon Sep 17 00:00:00 2001 From: Ethan Lafrenais <6609531+Francessco121@users.noreply.github.com> Date: Tue, 19 Jul 2022 18:34:30 -0400 Subject: [PATCH] Depth Cue (#1676) * Initial depth-cue implementation * Oops * Finish merge + fix issues with letterboxing * Fix alpha blending * Add some debug options + profiler stats * More debug options + respect xyoffset GS register * Clean up GOAL code * Disable depth-cue by default * typo * very important typo * depth-cue disable, but better --- common/dma/gs.cpp | 10 +- common/dma/gs.h | 46 ++ game/CMakeLists.txt | 1 + game/graphics/opengl_renderer/DepthCue.cpp | 684 ++++++++++++++++++ game/graphics/opengl_renderer/DepthCue.h | 183 +++++ .../opengl_renderer/OpenGLRenderer.cpp | 7 +- game/graphics/opengl_renderer/Shader.cpp | 1 + game/graphics/opengl_renderer/Shader.h | 1 + game/graphics/opengl_renderer/buckets.h | 2 +- .../opengl_renderer/shaders/depth_cue.frag | 13 + .../opengl_renderer/shaders/depth_cue.vert | 27 + goal_src/jak1/engine/game/main.gc | 4 + goal_src/jak1/engine/gfx/depth-cue.gc | 392 ++++------ goal_src/jak1/engine/gfx/vu1-user-h.gc | 5 + 14 files changed, 1131 insertions(+), 245 deletions(-) create mode 100644 game/graphics/opengl_renderer/DepthCue.cpp create mode 100644 game/graphics/opengl_renderer/DepthCue.h create mode 100644 game/graphics/opengl_renderer/shaders/depth_cue.frag create mode 100644 game/graphics/opengl_renderer/shaders/depth_cue.vert diff --git a/common/dma/gs.cpp b/common/dma/gs.cpp index 932f00e9e..6113f10fa 100644 --- a/common/dma/gs.cpp +++ b/common/dma/gs.cpp @@ -359,6 +359,14 @@ std::string GsPrim::print() const { return fmt::format("0x{:x}, kind {}\n", data, kind()); } +std::string GsFrame::print() const { + return fmt::format("fbp: {} fbw: {} psm: {} fbmsk: {:x}\n", fbp(), fbw(), psm(), fbmsk()); +} + +std::string GsXYOffset::print() const { + return fmt::format("ofx: {} ofy: {}\n", ofx(), ofy()); +} + std::string DrawMode::to_string() const { std::string result; result += fmt::format(" depth-write: {}\n", get_depth_write_enable()); @@ -449,4 +457,4 @@ std::string DrawMode::to_string() const { } result += fmt::format(" fog: {}\n decal: {}\n", get_fog_enable(), get_decal()); return result; -} \ No newline at end of file +} diff --git a/common/dma/gs.h b/common/dma/gs.h index 4ecfb3d92..73b7a3546 100644 --- a/common/dma/gs.h +++ b/common/dma/gs.h @@ -341,6 +341,52 @@ struct GsTexa { u64 data = 0; }; +struct GsFrame { + enum class PSM { + PSMCT32 = 0, + PSMCT24 = 1, + PSMCT16 = 2, + PSMCT16S = 0b1010, + PSMT8 = 0b10011, + PSMT4 = 0b10100, + PSMT8H = 0b011011, + PSMT4HL = 0b100100, + PSMT4HH = 0b101100, + PSMZ32 = 0b110000, + PSMZ24 = 0b110001, + PSMZ16 = 0b110010, + PSMZ16S = 0b111010 + }; + + GsFrame() = default; + GsFrame(u64 val) : data(val) {} + + // Frame buffer base pointer (word address / 2048) + u32 fbp() const { return (data & 0b1'1111'1111); } + // Frame buffer width (pixels / 64) + u32 fbw() const { return ((data >> 16) & 0b11'1111); } + // Frame buffer pixel storage format + PSM psm() const { return (PSM)((data >> 24) & 0b11'1111); } + // Frame buffer drawing mask + u32 fbmsk() const { return ((data >> 32) & 0xFFFF'FFFF); } + + std::string print() const; + + u64 data = 0; +}; + +struct GsXYOffset { + GsXYOffset() = default; + GsXYOffset(u64 val) : data(val) {} + + u32 ofx() const { return data & 0xFFFF; } + u32 ofy() const { return (data >> 32) & 0xFFFF; } + + std::string print() const; + + u64 data = 0; +}; + // not including the giftag struct AdGifData { u64 tex0_data; diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 9ae6b249b..3096b15cb 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -138,6 +138,7 @@ set(RUNTIME_SOURCE graphics/opengl_renderer/Sprite3.cpp graphics/opengl_renderer/SpriteRenderer.cpp graphics/opengl_renderer/TextureUploadHandler.cpp + graphics/opengl_renderer/DepthCue.cpp graphics/texture/jak1_tpage_dir.cpp graphics/texture/TextureConverter.cpp graphics/texture/TexturePool.cpp diff --git a/game/graphics/opengl_renderer/DepthCue.cpp b/game/graphics/opengl_renderer/DepthCue.cpp new file mode 100644 index 000000000..c5dd5ad7d --- /dev/null +++ b/game/graphics/opengl_renderer/DepthCue.cpp @@ -0,0 +1,684 @@ +#include "DepthCue.h" + +#include "game/graphics/opengl_renderer/dma_helpers.h" + +#include "third-party/fmt/core.h" +#include "third-party/imgui/imgui.h" + +namespace { +// Converts fixed point (with 4 bits for decimal) to floating point. +float fixed_to_floating_point(int fixed) { + return fixed / 16.0f; +} + +math::Vector2f fixed_to_floating_point(const math::Vector& fixed_vec) { + return math::Vector2f(fixed_to_floating_point(fixed_vec.x()), + fixed_to_floating_point(fixed_vec.y())); +} +} // namespace + +// Total number of loops depth-cue performs to draw to the framebuffer +constexpr int TOTAL_DRAW_SLICES = 16; + +DepthCue::DepthCue(const std::string& name, BucketId my_id) : BucketRenderer(name, my_id) { + opengl_setup(); + + m_draw_slices.resize(TOTAL_DRAW_SLICES); +} + +void DepthCue::opengl_setup() { + // Gen texture for sampling the framebuffer + glGenFramebuffers(1, &m_ogl.framebuffer_sample_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.framebuffer_sample_fbo); + + glGenTextures(1, &m_ogl.framebuffer_sample_tex); + glBindTexture(GL_TEXTURE_2D, m_ogl.framebuffer_sample_tex); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + m_ogl.framebuffer_sample_tex, 0); + + ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Gen framebuffer for depth-cue-base-page + glGenFramebuffers(1, &m_ogl.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.fbo); + + glGenTextures(1, &m_ogl.fbo_texture); + glBindTexture(GL_TEXTURE_2D, m_ogl.fbo_texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ogl.fbo_texture, 0); + + ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Gen vertex array for drawing to depth-cue-base-page + glGenVertexArrays(1, &m_ogl.depth_cue_page_vao); + glBindVertexArray(m_ogl.depth_cue_page_vao); + glGenBuffers(1, &m_ogl.depth_cue_page_vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, m_ogl.depth_cue_page_vertex_buffer); + + glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(SpriteVertex), nullptr, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, // location 0 in the shader + 2, // 2 floats per vert + GL_FLOAT, // floats + GL_FALSE, // don't normalize, ignored + sizeof(SpriteVertex), // + (void*)offsetof(SpriteVertex, xy) // offset in array + ); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, // location 1 in the shader + 2, // 2 floats per vert + GL_FLOAT, // floats + GL_FALSE, // don't normalize, ignored + sizeof(SpriteVertex), // + (void*)offsetof(SpriteVertex, st) // offset in array + ); + + // Gen vertex array for drawing to on-screen framebuffer + glGenVertexArrays(1, &m_ogl.on_screen_vao); + glBindVertexArray(m_ogl.on_screen_vao); + glGenBuffers(1, &m_ogl.on_screen_vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, m_ogl.on_screen_vertex_buffer); + + glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(SpriteVertex), nullptr, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, // location 0 in the shader + 2, // 2 floats per vert + GL_FLOAT, // floats + GL_FALSE, // don't normalize, ignored + sizeof(SpriteVertex), // + (void*)offsetof(SpriteVertex, xy) // offset in array + ); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, // location 1 in the shader + 2, // 2 floats per vert + GL_FLOAT, // floats + GL_FALSE, // don't normalize, ignored + sizeof(SpriteVertex), // + (void*)offsetof(SpriteVertex, st) // offset in array + ); + + // Done + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +void DepthCue::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) { + // First thing should be a NEXT with two nops. this is a jump from buckets to depth-cue + auto data0 = dma.read_and_advance(); + ASSERT(data0.vif1() == 0); + ASSERT(data0.vif0() == 0); + ASSERT(data0.size_bytes == 0); + + if (dma.current_tag().kind == DmaTag::Kind::CALL) { + // depth-cue renderer didn't run, let's just get out of here. + for (int i = 0; i < 4; i++) { + dma.read_and_advance(); + } + ASSERT(dma.current_tag_offset() == render_state->next_bucket); + return; + } + + // Read DMA + { + auto prof_node = prof.make_scoped_child("dma"); + read_dma(dma, render_state, prof_node); + } + + if (!m_enabled) { + // Renderer disabled, stop early + return; + } + + // Set up draw info + { + auto prof_node = prof.make_scoped_child("setup"); + setup(render_state, prof_node); + } + + // Draw + { + auto prof_node = prof.make_scoped_child("drawing"); + draw(render_state, prof_node); + } +} + +/*! + * Reads all depth-cue DMA packets. + */ +void DepthCue::read_dma(DmaFollower& dma, + SharedRenderState* render_state, + ScopedProfilerNode& /*prof*/) { + // First should be general GS register setup + { + auto gs_setup = dma.read_and_advance(); + ASSERT(gs_setup.size_bytes == sizeof(DepthCueGsSetup)); + ASSERT(gs_setup.vifcode0().kind == VifCode::Kind::NOP); + ASSERT(gs_setup.vifcode1().kind == VifCode::Kind::DIRECT); + memcpy(&m_gs_setup, gs_setup.data, sizeof(DepthCueGsSetup)); + + ASSERT(m_gs_setup.gif_tag.nreg() == 6); + ASSERT(m_gs_setup.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD); + + ASSERT(m_gs_setup.test1.ztest() == GsTest::ZTest::ALWAYS); + ASSERT(m_gs_setup.zbuf1.zmsk() == true); + ASSERT(m_gs_setup.tex1.mmag() == true); + ASSERT(m_gs_setup.tex1.mmin() == 1); + ASSERT(m_gs_setup.miptbp1 == 0); + ASSERT(m_gs_setup.alpha1.b_mode() == GsAlpha::BlendMode::DEST); + ASSERT(m_gs_setup.alpha1.d_mode() == GsAlpha::BlendMode::DEST); + } + + // Next is 64 DMAs to draw to the depth-cue-base-page and back to the on-screen framebuffer + // We'll group these by each slice of the framebuffer being drawn to + for (int i = 0; i < TOTAL_DRAW_SLICES; i++) { + // Each 'slice' should be: + // 1. GS setup for drawing from on-screen framebuffer to depth-cue-base-page + // 2. Draw to depth-cue-base-page + // 3. GS setup for drawing from depth-cue-base-page back to on-screen framebuffer + // 4. Draw to on-screen framebuffer + DrawSlice& slice = m_draw_slices.at(i); + + // depth-cue-base-page setup + { + auto depth_cue_page_setup = dma.read_and_advance(); + ASSERT(depth_cue_page_setup.size_bytes == sizeof(DepthCuePageGsSetup)); + ASSERT(depth_cue_page_setup.vifcode0().kind == VifCode::Kind::NOP); + ASSERT(depth_cue_page_setup.vifcode1().kind == VifCode::Kind::DIRECT); + memcpy(&slice.depth_cue_page_setup, depth_cue_page_setup.data, sizeof(DepthCuePageGsSetup)); + + ASSERT(slice.depth_cue_page_setup.gif_tag.nreg() == 5); + ASSERT(slice.depth_cue_page_setup.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD); + + ASSERT(slice.depth_cue_page_setup.tex01.tcc() == 1); + ASSERT(slice.depth_cue_page_setup.test1.ztest() == GsTest::ZTest::ALWAYS); + ASSERT(slice.depth_cue_page_setup.alpha1.b_mode() == GsAlpha::BlendMode::SOURCE); + ASSERT(slice.depth_cue_page_setup.alpha1.d_mode() == GsAlpha::BlendMode::SOURCE); + } + + // depth-cue-base-page draw + { + auto depth_cue_page_draw = dma.read_and_advance(); + ASSERT(depth_cue_page_draw.size_bytes == sizeof(DepthCuePageDraw)); + ASSERT(depth_cue_page_draw.vifcode0().kind == VifCode::Kind::NOP); + ASSERT(depth_cue_page_draw.vifcode1().kind == VifCode::Kind::DIRECT); + memcpy(&slice.depth_cue_page_draw, depth_cue_page_draw.data, sizeof(DepthCuePageDraw)); + + ASSERT(slice.depth_cue_page_draw.gif_tag.nloop() == 1); + ASSERT(slice.depth_cue_page_draw.gif_tag.pre() == true); + ASSERT(slice.depth_cue_page_draw.gif_tag.prim() == 6); + ASSERT(slice.depth_cue_page_draw.gif_tag.flg() == GifTag::Format::PACKED); + ASSERT(slice.depth_cue_page_draw.gif_tag.nreg() == 5); + ASSERT(slice.depth_cue_page_draw.gif_tag.reg(0) == GifTag::RegisterDescriptor::RGBAQ); + } + + // on-screen setup + { + auto on_screen_setup = dma.read_and_advance(); + ASSERT(on_screen_setup.size_bytes == sizeof(OnScreenGsSetup)); + ASSERT(on_screen_setup.vifcode0().kind == VifCode::Kind::NOP); + ASSERT(on_screen_setup.vifcode1().kind == VifCode::Kind::DIRECT); + memcpy(&slice.on_screen_setup, on_screen_setup.data, sizeof(OnScreenGsSetup)); + + ASSERT(slice.on_screen_setup.gif_tag.nreg() == 5); + ASSERT(slice.on_screen_setup.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD); + + ASSERT(slice.on_screen_setup.tex01.tcc() == 0); + ASSERT(slice.on_screen_setup.texa.ta0() == 0x80); + ASSERT(slice.on_screen_setup.texa.ta1() == 0x80); + ASSERT(slice.on_screen_setup.alpha1.b_mode() == GsAlpha::BlendMode::DEST); + ASSERT(slice.on_screen_setup.alpha1.d_mode() == GsAlpha::BlendMode::DEST); + } + + // on-screen draw + { + auto on_screen_draw = dma.read_and_advance(); + ASSERT(on_screen_draw.size_bytes == sizeof(OnScreenDraw)); + ASSERT(on_screen_draw.vifcode0().kind == VifCode::Kind::NOP); + ASSERT(on_screen_draw.vifcode1().kind == VifCode::Kind::DIRECT); + memcpy(&slice.on_screen_draw, on_screen_draw.data, sizeof(OnScreenDraw)); + + ASSERT(slice.on_screen_draw.gif_tag.nloop() == 1); + ASSERT(slice.on_screen_draw.gif_tag.pre() == true); + ASSERT(slice.on_screen_draw.gif_tag.prim() == 6); + ASSERT(slice.on_screen_draw.gif_tag.flg() == GifTag::Format::PACKED); + ASSERT(slice.on_screen_draw.gif_tag.nreg() == 5); + ASSERT(slice.on_screen_draw.gif_tag.reg(0) == GifTag::RegisterDescriptor::RGBAQ); + } + } + + // Finally, a packet to restore GS state + { + auto gs_restore = dma.read_and_advance(); + ASSERT(gs_restore.size_bytes == sizeof(DepthCueGsRestore)); + ASSERT(gs_restore.vifcode0().kind == VifCode::Kind::NOP); + ASSERT(gs_restore.vifcode1().kind == VifCode::Kind::DIRECT); + memcpy(&m_gs_restore, gs_restore.data, sizeof(DepthCueGsRestore)); + + ASSERT(m_gs_restore.gif_tag.nreg() == 2); + ASSERT(m_gs_restore.gif_tag.reg(0) == GifTag::RegisterDescriptor::AD); + } + + // End with 'NEXT' + { + ASSERT(dma.current_tag().kind == DmaTag::Kind::NEXT); + + while (dma.current_tag_offset() != render_state->next_bucket) { + dma.read_and_advance(); + } + } +} + +void DepthCue::setup(SharedRenderState* render_state, ScopedProfilerNode& /*prof*/) { + if (m_debug.cache_setup && (m_ogl.last_draw_region_w == render_state->draw_region_w && + m_ogl.last_draw_region_h == render_state->draw_region_h && + // Also recompute when certain debug settings change + m_ogl.last_override_sharpness == m_debug.override_sharpness && + m_ogl.last_custom_sharpness == m_debug.sharpness && + m_ogl.last_force_original_res == m_debug.force_original_res && + m_ogl.last_res_scale == m_debug.res_scale)) { + // Draw region didn't change, everything is already set up + return; + } + + m_ogl.last_draw_region_w = render_state->draw_region_w; + m_ogl.last_draw_region_h = render_state->draw_region_h; + m_ogl.last_override_sharpness = m_debug.override_sharpness; + m_ogl.last_custom_sharpness = m_debug.sharpness; + m_ogl.last_force_original_res = m_debug.force_original_res; + m_ogl.last_res_scale = m_debug.res_scale; + + // ASSUMPTIONS + // -------------------------- + // Assert some assumptions that most of the data for each depth-cue draw is the same. + // The way the game wants to render this effect is very inefficient in OpenGL, we can use these + // assumptions to only alter state once, do setup once, and group multiple draw calls. + const DrawSlice& first_slice = m_draw_slices[0]; + + // 1. Assume each draw slice has the exact same width of 32 + // We'll compare each slice to the first as we go + float slice_width = fixed_to_floating_point(first_slice.on_screen_draw.xyzf2_2.x() - + first_slice.on_screen_draw.xyzf2_1.x()); + // NOTE: Y-coords will range between [0,1/2 output res], usually 224 but not always. + // We'll capture it here so we can convert to coords to [0,1] ranges later. + float slice_height = fixed_to_floating_point(first_slice.on_screen_draw.xyzf2_2.y()); + + ASSERT(slice_width == 32.0f); + ASSERT(first_slice.on_screen_draw.xyzf2_1.y() == 0); + + // 2. Assume that the framebuffer is sampled as a 1024x256 texel view and that the game thinks the + // framebuffer is 512 pixels wide. + int fb_sample_width = (int)pow(2, first_slice.depth_cue_page_setup.tex01.tw()); + int fb_sample_height = (int)pow(2, first_slice.depth_cue_page_setup.tex01.th()); + int fb_width = first_slice.depth_cue_page_setup.tex01.tbw() * 64; + + ASSERT(fb_sample_width == 1024); + ASSERT(fb_sample_height == 256); + ASSERT(fb_width == 512); + ASSERT(fb_width * 2 == fb_sample_width); + + // 3. Finally, assert that all slices match the above assumptions + for (const DrawSlice& slice : m_draw_slices) { + float _slice_width = fixed_to_floating_point(slice.on_screen_draw.xyzf2_2.x() - + slice.on_screen_draw.xyzf2_1.x()); + float _slice_height = fixed_to_floating_point(slice.on_screen_draw.xyzf2_2.y()); + + ASSERT(slice_width == _slice_width); + ASSERT(slice_height == _slice_height); + ASSERT(slice.on_screen_draw.xyzf2_1.y() == 0); + + int _fb_sample_width = (int)pow(2, slice.depth_cue_page_setup.tex01.tw()); + int _fb_sample_height = (int)pow(2, slice.depth_cue_page_setup.tex01.th()); + int _fb_width = slice.depth_cue_page_setup.tex01.tbw() * 64; + + ASSERT(fb_sample_width == _fb_sample_width); + ASSERT(fb_sample_height == _fb_sample_height); + ASSERT(fb_width == _fb_width); + } + + // FRAMEBUFFER SAMPLE TEXTURE + // -------------------------- + // We need a copy of the framebuffer to sample from. If the framebuffer wasn't using + // multisampling, this wouldn't be necessary and the framebuffer could just be bound. Instead, + // we'll just blit to a new texture. + // + // The original game code would have created this as a view into the framebuffer whose width is 2x + // as large, however this isn't necessary for the effect to work. + int pc_fb_sample_width = render_state->draw_region_w; + int pc_fb_sample_height = render_state->draw_region_h; + + m_ogl.framebuffer_sample_width = pc_fb_sample_width; + m_ogl.framebuffer_sample_height = pc_fb_sample_height; + + glBindTexture(GL_TEXTURE_2D, m_ogl.framebuffer_sample_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pc_fb_sample_width, pc_fb_sample_height, 0, GL_RGB, + GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + // DEPTH CUE BASE PAGE FRAMEBUFFER + // -------------------------- + // Next, we need a framebuffer to draw slices of the sample texture to. The depth-cue effect + // usually does this in 16 vertical slices that are 32 pixels wide each. The destination + // drawn to is smaller than the source by a very small amount (defined by sharpness in the + // GOAL code), which kicks in the bilinear filtering effect. Normally, a 32x224 texture will + // be reused for each slice but for the sake of efficient rendering, we'll create a framebuffer + // that can store all 16 slices side-by-side and draw all slices to it all at once. + int pc_depth_cue_fb_width = render_state->draw_region_w; + int pc_depth_cue_fb_height = render_state->draw_region_h; + + if (m_debug.force_original_res) { + pc_depth_cue_fb_width = 512; + } + + pc_depth_cue_fb_width *= m_debug.res_scale; + + m_ogl.fbo_width = pc_depth_cue_fb_width; + m_ogl.fbo_height = pc_depth_cue_fb_height; + + glBindTexture(GL_TEXTURE_2D, m_ogl.fbo_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pc_depth_cue_fb_width, pc_depth_cue_fb_height, 0, GL_RGB, + GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + // DEPTH CUE BASE PAGE VERTEX DATA + // -------------------------- + // Now that we have a framebuffer to draw each slice to, we need the actual vertex data. + // We'll take the exact data DMA'd and scale it up the PC dimensions. + std::vector depth_cue_page_vertices; + + // U-coordinates here will range from [0,512], but the maximum U value in the original is + // 1024 since the sample texel width is usually 1024. Since we're not using a texture with + // 2x the width, the maximum U value used to convert UVs to [0,1] should be 512. + float max_u = fb_sample_width / 2.0f; + ASSERT(max_u == 512.0f); + + for (const auto& slice : m_draw_slices) { + math::Vector2f xyoffset = fixed_to_floating_point( + math::Vector2((s32)slice.depth_cue_page_setup.xyoffset1.ofx(), + (s32)slice.depth_cue_page_setup.xyoffset1.ofy())); + + math::Vector2f xy1 = fixed_to_floating_point(slice.depth_cue_page_draw.xyzf2_1.xy()); + math::Vector2f xy2 = fixed_to_floating_point(slice.depth_cue_page_draw.xyzf2_2.xy()); + math::Vector2f uv1 = fixed_to_floating_point(slice.depth_cue_page_draw.uv_1.xy()); + math::Vector2f uv2 = fixed_to_floating_point(slice.depth_cue_page_draw.uv_2.xy()); + + ASSERT(xy1.x() == 0); + ASSERT(xy1.y() == 0); + ASSERT(xy2.x() <= 32.0f); + ASSERT(xy2.y() <= slice_height); + + if (m_debug.override_sharpness) { + // Undo sharpness from GOAL code and apply custom + xy2.x() = 32.0f * m_debug.sharpness; + xy2.y() = 224.0f * m_debug.sharpness; + } + + // Apply xyoffset GS register + xy1.x() += xyoffset.x() / 4096.0f; + xy1.y() += xyoffset.y() / 4096.0f; + xy2.x() += xyoffset.x() / 4096.0f; + xy2.y() += xyoffset.y() / 4096.0f; + + // U-coord will range from [0,512], which is half of the original framebuffer sample width + // Let's also use it to determine the X offset into the depth-cue framebuffer since the + // original draw assumes each slice is at 0,0. + float x_offset = (uv1.x() / 512.0f) * (xy2.x() / 32.0f); + + build_sprite(depth_cue_page_vertices, + // Top-left + (xy1.x() / 512.0f) + x_offset, // x1 + xy1.y() / slice_height, // y1 + uv1.x() / max_u, // s1 + uv1.y() / slice_height, // t1 + // Bottom-right + (xy2.x() / 512.0f) + x_offset, // x2 + xy2.y() / slice_height, // y2 + uv2.x() / max_u, // s2 + uv2.y() / slice_height // t2 + ); + } + + glBindBuffer(GL_ARRAY_BUFFER, m_ogl.depth_cue_page_vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, depth_cue_page_vertices.size() * sizeof(SpriteVertex), + depth_cue_page_vertices.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // ON SCREEN VERTEX DATA + // -------------------------- + // Finally, we need to draw pixels from the depth-cue-base-page back to the on-screen + // framebuffer. We'll take the same approach as above. + std::vector on_screen_vertices; + + for (const auto& slice : m_draw_slices) { + math::Vector2f xyoffset = fixed_to_floating_point(math::Vector2( + (s32)slice.on_screen_setup.xyoffset1.ofx(), (s32)slice.on_screen_setup.xyoffset1.ofy())); + + math::Vector2f xy1 = fixed_to_floating_point(slice.on_screen_draw.xyzf2_1.xy()); + math::Vector2f xy2 = fixed_to_floating_point(slice.on_screen_draw.xyzf2_2.xy()); + math::Vector2f uv1 = fixed_to_floating_point(slice.on_screen_draw.uv_1.xy()); + math::Vector2f uv2 = fixed_to_floating_point(slice.on_screen_draw.uv_2.xy()); + + ASSERT(uv1.x() == 0); + ASSERT(uv1.y() == 0); + ASSERT(uv2.x() <= 32.0f); + ASSERT(uv2.y() <= slice_height); + + if (m_debug.override_sharpness) { + // Undo sharpness from GOAL code and apply custom + uv2.x() = 32.0f * m_debug.sharpness; + uv2.y() = 224.0f * m_debug.sharpness; + } + + // Apply xyoffset GS register + xy1.x() += xyoffset.x() / 4096.0f; + xy1.y() += xyoffset.y() / 4096.0f; + xy2.x() += xyoffset.x() / 4096.0f; + xy2.y() += xyoffset.y() / 4096.0f; + + // X-coord will range from [0,512], which is half of the original framebuffer sample width + // Let's also use it to determine the U offset into the on-screen framebuffer since the + // original draw assumes each slice is at 0,0. + float u_offset = (xy1.x() / 512.0f) * (uv2.x() / 32.0f); + + build_sprite(on_screen_vertices, + // Top-left + xy1.x() / 512.0f, // x1 + xy1.y() / slice_height, // y1 + (uv1.x() / 512.0f) + u_offset, // s1 + uv1.y() / slice_height, // t1 + // Bottom-right + xy2.x() / 512.0f, // x2 + xy2.y() / slice_height, // y2 + (uv2.x() / 512.0f) + u_offset, // s2 + uv2.y() / slice_height // t2 + ); + } + + glBindBuffer(GL_ARRAY_BUFFER, m_ogl.on_screen_vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, on_screen_vertices.size() * sizeof(SpriteVertex), + on_screen_vertices.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void DepthCue::draw(SharedRenderState* render_state, ScopedProfilerNode& prof) { + // Disable depth writing but keep test + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + // Activate shader + auto shader = &render_state->shaders[ShaderId::DEPTH_CUE]; + shader->activate(); + + glUniform1i(glGetUniformLocation(shader->id(), "tex"), 0); + + // First, we need to copy the framebuffer into the framebuffer sample texture + glBindFramebuffer(GL_READ_FRAMEBUFFER, render_state->render_fb); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_ogl.framebuffer_sample_fbo); + + glBlitFramebuffer(render_state->draw_offset_x, // srcX0 + render_state->draw_offset_y, // srcY0 + render_state->draw_offset_x + render_state->draw_region_w, // srcX1 + render_state->draw_offset_y + render_state->draw_region_h, // srcY1 + 0, // dstX0 + 0, // dstY0 + m_ogl.framebuffer_sample_width, // dstX1 + m_ogl.framebuffer_sample_height, // dstY1 + GL_COLOR_BUFFER_BIT, // mask + GL_NEAREST // filter + ); + + glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb); + + // Next, we need to draw from the framebuffer sample texture to the depth-cue-base-page + // framebuffer + { + const auto& depth_cue_page_draw = m_draw_slices[0].depth_cue_page_draw; + + math::Vector4f colorf = math::Vector4f( + depth_cue_page_draw.rgbaq.x() / 255.0f, depth_cue_page_draw.rgbaq.y() / 255.0f, + depth_cue_page_draw.rgbaq.z() / 255.0f, depth_cue_page_draw.rgbaq.w() / 255.0f); + glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data()); + + glUniform1f(glGetUniformLocation(shader->id(), "u_depth"), 1.0f); + + glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.fbo); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_ogl.framebuffer_sample_tex); + + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ZERO); + + glViewport(0, 0, m_ogl.fbo_width, m_ogl.fbo_height); + + prof.add_draw_call(); + prof.add_tri(2 * TOTAL_DRAW_SLICES); + + glBindVertexArray(m_ogl.depth_cue_page_vao); + glDrawArrays(GL_TRIANGLES, 0, 6 * TOTAL_DRAW_SLICES); // 6 verts per slice + } + + // Finally, the contents of depth-cue-base-page need to be overlayed onto the on-screen + // framebuffer + { + const auto& on_screen_draw = m_draw_slices[0].on_screen_draw; + + math::Vector4f colorf = + math::Vector4f(on_screen_draw.rgbaq.x() / 255.0f, on_screen_draw.rgbaq.y() / 255.0f, + on_screen_draw.rgbaq.z() / 255.0f, on_screen_draw.rgbaq.w() / 255.0f); + if (m_debug.override_alpha) { + colorf.w() = m_debug.draw_alpha / 2.0f; + } + glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data()); + + if (m_debug.depth == 1.0f) { + glUniform1f(glGetUniformLocation(shader->id(), "u_depth"), m_debug.depth); + } else { + // Scale debug depth expontentially to make the slider easier to use + glUniform1f(glGetUniformLocation(shader->id(), "u_depth"), pow(m_debug.depth, 8)); + } + + glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_ogl.fbo_texture); + + glBlendEquation(GL_FUNC_ADD); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + + glViewport(render_state->draw_offset_x, render_state->draw_offset_y, + render_state->draw_region_w, render_state->draw_region_h); + + prof.add_draw_call(); + prof.add_tri(2 * TOTAL_DRAW_SLICES); + + glBindVertexArray(m_ogl.on_screen_vao); + glDrawArrays(GL_TRIANGLES, 0, 6 * TOTAL_DRAW_SLICES); // 6 verts per slice + } + + // Done + glDepthMask(GL_TRUE); + glBindTexture(GL_TEXTURE_2D, 0); + glBindVertexArray(0); +} + +void DepthCue::build_sprite(std::vector& vertices, + float x1, + float y1, + float s1, + float t1, + float x2, + float y2, + float s2, + float t2) { + // First triangle + // ------------- + // Top-left + vertices.push_back(SpriteVertex(x1, y1, s1, t1)); + + // Top-right + vertices.push_back(SpriteVertex(x2, y1, s2, t1)); + + // Bottom-left + vertices.push_back(SpriteVertex(x1, y2, s1, t2)); + + // Second triangle + // ------------- + // Top-right + vertices.push_back(SpriteVertex(x2, y1, s2, t1)); + + // Bottom-left + vertices.push_back(SpriteVertex(x1, y2, s1, t2)); + + // Bottom-right + vertices.push_back(SpriteVertex(x2, y2, s2, t2)); +} + +void DepthCue::draw_debug_window() { + ImGui::Text("NOTE: depth-cue may be disabled by '*vu1-enable-user-menu*'!"); + + ImGui::Checkbox("Cache setup", &m_debug.cache_setup); + ImGui::Checkbox("Force original resolution", &m_debug.force_original_res); + + ImGui::Checkbox("Override alpha", &m_debug.override_alpha); + if (m_debug.override_alpha) { + ImGui::SliderFloat("Alpha", &m_debug.draw_alpha, 0.0f, 1.0f); + } + + ImGui::Checkbox("Override sharpness", &m_debug.override_sharpness); + if (m_debug.override_sharpness) { + ImGui::SliderFloat("Sharpness", &m_debug.sharpness, 0.001f, 1.0f); + } + + ImGui::SliderFloat("Depth", &m_debug.depth, 0.0f, 1.0f); + ImGui::SliderFloat("Resolution scale", &m_debug.res_scale, 0.001f, 2.0f); + + if (ImGui::Button("Reset")) { + m_debug.draw_alpha = 0.4f; + m_debug.sharpness = 0.999f; + m_debug.depth = 1.0f; + m_debug.res_scale = 1.0f; + } +} diff --git a/game/graphics/opengl_renderer/DepthCue.h b/game/graphics/opengl_renderer/DepthCue.h new file mode 100644 index 000000000..f06e46e6a --- /dev/null +++ b/game/graphics/opengl_renderer/DepthCue.h @@ -0,0 +1,183 @@ +#pragma once + +#include "common/dma/gs.h" +#include "common/math/Vector.h" + +#include "game/graphics/opengl_renderer/BucketRenderer.h" + +class DepthCue : public BucketRenderer { + public: + DepthCue(const std::string& name, BucketId my_id); + void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; + void draw_debug_window() override; + + private: + // One-time initial GS setup per frame + struct DepthCueGsSetup { + GifTag gif_tag; + GsTest test1; + u64 test1_addr; + GsZbuf zbuf1; + u64 zbuf1_addr; + GsTex1 tex1; + u64 tex1_addr; + u64 miptbp1; + u64 miptbp1_addr; + u64 clamp1; + u64 clamp1_addr; + GsAlpha alpha1; + u64 alpha1_addr; + }; + static_assert(sizeof(DepthCueGsSetup) == (7 * 16)); + + // One-time GS state restoration at the end of each depth-cue frame + struct DepthCueGsRestore { + GifTag gif_tag; + u64 xyoffset1; + u64 xyoffset1_addr; + GsFrame frame1; + u64 frame1_addr; + }; + static_assert(sizeof(DepthCueGsRestore) == (3 * 16)); + + // GS setup for drawing to the depth-cue-base-page framebuffer + struct DepthCuePageGsSetup { + GifTag gif_tag; + GsXYOffset xyoffset1; + u64 xyoffset1_addr; + GsFrame frame1; + u64 frame1_addr; + GsTex0 tex01; + u64 tex01_addr; + GsTest test1; + u64 test1_addr; + GsAlpha alpha1; + u64 alpha1_addr; + }; + static_assert(sizeof(DepthCuePageGsSetup) == (6 * 16)); + + // GS setup for drawing to the on-screen framebuffer + struct OnScreenGsSetup { + GifTag gif_tag; + GsXYOffset xyoffset1; + u64 xyoffset1_addr; + GsFrame frame1; + u64 frame1_addr; + GsTexa texa; + u64 texa_addr; + GsTex0 tex01; + u64 tex01_addr; + GsAlpha alpha1; + u64 alpha1_addr; + }; + static_assert(sizeof(OnScreenGsSetup) == (6 * 16)); + + // Sprite draw command to the depth-cue-base-page framebuffer + struct DepthCuePageDraw { + GifTag gif_tag; + math::Vector4 rgbaq; + math::Vector4 uv_1; + math::Vector4 xyzf2_1; + math::Vector4 uv_2; + math::Vector4 xyzf2_2; + }; + static_assert(sizeof(DepthCuePageDraw) == (6 * 16)); + + // Sprite draw command to the on-screen framebuffer + struct OnScreenDraw { + GifTag gif_tag; + math::Vector4 rgbaq; + math::Vector4 uv_1; + math::Vector4 xyzf2_1; + math::Vector4 uv_2; + math::Vector4 xyzf2_2; + }; + static_assert(sizeof(OnScreenDraw) == (6 * 16)); + + // A draw to the depth-cue-base-page and then back to the on-screen framebuffer. + // + // This is done 16 times per frame across the entire on-screen framebuffer in vertical strips. + struct DrawSlice { + DepthCuePageGsSetup depth_cue_page_setup; + DepthCuePageDraw depth_cue_page_draw; + OnScreenGsSetup on_screen_setup; + OnScreenDraw on_screen_draw; + }; + + struct SpriteVertex { + math::Vector2f xy; + math::Vector2f st; + + SpriteVertex() = default; + SpriteVertex(float x, float y, float s, float t) : xy(x, y), st(s, t) {} + }; + + DepthCueGsSetup m_gs_setup; + DepthCueGsRestore m_gs_restore; + std::vector m_draw_slices; + + struct { + // Framebuffer for depth-cue-base-page + GLuint fbo; + GLuint fbo_texture; + int fbo_width = 0; + int fbo_height = 0; + + // Vertex data for drawing to depth-cue-base-page + GLuint depth_cue_page_vao; + GLuint depth_cue_page_vertex_buffer; + + // Vertex data for drawing to on-screen framebuffer + GLuint on_screen_vao; + GLuint on_screen_vertex_buffer; + + // Texture to sample the framebuffer from + GLuint framebuffer_sample_fbo; + GLuint framebuffer_sample_tex; + int framebuffer_sample_width = 0; + int framebuffer_sample_height = 0; + + int last_draw_region_w = -1; + int last_draw_region_h = -1; + bool last_override_sharpness = false; + float last_custom_sharpness = 0.999f; + bool last_force_original_res = false; + float last_res_scale = 1.0f; + } m_ogl; + + struct { + // false = recompute setup each frame + // true = only recompute setup when draw dimensions change + bool cache_setup = true; + // true = render depth-cue at original 512px wide resolution + bool force_original_res = false; + // true = render with m_draw_alpha alpha + bool override_alpha = false; + // 0.4 = default in GOAL + float draw_alpha = 0.4f; + // true = render with m_sharpness sharpness + bool override_sharpness = false; + // 1.0 = pixel perfect, depth-cue has no effect + // 0.999 = default in GOAL + float sharpness = 0.999f; + // lower to have effect only apply to further away pixels + // 1.0 = default (apply to all) + float depth = 1.0f; + // depth-cue resolution multiplier + float res_scale = 1.0f; + } m_debug; + + void opengl_setup(); + void read_dma(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof); + void setup(SharedRenderState* render_state, ScopedProfilerNode& prof); + void draw(SharedRenderState* render_state, ScopedProfilerNode& prof); + void build_sprite(std::vector& vertices, + float x1, + float y1, + float x2, + float y2, + float s1, + float t1, + float s2, + float t2); +}; diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 542e6f737..2cfb22721 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -3,6 +3,7 @@ #include "common/log/log.h" #include "common/util/FileUtil.h" +#include "game/graphics/opengl_renderer/DepthCue.h" #include "game/graphics/opengl_renderer/DirectRenderer.h" #include "game/graphics/opengl_renderer/EyeRenderer.h" #include "game/graphics/opengl_renderer/ShadowRenderer.h" @@ -256,7 +257,11 @@ void OpenGLRenderer::init_bucket_renderers() { BucketId::GENERIC_WATER_LEVEL1); // 62 init_bucket_renderer("ocean-near", BucketCategory::OCEAN, BucketId::OCEAN_NEAR); // 63 - // 64? + + //----------------------- + // DEPTH CUE + //----------------------- + init_bucket_renderer("depth-cue", BucketCategory::OTHER, BucketId::DEPTH_CUE); // 64 //----------------------- // COMMON texture diff --git a/game/graphics/opengl_renderer/Shader.cpp b/game/graphics/opengl_renderer/Shader.cpp index a129abcb0..044429994 100644 --- a/game/graphics/opengl_renderer/Shader.cpp +++ b/game/graphics/opengl_renderer/Shader.cpp @@ -90,6 +90,7 @@ ShaderLibrary::ShaderLibrary() { at(ShaderId::SPRITE_DISTORT) = {"sprite_distort"}; at(ShaderId::SPRITE_DISTORT_INSTANCED) = {"sprite_distort_instanced"}; at(ShaderId::POST_PROCESSING) = {"post_processing"}; + at(ShaderId::DEPTH_CUE) = {"depth_cue"}; for (auto& shader : m_shaders) { ASSERT_MSG(shader.okay(), "Shader compiled"); diff --git a/game/graphics/opengl_renderer/Shader.h b/game/graphics/opengl_renderer/Shader.h index e05eb4534..7e1fdbeda 100644 --- a/game/graphics/opengl_renderer/Shader.h +++ b/game/graphics/opengl_renderer/Shader.h @@ -45,6 +45,7 @@ enum class ShaderId { SPRITE_DISTORT = 20, SPRITE_DISTORT_INSTANCED = 21, POST_PROCESSING = 22, + DEPTH_CUE = 23, MAX_SHADERS }; diff --git a/game/graphics/opengl_renderer/buckets.h b/game/graphics/opengl_renderer/buckets.h index 676bd885b..c9aec4222 100644 --- a/game/graphics/opengl_renderer/buckets.h +++ b/game/graphics/opengl_renderer/buckets.h @@ -67,7 +67,7 @@ enum class BucketId { MERC_WATER_LEVEL1 = 61, GENERIC_WATER_LEVEL1 = 62, OCEAN_NEAR = 63, - // 64 + DEPTH_CUE = 64, PRE_SPRITE_TEX = 65, // maybe it's just common textures? SPRITE = 66, DEBUG = 67, diff --git a/game/graphics/opengl_renderer/shaders/depth_cue.frag b/game/graphics/opengl_renderer/shaders/depth_cue.frag new file mode 100644 index 000000000..03b3f3d5e --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/depth_cue.frag @@ -0,0 +1,13 @@ +#version 430 core + +in flat vec4 fragment_color; +in vec2 tex_coord; + +uniform sampler2D tex; + +out vec4 out_color; + +void main() { + // sample texture + out_color = fragment_color * texture(tex, tex_coord); +} diff --git a/game/graphics/opengl_renderer/shaders/depth_cue.vert b/game/graphics/opengl_renderer/shaders/depth_cue.vert new file mode 100644 index 000000000..b22bd72f4 --- /dev/null +++ b/game/graphics/opengl_renderer/shaders/depth_cue.vert @@ -0,0 +1,27 @@ +#version 430 core + +layout (location = 0) in vec2 xy; +layout (location = 1) in vec2 st; + +uniform vec4 u_color; +uniform float u_depth; + +out flat vec4 fragment_color; +out vec2 tex_coord; + +void main() { + // Calculate color + vec4 color = u_color; + color *= 2; // correct + + fragment_color = color; + + // Pass on texture coord + tex_coord = st; + + // Calculate vertex position + vec4 position = vec4(xy.x, xy.y, u_depth, 1.0); + position.xyz = (position.xyz * 2) - 1.0; // convert from [0,1] to clip-space + + gl_Position = position; +} diff --git a/goal_src/jak1/engine/game/main.gc b/goal_src/jak1/engine/game/main.gc index 047d1ffb6..c7d192b6a 100644 --- a/goal_src/jak1/engine/game/main.gc +++ b/goal_src/jak1/engine/game/main.gc @@ -714,6 +714,10 @@ ) ;; depth cue + (if (not *progress-process*) + (depth-cue disp) + ) + ;; screen filter (with-profiler "post-sync-draw" diff --git a/goal_src/jak1/engine/gfx/depth-cue.gc b/goal_src/jak1/engine/gfx/depth-cue.gc index 0625dfecc..59f4fd167 100644 --- a/goal_src/jak1/engine/gfx/depth-cue.gc +++ b/goal_src/jak1/engine/gfx/depth-cue.gc @@ -14,14 +14,42 @@ :dma (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)) :vif1 (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1) ) - :gif (new 'static 'array uint64 2 #x50ab400000008001 #x43431) + :gif0 (new 'static 'gif-tag64 + :nloop 1 + :eop 1 + :pre 1 + :prim (gs-prim-type sprite) ;; actually #b001101010110 + :flg (gif-flag packed) + :nreg 5 + ) + :gif1 (new 'static 'gif-tag-regs + :regs0 (gif-reg-id rgbaq) + :regs1 (gif-reg-id uv) + :regs2 (gif-reg-id xyzf2) + :regs3 (gif-reg-id uv) + :regs4 (gif-reg-id xyzf2) + ) ) :temp-strip-tmpl (new 'static 'dma-gif-packet :dma-vif (new 'static 'dma-packet :dma (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt)) :vif1 (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1) ) - :gif (new 'static 'array uint64 2 #x508b400000008001 #x43431) + :gif0 (new 'static 'gif-tag64 + :nloop 1 + :eop 1 + :pre 1 + :prim (gs-prim-type sprite) ;; actually #b00100010110 + :flg (gif-flag packed) + :nreg 5 + ) + :gif1 (new 'static 'gif-tag-regs + :regs0 (gif-reg-id rgbaq) + :regs1 (gif-reg-id uv) + :regs2 (gif-reg-id xyzf2) + :regs3 (gif-reg-id uv) + :regs4 (gif-reg-id xyzf2) + ) ) :stencil-tmpl (new 'static 'dma-gif-packet :dma-vif (new 'static 'dma-packet @@ -255,145 +283,93 @@ #f ) -(defun depth-cue-draw-front ((arg0 dma-buffer) (arg1 int) (arg2 float) (arg3 float) (arg4 uint) (arg5 int)) - (set! (-> *depth-cue-work* draw-color w) (the int (* 128.0 arg3))) - (let ((v1-1 (the int (* 512.0 arg2))) - (a2-1 (the int (* (the float (* (-> *video-parms* screen-sy) 16)) arg2))) - (a3-4 0) - (t2-0 512) - (t3-0 *depth-cue-base-page*) +(defun depth-cue-draw-front ((dma-buff dma-buffer) (depth int) (sharpness float) (alpha float) (on-screen-fbp uint) (oddeven int)) + ;; set draw-color alpha + (set! (-> *depth-cue-work* draw-color w) (the int (* 128.0 alpha))) + + ;; sample the framebuffer in 16 vertical strips shrinking each a little, + ;; then overlay them back onto the framebuffer + (let ((strip-w (the int (* 512.0 sharpness))) + (strip-h (the int (* (the float (* (-> *video-parms* screen-sy) 16)) sharpness))) + (x-offset 0) ;; incremented by 512 each loop + (strip-max-w 512) ) - (dotimes (t4-0 16) - (let* ((t5-0 arg0) - (t6-0 (the-as object (-> t5-0 base))) - ) - (set! (-> (the-as dma-packet t6-0) dma) (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet t6-0) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet t6-0) vif1) (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> t5-0 base) (the-as pointer (the-as gs-gif-tag (&+ (the-as pointer t6-0) 16)))) + ;; repeat for each strip + (dotimes (i 16) + ;; sample strip from framebuffer to depth-cue-base-page + ;; ------------------------------------------------------ + ;; update GS registers + (dma-buffer-add-gs-set dma-buff + ;; set vertex position offset + (xyoffset-1 (new 'static 'gs-xy-offset :ofy (- 8 oddeven))) + ;; draw to depth-cue-base-page (64px wide) + (frame-1 (new 'static 'gs-frame :fbw #x1 :fbp *depth-cue-base-page*)) + ;; use on-screen framebuffer as texture 0 + ;; buffer width = 512 pixels + ;; USIZE = 1024 texels + ;; VSIZE = 256 texels + ;; RGBA + (tex0-1 (new 'static 'gs-tex0 :tbw #x8 :tw #xa :th #x8 :tcc #x1 :tbp0 (* on-screen-fbp 32))) + ;; enable depth test, all pixels pass + (test-1 (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always))) + ;; keep source rgb, no blending + (alpha-1 (new 'static 'gs-alpha)) ) - (let* ((t5-1 arg0) - (t6-2 (the-as object (-> t5-1 base))) - ) - (set! (-> (the-as gs-gif-tag t6-2) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x5)) - (set! (-> (the-as gs-gif-tag t6-2) regs) - (new 'static 'gif-tag-regs - :regs0 (gif-reg-id a+d) - :regs1 (gif-reg-id a+d) - :regs2 (gif-reg-id a+d) - :regs3 (gif-reg-id a+d) - :regs4 (gif-reg-id a+d) - :regs5 (gif-reg-id a+d) - :regs6 (gif-reg-id a+d) - :regs7 (gif-reg-id a+d) - :regs8 (gif-reg-id a+d) - :regs9 (gif-reg-id a+d) - :regs10 (gif-reg-id a+d) - :regs11 (gif-reg-id a+d) - :regs12 (gif-reg-id a+d) - :regs13 (gif-reg-id a+d) - :regs14 (gif-reg-id a+d) - :regs15 (gif-reg-id a+d) - ) - ) - (set! (-> t5-1 base) (&+ (the-as pointer t6-2) 16)) + ;; draw sprite + (let ((t5-3 (the-as (inline-array vector4w) (-> dma-buff base)))) + (set! (-> t5-3 0 quad) (-> *depth-cue-work* temp-strip-tmpl dma-vif quad)) ;; cnt direct + (set! (-> t5-3 1 quad) (-> *depth-cue-work* temp-strip-tmpl quad 1)) ;; draw sprite, 5 regs + (set! (-> t5-3 2 quad) (-> *depth-cue-work* set-color quad)) ;; rgbaq + (set-vector! (-> t5-3 3) x-offset 0 0 0) ;; uv + (set-vector! (-> t5-3 4) 0 0 0 0) ;; xyzf2 + (set-vector! (-> t5-3 5) (+ x-offset strip-max-w) (* (-> *video-parms* screen-sy) 16) 0 0) ;; uv + (set-vector! (-> t5-3 6) strip-w strip-h 0 #x10000) ;; xyzf2 ) - (let* ((t5-2 arg0) - (t6-4 (-> t5-2 base)) - ) - (set! (-> (the-as (pointer gs-xy-offset) t6-4) 0) (new 'static 'gs-xy-offset :ofy (- 8 arg5))) - (set! (-> (the-as (pointer gs-reg64) t6-4) 1) (gs-reg64 xyoffset-1)) - (set! (-> (the-as (pointer gs-frame) t6-4) 2) (new 'static 'gs-frame :fbw #x1 :fbp t3-0)) - (set! (-> (the-as (pointer gs-reg64) t6-4) 3) (gs-reg64 frame-1)) - (set! (-> (the-as (pointer gs-tex0) t6-4) 4) - (new 'static 'gs-tex0 :tbw #x8 :tw #xa :th #x8 :tcc #x1 :tbp0 (* arg4 32)) - ) - (set! (-> (the-as (pointer gs-reg64) t6-4) 5) (gs-reg64 tex0-1)) - (set! (-> (the-as (pointer gs-test) t6-4) 6) (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always))) - (set! (-> (the-as (pointer gs-reg64) t6-4) 7) (gs-reg64 test-1)) - (set! (-> (the-as (pointer gs-alpha) t6-4) 8) (new 'static 'gs-alpha)) - (set! (-> (the-as (pointer gs-reg64) t6-4) 9) (gs-reg64 alpha-1)) - (set! (-> t5-2 base) (&+ t6-4 80)) + (&+! (-> dma-buff base) 112) + + ;; overlay strip back onto the on-screen framebuffer + ;; ------------------------------------------------------ + ;; update GS registers + (dma-buffer-add-gs-set dma-buff + ;; set vertex position offset + (xyoffset-1 (new 'static 'gs-xy-offset :ofy (+ oddeven 4))) + ;; draw to on-screen-fbp but only the alpha channel + (frame-1 (new 'static 'gs-frame :fbw #x8 :fbmsk #xff000000 :fbp on-screen-fbp)) + ;; use an alpha value of 128 + (texa (new 'static 'gs-texa :ta0 #x80 :ta1 #x80)) + ;; use depth-cue-base-page as texture 0 + ;; buffer width = 64 pixels + ;; format = PSMCT24 + ;; USIZE = 32 texels + ;; VSIZE = 256 texels + ;; RGB + (tex0-1 (new 'static 'gs-tex0 :tbw #x1 :psm #x1 :tw #x5 :th #x8 :tbp0 (* *depth-cue-base-page* 32))) + ;; blend source and framebuffer RGB + (alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1)) ) - (let ((t5-3 (the-as (inline-array vector4w) (-> arg0 base)))) - (set! (-> t5-3 0 quad) (-> *depth-cue-work* temp-strip-tmpl dma-vif quad)) - (set! (-> t5-3 1 quad) (-> *depth-cue-work* temp-strip-tmpl quad 1)) - (set! (-> t5-3 2 quad) (-> *depth-cue-work* set-color quad)) - (set-vector! (-> t5-3 3) a3-4 0 0 0) - (set-vector! (-> t5-3 4) 0 0 0 0) - (set-vector! (-> t5-3 5) (+ a3-4 t2-0) (* (-> *video-parms* screen-sy) 16) 0 0) - (set-vector! (-> t5-3 6) v1-1 a2-1 0 #x10000) - ) - (set! (-> arg0 base) (the-as pointer (-> (the-as depth-cue-work (-> arg0 base)) set-color))) - (let* ((t5-7 arg0) - (t6-16 (the-as object (-> t5-7 base))) - ) - (set! (-> (the-as dma-packet t6-16) dma) (new 'static 'dma-tag :qwc #x6 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet t6-16) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet t6-16) vif1) (new 'static 'vif-tag :imm #x6 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> t5-7 base) (the-as pointer (the-as gs-gif-tag (&+ (the-as pointer t6-16) 16)))) - ) - (let* ((t5-8 arg0) - (t6-18 (the-as object (-> t5-8 base))) - ) - (set! (-> (the-as gs-gif-tag t6-18) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x5)) - (set! (-> (the-as gs-gif-tag t6-18) regs) (new 'static 'gif-tag-regs - :regs0 (gif-reg-id a+d) - :regs1 (gif-reg-id a+d) - :regs2 (gif-reg-id a+d) - :regs3 (gif-reg-id a+d) - :regs4 (gif-reg-id a+d) - :regs5 (gif-reg-id a+d) - :regs6 (gif-reg-id a+d) - :regs7 (gif-reg-id a+d) - :regs8 (gif-reg-id a+d) - :regs9 (gif-reg-id a+d) - :regs10 (gif-reg-id a+d) - :regs11 (gif-reg-id a+d) - :regs12 (gif-reg-id a+d) - :regs13 (gif-reg-id a+d) - :regs14 (gif-reg-id a+d) - :regs15 (gif-reg-id a+d) - ) - ) - (set! (-> t5-8 base) (&+ (the-as pointer t6-18) 16)) - ) - (let* ((t5-9 arg0) - (t6-20 (-> t5-9 base)) - ) - (set! (-> (the-as (pointer gs-xy-offset) t6-20) 0) (new 'static 'gs-xy-offset :ofy (+ arg5 4))) - (set! (-> (the-as (pointer gs-reg64) t6-20) 1) (gs-reg64 xyoffset-1)) - (set! (-> (the-as (pointer gs-frame) t6-20) 2) (new 'static 'gs-frame :fbw #x8 :fbmsk #xff000000 :fbp arg4)) - (set! (-> (the-as (pointer gs-reg64) t6-20) 3) (gs-reg64 frame-1)) - (set! (-> (the-as (pointer gs-texa) t6-20) 4) (new 'static 'gs-texa :ta0 #x80 :ta1 #x80)) - (set! (-> (the-as (pointer gs-reg64) t6-20) 5) (gs-reg64 texa)) - (set! (-> (the-as (pointer gs-tex0) t6-20) 6) - (new 'static 'gs-tex0 :tbw #x1 :psm #x1 :tw #x5 :th #x8 :tbp0 (* t3-0 32)) - ) - (set! (-> (the-as (pointer gs-reg64) t6-20) 7) (gs-reg64 tex0-1)) - (set! (-> (the-as (pointer gs-alpha) t6-20) 8) (new 'static 'gs-alpha :b #x1 :d #x1)) - (set! (-> (the-as (pointer gs-reg64) t6-20) 9) (gs-reg64 alpha-1)) - (set! (-> t5-9 base) (&+ t6-20 80)) - ) - (let ((t5-10 (the-as object (-> arg0 base)))) + ;; draw sprite + (let ((t5-10 (the-as object (-> dma-buff base)))) (set! (-> (the-as (inline-array vector4w) t5-10) 0 quad) (-> *depth-cue-work* texture-strip-tmpl dma-vif quad) ) (set! (-> (the-as (inline-array vector4w) t5-10) 1 quad) (-> *depth-cue-work* texture-strip-tmpl quad 1)) - (set! (-> (the-as (inline-array vector4w) t5-10) 2 quad) (-> *depth-cue-work* draw-color quad)) - (set-vector! (-> (the-as (inline-array vector4w) t5-10) 3) 0 0 0 0) - (set-vector! (-> (the-as (inline-array vector4w) t5-10) 4) a3-4 0 0 0) - (set-vector! (-> (the-as (inline-array vector4w) t5-10) 5) v1-1 a2-1 0 0) - (set-vector! + (set! (-> (the-as (inline-array vector4w) t5-10) 2 quad) (-> *depth-cue-work* draw-color quad)) ;; rgbaq + (set-vector! (-> (the-as (inline-array vector4w) t5-10) 3) 0 0 0 0) ;; uv + (set-vector! (-> (the-as (inline-array vector4w) t5-10) 4) x-offset 0 0 0) ;; xyzf2 + (set-vector! (-> (the-as (inline-array vector4w) t5-10) 5) strip-w strip-h 0 0) ;; uv + (set-vector! ;; xyzf2 (the-as vector4w (&+ (the-as pointer t5-10) 96)) - (+ a3-4 t2-0) + (+ x-offset strip-max-w) (* (-> *video-parms* screen-sy) 16) - arg1 + depth #x10000 ) ) - (set! (-> arg0 base) (the-as pointer (-> (the-as depth-cue-work (-> arg0 base)) set-color))) - (+! a3-4 t2-0) + (&+! (-> dma-buff base) 112) + + ;; next strip + ;; ------------------------------------------------------ + (+! x-offset strip-max-w) ) ) #f @@ -407,132 +383,63 @@ ) ) -(defun depth-cue ((arg0 display)) +(defun depth-cue ((disp display)) + ;; is depth-cue enabled? (when (logtest? (vu1-renderer-mask depth-cue) *vu1-enable-user*) - (let* ((gp-0 (-> *display* frames (-> *display* on-screen) frame global-buf base)) - (s4-0 (-> *display* frames (-> *display* on-screen) frame global-buf)) - (s5-0 (-> s4-0 base)) + (let* ((dma-start (-> *display* frames (-> *display* on-screen) frame global-buf base)) + (dma-buff (-> *display* frames (-> *display* on-screen) frame global-buf)) + (s5-0 (-> dma-buff base)) ) - (let ((v1-9 (-> arg0 on-screen))) - (let* ((a1-7 s4-0) - (a2-0 (the-as object (-> a1-7 base))) - ) - (set! (-> (the-as dma-packet a2-0) dma) (new 'static 'dma-tag :qwc #x7 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet a2-0) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet a2-0) vif1) (new 'static 'vif-tag :imm #x7 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> a1-7 base) (&+ (the-as pointer a2-0) 16)) - ) - (let* ((a1-8 s4-0) - (a2-2 (the-as object (-> a1-8 base))) - ) - (set! (-> (the-as gs-gif-tag a2-2) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x6)) - (set! (-> (the-as gs-gif-tag a2-2) regs) (new 'static 'gif-tag-regs - :regs0 (gif-reg-id a+d) - :regs1 (gif-reg-id a+d) - :regs2 (gif-reg-id a+d) - :regs3 (gif-reg-id a+d) - :regs4 (gif-reg-id a+d) - :regs5 (gif-reg-id a+d) - :regs6 (gif-reg-id a+d) - :regs7 (gif-reg-id a+d) - :regs8 (gif-reg-id a+d) - :regs9 (gif-reg-id a+d) - :regs10 (gif-reg-id a+d) - :regs11 (gif-reg-id a+d) - :regs12 (gif-reg-id a+d) - :regs13 (gif-reg-id a+d) - :regs14 (gif-reg-id a+d) - :regs15 (gif-reg-id a+d) - ) - ) - (set! (-> a1-8 base) (&+ (the-as pointer a2-2) 16)) - ) - (let* ((a1-9 s4-0) - (a2-4 (-> a1-9 base)) - ) - (set! (-> (the-as (pointer gs-test) a2-4) 0) (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always))) - (set! (-> (the-as (pointer gs-reg64) a2-4) 1) (gs-reg64 test-1)) - (set! (-> (the-as (pointer gs-zbuf) a2-4) 2) (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk #x1)) - (set! (-> (the-as (pointer gs-reg64) a2-4) 3) (gs-reg64 zbuf-1)) - (set! (-> (the-as (pointer gs-reg64) a2-4) 4) (gs-reg64 signal)) - (set! (-> (the-as (pointer gs-reg64) a2-4) 5) (gs-reg64 tex1-1)) - (set! (-> (the-as (pointer gs-tex1) a2-4) 6) (new 'static 'gs-tex1)) - (set! (-> (the-as (pointer gs-reg64) a2-4) 7) (gs-reg64 miptbp1-1)) - (set! (-> (the-as (pointer gs-clamp) a2-4) 8) (new 'static 'gs-clamp - :wms (gs-tex-wrap-mode clamp) - :wmt (gs-tex-wrap-mode clamp) - :maxu #x1ff - :maxv (-> *video-parms* screen-masky) - ) - ) - (set! (-> (the-as (pointer gs-reg64) a2-4) 9) (gs-reg64 clamp-1)) - (set! (-> (the-as (pointer gs-reg64) a2-4) 10) (gs-reg64 dimx)) - (set! (-> (the-as (pointer gs-reg64) a2-4) 11) (gs-reg64 alpha-1)) - (set! (-> a1-9 base) (&+ a2-4 96)) + (let ((v1-9 (-> disp on-screen))) + ;; initial GS register setup + (dma-buffer-add-gs-set dma-buff + ;; depth test on, all pixels pass + (test-1 (new 'static 'gs-test :zte #x1 :ztst (gs-ztest always))) + ;; don't write to depth buffer + (zbuf-1 (new 'static 'gs-zbuf :zbp #x1c0 :psm (gs-psm ct24) :zmsk #x1)) + ;; bilinear texture sampling + (tex1-1 (new 'static 'gs-tex1 :mmag 1 :mmin 1)) + ;; no mip + (miptbp1-1 (new 'static 'gs-miptbp)) + ;; set texture wrap mode to clamp + (clamp-1 (new 'static 'gs-clamp + :wms (gs-tex-wrap-mode clamp) + :wmt (gs-tex-wrap-mode clamp) + :maxu #x1ff + :maxv (-> *video-parms* screen-masky) + )) + ;; blend source and dest + (alpha-1 (new 'static 'gs-alpha :b 1 :d 1)) ) + (let ((s3-0 (* *oddeven* 8)) - (s2-0 (-> arg0 frames v1-9 draw frame1 fbp)) + (on-screen-fbp (-> disp frames v1-9 draw frame1 fbp)) ) + ;; draw (depth-cue-draw-front - s4-0 - #xffffff - (-> *depth-cue-work* front data x) - (-> *depth-cue-work* front data y) - s2-0 - s3-0 + dma-buff ;; dma-buff + #xffffff ;; depth + (-> *depth-cue-work* front data x) ;; sharpness + (-> *depth-cue-work* front data y) ;; alpha + on-screen-fbp ;; on-screen frame pointer + s3-0 ;; oddeven * 8 ) - (let* ((v1-19 s4-0) - (a0-2 (the-as object (-> v1-19 base))) - ) - (set! (-> (the-as dma-packet a0-2) dma) (new 'static 'dma-tag :qwc #x3 :id (dma-tag-id cnt))) - (set! (-> (the-as dma-packet a0-2) vif0) (new 'static 'vif-tag)) - (set! (-> (the-as dma-packet a0-2) vif1) (new 'static 'vif-tag :imm #x3 :cmd (vif-cmd direct) :msk #x1)) - (set! (-> v1-19 base) (&+ (the-as pointer a0-2) 16)) - ) - (let* ((v1-20 s4-0) - (a0-4 (the-as object (-> v1-20 base))) - ) - (set! (-> (the-as gs-gif-tag a0-4) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x2)) - (set! (-> (the-as gs-gif-tag a0-4) regs) (new 'static 'gif-tag-regs - :regs0 (gif-reg-id a+d) - :regs1 (gif-reg-id a+d) - :regs2 (gif-reg-id a+d) - :regs3 (gif-reg-id a+d) - :regs4 (gif-reg-id a+d) - :regs5 (gif-reg-id a+d) - :regs6 (gif-reg-id a+d) - :regs7 (gif-reg-id a+d) - :regs8 (gif-reg-id a+d) - :regs9 (gif-reg-id a+d) - :regs10 (gif-reg-id a+d) - :regs11 (gif-reg-id a+d) - :regs12 (gif-reg-id a+d) - :regs13 (gif-reg-id a+d) - :regs14 (gif-reg-id a+d) - :regs15 (gif-reg-id a+d) - ) - ) - (set! (-> v1-20 base) (&+ (the-as pointer a0-4) 16)) - ) - (let* ((v1-21 s4-0) - (a0-6 (-> v1-21 base)) - ) - (set! (-> (the-as (pointer gs-xy-offset) a0-6) 0) - (new 'static 'gs-xy-offset :ofx #x7000 :ofy (+ (* (-> *video-parms* screen-miny) 16) s3-0)) - ) - (set! (-> (the-as (pointer gs-reg64) a0-6) 1) (gs-reg64 xyoffset-1)) - (set! (-> (the-as (pointer gs-frame) a0-6) 2) (new 'static 'gs-frame :fbw #x8 :fbp s2-0)) - (set! (-> (the-as (pointer gs-reg64) a0-6) 3) (gs-reg64 frame-1)) - (set! (-> v1-21 base) (&+ a0-6 32)) + ;; restore GS registers + (dma-buffer-add-gs-set dma-buff + ;; restore xyoffset register + (xyoffset-1 (new 'static 'gs-xy-offset :ofx #x7000 :ofy (+ (* (-> *video-parms* screen-miny) 16) s3-0))) + ;; restore drawing destination to on-screen framebuffer + (frame-1 (new 'static 'gs-frame :fbw #x8 :fbp on-screen-fbp)) ) ) ) - (let ((a3-18 (-> s4-0 base))) - (let ((v1-22 (the-as object (-> s4-0 base)))) + (let ((a3-18 (-> dma-buff base))) + ;; add DMA chain + (let ((v1-22 (the-as object (-> dma-buff base)))) (set! (-> (the-as dma-packet v1-22) dma) (new 'static 'dma-tag :id (dma-tag-id next))) (set! (-> (the-as dma-packet v1-22) vif0) (new 'static 'vif-tag)) (set! (-> (the-as dma-packet v1-22) vif1) (new 'static 'vif-tag)) - (set! (-> s4-0 base) (&+ (the-as pointer v1-22) 16)) + (set! (-> dma-buff base) (&+ (the-as pointer v1-22) 16)) ) (let ((v0-0 (dma-bucket-insert-tag (-> *display* frames (-> *display* on-screen) frame bucket-group) @@ -542,13 +449,14 @@ ) ) ) + ;; record memory usage (let ((v1-27 *dma-mem-usage*)) (when (nonzero? v1-27) (set! (-> v1-27 length) (max 84 (-> v1-27 length))) (set! (-> v1-27 data 83 name) "depth-cue") (+! (-> v1-27 data 83 count) 1) (+! (-> v1-27 data 83 used) - (&- (-> *display* frames (-> *display* on-screen) frame global-buf base) (the-as uint gp-0)) + (&- (-> *display* frames (-> *display* on-screen) frame global-buf base) (the-as uint dma-start)) ) (set! (-> v1-27 data 83 total) (-> v1-27 data 83 used)) ) diff --git a/goal_src/jak1/engine/gfx/vu1-user-h.gc b/goal_src/jak1/engine/gfx/vu1-user-h.gc index f67ab3467..944c4d948 100644 --- a/goal_src/jak1/engine/gfx/vu1-user-h.gc +++ b/goal_src/jak1/engine/gfx/vu1-user-h.gc @@ -54,6 +54,11 @@ ) ) +;; disable depth-cue by default for the PC port +(#when PC_PORT + (logclear! *vu1-enable-user-menu* (vu1-renderer-mask depth-cue)) + ) + ;; by default, all off. ;; the menu renderers get copied to this on each frame (define *vu1-enable-user* (the-as vu1-renderer-mask 0))