render/swapchain: add support for buffer age

This commit is contained in:
Simon Ser 2020-07-27 18:36:31 +02:00
parent ef846a8839
commit c11c6c4568
2 changed files with 52 additions and 7 deletions

View file

@ -10,6 +10,7 @@
struct wlr_swapchain_slot {
struct wlr_buffer *buffer;
bool acquired; // waiting for release
int age;
struct wl_listener release;
};
@ -35,7 +36,15 @@ void wlr_swapchain_destroy(struct wlr_swapchain *swapchain);
* The returned buffer is locked. When the caller is done with it, they must
* unlock it by calling wlr_buffer_unlock.
*/
struct wlr_buffer *wlr_swapchain_acquire(
struct wlr_swapchain *swapchain);
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain,
int *age);
/**
* Mark the buffer as submitted for presentation. This needs to be called by
* swap chain users on frame boundaries.
*
* If the buffer hasn't been created via the swap chain, the call is ignored.
*/
void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain,
struct wlr_buffer *buffer);
#endif

View file

@ -63,7 +63,8 @@ static void slot_handle_release(struct wl_listener *listener, void *data) {
slot->acquired = false;
}
static struct wlr_buffer *slot_acquire(struct wlr_swapchain_slot *slot) {
static struct wlr_buffer *slot_acquire(struct wlr_swapchain *swapchain,
struct wlr_swapchain_slot *slot, int *age) {
assert(!slot->acquired);
assert(slot->buffer != NULL);
@ -72,11 +73,15 @@ static struct wlr_buffer *slot_acquire(struct wlr_swapchain_slot *slot) {
slot->release.notify = slot_handle_release;
wl_signal_add(&slot->buffer->events.release, &slot->release);
if (age != NULL) {
*age = slot->age;
}
return wlr_buffer_lock(slot->buffer);
}
struct wlr_buffer *wlr_swapchain_acquire(
struct wlr_swapchain *swapchain) {
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain,
int *age) {
struct wlr_swapchain_slot *free_slot = NULL;
for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) {
struct wlr_swapchain_slot *slot = &swapchain->slots[i];
@ -84,7 +89,7 @@ struct wlr_buffer *wlr_swapchain_acquire(
continue;
}
if (slot->buffer != NULL) {
return slot_acquire(slot);
return slot_acquire(swapchain, slot, age);
}
free_slot = slot;
}
@ -104,5 +109,36 @@ struct wlr_buffer *wlr_swapchain_acquire(
wlr_log(WLR_ERROR, "Failed to allocate buffer");
return NULL;
}
return slot_acquire(free_slot);
return slot_acquire(swapchain, free_slot, age);
}
static bool swapchain_has_buffer(struct wlr_swapchain *swapchain,
struct wlr_buffer *buffer) {
for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) {
struct wlr_swapchain_slot *slot = &swapchain->slots[i];
if (slot->buffer == buffer) {
return true;
}
}
return false;
}
void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain,
struct wlr_buffer *buffer) {
assert(buffer != NULL);
if (!swapchain_has_buffer(swapchain, buffer)) {
return;
}
// See the algorithm described in:
// https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_buffer_age.txt
for (size_t i = 0; i < WLR_SWAPCHAIN_CAP; i++) {
struct wlr_swapchain_slot *slot = &swapchain->slots[i];
if (slot->buffer == buffer) {
slot->age = 1;
} else if (slot->age > 0) {
slot->age++;
}
}
}