| /* |
| * Copyright 2022 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/gpu/graphite/dawn/DawnUtils.h" |
| #include "src/gpu/graphite/dawn/DawnGraphiteUtilsPriv.h" |
| |
| #include "include/gpu/ShaderErrorHandler.h" |
| #include "include/gpu/graphite/Context.h" |
| #include "include/gpu/graphite/dawn/DawnBackendContext.h" |
| #include "src/gpu/graphite/ContextPriv.h" |
| #include "src/gpu/graphite/dawn/DawnQueueManager.h" |
| #include "src/gpu/graphite/dawn/DawnSharedContext.h" |
| |
| namespace skgpu::graphite { |
| |
| namespace ContextFactory { |
| std::unique_ptr<Context> MakeDawn(const DawnBackendContext& backendContext, |
| const ContextOptions& options) { |
| sk_sp<SharedContext> sharedContext = DawnSharedContext::Make(backendContext, options); |
| if (!sharedContext) { |
| return nullptr; |
| } |
| |
| auto queueManager = |
| std::make_unique<DawnQueueManager>(backendContext.fQueue, sharedContext.get()); |
| if (!queueManager) { |
| return nullptr; |
| } |
| |
| auto context = ContextCtorAccessor::MakeContext(std::move(sharedContext), |
| std::move(queueManager), |
| options); |
| SkASSERT(context); |
| return context; |
| } |
| } // namespace ContextFactory |
| |
| bool DawnFormatIsDepthOrStencil(wgpu::TextureFormat format) { |
| switch (format) { |
| case wgpu::TextureFormat::Stencil8: [[fallthrough]]; |
| case wgpu::TextureFormat::Depth16Unorm: |
| case wgpu::TextureFormat::Depth32Float: |
| case wgpu::TextureFormat::Depth24PlusStencil8: |
| case wgpu::TextureFormat::Depth32FloatStencil8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool DawnFormatIsDepth(wgpu::TextureFormat format) { |
| switch (format) { |
| case wgpu::TextureFormat::Depth16Unorm: [[fallthrough]]; |
| case wgpu::TextureFormat::Depth32Float: |
| case wgpu::TextureFormat::Depth24PlusStencil8: |
| case wgpu::TextureFormat::Depth32FloatStencil8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool DawnFormatIsStencil(wgpu::TextureFormat format) { |
| switch (format) { |
| case wgpu::TextureFormat::Stencil8: [[fallthrough]]; |
| case wgpu::TextureFormat::Depth24PlusStencil8: |
| case wgpu::TextureFormat::Depth32FloatStencil8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| wgpu::TextureFormat DawnDepthStencilFlagsToFormat(SkEnumBitMask<DepthStencilFlags> mask) { |
| // TODO: Decide if we want to change this to always return a combined depth and stencil format |
| // to allow more sharing of depth stencil allocations. |
| if (mask == DepthStencilFlags::kDepth) { |
| // If needed for workarounds or performance, Depth32Float is also available but requires 2x |
| // the amount of memory. |
| return wgpu::TextureFormat::Depth16Unorm; |
| } else if (mask == DepthStencilFlags::kStencil) { |
| return wgpu::TextureFormat::Stencil8; |
| } else if (mask == DepthStencilFlags::kDepthStencil) { |
| return wgpu::TextureFormat::Depth24PlusStencil8; |
| } |
| SkASSERT(false); |
| return wgpu::TextureFormat::Undefined; |
| } |
| |
| static bool check_shader_module([[maybe_unused]] const DawnSharedContext* sharedContext, |
| wgpu::ShaderModule* module, |
| const char* shaderText, |
| ShaderErrorHandler* errorHandler) { |
| // Prior to emsdk 3.1.51 wgpu::ShaderModule::GetCompilationInfo is unimplemented. |
| #if defined(__EMSCRIPTEN__) && \ |
| ((__EMSCRIPTEN_major__ < 3 || \ |
| (__EMSCRIPTEN_major__ == 3 && __EMSCRIPTEN_minor__ < 1) || \ |
| (__EMSCRIPTEN_major__ == 3 && __EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ < 51))) |
| return true; |
| #else |
| struct Handler { |
| static void Fn(WGPUCompilationInfoRequestStatus status, |
| const WGPUCompilationInfo* info, |
| void* userdata) { |
| Handler* self = reinterpret_cast<Handler*>(userdata); |
| SkASSERT(status == WGPUCompilationInfoRequestStatus_Success); |
| |
| // Walk the message list and check for hard errors. |
| self->fSuccess = true; |
| for (size_t index = 0; index < info->messageCount; ++index) { |
| const WGPUCompilationMessage& entry = info->messages[index]; |
| if (entry.type == WGPUCompilationMessageType_Error) { |
| self->fSuccess = false; |
| break; |
| } |
| } |
| |
| // If we found a hard error, report the compilation messages to the error handler. |
| if (!self->fSuccess) { |
| std::string errors; |
| for (size_t index = 0; index < info->messageCount; ++index) { |
| const WGPUCompilationMessage& entry = info->messages[index]; |
| errors += "line " + |
| std::to_string(entry.lineNum) + ':' + |
| std::to_string(entry.linePos) + ' ' + |
| entry.message + '\n'; |
| } |
| self->fErrorHandler->compileError( |
| self->fShaderText, errors.c_str(), /*shaderWasCached=*/false); |
| } |
| } |
| |
| const char* fShaderText; |
| ShaderErrorHandler* fErrorHandler; |
| bool fSuccess = false; |
| }; |
| |
| Handler handler; |
| handler.fShaderText = shaderText; |
| handler.fErrorHandler = errorHandler; |
| #if defined(__EMSCRIPTEN__) |
| // Deprecated function. |
| module->GetCompilationInfo(&Handler::Fn, &handler); |
| #else |
| // New API. |
| wgpu::FutureWaitInfo waitInfo{}; |
| waitInfo.future = module->GetCompilationInfo( |
| wgpu::CallbackMode::WaitAnyOnly, |
| [handlerPtr = &handler](wgpu::CompilationInfoRequestStatus status, |
| const wgpu::CompilationInfo* info) { |
| Handler::Fn(static_cast<WGPUCompilationInfoRequestStatus>(status), |
| reinterpret_cast<const WGPUCompilationInfo*>(info), |
| handlerPtr); |
| }); |
| |
| const auto& instance = static_cast<const DawnSharedContext*>(sharedContext) |
| ->device() |
| .GetAdapter() |
| .GetInstance(); |
| [[maybe_unused]] auto status = |
| instance.WaitAny(1, &waitInfo, /*timeoutNS=*/std::numeric_limits<uint64_t>::max()); |
| SkASSERT(status == wgpu::WaitStatus::Success); |
| #endif // defined(__EMSCRIPTEN__) |
| |
| return handler.fSuccess; |
| #endif |
| } |
| |
| bool DawnCompileWGSLShaderModule(const DawnSharedContext* sharedContext, |
| const char* label, |
| const std::string& wgsl, |
| wgpu::ShaderModule* module, |
| ShaderErrorHandler* errorHandler) { |
| wgpu::ShaderModuleWGSLDescriptor wgslDesc; |
| wgslDesc.code = wgsl.c_str(); |
| |
| wgpu::ShaderModuleDescriptor desc; |
| desc.nextInChain = &wgslDesc; |
| if (sharedContext->caps()->setBackendLabels()) { |
| desc.label = label; |
| } |
| |
| *module = sharedContext->device().CreateShaderModule(&desc); |
| |
| return check_shader_module(sharedContext, module, wgsl.c_str(), errorHandler); |
| } |
| |
| } // namespace skgpu::graphite |