vo_opengl: refactor tex_upload to ra_buf_pool

Also refactors the usage of tex_upload to make ra_tex_upload_pbo a
RA-internal thing again.

ra_buf_pool has the main advantage of being dynamically sized depending
on buf_poll, so for OpenGL we'll end up only using one buffer (when not
persistently mapping) - while for vulkan we'll use as many as necessary,
which depends on the swapchain depth anyway.
This commit is contained in:
Niklas Haas 2017-08-19 04:33:40 +02:00
parent 371000108a
commit 09c501a40e
No known key found for this signature in database
GPG Key ID: 9A09076581B27402
7 changed files with 124 additions and 84 deletions

View File

@ -54,7 +54,6 @@ struct mpgl_osd_part {
enum sub_bitmap_format format;
int change_id;
struct ra_tex *texture;
struct tex_upload pbo;
int w, h;
int num_subparts;
int prev_num_subparts;
@ -71,7 +70,6 @@ struct mpgl_osd {
const struct ra_format *fmt_table[SUBBITMAP_COUNT];
bool formats[SUBBITMAP_COUNT];
bool change_flag; // for reporting to API user only
bool want_pbo;
// temporary
int stereo_mode;
struct mp_osd_res osd_res;
@ -79,7 +77,7 @@ struct mpgl_osd {
};
struct mpgl_osd *mpgl_osd_init(struct ra *ra, struct mp_log *log,
struct osd_state *osd, bool want_pbo)
struct osd_state *osd)
{
struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx);
*ctx = (struct mpgl_osd) {
@ -88,7 +86,6 @@ struct mpgl_osd *mpgl_osd_init(struct ra *ra, struct mp_log *log,
.ra = ra,
.change_flag = true,
.scratch = talloc_zero_size(ctx, 1),
.want_pbo = want_pbo,
};
ctx->fmt_table[SUBBITMAP_LIBASS] = ra_find_unorm_format(ra, 1, 1);
@ -111,7 +108,6 @@ void mpgl_osd_destroy(struct mpgl_osd *ctx)
for (int n = 0; n < MAX_OSD_PARTS; n++) {
struct mpgl_osd_part *p = ctx->parts[n];
ra_tex_free(ctx->ra, &p->texture);
tex_upload_uninit(ctx->ra, &p->pbo);
}
talloc_free(ctx);
}
@ -180,7 +176,7 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
.stride = imgs->packed->stride[0],
};
ok = tex_upload(ra, &osd->pbo, ctx->want_pbo, &params);
ok = ra->fns->tex_upload(ra, &params);
done:
return ok;

View File

