summaryrefslogtreecommitdiffstats
path: root/video/out/gpu
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-02-07 20:18:36 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-02-11 17:45:51 -0800
commit9f595f3a80eeaa0bfbda5702031f054f684f6123 (patch)
tree0667e6e7ab4c64dcfd28aa23e10690e1776a6f03 /video/out/gpu
parent7b1e73139f73f446a472782e1465040c0e6b16dd (diff)
downloadmpv-9f595f3a80eeaa0bfbda5702031f054f684f6123.tar.bz2
mpv-9f595f3a80eeaa0bfbda5702031f054f684f6123.tar.xz
vo_gpu: make screenshots use the GL renderer
Using the GL renderer for color conversion will make sure screenshots will use the same conversion as normal video rendering. It can do this for all types of screenshots. The logic when to write 16 bit PNGs changes. To approximate the old behavior, we decide by looking whether the source video format has more than 8 bits per component. We apply this logic even for window screenshots. Also, 16 bit PNGs now always include an unused alpha channel. The reason is that FFmpeg has RGB48 and RGBA64 formats, but no RGB064. RGB48 is 3 bytes and usually not supported by GPUs for rendering, so we have to use RGBA64, which forces an alpha channel. Will break for users who use --target-trc and similar options. I considered creating a new gl_video context, but it could double GPU memory use, so I didn't. This uses FBOs instead of glGetTexImage(), because that increases the chance it could work on GLES (e.g. ANGLE). Untested. No support for the Vulkan and D3D11 backends yet. Fixes #5498. Also fixes #5240, because the code for reading back is not used with the new code path.
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);