mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
fast3d: reliable pre-swap frame capture + fb_id 0 = window
- gfx_opengl_start_draw_to_framebuffer: fb_id 0 now binds GL framebuffer 0 (the window) instead of framebuffers[0].fbo, a generated attachment-less FBO. Harmless on Windows (verified: -level_09 renders, mean RGB ~80); strict GL (Mesa) treats the incomplete FBO as an error and drops draws. - GE_PCDUMP / F12 screenshots move to a pre-swap hook (gfx_pre_swap_hook, called from gfx_sdl_swap_buffers_begin before SDL_GL_SwapWindow). Reading the back buffer AFTER the swap is undefined on buffer-exchange drivers (Mesa/WSLg) -> black capture. Also: read GL_BACK explicitly, glFinish first, GL_PACK_ALIGNMENT=1 (639*3 is not 4-aligned -> row shear), and log any glReadPixels error. Windows -level_09 verified: renders, no crash, capture non-black.
This commit is contained in:
1 parent
bd7a6cde8a
commit
4d406462bb
3 files changed
+42
-12
No files matched your search
@@ -1083,7 +1083,15 @@ extern "C" bool gfx_opengl_dump_bound_fbo(uint32_t width, uint32_t height, const
|
||||
size_t n = (size_t)width * height * 3;
|
||||
uint8_t* pixels = (uint8_t*)malloc(n);
|
||||
if (!pixels) return false;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glReadBuffer(GL_BACK);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glFinish();
|
||||
glReadPixels(0, 0, (GLsizei)width, (GLsizei)height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||
{
|
||||
GLenum e = glGetError();
|
||||
if (e) sysLogPrintf(LOG_WARNING, "dump_bound_fbo: glReadPixels err 0x%x (%ux%u)", (unsigned)e, width, height);
|
||||
}
|
||||
FILE* f = fopen(path, "wb");
|
||||
if (!f) { free(pixels); return false; }
|
||||
fprintf(f, "P6\n%u %u\n255\n", width, height);
|
||||
@@ -1199,7 +1207,11 @@ bool gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) {
|
||||
if (noise_scale != 0.0f) {
|
||||
current_noise_scale = 1.0f / noise_scale;
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo);
|
||||
/* fb_id 0 is the on-screen target: bind the window's default
|
||||
* framebuffer (GL name 0), not framebuffers[0].fbo (a generated but
|
||||
* attachment-less FBO -> incomplete -> nothing renders on a strict
|
||||
* GL implementation like Mesa/llvmpipe). */
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb_id == 0 ? 0 : fb.fbo);
|
||||
current_framebuffer = fb_id;
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -427,10 +427,19 @@ static inline void sync_framerate_with_timer(void) {
|
||||
previous_time = t;
|
||||
}
|
||||
|
||||
/* Optional hook run with the freshly-composited frame still in the back
|
||||
* buffer, immediately before the swap. video.c uses it for GE_PCDUMP /
|
||||
* screenshots: reading the back buffer AFTER SDL_GL_SwapWindow is undefined
|
||||
* on buffer-exchange drivers (Mesa, WSLg) and yields a black capture. */
|
||||
extern "C" void (*gfx_pre_swap_hook)(void) = NULL;
|
||||
|
||||
static void gfx_sdl_swap_buffers_begin(void) {
|
||||
if (target_fps) {
|
||||
sync_framerate_with_timer();
|
||||
}
|
||||
if (gfx_pre_swap_hook) {
|
||||
gfx_pre_swap_hook();
|
||||
}
|
||||
SDL_GL_SwapWindow(wnd);
|
||||
}
|
||||
|
||||
|
||||
+20
-11
@@ -100,6 +100,10 @@ static u32 frames = 0;
|
||||
/* Set by the host event pump (F12), consumed on the render thread in
|
||||
* videoEndFrame where a GL context is current. */
|
||||
static volatile int screenshotReq = 0;
|
||||
|
||||
/* Pre-swap capture hook (defined below, registered in videoInit). */
|
||||
static void videoPreSwapCapture(void);
|
||||
extern void (*gfx_pre_swap_hook)(void);
|
||||
static double fpsWindowStart = 0.0;
|
||||
static int fpsNumFrames = 0;
|
||||
static float vidAvgFPS = 0.f;
|
||||
@@ -172,6 +176,8 @@ int videoInit(void)
|
||||
* still needs a current context on this thread. */
|
||||
gfx_sdl_release_context();
|
||||
|
||||
gfx_pre_swap_hook = videoPreSwapCapture;
|
||||
|
||||
initDone = 1;
|
||||
sysLogPrintf(LOG_INFO, "video: %dx%d window (native %dx%d)",
|
||||
(int)gfx_current_dimensions.width, (int)gfx_current_dimensions.height,
|
||||
@@ -289,18 +295,13 @@ void videoSubmitCommands(Gfx *cmds)
|
||||
gfx_run(cmds);
|
||||
}
|
||||
|
||||
void videoEndFrame(void)
|
||||
/* Runs from gfx_sdl_swap_buffers_begin with the composited frame still in the
|
||||
* back buffer, just before SDL_GL_SwapWindow. Reading the back buffer after
|
||||
* the swap is undefined on buffer-exchange drivers (Mesa/WSLg) -> black. */
|
||||
static void videoPreSwapCapture(void)
|
||||
{
|
||||
if (!initDone) {
|
||||
return;
|
||||
}
|
||||
gfx_end_frame();
|
||||
|
||||
/* TEMP D70 (env-gated, debug-only, env-gated): GE_PCDUMP="first-last"
|
||||
* or "first-last:step" dumps the presented frame as ./ppm/frame_NNNNNN.ppm
|
||||
* (one frame behind real time — read happens after SwapWindow). Used to
|
||||
* pixel-verify the intro's 3D content. Also honours [Debug] FrameDump in
|
||||
* ge007.ini (env var wins). */
|
||||
/* GE_PCDUMP="first-last" / "first-last:step" -> ./ppm/frame_NNNNNN.ppm.
|
||||
* Also honours [Debug] FrameDump in ge007.ini (env var wins). */
|
||||
const char *pcdump = configGetFrameDump();
|
||||
if (pcdump) {
|
||||
static int lo = -1, hi = 0, step = 1;
|
||||
@@ -335,6 +336,14 @@ void videoEndFrame(void)
|
||||
sysLogPrintf(LOG_WARNING, "video: screenshot failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void videoEndFrame(void)
|
||||
{
|
||||
if (!initDone) {
|
||||
return;
|
||||
}
|
||||
gfx_end_frame();
|
||||
|
||||
++frames;
|
||||
++fpsNumFrames;
|
||||
|
||||
Reference in new issue
Block a user