1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ProgramWgpu.cpp:
7 // Implements the class methods for ProgramWgpu.
8 //
9
10 #include "libANGLE/renderer/wgpu/ProgramWgpu.h"
11
12 #include "common/debug.h"
13 #include "libANGLE/renderer/wgpu/ProgramExecutableWgpu.h"
14 #include "libANGLE/renderer/wgpu/wgpu_utils.h"
15 #include "libANGLE/trace.h"
16
17 #include <dawn/webgpu_cpp.h>
18
19 namespace rx
20 {
21 namespace
22 {
23 class CreateWGPUShaderModuleTask : public LinkSubTask
24 {
25 public:
CreateWGPUShaderModuleTask(wgpu::Instance instance,wgpu::Device device,const gl::SharedCompiledShaderState & compiledShaderState,TranslatedWGPUShaderModule & resultShaderModule)26 CreateWGPUShaderModuleTask(wgpu::Instance instance,
27 wgpu::Device device,
28 const gl::SharedCompiledShaderState &compiledShaderState,
29 TranslatedWGPUShaderModule &resultShaderModule)
30 : mInstance(instance),
31 mDevice(device),
32 mCompiledShaderState(compiledShaderState),
33 mShaderModule(resultShaderModule)
34 {}
35
getResult(const gl::Context * context,gl::InfoLog & infoLog)36 angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
37 {
38 infoLog << mLog.str();
39 return mResult;
40 }
41
operator ()()42 void operator()() override
43 {
44 ANGLE_TRACE_EVENT0("gpu.angle", "CreateWGPUShaderModuleTask");
45
46 wgpu::ShaderModuleWGSLDescriptor shaderModuleWGSLDescriptor;
47 shaderModuleWGSLDescriptor.code = mCompiledShaderState->translatedSource.c_str();
48
49 wgpu::ShaderModuleDescriptor shaderModuleDescriptor;
50 shaderModuleDescriptor.nextInChain = &shaderModuleWGSLDescriptor;
51
52 mShaderModule.module = mDevice.CreateShaderModule(&shaderModuleDescriptor);
53
54 wgpu::CompilationInfoCallbackInfo callbackInfo;
55 callbackInfo.mode = wgpu::CallbackMode::WaitAnyOnly;
56 callbackInfo.callback = [](WGPUCompilationInfoRequestStatus status,
57 struct WGPUCompilationInfo const *compilationInfo,
58 void *userdata) {
59 CreateWGPUShaderModuleTask *task = static_cast<CreateWGPUShaderModuleTask *>(userdata);
60
61 if (status != WGPUCompilationInfoRequestStatus_Success)
62 {
63 task->mResult = angle::Result::Stop;
64 }
65
66 for (size_t msgIdx = 0; msgIdx < compilationInfo->messageCount; ++msgIdx)
67 {
68 const WGPUCompilationMessage &message = compilationInfo->messages[msgIdx];
69 switch (message.type)
70 {
71 case WGPUCompilationMessageType_Error:
72 task->mLog << "Error: ";
73 break;
74 case WGPUCompilationMessageType_Warning:
75 task->mLog << "Warning: ";
76 break;
77 case WGPUCompilationMessageType_Info:
78 task->mLog << "Info: ";
79 break;
80 default:
81 task->mLog << "Unknown: ";
82 break;
83 }
84 task->mLog << message.lineNum << ":" << message.linePos << ": " << message.message
85 << std::endl;
86 }
87 };
88 callbackInfo.userdata = this;
89
90 wgpu::FutureWaitInfo waitInfo;
91 waitInfo.future = mShaderModule.module.GetCompilationInfo(callbackInfo);
92
93 wgpu::WaitStatus waitStatus = mInstance.WaitAny(1, &waitInfo, -1);
94 if (waitStatus != wgpu::WaitStatus::Success)
95 {
96 mResult = angle::Result::Stop;
97 }
98 }
99
100 private:
101 wgpu::Instance mInstance;
102 wgpu::Device mDevice;
103 gl::SharedCompiledShaderState mCompiledShaderState;
104
105 TranslatedWGPUShaderModule &mShaderModule;
106
107 std::ostringstream mLog;
108 angle::Result mResult = angle::Result::Continue;
109 };
110
111 class LinkTaskWgpu : public LinkTask
112 {
113 public:
LinkTaskWgpu(wgpu::Instance instance,wgpu::Device device,ProgramWgpu * program)114 LinkTaskWgpu(wgpu::Instance instance, wgpu::Device device, ProgramWgpu *program)
115 : mInstance(instance), mDevice(device), mProgram(program)
116 {}
117 ~LinkTaskWgpu() override = default;
118
link(const gl::ProgramLinkedResources & resources,const gl::ProgramMergedVaryings & mergedVaryings,std::vector<std::shared_ptr<LinkSubTask>> * linkSubTasksOut,std::vector<std::shared_ptr<LinkSubTask>> * postLinkSubTasksOut)119 void link(const gl::ProgramLinkedResources &resources,
120 const gl::ProgramMergedVaryings &mergedVaryings,
121 std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
122 std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut) override
123 {
124 ASSERT(linkSubTasksOut && linkSubTasksOut->empty());
125 ASSERT(postLinkSubTasksOut && postLinkSubTasksOut->empty());
126
127 ProgramExecutableWgpu *executable =
128 GetImplAs<ProgramExecutableWgpu>(&mProgram->getState().getExecutable());
129
130 const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders =
131 mProgram->getState().getAttachedShaders();
132 for (gl::ShaderType shaderType : gl::AllShaderTypes())
133 {
134 if (shaders[shaderType])
135 {
136 auto task = std::make_shared<CreateWGPUShaderModuleTask>(
137 mInstance, mDevice, shaders[shaderType],
138 executable->getShaderModule(shaderType));
139 linkSubTasksOut->push_back(task);
140 }
141 }
142 }
143
getResult(const gl::Context * context,gl::InfoLog & infoLog)144 angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
145 {
146 return angle::Result::Continue;
147 }
148
149 private:
150 wgpu::Instance mInstance;
151 wgpu::Device mDevice;
152 ProgramWgpu *mProgram = nullptr;
153 };
154 } // anonymous namespace
155
ProgramWgpu(const gl::ProgramState & state)156 ProgramWgpu::ProgramWgpu(const gl::ProgramState &state) : ProgramImpl(state) {}
157
~ProgramWgpu()158 ProgramWgpu::~ProgramWgpu() {}
159
load(const gl::Context * context,gl::BinaryInputStream * stream,std::shared_ptr<LinkTask> * loadTaskOut,egl::CacheGetResult * resultOut)160 angle::Result ProgramWgpu::load(const gl::Context *context,
161 gl::BinaryInputStream *stream,
162 std::shared_ptr<LinkTask> *loadTaskOut,
163 egl::CacheGetResult *resultOut)
164 {
165 *loadTaskOut = {};
166 *resultOut = egl::CacheGetResult::Success;
167 return angle::Result::Continue;
168 }
169
save(const gl::Context * context,gl::BinaryOutputStream * stream)170 void ProgramWgpu::save(const gl::Context *context, gl::BinaryOutputStream *stream) {}
171
setBinaryRetrievableHint(bool retrievable)172 void ProgramWgpu::setBinaryRetrievableHint(bool retrievable) {}
173
setSeparable(bool separable)174 void ProgramWgpu::setSeparable(bool separable) {}
175
link(const gl::Context * context,std::shared_ptr<LinkTask> * linkTaskOut)176 angle::Result ProgramWgpu::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
177 {
178 wgpu::Device device = webgpu::GetDevice(context);
179 wgpu::Instance instance = webgpu::GetInstance(context);
180
181 *linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskWgpu(instance, device, this));
182 return angle::Result::Continue;
183 }
184
validate(const gl::Caps & caps)185 GLboolean ProgramWgpu::validate(const gl::Caps &caps)
186 {
187 return GL_TRUE;
188 }
189
190 } // namespace rx
191