@ -9,7 +9,7 @@
#include "sub/osd.h"
struct mpgl_osd *mpgl_osd_init(struct ra *ra, struct mp_log *log,
struct osd_state *osd, bool want_pbo);
struct osd_state *osd);
void mpgl_osd_destroy(struct mpgl_osd *ctx);
void mpgl_osd_generate(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,

View File

@ -30,6 +30,11 @@ struct ra {
// formats should have a lower index. (E.g. GLES3 should put rg8 before la.)
struct ra_format **formats;
int num_formats;
// Accelerate texture uploads via an extra PBO even when
// RA_CAP_DIRECT_UPLOAD is supported. This is basically only relevant for
// OpenGL. Set by the RA user.
bool use_pbo;
};
enum {

View File

@ -15,6 +15,7 @@ struct ra_gl {
// For ra_tex.priv
struct ra_tex_gl {
struct ra_buf_pool pbo; // for ra.use_pbo
bool own_objects;
GLenum target;
GLuint texture; // 0 if no texture data associated
@ -218,6 +219,8 @@ static void gl_tex_destroy(struct ra *ra, struct ra_tex *tex)
GL *gl = ra_gl_get(ra);
struct ra_tex_gl *tex_gl = tex->priv;
ra_buf_pool_uninit(ra, &tex_gl->pbo);
if (tex_gl->own_objects) {
if (tex_gl->fbo)
gl->DeleteFramebuffers(1, &tex_gl->fbo);
@ -435,6 +438,9 @@ static bool gl_tex_upload(struct ra *ra,
assert(tex->params.host_mutable);
assert(!params->buf || !params->src);
if (ra->use_pbo && !params->buf)
return ra_tex_upload_pbo(ra, &tex_gl->pbo, params);
const void *src = params->src;
if (buf) {
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, buf_gl->buffer);

View File

@ -39,6 +39,91 @@ void gl_transform_ortho_fbodst(struct gl_transform *t, struct fbodst fbo)
gl_transform_ortho(t, 0, fbo.tex->params.w, 0, fbo.tex->params.h * y_dir);
}
void ra_buf_pool_uninit(struct ra *ra, struct ra_buf_pool *pool)
{
for (int i = 0; i < pool->num_buffers; i++)
ra_buf_free(ra, &pool->buffers[i]);
talloc_free(pool->buffers);
*pool = (struct ra_buf_pool){0};
}
static bool ra_buf_params_compatible(const struct ra_buf_params *new,
const struct ra_buf_params *old)
{
return new->type == old->type &&
new->size <= old->size &&
new->host_mapped == old->host_mapped &&
new->host_mutable == old->host_mutable;
}
static bool ra_buf_pool_grow(struct ra *ra, struct ra_buf_pool *pool)
{
struct ra_buf *buf = ra_buf_create(ra, &pool->current_params);
if (!buf)
return false;
MP_TARRAY_INSERT_AT(NULL, pool->buffers, pool->num_buffers, pool->index, buf);
MP_VERBOSE(ra, "Resized buffer pool to size %d\n", pool->num_buffers);
return true;
}
struct ra_buf *ra_buf_pool_get(struct ra *ra, struct ra_buf_pool *pool,
const struct ra_buf_params *params)
{
assert(!params->initial_data);
if (!ra_buf_params_compatible(params, &pool->current_params)) {
ra_buf_pool_uninit(ra, pool);
pool->current_params = *params;
}
// Make sure we have at least one buffer available
if (!pool->buffers && !ra_buf_pool_grow(ra, pool))
return NULL;
// Make sure the next buffer is available for use
if (!ra->fns->buf_poll(ra, pool->buffers[pool->index]) &&
!ra_buf_pool_grow(ra, pool))
{
return NULL;
}
struct ra_buf *buf = pool->buffers[pool->index++];
pool->index %= pool->num_buffers;
return buf;
}
bool ra_tex_upload_pbo(struct ra *ra, struct ra_buf_pool *pbo,
const struct ra_tex_upload_params *params)
{
if (params->buf)
return ra->fns->tex_upload(ra, params);
struct ra_tex *tex = params->tex;
size_t row_size = tex->params.dimensions == 2 ? params->stride :
tex->params.w * tex->params.format->pixel_size;
struct ra_buf_params bufparams = {
.type = RA_BUF_TYPE_TEX_UPLOAD,
.size = row_size * tex->params.h * tex->params.d,
.host_mutable = true,
};
struct ra_buf *buf = ra_buf_pool_get(ra, pbo, &bufparams);
if (!buf)
return false;
ra->fns->buf_update(ra, buf, 0, params->src, bufparams.size);
struct ra_tex_upload_params newparams = *params;
newparams.buf = buf;
newparams.src = NULL;
return ra->fns->tex_upload(ra, &newparams);
}
// Create a texture and a FBO using the texture as color attachments.
// fmt: texture internal format
// If the parameters are the same as the previous call, do not touch it.
@ -120,63 +205,6 @@ void fbotex_uninit(struct fbotex *fbo)
}
}
bool tex_upload(struct ra *ra, struct tex_upload *pbo, bool want_pbo,
const struct ra_tex_upload_params *params)
{
if (!(ra->caps & RA_CAP_DIRECT_UPLOAD))
want_pbo = true;
if (!want_pbo || params->buf)
return ra->fns->tex_upload(ra, params);
struct ra_tex *tex = params->tex;
size_t row_size = tex->params.dimensions == 2 ? params->stride :
tex->params.w * tex->params.format->pixel_size;
size_t needed_size = row_size * tex->params.h * tex->params.d;
if (needed_size > pbo->buffer_size)
tex_upload_uninit(ra, pbo);
if (!pbo->buffers[0]) {
struct ra_buf_params bufparams = {
.type = RA_BUF_TYPE_TEX_UPLOAD,
.size = needed_size,
.host_mutable = true,
};
pbo->buffer_size = bufparams.size;
for (int i = 0; i < NUM_PBO_BUFFERS; i++) {
pbo->buffers[i] = ra_buf_create(ra, &bufparams);
if (!pbo->buffers[i])
return false;
}
}
struct ra_buf *buf = pbo->buffers[pbo->index++];
pbo->index %= NUM_PBO_BUFFERS;
if (!ra->fns->buf_poll(ra, buf)) {
MP_WARN(ra, "Texture upload buffer was not free to use! Try "
"increasing NUM_PBO_BUFFERS.\n");
return false;
}
ra->fns->buf_update(ra, buf, 0, params->src, needed_size);
struct ra_tex_upload_params newparams = *params;
newparams.buf = buf;
newparams.src = NULL;
return ra->fns->tex_upload(ra, &newparams);
}
void tex_upload_uninit(struct ra *ra, struct tex_upload *pbo)
{
for (int i = 0; i < NUM_PBO_BUFFERS; i++)
ra_buf_free(ra, &pbo->buffers[i]);
*pbo = (struct tex_upload){0};
}
struct timer_pool {
struct ra *ra;
ra_timer *timer;

View File

@ -69,6 +69,25 @@ struct fbodst {
void gl_transform_ortho_fbodst(struct gl_transform *t, struct fbodst fbo);
// A pool of buffers, which can grow as needed
struct ra_buf_pool {
struct ra_buf_params current_params;
struct ra_buf **buffers;
int num_buffers;
int index;
};
void ra_buf_pool_uninit(struct ra *ra, struct ra_buf_pool *pool);
// Note: params->initial_data is *not* supported
struct ra_buf *ra_buf_pool_get(struct ra *ra, struct ra_buf_pool *pool,
const struct ra_buf_params *params);
// Helper that wraps ra_tex_upload using texture upload buffers to ensure that
// params->buf is always set. This is intended for RA-internal usage.
bool ra_tex_upload_pbo(struct ra *ra, struct ra_buf_pool *pbo,
const struct ra_tex_upload_params *params);
struct fbotex {
struct ra *ra;
struct ra_tex *tex;
@ -83,21 +102,6 @@ bool fbotex_change(struct fbotex *fbo, struct ra *ra, struct mp_log *log,
#define FBOTEX_FUZZY_H 2
#define FBOTEX_FUZZY (FBOTEX_FUZZY_W | FBOTEX_FUZZY_H)
#define NUM_PBO_BUFFERS 3
// A wrapper around tex_upload that uses PBOs internally if requested or
// required
struct tex_upload {
size_t buffer_size;
struct ra_buf *buffers[NUM_PBO_BUFFERS];
int index;
};
bool tex_upload(struct ra *ra, struct tex_upload *pbo, bool want_pbo,
const struct ra_tex_upload_params *params);
void tex_upload_uninit(struct ra *ra, struct tex_upload *pbo);
// A wrapper around ra_timer that does result pooling, averaging etc.
struct timer_pool;

View File

@ -84,7 +84,6 @@ static const struct ra_renderpass_input vertex_vao[] = {
struct texplane {
struct ra_tex *tex;
struct tex_upload pbo;
int w, h;
bool flipped;
};
@ -494,7 +493,7 @@ static void reinit_osd(struct gl_video *p)
mpgl_osd_destroy(p->osd);
p->osd = NULL;
if (p->osd_state)
p->osd = mpgl_osd_init(p->ra, p->log, p->osd_state, p->opts.pbo);
p->osd = mpgl_osd_init(p->ra, p->log, p->osd_state);
}
static void uninit_rendering(struct gl_video *p)
@ -987,7 +986,6 @@ static void uninit_video(struct gl_video *p)
for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n];
ra_tex_free(p->ra, &plane->tex);
tex_upload_uninit(p->ra, &plane->pbo);
}
*vimg = (struct video_image){0};
@ -3291,7 +3289,7 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
MP_VERBOSE(p, "DR enabled: %s\n", p->using_dr_path ? "yes" : "no");
}
if (!tex_upload(p->ra, &plane->pbo, p->opts.pbo, &params)) {
if (!p->ra->fns->tex_upload(p->ra, &params)) {
timer_pool_stop(p->upload_timer);
goto error;
}
@ -3300,7 +3298,9 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
mapped->mpi = mp_image_new_ref(mpi);
}
timer_pool_stop(p->upload_timer);
const char *mode = p->using_dr_path ? "DR" : p->opts.pbo ? "PBO" : "naive";
bool using_pbo = p->ra->use_pbo || !(p->ra->caps & RA_CAP_DIRECT_UPLOAD);
const char *mode = p->using_dr_path ? "DR" : using_pbo ? "PBO" : "naive";
pass_describe(p, "upload frame (%s)", mode);
pass_record(p, timer_pool_measure(p->upload_timer));
@ -3639,6 +3639,7 @@ static void reinit_from_options(struct gl_video *p)
check_gl_features(p);
uninit_rendering(p);
gl_sc_set_cache_dir(p->sc, p->opts.shader_cache_dir);
p->ra->use_pbo = p->opts.pbo;
gl_video_setup_hooks(p);
reinit_osd(p);