1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/gpu/graphite/dawn/DawnUtils.h"
9 #include "src/gpu/graphite/dawn/DawnUtilsPriv.h"
10
11 #include "include/gpu/ShaderErrorHandler.h"
12 #include "include/gpu/graphite/Context.h"
13 #include "include/gpu/graphite/dawn/DawnBackendContext.h"
14 #include "src/gpu/graphite/ContextPriv.h"
15 #include "src/gpu/graphite/dawn/DawnQueueManager.h"
16 #include "src/gpu/graphite/dawn/DawnSharedContext.h"
17 #include "src/sksl/SkSLCompiler.h"
18 #include "src/sksl/SkSLProgramSettings.h"
19 #include "src/utils/SkShaderUtils.h"
20
21 namespace skgpu::graphite {
22
23 namespace ContextFactory {
MakeDawn(const DawnBackendContext & backendContext,const ContextOptions & options)24 std::unique_ptr<Context> MakeDawn(const DawnBackendContext& backendContext,
25 const ContextOptions& options) {
26 sk_sp<SharedContext> sharedContext = DawnSharedContext::Make(backendContext, options);
27 if (!sharedContext) {
28 return nullptr;
29 }
30
31 auto queueManager =
32 std::make_unique<DawnQueueManager>(backendContext.fQueue, sharedContext.get());
33 if (!queueManager) {
34 return nullptr;
35 }
36
37 auto context = ContextCtorAccessor::MakeContext(std::move(sharedContext),
38 std::move(queueManager),
39 options);
40 SkASSERT(context);
41 return context;
42 }
43 } // namespace ContextFactory
44
DawnFormatIsDepthOrStencil(wgpu::TextureFormat format)45 bool DawnFormatIsDepthOrStencil(wgpu::TextureFormat format) {
46 switch (format) {
47 case wgpu::TextureFormat::Stencil8: // fallthrough
48 case wgpu::TextureFormat::Depth32Float:
49 case wgpu::TextureFormat::Depth32FloatStencil8:
50 return true;
51 default:
52 return false;
53 }
54 }
55
DawnFormatIsDepth(wgpu::TextureFormat format)56 bool DawnFormatIsDepth(wgpu::TextureFormat format) {
57 switch (format) {
58 case wgpu::TextureFormat::Depth32Float:
59 case wgpu::TextureFormat::Depth32FloatStencil8:
60 return true;
61 default:
62 return false;
63 }
64 }
65
DawnFormatIsStencil(wgpu::TextureFormat format)66 bool DawnFormatIsStencil(wgpu::TextureFormat format) {
67 switch (format) {
68 case wgpu::TextureFormat::Stencil8: // fallthrough
69 case wgpu::TextureFormat::Depth32FloatStencil8:
70 return true;
71 default:
72 return false;
73 }
74 }
75
DawnDepthStencilFlagsToFormat(SkEnumBitMask<DepthStencilFlags> mask)76 wgpu::TextureFormat DawnDepthStencilFlagsToFormat(SkEnumBitMask<DepthStencilFlags> mask) {
77 // TODO: Decide if we want to change this to always return a combined depth and stencil format
78 // to allow more sharing of depth stencil allocations.
79 if (mask == DepthStencilFlags::kDepth) {
80 // wgpu::TextureFormatDepth16Unorm is also a universally supported option here
81 return wgpu::TextureFormat::Depth32Float;
82 } else if (mask == DepthStencilFlags::kStencil) {
83 return wgpu::TextureFormat::Stencil8;
84 } else if (mask == DepthStencilFlags::kDepthStencil) {
85 // wgpu::TextureFormatDepth24Unorm_Stencil8 is supported on Mac family GPUs.
86 return wgpu::TextureFormat::Depth32FloatStencil8;
87 }
88 SkASSERT(false);
89 return wgpu::TextureFormat::Undefined;
90 }
91
92 // Print the source code for all shaders generated.
93 #ifdef SK_PRINT_SKSL_SHADERS
94 static constexpr bool gPrintSKSL = true;
95 #else
96 static constexpr bool gPrintSKSL = false;
97 #endif
SkSLToSPIRV(SkSL::Compiler * compiler,const std::string & sksl,SkSL::ProgramKind programKind,const SkSL::ProgramSettings & settings,std::string * spirv,SkSL::Program::Inputs * outInputs,ShaderErrorHandler * errorHandler)98 bool SkSLToSPIRV(SkSL::Compiler* compiler,
99 const std::string& sksl,
100 SkSL::ProgramKind programKind,
101 const SkSL::ProgramSettings& settings,
102 std::string* spirv,
103 SkSL::Program::Inputs* outInputs,
104 ShaderErrorHandler* errorHandler) {
105 #ifdef SK_DEBUG
106 std::string src = SkShaderUtils::PrettyPrint(sksl);
107 #else
108 const std::string& src = sksl;
109 #endif
110 std::unique_ptr<SkSL::Program> program = compiler->convertProgram(programKind,
111 src,
112 settings);
113 if (!program || !compiler->toSPIRV(*program, spirv)) {
114 errorHandler->compileError(src.c_str(), compiler->errorText().c_str());
115 return false;
116 }
117
118 if (gPrintSKSL) {
119 SkShaderUtils::PrintShaderBanner(programKind);
120 SkDebugf("SKSL:\n");
121 SkShaderUtils::PrintLineByLine(SkShaderUtils::PrettyPrint(sksl));
122 }
123
124 *outInputs = program->fInputs;
125 return true;
126 }
127
DawnCompileSPIRVShaderModule(const DawnSharedContext * sharedContext,const std::string & spirv,ShaderErrorHandler * errorHandler)128 wgpu::ShaderModule DawnCompileSPIRVShaderModule(const DawnSharedContext* sharedContext,
129 const std::string& spirv,
130 ShaderErrorHandler* errorHandler) {
131 wgpu::ShaderModuleSPIRVDescriptor spirvDesc;
132 spirvDesc.codeSize = spirv.size() / 4;
133 spirvDesc.code = reinterpret_cast<const uint32_t*>(spirv.c_str());
134
135 // Skia often generates shaders that select a texture/sampler conditionally based on an
136 // attribute (specifically in the case of texture atlas indexing). We disable derivative
137 // uniformity warnings as we expect Skia's behavior to result in well-defined values.
138 wgpu::DawnShaderModuleSPIRVOptionsDescriptor dawnSpirvOptions;
139 dawnSpirvOptions.allowNonUniformDerivatives = true;
140
141 wgpu::ShaderModuleDescriptor desc;
142 desc.nextInChain = &spirvDesc;
143 spirvDesc.nextInChain = &dawnSpirvOptions;
144
145 return sharedContext->device().CreateShaderModule(&desc);
146 }
147
148 } // namespace skgpu::graphite
149