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