Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / widget / gtk / vaapitest / vaapitest.cpp
blob6c824a5895c7e0e4e4fc8885c5409e8d265281ce
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include <cstdio>
9 #include <cstdlib>
10 #include <dlfcn.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <getopt.h>
16 #include <stdint.h>
17 #include <stdarg.h>
19 #if defined(MOZ_ASAN) || defined(FUZZING)
20 # include <signal.h>
21 #endif
23 #include "mozilla/ScopeExit.h"
25 #ifdef __SUNPRO_CC
26 # include <stdio.h>
27 #endif
29 #include "prlink.h"
30 #include "va/va.h"
32 #include "mozilla/GfxInfoUtils.h"
34 // Print VA-API test results to stdout and logging to stderr
35 #define OUTPUT_PIPE 1
37 #define MIN(a, b) ((a) < (b) ? (a) : (b))
39 // bits to use decoding vaapitest() return values.
40 constexpr int CODEC_HW_H264 = 1 << 4;
41 constexpr int CODEC_HW_VP8 = 1 << 5;
42 constexpr int CODEC_HW_VP9 = 1 << 6;
43 constexpr int CODEC_HW_AV1 = 1 << 7;
45 // childgltest is declared inside extern "C" so that the name is not mangled.
46 // The name is used in build/valgrind/x86_64-pc-linux-gnu.sup to suppress
47 // memory leak errors because we run it inside a short lived fork and we don't
48 // care about leaking memory
49 extern "C" {
51 static constexpr struct {
52 VAProfile mVAProfile;
53 const char* mName;
54 } kVAAPiProfileName[] = {
55 #define MAP(v) {VAProfile##v, #v}
56 MAP(H264ConstrainedBaseline),
57 MAP(H264Main),
58 MAP(H264High),
59 MAP(VP8Version0_3),
60 MAP(VP9Profile0),
61 MAP(VP9Profile2),
62 MAP(AV1Profile0),
63 MAP(AV1Profile1),
64 #undef MAP
67 static const char* VAProfileName(VAProfile aVAProfile) {
68 for (const auto& profile : kVAAPiProfileName) {
69 if (profile.mVAProfile == aVAProfile) {
70 return profile.mName;
73 return nullptr;
76 static void vaapitest(const char* aRenderDevicePath) {
77 int renderDeviceFD = -1;
78 VAProfile* profiles = nullptr;
79 VAEntrypoint* entryPoints = nullptr;
80 VADisplay display = nullptr;
81 void* libDrm = nullptr;
83 log("vaapitest start, device %s\n", aRenderDevicePath);
85 auto autoRelease = mozilla::MakeScopeExit([&] {
86 free(profiles);
87 free(entryPoints);
88 if (display) {
89 vaTerminate(display);
91 if (libDrm) {
92 dlclose(libDrm);
94 if (renderDeviceFD > -1) {
95 close(renderDeviceFD);
97 });
99 renderDeviceFD = open(aRenderDevicePath, O_RDWR);
100 if (renderDeviceFD == -1) {
101 record_error("VA-API test failed: failed to open renderDeviceFD.");
102 return;
105 libDrm = dlopen("libva-drm.so.2", RTLD_LAZY);
106 if (!libDrm) {
107 log("vaapitest failed: libva-drm.so.2 is missing\n");
108 return;
111 static auto sVaGetDisplayDRM =
112 (void* (*)(int fd))dlsym(libDrm, "vaGetDisplayDRM");
113 if (!sVaGetDisplayDRM) {
114 record_error("VA-API test failed: sVaGetDisplayDRM is missing.");
115 return;
118 display = sVaGetDisplayDRM(renderDeviceFD);
119 if (!display) {
120 record_error("VA-API test failed: vaGetDisplayDRM failed.");
121 return;
124 int major, minor;
125 VAStatus status = vaInitialize(display, &major, &minor);
126 if (status != VA_STATUS_SUCCESS) {
127 log("vaInitialize failed %d\n", status);
128 return;
129 } else {
130 log("vaInitialize finished\n");
133 int maxProfiles = vaMaxNumProfiles(display);
134 int maxEntryPoints = vaMaxNumEntrypoints(display);
135 if (maxProfiles <= 0 || maxEntryPoints <= 0) {
136 record_error("VA-API test failed: wrong VAAPI profiles/entry point nums.");
137 return;
140 profiles = (VAProfile*)malloc(sizeof(VAProfile) * maxProfiles);
141 int numProfiles = 0;
142 status = vaQueryConfigProfiles(display, profiles, &numProfiles);
143 if (status != VA_STATUS_SUCCESS) {
144 record_error("VA-API test failed: vaQueryConfigProfiles() failed.");
145 return;
147 numProfiles = MIN(numProfiles, maxProfiles);
149 entryPoints = (VAEntrypoint*)malloc(sizeof(VAEntrypoint) * maxEntryPoints);
150 int codecs = 0;
151 bool foundProfile = false;
152 for (int p = 0; p < numProfiles; p++) {
153 VAProfile profile = profiles[p];
155 // Check only supported profiles
156 if (!VAProfileName(profile)) {
157 continue;
160 int numEntryPoints = 0;
161 status = vaQueryConfigEntrypoints(display, profile, entryPoints,
162 &numEntryPoints);
163 if (status != VA_STATUS_SUCCESS) {
164 continue;
166 numEntryPoints = MIN(numEntryPoints, maxEntryPoints);
167 for (int entry = 0; entry < numEntryPoints; entry++) {
168 if (entryPoints[entry] != VAEntrypointVLD) {
169 continue;
171 VAConfigID config = VA_INVALID_ID;
172 status = vaCreateConfig(display, profile, entryPoints[entry], nullptr, 0,
173 &config);
174 if (status == VA_STATUS_SUCCESS) {
175 const char* profstr = VAProfileName(profile);
176 log("Profile: %s\n", profstr);
177 // VAProfileName returns null on failure, making the below calls safe
178 if (!strncmp(profstr, "H264", 4)) {
179 codecs |= CODEC_HW_H264;
180 } else if (!strncmp(profstr, "VP8", 3)) {
181 codecs |= CODEC_HW_VP8;
182 } else if (!strncmp(profstr, "VP9", 3)) {
183 codecs |= CODEC_HW_VP9;
184 } else if (!strncmp(profstr, "AV1", 3)) {
185 codecs |= CODEC_HW_AV1;
186 } else {
187 record_warning("VA-API test unknown profile.");
189 vaDestroyConfig(display, config);
190 foundProfile = true;
194 if (foundProfile) {
195 record_value("VAAPI_SUPPORTED\nTRUE\n");
196 record_value("VAAPI_HWCODECS\n%d\n", codecs);
197 } else {
198 record_value("VAAPI_SUPPORTED\nFALSE\n");
200 log("vaapitest finished\n");
203 } // extern "C"
205 static void PrintUsage() {
206 printf(
207 "Firefox VA-API probe utility\n"
208 "\n"
209 "usage: vaapitest [options]\n"
210 "\n"
211 "Options:\n"
212 "\n"
213 " -h --help show this message\n"
214 " -d --drm drm_device probe VA-API on drm_device (may be "
215 "/dev/dri/renderD128)\n"
216 "\n");
219 int main(int argc, char** argv) {
220 struct option longOptions[] = {{"help", no_argument, NULL, 'h'},
221 {"drm", required_argument, NULL, 'd'},
222 {NULL, 0, NULL, 0}};
223 const char* shortOptions = "hd:";
224 int c;
225 const char* drmDevice = nullptr;
226 while ((c = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
227 switch (c) {
228 case 'd':
229 drmDevice = optarg;
230 break;
231 case 'h':
232 default:
233 break;
236 if (drmDevice) {
237 #if defined(MOZ_ASAN) || defined(FUZZING)
238 // If handle_segv=1 (default), then glxtest crash will print a sanitizer
239 // report which can confuse the harness in fuzzing automation.
240 signal(SIGSEGV, SIG_DFL);
241 #endif
242 const char* env = getenv("MOZ_GFX_DEBUG");
243 enable_logging = env && *env == '1';
244 output_pipe = OUTPUT_PIPE;
245 if (!enable_logging) {
246 close_logging();
248 vaapitest(drmDevice);
249 record_flush();
250 return EXIT_SUCCESS;
252 PrintUsage();
253 return 0;