Something went wrong. Try again.
🎥 Command line media player
Something went wrong. Try again.
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335#include "common/msg.h"#include "video/out/vo.h"#include "utils.h"
// Standard parallel 2D projection, except y1 < y0 means that the coordinate// system is flipped, not the projection.void gl_transform_ortho(struct gl_transform *t, float x0, float x1, float y0, float y1){ if (y1 < y0) { float tmp = y0; y0 = tmp - y1; y1 = tmp; }
t->m[0][0] = 2.0f / (x1 - x0); t->m[0][1] = 0.0f; t->m[1][0] = 0.0f; t->m[1][1] = 2.0f / (y1 - y0); t->t[0] = -(x1 + x0) / (x1 - x0); t->t[1] = -(y1 + y0) / (y1 - y0);}
// Apply the effects of one transformation to another, transforming it in the// process. In other words: post-composes t onto xvoid gl_transform_trans(struct gl_transform t, struct gl_transform *x){ struct gl_transform xt = *x; x->m[0][0] = t.m[0][0] * xt.m[0][0] + t.m[0][1] * xt.m[1][0]; x->m[1][0] = t.m[1][0] * xt.m[0][0] + t.m[1][1] * xt.m[1][0]; x->m[0][1] = t.m[0][0] * xt.m[0][1] + t.m[0][1] * xt.m[1][1]; x->m[1][1] = t.m[1][0] * xt.m[0][1] + t.m[1][1] * xt.m[1][1]; gl_transform_vec(t, &x->t[0], &x->t[1]);}
void gl_transform_ortho_fbo(struct gl_transform *t, struct ra_fbo fbo){ int y_dir = fbo.flip ? -1 : 1; 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 of type %u to size %d\n", pool->current_params.type, 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;
int height = tex->params.h; if (tex->params.dimensions == 2 && params->rc) height = mp_rect_h(*params->rc);
struct ra_buf_params bufparams = { .type = RA_BUF_TYPE_TEX_UPLOAD, .size = row_size * height * 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);}
struct ra_layout std140_layout(struct ra_renderpass_input *inp){ size_t el_size = ra_vartype_size(inp->type);
// std140 packing rules: // 1. The alignment of generic values is their size in bytes // 2. The alignment of vectors is the vector length * the base count, with // the exception of vec3 which is always aligned like vec4 // 3. The alignment of arrays is that of the element size rounded up to // the nearest multiple of vec4 // 4. Matrices are treated like arrays of vectors // 5. Arrays/matrices are laid out with a stride equal to the alignment size_t stride = el_size * inp->dim_v; size_t align = stride; if (inp->dim_v == 3) align += el_size; if (inp->dim_m > 1) stride = align = MP_ALIGN_UP(stride, sizeof(float[4]));
return (struct ra_layout) { .align = align, .stride = stride, .size = stride * inp->dim_m, };}
struct ra_layout std430_layout(struct ra_renderpass_input *inp){ size_t el_size = ra_vartype_size(inp->type);
// std430 packing rules: like std140, except arrays/matrices are always // "tightly" packed, even arrays/matrices of vec3s size_t stride = el_size * inp->dim_v; size_t align = stride; if (inp->dim_v == 3 && inp->dim_m == 1) align += el_size;
return (struct ra_layout) { .align = align, .stride = stride, .size = stride * inp->dim_m, };}
// Resize a texture to a new desired size and format if necessarybool ra_tex_resize(struct ra *ra, struct mp_log *log, struct ra_tex **tex, int w, int h, const struct ra_format *fmt){ if (*tex) { struct ra_tex_params cur_params = (*tex)->params; if (cur_params.w == w && cur_params.h == h && cur_params.format == fmt) return true; }
mp_dbg(log, "Resizing texture: %dx%d\n", w, h);
if (!fmt || !fmt->renderable || !fmt->linear_filter || !fmt->storable) { mp_err(log, "Format %s not supported.\n", fmt ? fmt->name : "(unset)"); return false; }
ra_tex_free(ra, tex); struct ra_tex_params params = { .dimensions = 2, .w = w, .h = h, .d = 1, .format = fmt, .src_linear = true, .render_src = true, .render_dst = true, .storage_dst = true, .blit_src = true, };
*tex = ra_tex_create(ra, ¶ms); if (!*tex) mp_err(log, "Error: texture could not be created.\n");
return *tex;}
struct timer_pool { struct ra *ra; ra_timer *timer; bool running; // detect invalid usage
uint64_t samples[VO_PERF_SAMPLE_COUNT]; int sample_idx; int sample_count;
uint64_t sum; uint64_t peak;};
struct timer_pool *timer_pool_create(struct ra *ra){ if (!ra->fns->timer_create) return NULL;
ra_timer *timer = ra->fns->timer_create(ra); if (!timer) return NULL;
struct timer_pool *pool = talloc(NULL, struct timer_pool); if (!pool) { ra->fns->timer_destroy(ra, timer); return NULL; }
*pool = (struct timer_pool){ .ra = ra, .timer = timer }; return pool;}
void timer_pool_destroy(struct timer_pool *pool){ if (!pool) return;
pool->ra->fns->timer_destroy(pool->ra, pool->timer); talloc_free(pool);}
void timer_pool_start(struct timer_pool *pool){ if (!pool) return;
assert(!pool->running); pool->ra->fns->timer_start(pool->ra, pool->timer); pool->running = true;}
void timer_pool_stop(struct timer_pool *pool){ if (!pool) return;
assert(pool->running); uint64_t res = pool->ra->fns->timer_stop(pool->ra, pool->timer); pool->running = false;
if (res) { // Input res into the buffer and grab the previous value uint64_t old = pool->samples[pool->sample_idx]; pool->sample_count = MPMIN(pool->sample_count + 1, VO_PERF_SAMPLE_COUNT); pool->samples[pool->sample_idx++] = res; pool->sample_idx %= VO_PERF_SAMPLE_COUNT; pool->sum = pool->sum + res - old;
// Update peak if necessary if (res >= pool->peak) { pool->peak = res; } else if (pool->peak == old) { // It's possible that the last peak was the value we just removed, // if so we need to scan for the new peak uint64_t peak = res; for (int i = 0; i < VO_PERF_SAMPLE_COUNT; i++) peak = MPMAX(peak, pool->samples[i]); pool->peak = peak; } }}
struct mp_pass_perf timer_pool_measure(struct timer_pool *pool){ if (!pool) return (struct mp_pass_perf){0};
struct mp_pass_perf res = { .peak = pool->peak, .count = pool->sample_count, };
int idx = pool->sample_idx - pool->sample_count + VO_PERF_SAMPLE_COUNT; for (int i = 0; i < res.count; i++) { idx %= VO_PERF_SAMPLE_COUNT; res.samples[i] = pool->samples[idx++]; }
if (res.count > 0) { res.last = res.samples[res.count - 1]; res.avg = pool->sum / res.count; }
return res;}
void mp_log_source(struct mp_log *log, int lev, const char *src){ int line = 1; if (!src) return; while (*src) { const char *end = strchr(src, '\n'); const char *next = end + 1; if (!end) next = end = src + strlen(src); mp_msg(log, lev, "[%3d] %.*s\n", line, (int)(end - src), src); line++; src = next; }}