1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "host/commands/assemble_cvd/graphics_flags.h"
18
19 #include <ostream>
20
21 #include <GraphicsDetector.pb.h>
22 #include <android-base/strings.h>
23 #include <fmt/format.h>
24 #include <google/protobuf/text_format.h>
25
26 #include "common/libs/utils/contains.h"
27 #include "common/libs/utils/subprocess.h"
28 #include "host/libs/config/cuttlefish_config.h"
29
30 #ifdef __APPLE__
31 #define CF_UNUSED_ON_MACOS [[maybe_unused]]
32 #else
33 #define CF_UNUSED_ON_MACOS
34 #endif
35
36 namespace cuttlefish {
37 namespace {
38
39 enum class RenderingMode {
40 kNone,
41 kCustom,
42 kGuestSwiftShader,
43 kGfxstream,
44 kGfxstreamGuestAngle,
45 kGfxstreamGuestAngleHostSwiftshader,
46 kVirglRenderer,
47 };
48
49 CF_UNUSED_ON_MACOS
GetRenderingMode(const std::string & mode)50 Result<RenderingMode> GetRenderingMode(const std::string& mode) {
51 if (mode == std::string(kGpuModeDrmVirgl)) {
52 return RenderingMode::kVirglRenderer;
53 }
54 if (mode == std::string(kGpuModeGfxstream)) {
55 return RenderingMode::kGfxstream;
56 }
57 if (mode == std::string(kGpuModeGfxstreamGuestAngle)) {
58 return RenderingMode::kGfxstreamGuestAngle;
59 }
60 if (mode == std::string(kGpuModeGfxstreamGuestAngleHostSwiftShader)) {
61 return RenderingMode::kGfxstreamGuestAngleHostSwiftshader;
62 }
63 if (mode == std::string(kGpuModeGuestSwiftshader)) {
64 return RenderingMode::kGuestSwiftShader;
65 }
66 if (mode == std::string(kGpuModeCustom)) {
67 return RenderingMode::kCustom;
68 }
69 if (mode == std::string(kGpuModeNone)) {
70 return RenderingMode::kNone;
71 }
72 return CF_ERR("Unsupported rendering mode: " << mode);
73 }
74
75 struct AngleFeatures {
76 // Prefer linear filtering for YUV AHBs to pass
77 // android.media.decoder.cts.DecodeAccuracyTest on older branches.
78 // Generally not needed after b/315387961.
79 bool prefer_linear_filtering_for_yuv = false;
80
81 // Map unspecified color spaces to PASS_THROUGH to pass
82 // android.media.codec.cts.DecodeEditEncodeTest and
83 // android.media.codec.cts.EncodeDecodeTest.
84 bool map_unspecified_color_space_to_pass_through = true;
85
86 // b/264575911: Nvidia seems to have issues with YUV samplers with
87 // 'lowp' and 'mediump' precision qualifiers.
88 bool ignore_precision_qualifiers = false;
89 };
90
operator <<(std::ostream & stream,const AngleFeatures & features)91 std::ostream& operator<<(std::ostream& stream, const AngleFeatures& features) {
92 fmt::print(stream, "ANGLE features: \n");
93 fmt::print(stream, " - prefer_linear_filtering_for_yuv: {}\n",
94 features.prefer_linear_filtering_for_yuv);
95 fmt::print(stream, " - map_unspecified_color_space_to_pass_through: {}\n",
96 features.map_unspecified_color_space_to_pass_through);
97 fmt::print(stream, " - ignore_precision_qualifiers: {}\n",
98 features.ignore_precision_qualifiers);
99 return stream;
100 }
101
GetNeededAngleFeaturesBasedOnQuirks(const RenderingMode mode,const::gfxstream::proto::GraphicsAvailability & availability)102 Result<AngleFeatures> GetNeededAngleFeaturesBasedOnQuirks(
103 const RenderingMode mode,
104 const ::gfxstream::proto::GraphicsAvailability& availability) {
105 AngleFeatures features = {};
106 if (mode == RenderingMode::kGfxstreamGuestAngle) {
107 if (availability.has_vulkan() &&
108 !availability.vulkan().physical_devices().empty() &&
109 availability.vulkan().physical_devices(0).has_quirks() &&
110 availability.vulkan()
111 .physical_devices(0)
112 .quirks()
113 .has_issue_with_precision_qualifiers_on_yuv_samplers()) {
114 features.ignore_precision_qualifiers = true;
115 }
116 }
117 return features;
118 }
119
ToLower(const std::string & v)120 std::string ToLower(const std::string& v) {
121 std::string result = v;
122 std::transform(result.begin(), result.end(), result.begin(),
123 [](unsigned char c) { return std::tolower(c); });
124 return result;
125 }
126
IsLikelySoftwareRenderer(const std::string & renderer)127 bool IsLikelySoftwareRenderer(const std::string& renderer) {
128 const std::string lower_renderer = ToLower(renderer);
129 return lower_renderer.find("llvmpipe") != std::string::npos;
130 }
131
132 CF_UNUSED_ON_MACOS
ShouldEnableAcceleratedRendering(const::gfxstream::proto::GraphicsAvailability & availability)133 bool ShouldEnableAcceleratedRendering(
134 const ::gfxstream::proto::GraphicsAvailability& availability) {
135 const bool sufficient_gles2 =
136 availability.has_egl() && availability.egl().has_gles2_availability() &&
137 !IsLikelySoftwareRenderer(
138 availability.egl().gles2_availability().renderer());
139 const bool sufficient_gles3 =
140 availability.has_egl() && availability.egl().has_gles3_availability() &&
141 !IsLikelySoftwareRenderer(
142 availability.egl().gles3_availability().renderer());
143 const bool has_discrete_gpu =
144 availability.has_vulkan() &&
145 !availability.vulkan().physical_devices().empty() &&
146 (availability.vulkan().physical_devices(0).type() ==
147 ::gfxstream::proto::VulkanPhysicalDevice::TYPE_DISCRETE_GPU);
148 return (sufficient_gles2 || sufficient_gles3) && has_discrete_gpu;
149 }
150
151 struct AngleFeatureOverrides {
152 std::string angle_feature_overrides_enabled;
153 std::string angle_feature_overrides_disabled;
154 };
155
156 CF_UNUSED_ON_MACOS
GetNeededAngleFeatures(const RenderingMode mode,const::gfxstream::proto::GraphicsAvailability & availability)157 Result<AngleFeatureOverrides> GetNeededAngleFeatures(
158 const RenderingMode mode,
159 const ::gfxstream::proto::GraphicsAvailability& availability) {
160 const AngleFeatures features =
161 CF_EXPECT(GetNeededAngleFeaturesBasedOnQuirks(mode, availability));
162 LOG(DEBUG) << features;
163
164 std::vector<std::string> enable_feature_strings;
165 std::vector<std::string> disable_feature_strings;
166 if (features.prefer_linear_filtering_for_yuv) {
167 enable_feature_strings.push_back("preferLinearFilterForYUV");
168 }
169 if (features.map_unspecified_color_space_to_pass_through) {
170 enable_feature_strings.push_back("mapUnspecifiedColorSpaceToPassThrough");
171 }
172 if (features.ignore_precision_qualifiers) {
173 disable_feature_strings.push_back("enablePrecisionQualifiers");
174 }
175
176 return AngleFeatureOverrides{
177 .angle_feature_overrides_enabled =
178 android::base::Join(enable_feature_strings, ':'),
179 .angle_feature_overrides_disabled =
180 android::base::Join(disable_feature_strings, ':'),
181 };
182 }
183
184 struct VhostUserGpuHostRendererFeatures {
185 // If true, host Virtio GPU blob resources will be allocated with
186 // external memory and exported file descriptors will be shared
187 // with the VMM for mapping resources into the guest address space.
188 bool external_blob = false;
189
190 // If true, host Virtio GPU blob resources will be allocated with
191 // shmem and exported file descriptors will be shared with the VMM
192 // for mapping resources into the guest address space.
193 //
194 // This is an extension of the above external_blob that allows the
195 // VMM to map resources without graphics API support but requires
196 // additional features (VK_EXT_external_memory_host) from the GPU
197 // driver and is potentially less performant.
198 bool system_blob = false;
199 };
200
201 CF_UNUSED_ON_MACOS
202 Result<VhostUserGpuHostRendererFeatures>
GetNeededVhostUserGpuHostRendererFeatures(RenderingMode mode,const::gfxstream::proto::GraphicsAvailability & availability)203 GetNeededVhostUserGpuHostRendererFeatures(
204 RenderingMode mode,
205 const ::gfxstream::proto::GraphicsAvailability& availability) {
206 VhostUserGpuHostRendererFeatures features = {};
207
208 CF_EXPECT(
209 mode == RenderingMode::kGfxstream ||
210 mode == RenderingMode::kGfxstreamGuestAngle,
211 "vhost-user-gpu is only currently supported with --gpu_mode=gfxstream "
212 "and --gpu_mode=gfxstream_guest_angle");
213
214 features.external_blob = true;
215
216 const bool has_external_memory_host =
217 availability.has_vulkan() &&
218 !availability.vulkan().physical_devices().empty() &&
219 Contains(availability.vulkan().physical_devices(0).extensions(),
220 "VK_EXT_external_memory_host");
221
222 CF_EXPECT(
223 has_external_memory_host || mode != RenderingMode::kGfxstreamGuestAngle,
224 "VK_EXT_external_memory_host is required for running with "
225 "--gpu_mode=gfxstream_guest_angle and --enable_gpu_vhost_user=true");
226
227 features.system_blob = has_external_memory_host;
228
229 return features;
230 }
231
232 #ifndef __APPLE__
SelectGpuMode(const std::string & gpu_mode_arg,VmmMode vmm,const GuestConfig & guest_config,const gfxstream::proto::GraphicsAvailability & graphics_availability)233 Result<std::string> SelectGpuMode(
234 const std::string& gpu_mode_arg, VmmMode vmm,
235 const GuestConfig& guest_config,
236 const gfxstream::proto::GraphicsAvailability& graphics_availability) {
237 if (gpu_mode_arg != kGpuModeAuto && gpu_mode_arg != kGpuModeDrmVirgl &&
238 gpu_mode_arg != kGpuModeCustom && gpu_mode_arg != kGpuModeGfxstream &&
239 gpu_mode_arg != kGpuModeGfxstreamGuestAngle &&
240 gpu_mode_arg != kGpuModeGfxstreamGuestAngleHostSwiftShader &&
241 gpu_mode_arg != kGpuModeGuestSwiftshader &&
242 gpu_mode_arg != kGpuModeNone) {
243 return CF_ERR("Invalid gpu_mode: " << gpu_mode_arg);
244 }
245
246 if (gpu_mode_arg == kGpuModeAuto) {
247 if (ShouldEnableAcceleratedRendering(graphics_availability)) {
248 if (HostArch() == Arch::Arm64) {
249 LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated "
250 "rendering support but enabling "
251 "--gpu_mode=guest_swiftshader until vhost-user-gpu "
252 "based accelerated rendering on ARM has been more "
253 "thoroughly tested. Please explicitly use "
254 "--gpu_mode=gfxstream or "
255 "--gpu_mode=gfxstream_guest_angle to enable for now.";
256 return kGpuModeGuestSwiftshader;
257 }
258
259 LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated "
260 << "rendering support.";
261
262 if (vmm == VmmMode::kQemu && !UseQemuPrebuilt()) {
263 LOG(INFO) << "Not using QEMU prebuilt (QEMU 8+): selecting guest swiftshader";
264 return kGpuModeGuestSwiftshader;
265 } else if (!guest_config.gfxstream_supported) {
266 LOG(INFO) << "GPU auto mode: guest does not support gfxstream, "
267 "enabling --gpu_mode=guest_swiftshader";
268 return kGpuModeGuestSwiftshader;
269 } else {
270 LOG(INFO) << "Enabling --gpu_mode=gfxstream.";
271 return kGpuModeGfxstream;
272 }
273 } else {
274 LOG(INFO) << "GPU auto mode: did not detect prerequisites for "
275 "accelerated rendering support, enabling "
276 "--gpu_mode=guest_swiftshader.";
277 return kGpuModeGuestSwiftshader;
278 }
279 }
280
281 if (gpu_mode_arg == kGpuModeGfxstream ||
282 gpu_mode_arg == kGpuModeGfxstreamGuestAngle ||
283 gpu_mode_arg == kGpuModeDrmVirgl) {
284 if (!ShouldEnableAcceleratedRendering(graphics_availability)) {
285 LOG(ERROR) << "--gpu_mode=" << gpu_mode_arg
286 << " was requested but the prerequisites for accelerated "
287 "rendering were not detected so the device may not "
288 "function correctly. Please consider switching to "
289 "--gpu_mode=auto or --gpu_mode=guest_swiftshader.";
290 }
291
292 if (vmm == VmmMode::kQemu && !UseQemuPrebuilt()) {
293 LOG(INFO) << "Not using QEMU prebuilt (QEMU 8+): selecting guest swiftshader";
294 return kGpuModeGuestSwiftshader;
295 }
296 }
297
298 return gpu_mode_arg;
299 }
300
SelectGpuVhostUserMode(const std::string & gpu_mode,const std::string & gpu_vhost_user_mode_arg,VmmMode vmm)301 Result<bool> SelectGpuVhostUserMode(const std::string& gpu_mode,
302 const std::string& gpu_vhost_user_mode_arg,
303 VmmMode vmm) {
304 CF_EXPECT(gpu_vhost_user_mode_arg == kGpuVhostUserModeAuto ||
305 gpu_vhost_user_mode_arg == kGpuVhostUserModeOn ||
306 gpu_vhost_user_mode_arg == kGpuVhostUserModeOff);
307 if (gpu_vhost_user_mode_arg == kGpuVhostUserModeAuto) {
308 if (gpu_mode == kGpuModeGuestSwiftshader ||
309 gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
310 LOG(INFO) << "GPU vhost user auto mode: not needed for --gpu_mode="
311 << gpu_mode << ". Not enabling vhost user gpu.";
312 return false;
313 }
314
315 if (vmm != VmmMode::kCrosvm) {
316 LOG(INFO) << "GPU vhost user auto mode: not yet supported with " << vmm
317 << ". Not enabling vhost user gpu.";
318 return false;
319 }
320
321 // Android built ARM host tools seem to be incompatible with host GPU
322 // libraries. Enable vhost user gpu which will run the virtio GPU device
323 // in a separate process with a VMM prebuilt. See b/200592498.
324 const auto host_arch = HostArch();
325 if (host_arch == Arch::Arm64) {
326 LOG(INFO) << "GPU vhost user auto mode: detected arm64 host. Enabling "
327 "vhost user gpu.";
328 return true;
329 }
330
331 LOG(INFO) << "GPU vhost user auto mode: not needed. Not enabling vhost "
332 "user gpu.";
333 return false;
334 }
335
336 return gpu_vhost_user_mode_arg == kGpuVhostUserModeOn;
337 }
338
339 #endif
340
GraphicsDetectorBinaryPath()341 Result<std::string> GraphicsDetectorBinaryPath() {
342 const auto host_arch = HostArch();
343 switch (host_arch) {
344 case Arch::Arm64:
345 return HostBinaryPath("aarch64-linux-gnu/gfxstream_graphics_detector");
346 case Arch::X86:
347 case Arch::X86_64:
348 return HostBinaryPath("x86_64-linux-gnu/gfxstream_graphics_detector");
349 default:
350 break;
351 }
352 return CF_ERR("Graphics detector unavailable for host arch.");
353 }
354
355 CF_UNUSED_ON_MACOS
356 Result<const gfxstream::proto::GraphicsAvailability>
GetGraphicsAvailabilityWithSubprocessCheck()357 GetGraphicsAvailabilityWithSubprocessCheck() {
358 Command graphics_detector_cmd(CF_EXPECT(GraphicsDetectorBinaryPath()));
359 std::string graphics_detector_stdout;
360 auto ret = RunWithManagedStdio(std::move(graphics_detector_cmd), nullptr,
361 &graphics_detector_stdout, nullptr);
362 CF_EXPECT_EQ(ret, 0, "Failed to run graphics detector, bad return value");
363
364 gfxstream::proto::GraphicsAvailability availability;
365 google::protobuf::TextFormat::Parser parser;
366 if (!parser.ParseFromString(graphics_detector_stdout, &availability)) {
367 return CF_ERR("Failed to parse graphics detector stdout: "
368 << graphics_detector_stdout);
369 }
370
371 return availability;
372 }
373
IsAmdGpu(const gfxstream::proto::GraphicsAvailability & availability)374 bool IsAmdGpu(const gfxstream::proto::GraphicsAvailability& availability) {
375 return (availability.has_egl() &&
376 ((availability.egl().has_gles2_availability() &&
377 availability.egl().gles2_availability().has_vendor() &&
378 availability.egl().gles2_availability().vendor().find("AMD") !=
379 std::string::npos) ||
380 (availability.egl().has_gles3_availability() &&
381 availability.egl().gles3_availability().has_vendor() &&
382 availability.egl().gles3_availability().vendor().find("AMD") !=
383 std::string::npos))) ||
384 (availability.has_vulkan() &&
385 !availability.vulkan().physical_devices().empty() &&
386 availability.vulkan().physical_devices(0).has_name() &&
387 availability.vulkan().physical_devices(0).name().find("AMD") !=
388 std::string::npos);
389 }
390
391 const std::string kGfxstreamTransportAsg = "virtio-gpu-asg";
392 const std::string kGfxstreamTransportPipe = "virtio-gpu-pipe";
393
394 CF_UNUSED_ON_MACOS
ParseGfxstreamRendererFlag(const std::string & gpu_renderer_features_arg)395 Result<std::unordered_map<std::string, bool>> ParseGfxstreamRendererFlag(
396 const std::string& gpu_renderer_features_arg) {
397 std::unordered_map<std::string, bool> features;
398
399 for (const std::string& feature :
400 android::base::Split(gpu_renderer_features_arg, ";")) {
401 if (feature.empty()) {
402 continue;
403 }
404
405 const std::vector<std::string> feature_parts =
406 android::base::Split(feature, ":");
407 CF_EXPECT(feature_parts.size() == 2,
408 "Failed to parse renderer features from --gpu_renderer_features="
409 << gpu_renderer_features_arg);
410
411 const std::string& feature_name = feature_parts[0];
412 const std::string& feature_enabled = feature_parts[1];
413 CF_EXPECT(feature_enabled == "enabled" || feature_enabled == "disabled",
414 "Failed to parse renderer features from --gpu_renderer_features="
415 << gpu_renderer_features_arg);
416
417 features[feature_name] = (feature_enabled == "enabled");
418 }
419
420 return features;
421 }
422
423 CF_UNUSED_ON_MACOS
GetGfxstreamRendererFeaturesString(const std::unordered_map<std::string,bool> & features)424 std::string GetGfxstreamRendererFeaturesString(
425 const std::unordered_map<std::string, bool>& features) {
426 std::vector<std::string> parts;
427 for (const auto& [feature_name, feature_enabled] : features) {
428 parts.push_back(feature_name + ":" +
429 (feature_enabled ? "enabled" : "disabled"));
430 }
431 return android::base::Join(parts, ",");
432 }
433
434 CF_UNUSED_ON_MACOS
SetGfxstreamFlags(const std::string & gpu_mode,const std::string & gpu_renderer_features_arg,const GuestConfig & guest_config,const gfxstream::proto::GraphicsAvailability & availability,CuttlefishConfig::MutableInstanceSpecific & instance)435 Result<void> SetGfxstreamFlags(
436 const std::string& gpu_mode, const std::string& gpu_renderer_features_arg,
437 const GuestConfig& guest_config,
438 const gfxstream::proto::GraphicsAvailability& availability,
439 CuttlefishConfig::MutableInstanceSpecific& instance) {
440 std::string gfxstream_transport = kGfxstreamTransportAsg;
441
442 // Some older R branches are missing some Gfxstream backports
443 // which introduced a backward incompatible change (b/267483000).
444 if (guest_config.android_version_number == "11.0.0") {
445 gfxstream_transport = kGfxstreamTransportPipe;
446 }
447
448 if (IsAmdGpu(availability)) {
449 // KVM does not support mapping host graphics buffers into the guest because
450 // the AMD GPU driver uses TTM memory. More info in
451 // https://lore.kernel.org/all/20230911021637.1941096-1-stevensd@google.com
452 //
453 // TODO(b/254721007): replace with a kernel version check after KVM patches
454 // land.
455 CF_EXPECT(gpu_mode != kGpuModeGfxstreamGuestAngle,
456 "--gpu_mode=gfxstream_guest_angle is broken on AMD GPUs.");
457 }
458
459 std::unordered_map<std::string, bool> features;
460 // Apply features from host/mode requirements.
461 if (gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
462 features["VulkanUseDedicatedAhbMemoryType"] = true;
463 }
464 // Apply feature overrides from --gpu_renderer_features.
465 const auto feature_overrides =
466 CF_EXPECT(ParseGfxstreamRendererFlag(gpu_renderer_features_arg));
467 for (const auto& [feature_name, feature_enabled] : feature_overrides) {
468 LOG(DEBUG) << "GPU renderer feature " << feature_name << " overridden to "
469 << (feature_enabled ? "enabled" : "disabled")
470 << " via command line argument.";
471 features[feature_name] = feature_enabled;
472 }
473 // Convert features back to a string for passing to the VMM.
474 const std::string features_string =
475 GetGfxstreamRendererFeaturesString(features);
476 if (!features_string.empty()) {
477 instance.set_gpu_renderer_features(features_string);
478 }
479
480 instance.set_gpu_gfxstream_transport(gfxstream_transport);
481 return {};
482 }
483
484 } // namespace
485
486 static std::unordered_set<std::string> kSupportedGpuContexts{
487 "gfxstream-vulkan", "gfxstream-composer", "cross-domain", "magma"};
488
ConfigureGpuSettings(const std::string & gpu_mode_arg,const std::string & gpu_vhost_user_mode_arg,const std::string & gpu_renderer_features_arg,std::string & gpu_context_types_arg,VmmMode vmm,const GuestConfig & guest_config,CuttlefishConfig::MutableInstanceSpecific & instance)489 Result<std::string> ConfigureGpuSettings(
490 const std::string& gpu_mode_arg, const std::string& gpu_vhost_user_mode_arg,
491 const std::string& gpu_renderer_features_arg,
492 std::string& gpu_context_types_arg, VmmMode vmm,
493 const GuestConfig& guest_config,
494 CuttlefishConfig::MutableInstanceSpecific& instance) {
495 #ifdef __APPLE__
496 (void)gpu_vhost_user_mode_arg;
497 (void)vmm;
498 (void)guest_config;
499 CF_EXPECT(gpu_mode_arg == kGpuModeAuto ||
500 gpu_mode_arg == kGpuModeGuestSwiftshader ||
501 gpu_mode_arg == kGpuModeDrmVirgl || gpu_mode_arg == kGpuModeNone);
502 std::string gpu_mode = gpu_mode_arg;
503 if (gpu_mode == kGpuModeAuto) {
504 gpu_mode = kGpuModeGuestSwiftshader;
505 }
506 instance.set_gpu_mode(gpu_mode);
507 instance.set_enable_gpu_vhost_user(false);
508 #else
509 gfxstream::proto::GraphicsAvailability graphics_availability;
510
511 auto graphics_availability_result =
512 GetGraphicsAvailabilityWithSubprocessCheck();
513 if (!graphics_availability_result.ok()) {
514 LOG(ERROR) << "Failed to get graphics availability: "
515 << graphics_availability_result.error().Message()
516 << ". Assuming none.";
517 } else {
518 graphics_availability = graphics_availability_result.value();
519 LOG(DEBUG) << "Host Graphics Availability:"
520 << graphics_availability.DebugString();
521 }
522
523 const std::string gpu_mode = CF_EXPECT(
524 SelectGpuMode(gpu_mode_arg, vmm, guest_config, graphics_availability));
525 const bool enable_gpu_vhost_user =
526 CF_EXPECT(SelectGpuVhostUserMode(gpu_mode, gpu_vhost_user_mode_arg, vmm));
527
528 if (gpu_mode == kGpuModeGfxstream ||
529 gpu_mode == kGpuModeGfxstreamGuestAngle ||
530 gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
531 CF_EXPECT(SetGfxstreamFlags(gpu_mode, gpu_renderer_features_arg,
532 guest_config, graphics_availability, instance));
533 }
534
535 if (gpu_mode == kGpuModeCustom) {
536 auto requested_types = android::base::Split(gpu_context_types_arg, ":");
537 for (const std::string& requested : requested_types) {
538 CF_EXPECT(kSupportedGpuContexts.count(requested) == 1,
539 "unsupported context type: " + requested);
540 }
541 }
542
543 const auto angle_features = CF_EXPECT(GetNeededAngleFeatures(
544 CF_EXPECT(GetRenderingMode(gpu_mode)), graphics_availability));
545 instance.set_gpu_angle_feature_overrides_enabled(
546 angle_features.angle_feature_overrides_enabled);
547 instance.set_gpu_angle_feature_overrides_disabled(
548 angle_features.angle_feature_overrides_disabled);
549
550 if (enable_gpu_vhost_user) {
551 const auto gpu_vhost_user_features =
552 CF_EXPECT(GetNeededVhostUserGpuHostRendererFeatures(
553 CF_EXPECT(GetRenderingMode(gpu_mode)), graphics_availability));
554 instance.set_enable_gpu_external_blob(
555 gpu_vhost_user_features.external_blob);
556 instance.set_enable_gpu_system_blob(gpu_vhost_user_features.system_blob);
557 } else {
558 instance.set_enable_gpu_external_blob(false);
559 instance.set_enable_gpu_system_blob(false);
560 }
561
562 instance.set_gpu_mode(gpu_mode);
563 instance.set_enable_gpu_vhost_user(enable_gpu_vhost_user);
564 #endif
565
566 return gpu_mode;
567 }
568
569 } // namespace cuttlefish
570