diff options
Diffstat (limited to 'video/out/gpu')
-rw-r--r-- | video/out/gpu/ra.h | 12 | ||||
-rw-r--r-- | video/out/gpu/video.c | 80 | ||||
-rw-r--r-- | video/out/gpu/video.h | 4 |
3 files changed, 95 insertions, 1 deletions
diff --git a/video/out/gpu/ra.h b/video/out/gpu/ra.h index f1037e45c3..05a7c54a66 100644 --- a/video/out/gpu/ra.h +++ b/video/out/gpu/ra.h @@ -110,6 +110,7 @@ struct ra_tex_params { bool blit_src; // must be usable as a blit source bool blit_dst; // must be usable as a blit destination bool host_mutable; // texture may be updated with tex_upload + bool downloadable; // texture can be read with tex_download // When used as render source texture. bool src_linear; // if false, use nearest sampling (whether this can // be true depends on ra_format.linear_filter) @@ -151,6 +152,13 @@ struct ra_tex_upload_params { ptrdiff_t stride; // The size of a horizontal line in bytes (*not* texels!) }; +struct ra_tex_download_params { + struct ra_tex *tex; // Texture to download from + // Downloading directly (set by caller, data written to by callee): + void *dst; // Address of data (packed with no alignment) + ptrdiff_t stride; // The size of a horizontal line in bytes (*not* texels!) +}; + // Buffer usage type. This restricts what types of operations may be performed // on a buffer. enum ra_buf_type { @@ -379,6 +387,10 @@ struct ra_fns { // Returns whether successful. bool (*tex_upload)(struct ra *ra, const struct ra_tex_upload_params *params); + // Copy data from the texture to memory. ra_tex_params.downloadable must + // have been set to true on texture creation. + bool (*tex_download)(struct ra *ra, struct ra_tex_download_params *params); + // Create a buffer. This can be used as a persistently mapped buffer, // a uniform buffer, a shader storage buffer or possibly others. // Not all usage types must be supported; may return NULL if unavailable. diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index dcacdb1d01..6edf4b0ccf 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -2852,7 +2852,7 @@ static bool update_surface(struct gl_video *p, struct mp_image *mpi, // Draws an interpolate frame to fbo, based on the frame timing in t // flags: bit set of RENDER_FRAME_* flags static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t, - struct ra_fbo fbo, flags) + struct ra_fbo fbo, int flags) { bool is_new = false; @@ -3156,6 +3156,84 @@ done: pass_report_performance(p); } +void gl_video_screenshot(struct gl_video *p, struct vo_frame *frame, + struct voctrl_screenshot *args) +{ + bool ok = false; + struct mp_image *res = NULL; + + if (!p->ra->fns->tex_download) + return; + + struct mp_rect old_src = p->src_rect; + struct mp_rect old_dst = p->dst_rect; + struct mp_osd_res old_osd = p->osd_rect; + + if (!args->scaled) { + int w = p->real_image_params.w; + int h = p->real_image_params.h; + if (w < 1 || h < 1) + return; + + struct mp_rect rc = {0, 0, w, h}; + struct mp_osd_res osd = {.w = w, .h = h, .display_par = 1.0}; + gl_video_resize(p, &rc, &rc, &osd); + } + + gl_video_reset_surfaces(p); + + struct ra_tex_params params = { + .dimensions = 2, + .downloadable = true, + .w = p->osd_rect.w, + .h = p->osd_rect.h, + .render_dst = true, + }; + + params.format = ra_find_unorm_format(p->ra, 1, 4); + int mpfmt = IMGFMT_RGB0; + if (args->high_bit_depth && p->ra_format.component_bits > 8) { + const struct ra_format *fmt = ra_find_unorm_format(p->ra, 2, 4); + if (fmt && fmt->renderable) { + params.format = fmt; + mpfmt = IMGFMT_RGBA64; + } + } + + if (!params.format || !params.format->renderable) + goto done; + struct ra_tex *target = ra_tex_create(p->ra, ¶ms); + if (!target) + goto done; + + int flags = 0; + if (args->subs) + flags |= RENDER_FRAME_SUBS; + if (args->osd) + flags |= RENDER_FRAME_OSD; + gl_video_render_frame(p, frame, (struct ra_fbo){target}, flags); + + res = mp_image_alloc(mpfmt, params.w, params.h); + if (!res) + goto done; + + struct ra_tex_download_params download_params = { + .tex = target, + .dst = res->planes[0], + .stride = res->stride[0], + }; + if (!p->ra->fns->tex_download(p->ra, &download_params)) + goto done; + + ok = true; +done: + ra_tex_free(p->ra, &target); + gl_video_resize(p, &old_src, &old_dst, &old_osd); + if (!ok) + TA_FREEP(&res); + args->res = res; +} + // Use this color instead of the global option. void gl_video_set_clear_color(struct gl_video *p, struct m_color c) { diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h index cd17308810..80f31c2934 100644 --- a/video/out/gpu/video.h +++ b/video/out/gpu/video.h @@ -146,6 +146,7 @@ extern const struct m_sub_options gl_video_conf; struct gl_video; struct vo_frame; +struct voctrl_screenshot; enum { RENDER_FRAME_SUBS = 1 << 0, @@ -172,6 +173,9 @@ void gl_video_set_osd_pts(struct gl_video *p, double pts); bool gl_video_check_osd_change(struct gl_video *p, struct mp_osd_res *osd, double pts); +void gl_video_screenshot(struct gl_video *p, struct vo_frame *frame, + struct voctrl_screenshot *args); + float gl_video_scale_ambient_lux(float lmin, float lmax, float rmin, float rmax, float lux); void gl_video_set_ambient_lux(struct gl_video *p, int lux); |