Skip to content

Commit

Permalink
add support for "unresolved" texture frames in texture registry
Browse files Browse the repository at this point in the history
Up until now it was only allowed to push an
OpenGL frame with it's name, format etc, which
the engine will fetch from the external texture as
soon as possible.

Now, you can push an "unresolved" frame, which
is basically a callback and an opaque `void*`
pointer, which the engine texture registry will
call when the engine wants to know the exact
texture name, format, target etc, to fill in
("resolve") those details.

Basically allows you to be a bit smarter.
Maybe, in the time between
`texture_push_frame_unresolved` and the actual
execution of the resolve callback, a new
frame has arrived in the video player, and you
want to use that instead.
  • Loading branch information
ardera committed Apr 7, 2023
1 parent 0a4cc19 commit c81fa43
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 24 deletions.
8 changes: 8 additions & 0 deletions include/texture_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ struct texture_frame {
void *userdata;
};

struct unresolved_texture_frame {
int (*resolve)(size_t width, size_t height, void *userdata, struct texture_frame *frame_out);
void (*destroy)(void *userdata);
void *userdata;
};

struct texture_registry *texture_registry_new(const struct texture_registry_interface *interface, void *userdata);

void texture_registry_destroy(struct texture_registry *reg);
Expand All @@ -54,6 +60,8 @@ int64_t texture_get_id(struct texture *texture);

int texture_push_frame(struct texture *texture, const struct texture_frame *frame);

int texture_push_unresolved_frame(struct texture *texture, const struct unresolved_texture_frame *frame);

void texture_destroy(struct texture *texture);

#endif
46 changes: 35 additions & 11 deletions src/dmabuf_surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,24 @@ ATTR_MALLOC struct dmabuf_surface *dmabuf_surface_new(struct tracer *tracer, str
return NULL;
}

int on_resolve_texture_frame(size_t width, size_t height, void *userdata, struct texture_frame *frame_out) {
/// TODO: Implement
(void) width;
(void) height;
(void) userdata;
frame_out->gl.target = GL_TEXTURE_2D;
frame_out->gl.name = 0;
frame_out->gl.format = GL_RGBA8_OES;
frame_out->gl.width = 0;
frame_out->gl.height = 0;
frame_out->userdata = NULL;
frame_out->destroy = NULL;
return 0;
}

