-#include "shared/va_display.h"
+#include "va_display.h"
+#include <assert.h>
+#include <fcntl.h>
+#include <string.h>
#include <unistd.h>
+#include <va/va.h>
+#include <va/va_drm.h>
+#include <va/va_x11.h>
+
+#include <string>
+#include <vector>
+
+using namespace std;
VADisplayWithCleanup::~VADisplayWithCleanup()
{
}
}
+unique_ptr<VADisplayWithCleanup> va_open_display(const string &va_display)
+{
+ if (va_display.empty() || va_display[0] != '/') { // An X display.
+ Display *x11_display = XOpenDisplay(va_display.empty() ? nullptr : va_display.c_str());
+ if (x11_display == nullptr) {
+ fprintf(stderr, "error: can't connect to X server!\n");
+ return nullptr;
+ }
+
+ unique_ptr<VADisplayWithCleanup> ret(new VADisplayWithCleanup);
+ ret->x11_display = x11_display;
+ ret->can_use_zerocopy = true;
+ ret->va_dpy = vaGetDisplay(x11_display);
+ if (ret->va_dpy == nullptr) {
+ return nullptr;
+ }
+ return ret;
+ } else { // A DRM node on the filesystem (e.g. /dev/dri/renderD128).
+ int drm_fd = open(va_display.c_str(), O_RDWR);
+ if (drm_fd == -1) {
+ perror(va_display.c_str());
+ return NULL;
+ }
+ unique_ptr<VADisplayWithCleanup> ret(new VADisplayWithCleanup);
+ ret->drm_fd = drm_fd;
+ ret->can_use_zerocopy = false;
+ ret->va_dpy = vaGetDisplayDRM(drm_fd);
+ if (ret->va_dpy == nullptr) {
+ return nullptr;
+ }
+ return ret;
+ }
+}
+
+unique_ptr<VADisplayWithCleanup> try_open_va(
+ const string &va_display, const vector<VAProfile> &desired_profiles, VAEntrypoint entrypoint,
+ const vector<ConfigRequest> &desired_configs, VAProfile *chosen_profile, string *error)
+{
+ unique_ptr<VADisplayWithCleanup> va_dpy = va_open_display(va_display);
+ if (va_dpy == nullptr) {
+ if (error) *error = "Opening VA display failed";
+ return nullptr;
+ }
+ int major_ver, minor_ver;
+ VAStatus va_status = vaInitialize(va_dpy->va_dpy, &major_ver, &minor_ver);
+ if (va_status != VA_STATUS_SUCCESS) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "vaInitialize() failed with status %d\n", va_status);
+ if (error != nullptr) *error = buf;
+ return nullptr;
+ }
+
+ int num_entrypoints = vaMaxNumEntrypoints(va_dpy->va_dpy);
+ unique_ptr<VAEntrypoint[]> entrypoints(new VAEntrypoint[num_entrypoints]);
+ if (entrypoints == nullptr) {
+ if (error != nullptr) *error = "Failed to allocate memory for VA entry points";
+ return nullptr;
+ }
+
+ // Try the profiles from highest to lowest until we find one that can be used.
+ VAProfile found_profile = VAProfileNone;
+ for (VAProfile profile : desired_profiles) {
+ vaQueryConfigEntrypoints(va_dpy->va_dpy, profile, entrypoints.get(), &num_entrypoints);
+ for (int slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
+ if (entrypoints[slice_entrypoint] != entrypoint) {
+ continue;
+ }
+
+ // We found a usable encoder/decoder, so return it.
+ if (chosen_profile != nullptr) {
+ *chosen_profile = profile;
+ }
+ found_profile = profile;
+ break;
+ }
+ if (found_profile != VAProfileNone) {
+ break;
+ }
+ }
+ if (found_profile == VAProfileNone) {
+ if (error != nullptr) *error = "Can't find entry points for suitable codec profile";
+ return nullptr;
+ }
+
+ int num_formats = vaMaxNumImageFormats(va_dpy->va_dpy);
+ assert(num_formats > 0);
+
+ unique_ptr<VAImageFormat[]> formats(new VAImageFormat[num_formats]);
+ va_status = vaQueryImageFormats(va_dpy->va_dpy, formats.get(), &num_formats);
+ if (va_status != VA_STATUS_SUCCESS) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "vaQueryImageFormats() failed with status %d\n", va_status);
+ if (error != nullptr) *error = buf;
+ return nullptr;
+ }
+
+ for (const ConfigRequest &request : desired_configs) {
+ // Create the config.
+ VAConfigAttrib attr = { VAConfigAttribRTFormat, request.rt_format };
+ va_status = vaCreateConfig(va_dpy->va_dpy, found_profile, entrypoint,
+ &attr, 1, request.config_id);
+ if (va_status == VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT) {
+ if (error != nullptr) *error = "No " + request.name + " hardware support";
+ return nullptr;
+ } else if (va_status != VA_STATUS_SUCCESS) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "vaCreateConfig() for %s failed with status %d\n", request.name.c_str(), va_status);
+ if (error != nullptr) *error = buf;
+ return nullptr;
+ }
+
+ // Find out which image format we're going to be using.
+ bool format_found = false;
+ for (int i = 0; i < num_formats; ++i) {
+ if (formats[i].fourcc == request.fourcc) {
+ memcpy(request.image_format, &formats[i], sizeof(VAImageFormat));
+ format_found = true;
+ break;
+ }
+ }
+ if (!format_found) {
+ if (error != nullptr) *error = "Format for " + request.name + " not found";
+ return nullptr;
+ }
+ }
+
+ return va_dpy;
+}