summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/opengl/utils.c')
-rw-r--r--video/out/opengl/utils.c75
1 files changed, 74 insertions, 1 deletions
diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c
index 73b411e66c..72a748a82d 100644
--- a/video/out/opengl/utils.c
+++ b/video/out/opengl/utils.c
@@ -109,8 +109,10 @@ mp_image_t *gl_read_window_contents(GL *gl)
mp_image_t *image = mp_image_alloc(IMGFMT_RGB24, vp[2], vp[3]);
if (!image)
return NULL;
+ gl->BindFramebuffer(GL_FRAMEBUFFER, gl->main_fb);
+ GLenum obj = gl->main_fb ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
gl->PixelStorei(GL_PACK_ALIGNMENT, 1);
- gl->ReadBuffer(GL_FRONT);
+ gl->ReadBuffer(obj);
//flip image while reading (and also avoid stride-related trouble)
for (int y = 0; y < vp[3]; y++) {
gl->ReadPixels(vp[0], vp[1] + vp[3] - y - 1, vp[2], 1,
@@ -118,6 +120,7 @@ mp_image_t *gl_read_window_contents(GL *gl)
image->planes[0] + y * image->stride[0]);
}
gl->PixelStorei(GL_PACK_ALIGNMENT, 4);
+ gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
return image;
}
@@ -1121,3 +1124,73 @@ void gl_timer_stop(struct gl_timer *timer)
if (gl->EndQuery)
gl->EndQuery(GL_TIME_ELAPSED);
}
+
+// Upload a texture, going through a PBO. PBO supposedly can facilitate
+// asynchronous copy from CPU to GPU, so this is an optimization. Note that
+// changing format/type/tex_w/tex_h or reusing the PBO in the same frame can
+// ruin performance.
+// This call is like gl_upload_tex(), plus PBO management/use.
+// target, format, type, dataptr, stride, x, y, w, h: texture upload params
+// (see gl_upload_tex())
+// tex_w, tex_h: maximum size of the used texture
+// use_pbo: for convenience, if false redirects the call to gl_upload_tex
+void gl_pbo_upload_tex(struct gl_pbo_upload *pbo, GL *gl, bool use_pbo,
+ GLenum target, GLenum format, GLenum type,
+ int tex_w, int tex_h, const void *dataptr, int stride,
+ int x, int y, int w, int h)
+{
+ assert(x >= 0 && y >= 0 && w >= 0 && h >= 0);
+ assert(x + w <= tex_w && y + h <= tex_h);
+
+ if (!use_pbo || !gl->MapBufferRange)
+ goto no_pbo;
+
+ size_t pix_stride = gl_bytes_per_pixel(format, type);
+ size_t buffer_size = pix_stride * tex_w * tex_h;
+ size_t needed_size = pix_stride * w * h;
+
+ if (buffer_size != pbo->buffer_size)
+ gl_pbo_upload_uninit(pbo);
+
+ if (!pbo->buffers[0]) {
+ pbo->gl = gl;
+ pbo->buffer_size = buffer_size;
+ gl->GenBuffers(2, &pbo->buffers[0]);
+ for (int n = 0; n < 2; n++) {
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->buffers[n]);
+ gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL,
+ GL_DYNAMIC_COPY);
+ }
+ }
+
+ pbo->index = (pbo->index + 1) % 2;
+
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->buffers[pbo->index]);
+ void *data = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, needed_size,
+ GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
+ if (!data)
+ goto no_pbo;
+
+ memcpy_pic(data, dataptr, pix_stride * w, h, pix_stride * w, stride);
+
+ if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ goto no_pbo;
+ }
+
+ gl_upload_tex(gl, target, format, type, NULL, pix_stride * w, x, y, w, h);
+
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ return;
+
+no_pbo:
+ gl_upload_tex(gl, target, format, type, dataptr, stride, x, y, w, h);
+}
+
+void gl_pbo_upload_uninit(struct gl_pbo_upload *pbo)
+{
+ if (pbo->gl)
+ pbo->gl->DeleteBuffers(2, &pbo->buffers[0]);
+ *pbo = (struct gl_pbo_upload){0};
+}