summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/video.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-07-26 11:19:51 +0200
committerwm4 <wm4@nowhere>2017-07-26 11:31:43 +0200
commit81851febc4766e053cc17134c779959f5942025a (patch)
tree48e6aedcdb3889e641dfb169e1fff8c144b01bfa /video/out/opengl/video.c
parent5904eddb38f20bf794aadff659050c0b32479054 (diff)
downloadmpv-81851febc4766e053cc17134c779959f5942025a.tar.bz2
mpv-81851febc4766e053cc17134c779959f5942025a.tar.xz
vo_opengl: start work on rendering API abstraction
This starts work on moving OpenGL-specific code out of the general renderer code, so that we can support other other GPU APIs. This is in a very early stage and it's only a proof of concept. It's unknown whether this will succeed or result in other backends. For now, the GL rendering API ("ra") and its only provider (ra_gl) does texture creation/upload/destruction only. And it's used for the main video texture only. All other code is still hardcoded to GL. There is some duplication with ra_format and gl_format handling. In the end, only the ra variants will be needed (plus the gl_format table of course). For now, this is simpler, because for some reason lots of hwdec code still requires the GL variants, and would have to be updated to use the ra ones. Currently, the video.c code accesses private ra_gl fields. In the end, it should not do that of course, and it would not include ra_gl.h. Probably adds bugs, but you can keep them.
Diffstat (limited to 'video/out/opengl/video.c')
-rw-r--r--video/out/opengl/video.c206
1 files changed, 85 insertions, 121 deletions
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index 8724d5ff9e..130d049136 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -36,6 +36,8 @@
#include "utils.h"
#include "hwdec.h"
#include "osd.h"
+#include "ra.h"
+#include "ra_gl.h"
#include "stream/stream.h"
#include "video_shaders.h"
#include "user_shaders.h"
@@ -84,6 +86,7 @@ static const struct gl_vao_entry vertex_vao[] = {
};
struct texplane {
+ struct ra_tex *texture;
int w, h;
int tex_w, tex_h;
GLint gl_internal_format;
@@ -92,7 +95,6 @@ struct texplane {
GLenum gl_type;
GLuint gl_texture;
bool flipped;
- struct gl_pbo_upload pbo;
};
struct video_image {
@@ -175,18 +177,15 @@ struct pass_info {
#define PASS_INFO_MAX (SHADER_MAX_HOOKS + 32)
struct dr_buffer {
- void *ptr;
- size_t size;
- GLuint pbo;
- // While a PBO is read-accessed by GL, we must not write to the mapped data.
- // The fence tells us when GL is done, and the mpi reference will keep the
- // data from being recycled (or from other references gaining write access).
- GLsync fence;
+ struct ra_mapped_buffer *buffer;
+ // The mpi reference will keep the data from being recycled (or from other
+ // references gaining write access) while the GPU is accessing the buffer.
struct mp_image *mpi;
};
struct gl_video {
GL *gl;
+ struct ra *ra;
struct mpv_global *global;
struct mp_log *log;
@@ -213,7 +212,7 @@ struct gl_video {
struct mp_image_params real_image_params; // configured format
struct mp_image_params image_params; // texture format (mind hwdec case)
- struct gl_imgfmt_desc gl_format; // texture format
+ struct ra_imgfmt_desc ra_format; // texture format
int plane_count;
bool is_gray;
@@ -715,8 +714,8 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg,
int h = p->image_params.h;
// Determine the chroma offset
- float ls_w = 1.0 / p->gl_format.chroma_w;
- float ls_h = 1.0 / p->gl_format.chroma_h;
+ float ls_w = 1.0 / p->ra_format.chroma_w;
+ float ls_h = 1.0 / p->ra_format.chroma_h;
struct gl_transform chroma = {{{ls_w, 0.0}, {0.0, ls_h}}};
@@ -733,12 +732,12 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg,
}
int msb_valid_bits =
- p->gl_format.component_bits + MPMIN(p->gl_format.component_pad, 0);
+ p->ra_format.component_bits + MPMIN(p->ra_format.component_pad, 0);
// The existing code assumes we just have a single tex multiplier for
// all of the planes. This may change in the future
float tex_mul = 1.0 / mp_get_csp_mul(p->image_params.color.space,
msb_valid_bits,
- p->gl_format.component_bits);
+ p->ra_format.component_bits);
memset(tex, 0, 4 * sizeof(tex[0]));
for (int n = 0; n < p->plane_count; n++) {
@@ -746,7 +745,7 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg,
enum plane_type type = PLANE_NONE;
for (int i = 0; i < 4; i++) {
- int c = p->gl_format.components[n][i];
+ int c = p->ra_format.components[n][i];
enum plane_type ctype;
if (c == 0) {
ctype = PLANE_NONE;
@@ -775,7 +774,7 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg,
};
for (int i = 0; i < 4; i++)
- tex[n].components += !!p->gl_format.components[n][i];
+ tex[n].components += !!p->ra_format.components[n][i];
get_transform(t->w, t->h, p->image_params.rotate, t->flipped,
&tex[n].transform);
@@ -791,8 +790,8 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg,
struct gl_transform tr = chroma;
gl_transform_vec(rot, &tr.t[0], &tr.t[1]);
- float dx = (chroma_upsize(w, p->gl_format.chroma_w) - w) * ls_w;
- float dy = (chroma_upsize(h, p->gl_format.chroma_h) - h) * ls_h;
+ float dx = (chroma_upsize(w, p->ra_format.chroma_w) - w) * ls_w;
+ float dy = (chroma_upsize(h, p->ra_format.chroma_h) - h) * ls_h;
// Adjust the chroma offset if the real chroma size is fractional
// due image sizes not aligned to chroma subsampling.
@@ -814,7 +813,7 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg,
// Return the index of the given component (assuming all non-padding components
// of all planes are concatenated into a linear list).
-static int find_comp(struct gl_imgfmt_desc *desc, int component)
+static int find_comp(struct ra_imgfmt_desc *desc, int component)
{
int cur = 0;
for (int n = 0; n < desc->num_planes; n++) {
@@ -831,8 +830,6 @@ static int find_comp(struct gl_imgfmt_desc *desc, int component)
static void init_video(struct gl_video *p)
{
- GL *gl = p->gl;
-
p->hwdec_active = false;
p->use_integer_conversion = false;
@@ -849,26 +846,26 @@ static void init_video(struct gl_video *p)
}
}
- p->gl_format = (struct gl_imgfmt_desc){0};
- gl_get_imgfmt_desc(p->gl, p->image_params.imgfmt, &p->gl_format);
+ p->ra_format = (struct ra_imgfmt_desc){0};
+ ra_get_imgfmt_desc(p->ra, p->image_params.imgfmt, &p->ra_format);
- p->plane_count = p->gl_format.num_planes;
+ p->plane_count = p->ra_format.num_planes;
p->has_alpha = false;
p->is_gray = true;
- for (int n = 0; n < p->gl_format.num_planes; n++) {
+ for (int n = 0; n < p->ra_format.num_planes; n++) {
for (int i = 0; i < 4; i++) {
- if (p->gl_format.components[n][i]) {
- p->has_alpha |= p->gl_format.components[n][i] == 4;
- p->is_gray &= p->gl_format.components[n][i] == 1 ||
- p->gl_format.components[n][i] == 4;
+ if (p->ra_format.components[n][i]) {
+ p->has_alpha |= p->ra_format.components[n][i] == 4;
+ p->is_gray &= p->ra_format.components[n][i] == 1 ||
+ p->ra_format.components[n][i] == 4;
}
}
}
for (int c = 0; c < 4; c++) {
- int loc = find_comp(&p->gl_format, c + 1);
+ int loc = find_comp(&p->ra_format, c + 1);
p->color_swizzle[c] = "rgba"[loc >= 0 && loc < 4 ? loc : 0];
}
p->color_swizzle[4] = '\0';
@@ -892,43 +889,41 @@ static void init_video(struct gl_video *p)
if (!p->hwdec_active) {
struct video_image *vimg = &p->image;
- GLenum gl_target =
- p->opts.use_rectangle ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D;
-
struct mp_image layout = {0};
mp_image_set_params(&layout, &p->image_params);
for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n];
- const struct gl_format *format = p->gl_format.planes[n];
-
- plane->gl_target = gl_target;
- plane->gl_format = format->format;
- plane->gl_internal_format = format->internal_format;
- plane->gl_type = format->type;
-
- p->use_integer_conversion |= gl_is_integer_format(plane->gl_format);
+ const struct ra_format *format = p->ra_format.planes[n];
plane->w = mp_image_plane_w(&layout, n);
plane->h = mp_image_plane_h(&layout, n);
plane->tex_w = plane->w + p->opts.tex_pad_x;
plane->tex_h = plane->h + p->opts.tex_pad_y;
- gl->GenTextures(1, &plane->gl_texture);
- gl->BindTexture(gl_target, plane->gl_texture);
+ struct ra_tex_params params = {
+ .dimensions = 2,
+ .w = plane->tex_w,
+ .h = plane->tex_h,
+ .d = 1,
+ .format = format,
+ .src_linear = format->linear_filter,
+ .non_normalized = p->opts.use_rectangle,
+ };
- gl->TexImage2D(gl_target, 0, plane->gl_internal_format,
- plane->tex_w, plane->tex_h, 0,
- plane->gl_format, plane->gl_type, NULL);
+ plane->texture = p->ra->fns->tex_create(p->ra, &params);
+ if (!plane->texture)
+ abort(); // shit happens
- int filter = gl_is_integer_format(plane->gl_format)
- ? GL_NEAREST : GL_LINEAR;
- gl->TexParameteri(gl_target, GL_TEXTURE_MIN_FILTER, filter);
- gl->TexParameteri(gl_target, GL_TEXTURE_MAG_FILTER, filter);
- gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ struct ra_tex_gl *tex_gl = plane->texture->priv;
- gl->BindTexture(gl_target, 0);
+ plane->gl_texture = tex_gl->texture;
+ plane->gl_target = tex_gl->target;
+ plane->gl_format = tex_gl->format;
+ plane->gl_internal_format = tex_gl->internal_format;
+ plane->gl_type = tex_gl->type;
+
+ p->use_integer_conversion |= format->ctype == RA_CTYPE_UINT;
MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", n,
plane->tex_w, plane->tex_h);
@@ -958,9 +953,11 @@ static void unmap_current_image(struct gl_video *p)
static struct dr_buffer *gl_find_dr_buffer(struct gl_video *p, uint8_t *ptr)
{
for (int i = 0; i < p->num_dr_buffers; i++) {
- struct dr_buffer *buf = &p->dr_buffers[i];
- if (ptr >= (uint8_t *)buf->ptr && ptr < (uint8_t *)buf->ptr + buf->size)
- return buf;
+ struct dr_buffer *buffer = &p->dr_buffers[i];
+ uint8_t *buf = buffer->buffer->data;
+ size_t size = buffer->buffer->size;
+ if (ptr >= buf && ptr < buf + size)
+ return buffer;
}
return NULL;
@@ -968,18 +965,14 @@ static struct dr_buffer *gl_find_dr_buffer(struct gl_video *p, uint8_t *ptr)
static void gc_pending_dr_fences(struct gl_video *p, bool force)
{
- GL *gl = p->gl;
-
again:;
for (int n = 0; n < p->num_dr_buffers; n++) {
struct dr_buffer *buffer = &p->dr_buffers[n];
- if (!buffer->fence)
+ if (!buffer->mpi)
continue;
- GLenum res = gl->ClientWaitSync(buffer->fence, 0, 0); // non-blocking
- if (res == GL_ALREADY_SIGNALED || force) {
- gl->DeleteSync(buffer->fence);
- buffer->fence = NULL;
+ bool res = p->ra->fns->poll_mapped_buffer(p->ra, buffer->buffer);
+ if (res || force) {
// Unreferencing the image could cause gl_video_dr_free_buffer()
// to be called by the talloc destructor (if it was the last
// reference). This will implicitly invalidate the buffer pointer
@@ -1018,8 +1011,6 @@ static void unmap_overlay(struct gl_video *p)
static void uninit_video(struct gl_video *p)
{
- GL *gl = p->gl;
-
uninit_rendering(p);
struct video_image *vimg = &p->image;
@@ -1030,8 +1021,8 @@ static void uninit_video(struct gl_video *p)
for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n];
- gl->DeleteTextures(1, &plane->gl_texture);
- gl_pbo_upload_uninit(&plane->pbo);
+ if (plane->texture)
+ p->ra->fns->tex_destroy(p->ra, plane->texture);
}
*vimg = (struct video_image){0};
@@ -1302,7 +1293,7 @@ static void copy_img_tex(struct gl_video *p, int *offset, struct img_tex img)
}
if (gl_is_integer_format(img.gl_format)) {
- uint64_t tex_max = 1ull << p->gl_format.component_bits;
+ uint64_t tex_max = 1ull << p->ra_format.component_bits;
img.multiplier *= 1.0 / (tex_max - 1);
}
@@ -2680,8 +2671,8 @@ static void pass_render_frame_dumb(struct gl_video *p, int fbo)
int index = 0;
for (int i = 0; i < p->plane_count; i++) {
- int cw = tex[i].type == PLANE_CHROMA ? p->gl_format.chroma_w : 1;
- int ch = tex[i].type == PLANE_CHROMA ? p->gl_format.chroma_h : 1;
+ int cw = tex[i].type == PLANE_CHROMA ? p->ra_format.chroma_w : 1;
+ int ch = tex[i].type == PLANE_CHROMA ? p->ra_format.chroma_h : 1;
if (p->image_params.rotate % 180 == 90)
MPSWAP(int, cw, ch);
@@ -3340,36 +3331,21 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
plane->flipped = mpi->stride[0] < 0;
- gl->BindTexture(plane->gl_target, plane->gl_texture);
+ // (It's unclear whether this should be changeable on the fly.)
+ plane->texture->use_pbo = p->opts.pbo;
struct dr_buffer *mapped = gl_find_dr_buffer(p, mpi->planes[n]);
- if (mapped) {
- assert(mapped->pbo > 0);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, mapped->pbo);
- uintptr_t offset = mpi->planes[n] - (uint8_t *)mapped->ptr;
- gl_upload_tex(gl, plane->gl_target,
- plane->gl_format, plane->gl_type,
- (void *)offset, mpi->stride[n],
- 0, 0, plane->w, plane->h);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- // Make sure the PBO is not reused until GL is done with it. If a
- // previous operation is pending, "update" it by creating a new
- // fence that will cover the previous operation as well.
- gl->DeleteSync(mapped->fence);
- mapped->fence = gl->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- if (!mapped->mpi)
- mapped->mpi = mp_image_new_ref(mpi);
- } else {
- gl_pbo_upload_tex(&plane->pbo, gl, p->opts.pbo, plane->gl_target,
- plane->gl_format, plane->gl_type, plane->w, plane->h,
- mpi->planes[n], mpi->stride[n],
- 0, 0, plane->w, plane->h);
- }
+
+ p->ra->fns->tex_upload(p->ra, plane->texture, mpi->planes[n],
+ mpi->stride[n], mapped ? mapped->buffer : NULL);
+
+ if (mapped && !mapped->mpi)
+ mapped->mpi = mp_image_new_ref(mpi);
+
if (p->using_dr_path != !!mapped) {
p->using_dr_path = !!mapped;
MP_VERBOSE(p, "DR enabled: %s\n", p->using_dr_path ? "yes" : "no");
}
- gl->BindTexture(plane->gl_target, 0);
}
gl_timer_stop(gl);
const char *mode = p->using_dr_path ? "DR" : p->opts.pbo ? "PBO" : "naive";
@@ -3565,8 +3541,6 @@ static void init_gl(struct gl_video *p)
debug_check_gl(p, "before init_gl");
- gl->Disable(GL_DITHER);
-
gl_video_set_gl_state(p);
// Test whether we can use 10 bit.
@@ -3578,6 +3552,9 @@ static void init_gl(struct gl_video *p)
p->blit_timer = gl_timer_create(gl);
debug_check_gl(p, "after init_gl");
+
+ ra_dump_tex_formats(p->ra, MSGL_DEBUG);
+ ra_dump_img_formats(p->ra, MSGL_DEBUG);
}
void gl_video_uninit(struct gl_video *p)
@@ -3612,6 +3589,8 @@ void gl_video_uninit(struct gl_video *p)
// Should all have been unreffed already.
assert(!p->num_dr_buffers);
+ p->ra->fns->destroy(p->ra);
+ talloc_free(p->ra);
talloc_free(p);
}
@@ -3703,14 +3682,17 @@ void gl_video_set_osd_source(struct gl_video *p, struct osd_state *osd)
struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g)
{
- if (gl->version < 210 && gl->es < 200) {
- mp_err(log, "At least OpenGL 2.1 or OpenGL ES 2.0 required.\n");
+ struct ra *ra = talloc_zero(NULL, struct ra);
+ ra->log = log;
+ if (ra_init_gl(ra, gl) < 0) {
+ talloc_free(ra);
return NULL;
}
struct gl_video *p = talloc_ptrtype(NULL, p);
*p = (struct gl_video) {
.gl = gl,
+ .ra = ra,
.global = g,
.log = log,
.sc = gl_sc_create(gl, log),
@@ -3899,9 +3881,7 @@ void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec)
void *gl_video_dr_alloc_buffer(struct gl_video *p, size_t size)
{
- GL *gl = p->gl;
-
- if (gl->version < 440)
+ if (!p->ra->fns->create_mapped_buffer)
return NULL;
MP_TARRAY_GROW(p, p->dr_buffers, p->num_dr_buffers);
@@ -3909,40 +3889,24 @@ void *gl_video_dr_alloc_buffer(struct gl_video *p, size_t size)
struct dr_buffer *buffer = &p->dr_buffers[index];
*buffer = (struct dr_buffer){
- .size = size,
+ .buffer = p->ra->fns->create_mapped_buffer(p->ra, size),
};
- unsigned flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT |
- GL_MAP_COHERENT_BIT;
-
- gl->GenBuffers(1, &buffer->pbo);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
- gl->BufferStorage(GL_PIXEL_UNPACK_BUFFER, size, NULL, flags);
- buffer->ptr = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size, flags);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- if (!buffer->ptr) {
- gl_check_error(p->gl, p->log, "mapping buffer");
- gl->DeleteBuffers(1, &buffer->pbo);
+ if (!buffer->buffer) {
MP_TARRAY_REMOVE_AT(p->dr_buffers, p->num_dr_buffers, index);
return NULL;
}
- return buffer->ptr;
+ return buffer->buffer->data;
};
void gl_video_dr_free_buffer(struct gl_video *p, void *ptr)
{
- GL *gl = p->gl;
-
for (int n = 0; n < p->num_dr_buffers; n++) {
struct dr_buffer *buffer = &p->dr_buffers[n];
- if (buffer->ptr == ptr) {
+ if (buffer->buffer->data == ptr) {
assert(!buffer->mpi); // can't be freed while it has a ref
- gl->DeleteSync(buffer->fence);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->pbo);
- gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
- gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- gl->DeleteBuffers(1, &buffer->pbo);
+ p->ra->fns->destroy_mapped_buffer(p->ra, buffer->buffer);
MP_TARRAY_REMOVE_AT(p->dr_buffers, p->num_dr_buffers, n);
return;