mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
[jak2] use current buffer for blit-displays (#2855)
This changes how `BlitDisplays.cpp` works so it looks at the current render buffer, rather than the back buffer. This approach is a bit faster because we avoid copying the back buffer on every single frame. It also removes the black frames when the transition starts/stops. The remaining issues are: - there's still a single frame of weirdness with the sprite glow renderer. - when changing resolutions, it doesn't work super well.
This commit is contained in:
parent
a48df0683f
commit
9662cd0228
|
@ -16,12 +16,9 @@ void BlitDisplays::init_textures(TexturePool& texture_pool, GameVersion version)
|
||||||
default:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
m_copier = std::make_unique<FramebufferCopier>();
|
||||||
TextureInput in;
|
TextureInput in;
|
||||||
glGenTextures(1, &in.gpu_texture);
|
in.gpu_texture = m_copier->texture();
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
in.w = 32;
|
in.w = 32;
|
||||||
in.h = 32;
|
in.h = 32;
|
||||||
in.debug_page_name = "PC-BLIT";
|
in.debug_page_name = "PC-BLIT";
|
||||||
|
@ -34,9 +31,6 @@ void BlitDisplays::init_textures(TexturePool& texture_pool, GameVersion version)
|
||||||
void BlitDisplays::render(DmaFollower& dma,
|
void BlitDisplays::render(DmaFollower& dma,
|
||||||
SharedRenderState* render_state,
|
SharedRenderState* render_state,
|
||||||
ScopedProfilerNode& /*prof*/) {
|
ScopedProfilerNode& /*prof*/) {
|
||||||
auto back = render_state->back_fbo;
|
|
||||||
bool valid = back && back->valid;
|
|
||||||
|
|
||||||
// loop through all data
|
// loop through all data
|
||||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||||
auto data = dma.read_and_advance();
|
auto data = dma.read_and_advance();
|
||||||
|
@ -46,28 +40,66 @@ void BlitDisplays::render(DmaFollower& dma,
|
||||||
case 0x10: { // copy buffer->texture (tbp in vif1)
|
case 0x10: { // copy buffer->texture (tbp in vif1)
|
||||||
u32 tbp = data.vifcode1().immediate;
|
u32 tbp = data.vifcode1().immediate;
|
||||||
ASSERT_MSG(tbp == m_tbp, fmt::format("unexpected tbp {}", tbp));
|
ASSERT_MSG(tbp == m_tbp, fmt::format("unexpected tbp {}", tbp));
|
||||||
if (valid) {
|
// copy buffer texture -> custom texture
|
||||||
// copy buffer texture -> custom texture
|
m_copier->copy_now(render_state->render_fb_w, render_state->render_fb_h,
|
||||||
auto my_tex_id = m_gpu_tex->gpu_textures.at(0).gl;
|
render_state->render_fb);
|
||||||
int w = back->width, h = back->height;
|
m_gpu_tex->w = render_state->render_fb_w;
|
||||||
|
m_gpu_tex->h = render_state->render_fb_h;
|
||||||
|
render_state->texture_pool->move_existing_to_vram(m_gpu_tex, m_tbp);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, my_tex_id);
|
} break;
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
case 0x11: {
|
||||||
|
// this case is "do nothing" on PS2 because the countdown is nonzero.
|
||||||
|
// On the PS2, there were two framebuffers. The first was where triangles were directly
|
||||||
|
// rendered to. Then, this was copied to the final buffer. These buffers were slightly
|
||||||
|
// different resolution.
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, back->fbo_id);
|
// On PC, we don't imitate this 2-buffer setup. So in cases where the original game
|
||||||
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, w, h, 0);
|
// skipped doing a copy, it would render to the first buffer but never copy to the second.
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
// On PC, we set this flag which means that after rendering is finished we copy the saved
|
||||||
|
// buffer back.
|
||||||
m_gpu_tex->w = w;
|
m_copy_back_pending = true;
|
||||||
m_gpu_tex->h = h;
|
|
||||||
render_state->texture_pool->move_existing_to_vram(m_gpu_tex, m_tbp);
|
|
||||||
} else {
|
|
||||||
lg::error("no valid back buffer to blit!");
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// after reading the framebuffer, clear it.
|
||||||
|
// The upcoming sky renderer bucket will clear it, but can't clear stuff in the letterbox regions,
|
||||||
|
// so we manually do the clear here. Note that we need to clear the window (framebuffer 0) in case
|
||||||
|
// the resolution/aspect/size changed, and there is a different letterbox than last frame.
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClearDepth(0.0);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClearDepth(0.0);
|
||||||
|
glClearStencil(0);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
render_state->stencil_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitDisplays::draw_debug_window() {}
|
void BlitDisplays::do_copy_back(SharedRenderState* render_state) {
|
||||||
|
if (m_copy_back_pending) {
|
||||||
|
if (render_state->render_fb_w == m_copier->width() &&
|
||||||
|
render_state->render_fb_h == m_copier->height()) {
|
||||||
|
m_copier->copy_back_now(render_state->render_fb_w, render_state->render_fb_h,
|
||||||
|
render_state->render_fb);
|
||||||
|
}
|
||||||
|
m_copy_back_pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlitDisplays::draw_debug_window() {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_copier->texture());
|
||||||
|
int w, h;
|
||||||
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
|
||||||
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
|
||||||
|
ImGui::Image((void*)(u64)m_copier->texture(), ImVec2(w, h));
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||||
|
#include "game/graphics/opengl_renderer/opengl_utils.h"
|
||||||
#include "game/graphics/texture/TexturePool.h"
|
#include "game/graphics/texture/TexturePool.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -12,8 +13,11 @@ class BlitDisplays : public BucketRenderer {
|
||||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||||
void init_textures(TexturePool& texture_pool, GameVersion) override;
|
void init_textures(TexturePool& texture_pool, GameVersion) override;
|
||||||
void draw_debug_window() override;
|
void draw_debug_window() override;
|
||||||
|
void do_copy_back(SharedRenderState* render_state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<FramebufferCopier> m_copier;
|
||||||
GpuTexture* m_gpu_tex;
|
GpuTexture* m_gpu_tex;
|
||||||
u32 m_tbp;
|
u32 m_tbp;
|
||||||
|
bool m_copy_back_pending = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -87,9 +87,6 @@ struct SharedRenderState {
|
||||||
int draw_offset_x = 0;
|
int draw_offset_x = 0;
|
||||||
int draw_offset_y = 0;
|
int draw_offset_y = 0;
|
||||||
|
|
||||||
// the FBO for blit buffer
|
|
||||||
const Fbo* back_fbo = nullptr;
|
|
||||||
|
|
||||||
int bucket_for_vis_copy = 0;
|
int bucket_for_vis_copy = 0;
|
||||||
int num_vis_to_copy = 0;
|
int num_vis_to_copy = 0;
|
||||||
GameVersion version;
|
GameVersion version;
|
||||||
|
|
|
@ -126,7 +126,8 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
||||||
|
|
||||||
// 0
|
// 0
|
||||||
init_bucket_renderer<VisDataHandler>("vis", BucketCategory::OTHER, BucketId::BUCKET_2);
|
init_bucket_renderer<VisDataHandler>("vis", BucketCategory::OTHER, BucketId::BUCKET_2);
|
||||||
init_bucket_renderer<BlitDisplays>("blit", BucketCategory::OTHER, BucketId::BUCKET_3);
|
m_blit_displays =
|
||||||
|
init_bucket_renderer<BlitDisplays>("blit", BucketCategory::OTHER, BucketId::BUCKET_3);
|
||||||
init_bucket_renderer<TextureUploadHandler>("tex-lcom-sky-pre", BucketCategory::TEX,
|
init_bucket_renderer<TextureUploadHandler>("tex-lcom-sky-pre", BucketCategory::TEX,
|
||||||
BucketId::TEX_LCOM_SKY_PRE, m_texture_animator);
|
BucketId::TEX_LCOM_SKY_PRE, m_texture_animator);
|
||||||
init_bucket_renderer<DirectRenderer>("sky-draw", BucketCategory::OTHER, BucketId::SKY_DRAW, 1024);
|
init_bucket_renderer<DirectRenderer>("sky-draw", BucketCategory::OTHER, BucketId::SKY_DRAW, 1024);
|
||||||
|
@ -645,34 +646,9 @@ Fbo make_fbo(int w, int h, int msaa, bool make_zbuf_and_stencil) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void OpenGLRenderer::blit_display() {
|
void OpenGLRenderer::blit_display() {
|
||||||
auto& back = m_fbo_state.resources.back_buffer;
|
if (m_blit_displays) {
|
||||||
if (!back.valid || !back.matches(*m_fbo_state.render_fbo)) {
|
m_blit_displays->do_copy_back(&m_render_state);
|
||||||
back.clear();
|
|
||||||
back = make_fbo(m_fbo_state.render_fbo->width, m_fbo_state.render_fbo->height, 1, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Fbo* window_blit_src = nullptr;
|
|
||||||
if (m_fbo_state.resources.resolve_buffer.valid) {
|
|
||||||
// since this is called after do_pcrtc_effects, the resolve buffer is already made
|
|
||||||
window_blit_src = &m_fbo_state.resources.resolve_buffer;
|
|
||||||
} else {
|
|
||||||
window_blit_src = m_fbo_state.render_fbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, window_blit_src->fbo_id);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, back.fbo_id);
|
|
||||||
glBlitFramebuffer(0, // srcX0
|
|
||||||
0, // srcY0
|
|
||||||
window_blit_src->width, // srcX1
|
|
||||||
window_blit_src->height, // srcY1
|
|
||||||
0, // dstX0
|
|
||||||
0, // dstY0
|
|
||||||
back.width, // dstX1
|
|
||||||
back.height, // dstY1
|
|
||||||
GL_COLOR_BUFFER_BIT, // mask
|
|
||||||
GL_LINEAR // filter
|
|
||||||
);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -714,6 +690,12 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// blit framebuffer so that it can be used as a texture by the game later
|
||||||
|
{
|
||||||
|
auto prof = m_profiler.root()->make_scoped_child("blit-display");
|
||||||
|
blit_display();
|
||||||
|
}
|
||||||
|
|
||||||
// apply effects done with PCRTC registers
|
// apply effects done with PCRTC registers
|
||||||
{
|
{
|
||||||
auto prof = m_profiler.root()->make_scoped_child("pcrtc");
|
auto prof = m_profiler.root()->make_scoped_child("pcrtc");
|
||||||
|
@ -723,12 +705,6 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// blit framebuffer so that it can be used as a texture by the game later
|
|
||||||
{
|
|
||||||
auto prof = m_profiler.root()->make_scoped_child("blit-display");
|
|
||||||
blit_display();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_last_pmode_alp = settings.pmode_alp_register;
|
m_last_pmode_alp = settings.pmode_alp_register;
|
||||||
|
|
||||||
if (settings.save_screenshot) {
|
if (settings.save_screenshot) {
|
||||||
|
@ -910,24 +886,27 @@ void OpenGLRenderer::setup_frame(const RenderOptions& settings) {
|
||||||
|
|
||||||
ASSERT_MSG(!m_fbo_state.render_fbo->is_window, "window fbo");
|
ASSERT_MSG(!m_fbo_state.render_fbo->is_window, "window fbo");
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
if (m_version == GameVersion::Jak1) {
|
||||||
glViewport(0, 0, m_fbo_state.resources.window.width, m_fbo_state.resources.window.height);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
glViewport(0, 0, m_fbo_state.resources.window.width, m_fbo_state.resources.window.height);
|
||||||
glClearDepth(0.0);
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
glDepthMask(GL_TRUE);
|
glClearDepth(0.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glDepthMask(GL_TRUE);
|
||||||
glDisable(GL_BLEND);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo_state.render_fbo->fbo_id);
|
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo_state.render_fbo->fbo_id);
|
||||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
glClearDepth(0.0);
|
glClearDepth(0.0);
|
||||||
glClearStencil(0);
|
glClearStencil(0);
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
// Note: could rely on sky renderer to clear depth and color, but this causes problems with
|
// Note: could rely on sky renderer to clear depth and color, but this causes problems with
|
||||||
// letterboxing
|
// letterboxing
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
m_render_state.stencil_dirty = false;
|
m_render_state.stencil_dirty = false;
|
||||||
|
}
|
||||||
|
// jak 2 does the clear in BlitDisplays.cpp
|
||||||
|
|
||||||
// setup the draw region to letterbox later
|
// setup the draw region to letterbox later
|
||||||
m_render_state.draw_region_w = settings.draw_region_width;
|
m_render_state.draw_region_w = settings.draw_region_width;
|
||||||
|
@ -940,7 +919,6 @@ void OpenGLRenderer::setup_frame(const RenderOptions& settings) {
|
||||||
(settings.window_framebuffer_height - m_render_state.draw_region_h) / 2;
|
(settings.window_framebuffer_height - m_render_state.draw_region_h) / 2;
|
||||||
|
|
||||||
m_render_state.render_fb = m_fbo_state.render_fbo->fbo_id;
|
m_render_state.render_fb = m_fbo_state.render_fbo->fbo_id;
|
||||||
m_render_state.back_fbo = &m_fbo_state.resources.back_buffer;
|
|
||||||
|
|
||||||
if (m_render_state.draw_region_w <= 0 || m_render_state.draw_region_h <= 0) {
|
if (m_render_state.draw_region_w <= 0 || m_render_state.draw_region_h <= 0) {
|
||||||
// trying to draw to 0 size region... opengl doesn't like this.
|
// trying to draw to 0 size region... opengl doesn't like this.
|
||||||
|
|
|
@ -113,6 +113,7 @@ class OpenGLRenderer {
|
||||||
std::shared_ptr<TextureAnimator> m_texture_animator;
|
std::shared_ptr<TextureAnimator> m_texture_animator;
|
||||||
std::vector<std::unique_ptr<BucketRenderer>> m_bucket_renderers;
|
std::vector<std::unique_ptr<BucketRenderer>> m_bucket_renderers;
|
||||||
std::vector<BucketCategory> m_bucket_categories;
|
std::vector<BucketCategory> m_bucket_categories;
|
||||||
|
class BlitDisplays* m_blit_displays = nullptr;
|
||||||
|
|
||||||
std::array<float, (int)BucketCategory::MAX_CATEGORIES> m_category_times;
|
std::array<float, (int)BucketCategory::MAX_CATEGORIES> m_category_times;
|
||||||
FullScreenDraw m_blackout_renderer;
|
FullScreenDraw m_blackout_renderer;
|
||||||
|
@ -126,7 +127,6 @@ class OpenGLRenderer {
|
||||||
Fbo window; // provided by glfw
|
Fbo window; // provided by glfw
|
||||||
Fbo render_buffer; // temporary buffer to render to
|
Fbo render_buffer; // temporary buffer to render to
|
||||||
Fbo resolve_buffer; // temporary buffer to resolve to
|
Fbo resolve_buffer; // temporary buffer to resolve to
|
||||||
Fbo back_buffer; // the previous buffer we rendered
|
|
||||||
} resources;
|
} resources;
|
||||||
|
|
||||||
Fbo* render_fbo = nullptr; // the selected fbo from the three above to use for rendering
|
Fbo* render_fbo = nullptr; // the selected fbo from the three above to use for rendering
|
||||||
|
|
|
@ -1806,6 +1806,14 @@ void TextureAnimator::run_fixed_animation_array(int idx,
|
||||||
ASSERT(tbp < 0x40000);
|
ASSERT(tbp < 0x40000);
|
||||||
m_skip_tbps.push_back(tbp); // known to be an output texture.
|
m_skip_tbps.push_back(tbp); // known to be an output texture.
|
||||||
if (anim.pool_gpu_tex) {
|
if (anim.pool_gpu_tex) {
|
||||||
|
// if the debug checkbox is checked, replace the texture with red.
|
||||||
|
if (m_output_debug_flags.at(anim.dest_slot).b) {
|
||||||
|
FramebufferTexturePairContext ctxt(*anim.fbt);
|
||||||
|
glColorMask(true, true, true, true);
|
||||||
|
glClearColor(1.0, 0.0, 0.0, 0.5);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
texture_pool->move_existing_to_vram(anim.pool_gpu_tex, tbp);
|
texture_pool->move_existing_to_vram(anim.pool_gpu_tex, tbp);
|
||||||
ASSERT(texture_pool->lookup(tbp).value() == anim.fbt->texture());
|
ASSERT(texture_pool->lookup(tbp).value() == anim.fbt->texture());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -208,5 +208,24 @@ void FramebufferCopier::copy_now(int render_fb_w, int render_fb_h, GLuint render
|
||||||
GL_NEAREST // filter
|
GL_NEAREST // filter
|
||||||
);
|
);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, render_fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramebufferCopier::copy_back_now(int render_fb_w, int render_fb_h, GLuint render_fb) {
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, render_fb);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
|
||||||
|
|
||||||
|
glBlitFramebuffer(0, // srcX0
|
||||||
|
0, // srcY0
|
||||||
|
m_fbo_width, // srcX1
|
||||||
|
m_fbo_height, // srcY1
|
||||||
|
0, // dstX0
|
||||||
|
0, // dstY0
|
||||||
|
render_fb_w, // dstX1
|
||||||
|
render_fb_h, // dstY1
|
||||||
|
GL_COLOR_BUFFER_BIT, // mask
|
||||||
|
GL_NEAREST // filter
|
||||||
|
);
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, render_fb);
|
glBindFramebuffer(GL_FRAMEBUFFER, render_fb);
|
||||||
}
|
}
|
|
@ -86,7 +86,10 @@ class FramebufferCopier {
|
||||||
FramebufferCopier(const FramebufferCopier&) = delete;
|
FramebufferCopier(const FramebufferCopier&) = delete;
|
||||||
FramebufferCopier& operator=(const FramebufferCopier&) = delete;
|
FramebufferCopier& operator=(const FramebufferCopier&) = delete;
|
||||||
void copy_now(int render_fb_w, int render_fb_h, GLuint render_fb);
|
void copy_now(int render_fb_w, int render_fb_h, GLuint render_fb);
|
||||||
|
void copy_back_now(int render_fb_w, int render_fb_h, GLuint render_fb);
|
||||||
u64 texture() const { return m_fbo_texture; }
|
u64 texture() const { return m_fbo_texture; }
|
||||||
|
int width() const { return m_fbo_width; }
|
||||||
|
int height() const { return m_fbo_height; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLuint m_fbo = 0, m_fbo_texture = 0;
|
GLuint m_fbo = 0, m_fbo_texture = 0;
|
||||||
|
|
|
@ -175,9 +175,17 @@
|
||||||
(else
|
(else
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(if (nonzero? (-> gp-0 count-down))
|
(when (nonzero? (-> gp-0 count-down))
|
||||||
(+! (-> gp-0 count-down) -1)
|
(+! (-> gp-0 count-down) -1)
|
||||||
|
|
||||||
|
(with-dma-buffer-add-bucket ((arg0 (-> *display* frames (-> *display* on-screen) global-buf))
|
||||||
|
(bucket-id bucket-3)
|
||||||
|
)
|
||||||
|
(dma-buffer-add-cnt-vif2 arg0 0 (new 'static 'vif-tag :cmd (vif-cmd pc-port) :imm #x11) ;; kind - do nothing
|
||||||
|
(new 'static 'vif-tag :cmd (vif-cmd pc-port)))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
)
|
||||||
)
|
)
|
||||||
(none)
|
(none)
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue