diff options
Diffstat (limited to 'video/out/opengl/utils.c')
-rw-r--r-- | video/out/opengl/utils.c | 75 |
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}; +} |