File: va_display.cpp

package info (click to toggle)
nageru 2.3.2-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 3,120 kB
  • sloc: cpp: 39,131; perl: 94; sh: 18; makefile: 4
file content (155 lines) | stat: -rw-r--r-- 4,768 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#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()
{
	if (va_dpy != nullptr) {
		vaTerminate(va_dpy);
	}
	if (x11_display != nullptr) {
		XCloseDisplay(x11_display);
	}
	if (drm_fd != -1) {
		close(drm_fd);
	}
}

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;
}