1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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/. */
19 #if defined(MOZ_ASAN) || defined(FUZZING)
23 #include "mozilla/ScopeExit.h"
32 #include "mozilla/GfxInfoUtils.h"
34 // Print VA-API test results to stdout and logging to stderr
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
51 static constexpr struct {
54 } kVAAPiProfileName
[] = {
55 #define MAP(v) {VAProfile##v, #v}
56 MAP(H264ConstrainedBaseline
),
67 static const char* VAProfileName(VAProfile aVAProfile
) {
68 for (const auto& profile
: kVAAPiProfileName
) {
69 if (profile
.mVAProfile
== aVAProfile
) {
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([&] {
94 if (renderDeviceFD
> -1) {
95 close(renderDeviceFD
);
99 renderDeviceFD
= open(aRenderDevicePath
, O_RDWR
);
100 if (renderDeviceFD
== -1) {
101 record_error("VA-API test failed: failed to open renderDeviceFD.");
105 libDrm
= dlopen("libva-drm.so.2", RTLD_LAZY
);
107 log("vaapitest failed: libva-drm.so.2 is missing\n");
111 static auto sVaGetDisplayDRM
=
112 (void* (*)(int fd
))dlsym(libDrm
, "vaGetDisplayDRM");
113 if (!sVaGetDisplayDRM
) {
114 record_error("VA-API test failed: sVaGetDisplayDRM is missing.");
118 display
= sVaGetDisplayDRM(renderDeviceFD
);
120 record_error("VA-API test failed: vaGetDisplayDRM failed.");
125 VAStatus status
= vaInitialize(display
, &major
, &minor
);
126 if (status
!= VA_STATUS_SUCCESS
) {
127 log("vaInitialize failed %d\n", status
);
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.");
140 profiles
= (VAProfile
*)malloc(sizeof(VAProfile
) * maxProfiles
);
142 status
= vaQueryConfigProfiles(display
, profiles
, &numProfiles
);
143 if (status
!= VA_STATUS_SUCCESS
) {
144 record_error("VA-API test failed: vaQueryConfigProfiles() failed.");
147 numProfiles
= MIN(numProfiles
, maxProfiles
);
149 entryPoints
= (VAEntrypoint
*)malloc(sizeof(VAEntrypoint
) * maxEntryPoints
);
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
)) {
160 int numEntryPoints
= 0;
161 status
= vaQueryConfigEntrypoints(display
, profile
, entryPoints
,
163 if (status
!= VA_STATUS_SUCCESS
) {
166 numEntryPoints
= MIN(numEntryPoints
, maxEntryPoints
);
167 for (int entry
= 0; entry
< numEntryPoints
; entry
++) {
168 if (entryPoints
[entry
] != VAEntrypointVLD
) {
171 VAConfigID config
= VA_INVALID_ID
;
172 status
= vaCreateConfig(display
, profile
, entryPoints
[entry
], nullptr, 0,
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
;
187 record_warning("VA-API test unknown profile.");
189 vaDestroyConfig(display
, config
);
195 record_value("VAAPI_SUPPORTED\nTRUE\n");
196 record_value("VAAPI_HWCODECS\n%d\n", codecs
);
198 record_value("VAAPI_SUPPORTED\nFALSE\n");
200 log("vaapitest finished\n");
205 static void PrintUsage() {
207 "Firefox VA-API probe utility\n"
209 "usage: vaapitest [options]\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"
219 int main(int argc
, char** argv
) {
220 struct option longOptions
[] = {{"help", no_argument
, NULL
, 'h'},
221 {"drm", required_argument
, NULL
, 'd'},
223 const char* shortOptions
= "hd:";
225 const char* drmDevice
= nullptr;
226 while ((c
= getopt_long(argc
, argv
, shortOptions
, longOptions
, NULL
)) != -1) {
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
);
242 const char* env
= getenv("MOZ_GFX_DEBUG");
243 enable_logging
= env
&& *env
== '1';
244 output_pipe
= OUTPUT_PIPE
;
245 if (!enable_logging
) {
248 vaapitest(drmDevice
);