mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Add isolated render capture with staged RGBA readback
This commit is contained in:
@@ -136,6 +136,7 @@ uint32_t gl_renderer_stereo_unavailable(void);
|
||||
int gl_renderer_stereo_begin(int x, int y, int w, int h, int reuse_backup);
|
||||
int gl_renderer_stereo_end(uint32_t eye, int keep);
|
||||
void gl_renderer_stereo_stage_reset(void);
|
||||
int gl_renderer_stereo_stage_readback(uint32_t eye,uint32_t width,uint32_t height,uint8_t *rgba);
|
||||
int gl_renderer_stereo_publish(uint64_t pair_id, uint64_t guest_cycle,
|
||||
const int32_t eye_view[2][3]);
|
||||
void gl_renderer_stereo_reset(void);
|
||||
|
||||
@@ -600,6 +600,14 @@ uint32_t psx_mod_render_pass_plan(uint32_t period_vblanks,
|
||||
* partially updated plugin state) across guest code, or tolerate the abort. */
|
||||
int psx_mod_render_pass(struct CPUState* cpu, const PSXModRenderPass* pass,
|
||||
PSXModRenderPassFn fn, void* user);
|
||||
/* Isolated draw/readback using the stereo-capable rollback transaction.
|
||||
* Never publishes an eye pair or changes presentation. Returns native-sized
|
||||
* top-to-bottom RGBA8 pixels (alpha remains the PSX mask bit, not coverage).
|
||||
* Call outside another pass. rgba_bytes must cover rect->w*rect->h*4. */
|
||||
int psx_mod_render_capture_rgba(struct CPUState *cpu,const PSXModRenderPass *rect,
|
||||
PSXModRenderPassFn fn,void *user,
|
||||
uint8_t *rgba,uint32_t rgba_bytes);
|
||||
#define PSX_MOD_RENDER_CAPTURE_RGBA 1
|
||||
/*
|
||||
* Why passes cannot run right now, the host-time budget aside (a plan that
|
||||
* returns 0 while this says READY was shed for time). A plugin that relies on
|
||||
|
||||
@@ -610,6 +610,8 @@ static GLuint s_osd_tex = 0;
|
||||
static int s_osd_tw = 0, s_osd_th = 0;
|
||||
static GLuint s_present_prog = 0, s_present_vao = 0;
|
||||
static GLuint s_xr_color_prog = 0, s_xr_native_tex = 0;
|
||||
static GLuint s_capture_read_tex,s_capture_read_fbo;
|
||||
static int s_capture_read_w,s_capture_read_h;
|
||||
static void gl_swap_with_osd(void);
|
||||
static int s_post_aa = 0; /* GL_POST_AA_*; post-process AA (post_aa_apply) */
|
||||
static int s_native_surface_enabled, s_native_surface_pending;
|
||||
@@ -8331,6 +8333,7 @@ static void pass_resources_release(void) {
|
||||
if(s_xr_native_tex) glDeleteTextures(1,&s_xr_native_tex);
|
||||
}
|
||||
s_xr_color_prog=s_xr_native_tex=0;
|
||||
pass_free_color_fbo(&s_capture_read_tex,NULL,&s_capture_read_fbo,&s_capture_read_w,&s_capture_read_h);
|
||||
stereo_resources_release();
|
||||
for(int gi=0;gi<PASS_GENERATIONS;++gi)pass_gen_release(gi);
|
||||
pass_gens_invalidate();
|
||||
@@ -8673,6 +8676,34 @@ void gl_renderer_stereo_stage_reset(void) {
|
||||
GL_RT_SYNC("stereo_stage_reset");
|
||||
s_stereo_pair[1 - s_stereo_current].mask = 0;
|
||||
}
|
||||
int gl_renderer_stereo_stage_readback(uint32_t eye,uint32_t w,uint32_t h,uint8_t *rgba) {
|
||||
GL_RT_SYNC("capture_readback");
|
||||
if(eye>=2 || !rgba || !w || !h || w>1024 || h>512)return 0;
|
||||
StereoPair *pair=&s_stereo_pair[1-s_stereo_current];
|
||||
if(!(pair->mask&(1u<<eye)))return 0;
|
||||
GLint read,draw,texture,pack,pbo,row,skipr,skipp;
|
||||
GLboolean scissor=glIsEnabled(GL_SCISSOR_TEST),srgb=glIsEnabled(0x8DB9);
|
||||
glGetIntegerv(0x8CAA,&read);glGetIntegerv(0x8CA6,&draw);glGetIntegerv(GL_TEXTURE_BINDING_2D,&texture);
|
||||
glGetIntegerv(GL_PACK_ALIGNMENT,&pack);glGetIntegerv(0x88ED,&pbo);glGetIntegerv(GL_PACK_ROW_LENGTH,&row);
|
||||
glGetIntegerv(GL_PACK_SKIP_ROWS,&skipr);glGetIntegerv(GL_PACK_SKIP_PIXELS,&skipp);
|
||||
int ok=pass_make_color_fbo(&s_capture_read_tex,NULL,&s_capture_read_fbo,&s_capture_read_w,&s_capture_read_h,
|
||||
w,h,GL_RGBA8,GL_RGBA,GL_UNSIGNED_BYTE);
|
||||
if(ok) {
|
||||
glDisable(GL_SCISSOR_TEST);glDisable(0x8DB9);
|
||||
p_glBindFramebuffer(PSXGL_READ_FRAMEBUFFER,pair->fbo[eye]);
|
||||
p_glBindFramebuffer(PSXGL_DRAW_FRAMEBUFFER,s_capture_read_fbo);
|
||||
p_glBlitFramebuffer(0,0,pair->tw[eye],pair->th[eye],0,0,w,h,GL_COLOR_BUFFER_BIT,GL_NEAREST);
|
||||
p_glBindFramebuffer(PSXGL_READ_FRAMEBUFFER,s_capture_read_fbo);
|
||||
p_glBindBuffer(0x88EB,0);glPixelStorei(GL_PACK_ALIGNMENT,1);glPixelStorei(GL_PACK_ROW_LENGTH,0);
|
||||
glPixelStorei(GL_PACK_SKIP_ROWS,0);glPixelStorei(GL_PACK_SKIP_PIXELS,0);
|
||||
glReadPixels(0,0,w,h,GL_RGBA,GL_UNSIGNED_BYTE,rgba);
|
||||
}
|
||||
p_glBindFramebuffer(PSXGL_READ_FRAMEBUFFER,read);p_glBindFramebuffer(PSXGL_DRAW_FRAMEBUFFER,draw);
|
||||
glBindTexture(GL_TEXTURE_2D,texture);glPixelStorei(GL_PACK_ALIGNMENT,pack);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH,row);glPixelStorei(GL_PACK_SKIP_ROWS,skipr);glPixelStorei(GL_PACK_SKIP_PIXELS,skipp);
|
||||
p_glBindBuffer(0x88EB,pbo);if(scissor)glEnable(GL_SCISSOR_TEST);if(srgb)glEnable(0x8DB9);
|
||||
return ok;
|
||||
}
|
||||
static void stereo_invalidate(void) {
|
||||
s_stereo_valid = 0;
|
||||
s_stereo_pair[0].mask = s_stereo_pair[1].mask = 0;
|
||||
|
||||
@@ -979,3 +979,19 @@ int psx_mod_render_stereo(CPUState *cpu, const PSXModStereoFrame *frame,
|
||||
s_pair_busy = 0;
|
||||
return ok;
|
||||
}
|
||||
|
||||
int psx_mod_render_capture_rgba(CPUState *cpu,const PSXModRenderPass *rect,
|
||||
PSXModRenderPassFn fn,void *user,
|
||||
uint8_t *rgba,uint32_t bytes) {
|
||||
if(s_pair_busy || !cpu || !rect || !fn || !rgba || rect->struct_size<sizeof *rect ||
|
||||
!rect->w || !rect->h || rect->x+rect->w>1024 || rect->y+rect->h>512 ||
|
||||
(uint64_t)rect->w*rect->h*4>bytes || transaction_status(1)!=PSX_MOD_RENDER_PASS_READY)return 0;
|
||||
if(g_overlay_flush_pending_cycles)g_overlay_flush_pending_cycles();
|
||||
s_pair_busy=1;s_plan_serial++;
|
||||
gl_renderer_stereo_stage_reset();
|
||||
PSXModRenderPass capture=*rect;capture.alpha_q16=0;
|
||||
int ok=render_transaction(cpu,&capture,fn,user,0);
|
||||
if(ok)ok=gl_renderer_stereo_stage_readback(0,rect->w,rect->h,rgba);
|
||||
gl_renderer_stereo_stage_reset();s_pair_busy=0;
|
||||
return ok;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user