summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Burakov <mburakov@mailbox.org>2024-09-21 10:37:38 +0200
committerMikhail Burakov <mburakov@mailbox.org>2024-09-21 10:37:38 +0200
commit8a93cfdc03683eedc270bae957288af853f22a61 (patch)
treeb408def1c226b0ddc7c1bcb6335b22e176c03082
parent2486ad6913fa3ad6488752a2c9414a239b18a936 (diff)
Adding threading infra to encode contextnext
-rw-r--r--encode_context.c104
1 files changed, 99 insertions, 5 deletions
diff --git a/encode_context.c b/encode_context.c
index 5efe8ca..7fc1142 100644
--- a/encode_context.c
+++ b/encode_context.c
@@ -19,9 +19,11 @@
#include <assert.h>
#include <errno.h>
+#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <threads.h>
#include <va/va.h>
#include <va/va_drmcommon.h>
#include <va/va_wayland.h>
@@ -31,6 +33,7 @@
struct EncodeContext {
struct IoContext* io_context;
+ atomic_bool running;
size_t width;
size_t height;
VADisplay display;
@@ -39,8 +42,33 @@ struct EncodeContext {
uint32_t packed_headers;
VAConfigAttribValEncHEVCFeatures hevc_features;
VAConfigAttribValEncHEVCBlockSizes hevc_block_sizes;
+
+ VAContextID context_id;
+
+ mtx_t mutex;
+ cnd_t cond;
+ thrd_t thread;
+ atomic_int refcount;
};
+static struct EncodeContext* EncodeContextRef(
+ struct EncodeContext* encode_context) {
+ atomic_fetch_add_explicit(&encode_context->refcount, 1, memory_order_relaxed);
+ return encode_context;
+}
+
+static void EncodeContextUnref(struct EncodeContext* encode_context) {
+ if (atomic_fetch_sub_explicit(&encode_context->refcount, 1,
+ memory_order_relaxed) == 1) {
+ assert(vaDestroyContext(encode_context->display,
+ encode_context->context_id) == VA_STATUS_SUCCESS);
+ assert(vaDestroyConfig(encode_context->display,
+ encode_context->config_id) == VA_STATUS_SUCCESS);
+ assert(vaTerminate(encode_context->display) == VA_STATUS_SUCCESS);
+ free(encode_context);
+ }
+}
+
static const char* VaErrorString(VAStatus error) {
static const char* kVaErrorStrings[] = {
"VA_STATUS_SUCCESS",
@@ -165,6 +193,30 @@ static bool InitializeCodecCaps(struct EncodeContext* encode_context) {
return true;
}
+static int EncodeContextThreadProc(void* arg) {
+ struct EncodeContext* encode_context = arg;
+ for (;;) {
+ if (mtx_lock(&encode_context->mutex) != thrd_success) {
+ LOG("Failed to lock mutex (%s)", strerror(errno));
+ goto leave;
+ }
+ while (
+ atomic_load_explicit(&encode_context->running, memory_order_relaxed)) {
+ assert(cnd_wait(&encode_context->cond, &encode_context->mutex) ==
+ thrd_success);
+ }
+ assert(mtx_unlock(&encode_context->mutex) == thrd_success);
+
+ if (!atomic_load_explicit(&encode_context->running, memory_order_relaxed)) {
+ goto leave;
+ }
+ }
+
+leave:
+ atomic_store_explicit(&encode_context->running, false, memory_order_relaxed);
+ return 0;
+}
+
struct EncodeContext* EncodeContextCreate(struct IoContext* io_context,
uint32_t width, uint32_t height,
struct wl_display* display) {
@@ -210,8 +262,50 @@ struct EncodeContext* EncodeContextCreate(struct IoContext* io_context,
goto rollback_config_id;
}
- return encode_context;
+ // mburakov: Intel fails badly when min_cb_size value is not set to 16 and
+ // log2_min_luma_coding_block_size_minus3 is not set to zero. Judging from
+ // ffmpeg code, calculating one from another should work on other platforms,
+ // but I hardcoded it instead since AMD is fine with alignment on 16 anyway.
+ static const size_t kMinCbSize = 16;
+ size_t aligned_width =
+ (encode_context->width + kMinCbSize - 1) & ~(kMinCbSize - 1);
+ size_t aligned_height =
+ (encode_context->height + kMinCbSize - 1) & ~(kMinCbSize - 1);
+ status =
+ vaCreateContext(encode_context->display, encode_context->config_id,
+ (int)aligned_width, (int)aligned_height, VA_PROGRESSIVE,
+ NULL, 0, &encode_context->context_id);
+ if (status != VA_STATUS_SUCCESS) {
+ LOG("Failed to create va context (%s)", VaErrorString(status));
+ goto rollback_config_id;
+ }
+
+ if (mtx_init(&encode_context->mutex, mtx_plain) != thrd_success) {
+ LOG("Failed to init mutex (%s)", strerror(errno));
+ goto rollback_context_id;
+ }
+
+ if (cnd_init(&encode_context->cond) != thrd_success) {
+ LOG("Failed to init condition variable (%s)", strerror(errno));
+ goto rollback_mutex;
+ }
+
+ if (thrd_create(&encode_context->thread, &EncodeContextThreadProc,
+ io_context) != thrd_success) {
+ LOG("Failed to create thread (%s)", strerror(errno));
+ goto rollback_cond;
+ }
+
+ return EncodeContextRef(encode_context);
+
+rollback_cond:
+ cnd_destroy(&encode_context->cond);
+rollback_mutex:
+ mtx_destroy(&encode_context->mutex);
+rollback_context_id:
+ assert(vaDestroyContext(encode_context->display,
+ encode_context->context_id) == VA_STATUS_SUCCESS);
rollback_config_id:
assert(vaDestroyConfig(encode_context->display, encode_context->config_id) ==
VA_STATUS_SUCCESS);
@@ -240,8 +334,8 @@ bool EncodeContextQueue(struct EncodeContext* encode_context,
}
void EncodeContextDestroy(struct EncodeContext* encode_context) {
- assert(vaDestroyConfig(encode_context->display, encode_context->config_id) ==
- VA_STATUS_SUCCESS);
- assert(vaTerminate(encode_context->display) == VA_STATUS_SUCCESS);
- free(encode_context);
+ atomic_store_explicit(&encode_context->running, false, memory_order_relaxed);
+ assert(cnd_broadcast(&encode_context->cond) == thrd_success);
+ assert(thrd_join(encode_context->thread, NULL) == thrd_success);
+ EncodeContextUnref(encode_context);
}