int dmabuf_surface_push_dmabuf(struct dmabuf_surface *s, const struct dmabuf *buf, dmabuf_release_cb_t release_cb) {
struct refcounted_dmabuf *b;
int ok;

DEBUG_ASSERT_NOT_NULL(s);
DEBUG_ASSERT_NOT_NULL(buf);
Expand All @@ -177,18 +193,31 @@ int dmabuf_surface_push_dmabuf(struct dmabuf_surface *s, const struct dmabuf *bu
return ENOMEM;
}

b->n_refs = REFCOUNT_INIT_1;
b->n_refs = REFCOUNT_INIT_0;
b->buf = *buf;
b->release_callback = release_cb;
b->drmdev = NULL;
b->drm_fb_id = DRM_ID_NONE;

surface_lock(CAST_SURFACE_UNCHECKED(s));

if (s->next_buf != NULL) {
refcounted_dmabuf_unref(s->next_buf);

ok = texture_push_unresolved_frame(
s->texture,
&(const struct unresolved_texture_frame) {
.resolve = on_resolve_texture_frame,
.destroy = surface_unref_void,
.userdata = surface_ref(CAST_SURFACE_UNCHECKED(s)),
}
);
if (ok != 0) {
LOG_ERROR("Couldn't post new frame to texture.\n");
surface_unref(CAST_SURFACE_UNCHECKED(s));
surface_unlock(CAST_SURFACE_UNCHECKED(s));
free(b);
return ok;
}
s->next_buf = b;

refcounted_dmabuf_swap_ptrs(&s->next_buf, b);

surface_unlock(CAST_SURFACE_UNCHECKED(s));

Expand All @@ -200,11 +229,6 @@ ATTR_PURE int64_t dmabuf_surface_get_texture_id(struct dmabuf_surface *s) {
return texture_get_id(s->texture);
}

static void on_release_layer(void *userdata) {
DEBUG_ASSERT_NOT_NULL(userdata);
refcounted_dmabuf_unref((struct refcounted_dmabuf*) userdata);
}

static int dmabuf_surface_present_kms(struct surface *_s, const struct fl_layer_props *props, struct kms_req_builder *builder) {
struct dmabuf_surface *s;
uint32_t fb_id;
Expand Down Expand Up @@ -265,7 +289,7 @@ static int dmabuf_surface_present_kms(struct surface *_s, const struct fl_layer_
.has_rotation = false, .rotation = PLANE_TRANSFORM_ROTATE_0,
.has_in_fence_fd = false, .in_fence_fd = 0,
},
on_release_layer,
refcounted_dmabuf_unref_void,
NULL,
refcounted_dmabuf_ref(s->next_buf)
);
Expand Down
70 changes: 57 additions & 13 deletions src/texture_registry.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,24 @@ struct texture_registry {

struct counted_texture_frame {
refcount_t n_refs;

bool is_resolved;
struct texture_frame frame;

struct unresolved_texture_frame unresolved_frame;
};

void counted_texture_frame_destroy(struct counted_texture_frame *frame) {
frame->frame.destroy(
&frame->frame,
frame->frame.userdata
);
if (frame->is_resolved) {
if (frame->frame.destroy != NULL) {
frame->frame.destroy(
&frame->frame,
frame->frame.userdata
);
}
} else if (frame->unresolved_frame.destroy != NULL){
frame->unresolved_frame.destroy(frame->unresolved_frame.userdata);
}
free(frame);
}

Expand Down Expand Up @@ -203,26 +213,28 @@ int64_t texture_get_id(struct texture *texture) {
return texture->id;
}

int texture_push_frame(struct texture *texture, const struct texture_frame *frame) {
static int push_frame(struct texture *texture, bool is_resolved, const struct texture_frame *frame, const struct unresolved_texture_frame *unresolved_frame) {
struct counted_texture_frame *counted_frame;
int ok;

// I know there's memdup, but let's just be explicit here.
counted_frame = malloc(sizeof *counted_frame);
if (counted_frame == NULL) {
return ENOMEM;
}

counted_frame->n_refs = REFCOUNT_INIT_1;
counted_frame->frame = *frame;
counted_frame->n_refs = REFCOUNT_INIT_0;
counted_frame->is_resolved = is_resolved;
if (frame != NULL) {
counted_frame->frame = *frame;
}
if (unresolved_frame != NULL) {
counted_frame->unresolved_frame = *unresolved_frame;
}

texture_lock(texture);

if (texture->next_frame != NULL) {
counted_texture_frame_unref(texture->next_frame);
texture->next_frame = NULL;
}

texture->next_frame = counted_frame;
counted_texture_frame_swap_ptrs(&texture->next_frame, counted_frame);

if (texture->dirty == false) {
ok = texture->registry->interface.mark_frame_available(texture->registry->userdata, texture->id);
Expand All @@ -242,6 +254,24 @@ int texture_push_frame(struct texture *texture, const struct texture_frame *fram
return 0;
}

int texture_push_frame(struct texture *texture, const struct texture_frame *frame) {
return push_frame(
texture,
true,
frame,
NULL
);
}

int texture_push_unresolved_frame(struct texture *texture, const struct unresolved_texture_frame *frame) {
return push_frame(
texture,
false,
NULL,
frame
);
}

void texture_destroy(struct texture *texture) {
texture_registry_unregister_texture(texture->registry, texture);
if (texture->next_frame != NULL) {
Expand All @@ -268,6 +298,7 @@ static bool texture_gl_external_texture_frame_callback(
FlutterOpenGLTexture *texture_out
) {
struct counted_texture_frame *frame;
int ok;

(void) width;
(void) height;
Expand All @@ -288,6 +319,19 @@ static bool texture_gl_external_texture_frame_callback(
/// flutter has now fetched the texture, so if we want to present a new frame
/// we need to call @ref texture_registry_engine_notify_frame_available again.
texture->dirty = false;

if (!frame->is_resolved) {
// resolve the frame to an actual OpenGL frame.
ok = frame->unresolved_frame.resolve(width, height, frame->unresolved_frame.userdata, &frame->frame);
if (ok != 0) {
LOG_ERROR("Couldn't resolve texture frame.\n");
counted_texture_frame_unrefp(&frame);
counted_texture_frame_unrefp(&texture->next_frame);
}

frame->unresolved_frame.destroy(frame->unresolved_frame.userdata);
frame->is_resolved = true;
}

texture_unlock(texture);

Expand Down

0 comments on commit c81fa43

Please sign in to comment.