910e62b5创建于 1月15日历史提交
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/dawn_instance.h"

#include <dawn/webgpu_cpp.h>

#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_split.h"
#include "build/buildflag.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_preferences.h"

#if BUILDFLAG(IS_MAC)
#include "base/apple/bundle_locations.h"
#include "base/apple/foundation_util.h"
#endif

namespace gpu::webgpu {

// static
std::unique_ptr<DawnInstance> DawnInstance::Create(
    dawn::platform::Platform* platform,
    const GpuPreferences& gpu_preferences,
    SafetyLevel safety,
    dawn::native::DawnInstanceDescriptor* dawn_instance_descriptor) {
  // Populate the WGSL blocklist based on the Finch feature.
  std::vector<std::string> wgsl_unsafe_features_owned;
  std::vector<const char*> wgsl_unsafe_features;

  if (safety != SafetyLevel::kUnsafe) {
    wgsl_unsafe_features_owned =
        base::SplitString(features::kWGSLUnsafeFeatures.Get(), ",",
                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
    wgsl_unsafe_features.reserve(wgsl_unsafe_features_owned.size());
    for (const auto& f : wgsl_unsafe_features_owned) {
      wgsl_unsafe_features.push_back(f.c_str());
    }
  }
  wgpu::DawnWGSLBlocklist wgsl_blocklist;
  wgsl_blocklist.nextInChain = nullptr;
  wgsl_blocklist.blocklistedFeatureCount = wgsl_unsafe_features.size();
  wgsl_blocklist.blocklistedFeatures = wgsl_unsafe_features.data();

  // Populate the instance toggles becaused on command line parameters and
  // safety levels. Toggles which are not instance toggles will be ignored by
  // the instance.
  std::vector<const char*> require_instance_enabled_toggles;
  std::vector<const char*> require_instance_disabled_toggles;

  if (safety == SafetyLevel::kSafeExperimental) {
    require_instance_enabled_toggles.push_back(
        "expose_wgsl_experimental_features");
  } else if (safety == SafetyLevel::kUnsafe) {
    require_instance_enabled_toggles.push_back("allow_unsafe_apis");
  }

  for (const std::string& toggles :
       gpu_preferences.enabled_dawn_features_list) {
    require_instance_enabled_toggles.push_back(toggles.c_str());
  }
  for (const std::string& toggles :
       gpu_preferences.disabled_dawn_features_list) {
    require_instance_disabled_toggles.push_back(toggles.c_str());
  }

  wgpu::DawnTogglesDescriptor dawn_toggle_desc;
  dawn_toggle_desc.nextInChain = &wgsl_blocklist;
  dawn_toggle_desc.enabledToggleCount = require_instance_enabled_toggles.size();
  dawn_toggle_desc.enabledToggles = require_instance_enabled_toggles.data();
  dawn_toggle_desc.disabledToggleCount =
      require_instance_disabled_toggles.size();
  dawn_toggle_desc.disabledToggles = require_instance_disabled_toggles.data();

  // Use DawnInstanceDescriptor to pass in the platform and additional search
  // paths
  std::string dawn_search_path;
  base::FilePath module_path;
#if BUILDFLAG(IS_MAC)
  if (base::apple::AmIBundled()) {
    dawn_search_path = base::apple::FrameworkBundlePath()
                           .Append("Libraries")
                           .AsEndingWithSeparator()
                           .AsUTF8Unsafe();
  }
  if (dawn_search_path.empty())
#endif
  {
#if BUILDFLAG(IS_IOS)
    if (base::PathService::Get(base::DIR_ASSETS, &module_path)) {
#else
    if (base::PathService::Get(base::DIR_MODULE, &module_path)) {
#endif
      dawn_search_path = module_path.AsEndingWithSeparator().AsUTF8Unsafe();
    }
  }
  const char* dawn_search_path_c_str = dawn_search_path.c_str();

  dawn::native::DawnInstanceDescriptor dawn_instance_desc;
  if (dawn_instance_descriptor) {
    dawn_instance_desc = *dawn_instance_descriptor;
  }
  dawn_instance_desc.nextInChain = &dawn_toggle_desc;
  dawn_instance_desc.additionalRuntimeSearchPathsCount =
      dawn_search_path.empty() ? 0u : 1u;
  dawn_instance_desc.additionalRuntimeSearchPaths = &dawn_search_path_c_str;
  dawn_instance_desc.platform = platform;

  // Create the instance with all the previous descriptors chained.
  wgpu::InstanceDescriptor instance_desc;
  instance_desc.nextInChain = &dawn_instance_desc;
  static constexpr auto kInstanceFeatures = std::array{
      wgpu::InstanceFeatureName::MultipleDevicesPerAdapter,
      wgpu::InstanceFeatureName::TimedWaitAny,
  };
  instance_desc.requiredFeatureCount = kInstanceFeatures.size();
  instance_desc.requiredFeatures = kInstanceFeatures.data();

  auto instance = std::make_unique<DawnInstance>(
      reinterpret_cast<const WGPUInstanceDescriptor*>(&instance_desc));

  switch (gpu_preferences.enable_dawn_backend_validation) {
    case DawnBackendValidationLevel::kDisabled:
      break;
    case DawnBackendValidationLevel::kPartial:
      instance->SetBackendValidationLevel(
          dawn::native::BackendValidationLevel::Partial);
      break;
    case DawnBackendValidationLevel::kFull:
      instance->SetBackendValidationLevel(
          dawn::native::BackendValidationLevel::Full);
      break;
  }

  return instance;
}

}  // namespace gpu::webgpu