summaryrefslogtreecommitdiffstats
path: root/video/out/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/gpu')
-rw-r--r--video/out/gpu/ra.h12
-rw-r--r--video/out/gpu/video.c80
-rw-r--r--video/out/gpu/video.h4
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, &params);
+ 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);