1 // Copyright 2017 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "utils/WGPUHelpers.h" 16 17 #include "common/Constants.h" 18 #include "common/Log.h" 19 20 #include <shaderc/shaderc.hpp> 21 22 #include <cstring> 23 #include <iomanip> 24 #include <mutex> 25 #include <sstream> 26 27 namespace utils { 28 29 namespace { 30 ShadercShaderKind(SingleShaderStage stage)31 shaderc_shader_kind ShadercShaderKind(SingleShaderStage stage) { 32 switch (stage) { 33 case SingleShaderStage::Vertex: 34 return shaderc_glsl_vertex_shader; 35 case SingleShaderStage::Fragment: 36 return shaderc_glsl_fragment_shader; 37 case SingleShaderStage::Compute: 38 return shaderc_glsl_compute_shader; 39 default: 40 UNREACHABLE(); 41 } 42 } 43 CreateShaderModuleFromResult(const wgpu::Device & device,const shaderc::SpvCompilationResult & result)44 wgpu::ShaderModule CreateShaderModuleFromResult( 45 const wgpu::Device& device, 46 const shaderc::SpvCompilationResult& result) { 47 // result.cend and result.cbegin return pointers to uint32_t. 48 const uint32_t* resultBegin = result.cbegin(); 49 const uint32_t* resultEnd = result.cend(); 50 // So this size is in units of sizeof(uint32_t). 51 ptrdiff_t resultSize = resultEnd - resultBegin; 52 // SetSource takes data as uint32_t*. 53 54 wgpu::ShaderModuleSPIRVDescriptor spirvDesc; 55 spirvDesc.codeSize = static_cast<uint32_t>(resultSize); 56 spirvDesc.code = result.cbegin(); 57 58 wgpu::ShaderModuleDescriptor descriptor; 59 descriptor.nextInChain = &spirvDesc; 60 61 return device.CreateShaderModule(&descriptor); 62 } 63 64 class CompilerSingleton { 65 public: Get()66 static shaderc::Compiler* Get() { 67 std::call_once(mInitFlag, &CompilerSingleton::Initialize); 68 return mCompiler; 69 } 70 71 private: 72 CompilerSingleton() = default; 73 ~CompilerSingleton() = default; 74 CompilerSingleton(const CompilerSingleton&) = delete; 75 CompilerSingleton& operator=(const CompilerSingleton&) = delete; 76 77 static shaderc::Compiler* mCompiler; 78 static std::once_flag mInitFlag; 79 Initialize()80 static void Initialize() { 81 mCompiler = new shaderc::Compiler(); 82 } 83 }; 84 85 shaderc::Compiler* CompilerSingleton::mCompiler = nullptr; 86 std::once_flag CompilerSingleton::mInitFlag; 87 88 } // anonymous namespace 89 CreateShaderModule(const wgpu::Device & device,SingleShaderStage stage,const char * source)90 wgpu::ShaderModule CreateShaderModule(const wgpu::Device& device, 91 SingleShaderStage stage, 92 const char* source) { 93 shaderc_shader_kind kind = ShadercShaderKind(stage); 94 95 shaderc::Compiler* compiler = CompilerSingleton::Get(); 96 auto result = compiler->CompileGlslToSpv(source, strlen(source), kind, "myshader?"); 97 if (result.GetCompilationStatus() != shaderc_compilation_status_success) { 98 dawn::ErrorLog() << result.GetErrorMessage(); 99 return {}; 100 } 101 #ifdef DUMP_SPIRV_ASSEMBLY 102 { 103 shaderc::CompileOptions options; 104 auto resultAsm = compiler->CompileGlslToSpvAssembly(source, strlen(source), kind, 105 "myshader?", options); 106 size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin()); 107 108 char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1)); 109 memcpy(buffer, resultAsm.cbegin(), sizeAsm); 110 buffer[sizeAsm] = '\0'; 111 printf("SPIRV ASSEMBLY DUMP START\n%s\nSPIRV ASSEMBLY DUMP END\n", buffer); 112 free(buffer); 113 } 114 #endif 115 116 #ifdef DUMP_SPIRV_JS_ARRAY 117 printf("SPIRV JS ARRAY DUMP START\n"); 118 for (size_t i = 0; i < size; i++) { 119 printf("%#010x", result.cbegin()[i]); 120 if ((i + 1) % 4 == 0) { 121 printf(",\n"); 122 } else { 123 printf(", "); 124 } 125 } 126 printf("\n"); 127 printf("SPIRV JS ARRAY DUMP END\n"); 128 #endif 129 130 return CreateShaderModuleFromResult(device, result); 131 } 132 CreateShaderModuleFromASM(const wgpu::Device & device,const char * source)133 wgpu::ShaderModule CreateShaderModuleFromASM(const wgpu::Device& device, const char* source) { 134 shaderc::Compiler* compiler = CompilerSingleton::Get(); 135 shaderc::SpvCompilationResult result = compiler->AssembleToSpv(source, strlen(source)); 136 if (result.GetCompilationStatus() != shaderc_compilation_status_success) { 137 dawn::ErrorLog() << result.GetErrorMessage(); 138 return {}; 139 } 140 141 return CreateShaderModuleFromResult(device, result); 142 } 143 CreateShaderModuleFromWGSL(const wgpu::Device & device,const char * source)144 wgpu::ShaderModule CreateShaderModuleFromWGSL(const wgpu::Device& device, const char* source) { 145 wgpu::ShaderModuleWGSLDescriptor wgslDesc; 146 wgslDesc.source = source; 147 wgpu::ShaderModuleDescriptor descriptor; 148 descriptor.nextInChain = &wgslDesc; 149 return device.CreateShaderModule(&descriptor); 150 } 151 CompileGLSLToSpirv(SingleShaderStage stage,const char * source)152 std::vector<uint32_t> CompileGLSLToSpirv(SingleShaderStage stage, const char* source) { 153 shaderc_shader_kind kind = ShadercShaderKind(stage); 154 155 shaderc::Compiler* compiler = CompilerSingleton::Get(); 156 auto result = compiler->CompileGlslToSpv(source, strlen(source), kind, "myshader?"); 157 if (result.GetCompilationStatus() != shaderc_compilation_status_success) { 158 dawn::ErrorLog() << result.GetErrorMessage(); 159 return {}; 160 } 161 return {result.cbegin(), result.cend()}; 162 } 163 CreateBufferFromData(const wgpu::Device & device,const void * data,uint64_t size,wgpu::BufferUsage usage)164 wgpu::Buffer CreateBufferFromData(const wgpu::Device& device, 165 const void* data, 166 uint64_t size, 167 wgpu::BufferUsage usage) { 168 wgpu::BufferDescriptor descriptor; 169 descriptor.size = size; 170 descriptor.usage = usage | wgpu::BufferUsage::CopyDst; 171 wgpu::Buffer buffer = device.CreateBuffer(&descriptor); 172 173 device.GetDefaultQueue().WriteBuffer(buffer, 0, data, size); 174 return buffer; 175 } 176 ComboRenderPassDescriptor(std::initializer_list<wgpu::TextureView> colorAttachmentInfo,wgpu::TextureView depthStencil)177 ComboRenderPassDescriptor::ComboRenderPassDescriptor( 178 std::initializer_list<wgpu::TextureView> colorAttachmentInfo, 179 wgpu::TextureView depthStencil) { 180 for (uint32_t i = 0; i < kMaxColorAttachments; ++i) { 181 cColorAttachments[i].loadOp = wgpu::LoadOp::Clear; 182 cColorAttachments[i].storeOp = wgpu::StoreOp::Store; 183 cColorAttachments[i].clearColor = {0.0f, 0.0f, 0.0f, 0.0f}; 184 } 185 186 cDepthStencilAttachmentInfo.clearDepth = 1.0f; 187 cDepthStencilAttachmentInfo.clearStencil = 0; 188 cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Clear; 189 cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store; 190 cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear; 191 cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store; 192 193 colorAttachmentCount = static_cast<uint32_t>(colorAttachmentInfo.size()); 194 uint32_t colorAttachmentIndex = 0; 195 for (const wgpu::TextureView& colorAttachment : colorAttachmentInfo) { 196 if (colorAttachment.Get() != nullptr) { 197 cColorAttachments[colorAttachmentIndex].attachment = colorAttachment; 198 } 199 ++colorAttachmentIndex; 200 } 201 colorAttachments = cColorAttachments.data(); 202 203 if (depthStencil.Get() != nullptr) { 204 cDepthStencilAttachmentInfo.attachment = depthStencil; 205 depthStencilAttachment = &cDepthStencilAttachmentInfo; 206 } else { 207 depthStencilAttachment = nullptr; 208 } 209 } 210 ComboRenderPassDescriptor(const ComboRenderPassDescriptor & other)211 ComboRenderPassDescriptor::ComboRenderPassDescriptor(const ComboRenderPassDescriptor& other) { 212 *this = other; 213 } 214 operator =(const ComboRenderPassDescriptor & otherRenderPass)215 const ComboRenderPassDescriptor& ComboRenderPassDescriptor::operator=( 216 const ComboRenderPassDescriptor& otherRenderPass) { 217 cDepthStencilAttachmentInfo = otherRenderPass.cDepthStencilAttachmentInfo; 218 cColorAttachments = otherRenderPass.cColorAttachments; 219 colorAttachmentCount = otherRenderPass.colorAttachmentCount; 220 221 colorAttachments = cColorAttachments.data(); 222 223 if (otherRenderPass.depthStencilAttachment != nullptr) { 224 // Assign desc.depthStencilAttachment to this->depthStencilAttachmentInfo; 225 depthStencilAttachment = &cDepthStencilAttachmentInfo; 226 } else { 227 depthStencilAttachment = nullptr; 228 } 229 230 return *this; 231 } 232 BasicRenderPass()233 BasicRenderPass::BasicRenderPass() 234 : width(0), 235 height(0), 236 color(nullptr), 237 colorFormat(wgpu::TextureFormat::RGBA8Unorm), 238 renderPassInfo({}) { 239 } 240 BasicRenderPass(uint32_t texWidth,uint32_t texHeight,wgpu::Texture colorAttachment,wgpu::TextureFormat textureFormat)241 BasicRenderPass::BasicRenderPass(uint32_t texWidth, 242 uint32_t texHeight, 243 wgpu::Texture colorAttachment, 244 wgpu::TextureFormat textureFormat) 245 : width(texWidth), 246 height(texHeight), 247 color(colorAttachment), 248 colorFormat(textureFormat), 249 renderPassInfo({colorAttachment.CreateView()}) { 250 } 251 CreateBasicRenderPass(const wgpu::Device & device,uint32_t width,uint32_t height)252 BasicRenderPass CreateBasicRenderPass(const wgpu::Device& device, 253 uint32_t width, 254 uint32_t height) { 255 DAWN_ASSERT(width > 0 && height > 0); 256 257 wgpu::TextureDescriptor descriptor; 258 descriptor.dimension = wgpu::TextureDimension::e2D; 259 descriptor.size.width = width; 260 descriptor.size.height = height; 261 descriptor.size.depth = 1; 262 descriptor.sampleCount = 1; 263 descriptor.format = BasicRenderPass::kDefaultColorFormat; 264 descriptor.mipLevelCount = 1; 265 descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc; 266 wgpu::Texture color = device.CreateTexture(&descriptor); 267 268 return BasicRenderPass(width, height, color); 269 } 270 CreateBufferCopyView(wgpu::Buffer buffer,uint64_t offset,uint32_t bytesPerRow,uint32_t rowsPerImage)271 wgpu::BufferCopyView CreateBufferCopyView(wgpu::Buffer buffer, 272 uint64_t offset, 273 uint32_t bytesPerRow, 274 uint32_t rowsPerImage) { 275 wgpu::BufferCopyView bufferCopyView = {}; 276 bufferCopyView.buffer = buffer; 277 bufferCopyView.layout = CreateTextureDataLayout(offset, bytesPerRow, rowsPerImage); 278 279 return bufferCopyView; 280 } 281 CreateTextureCopyView(wgpu::Texture texture,uint32_t mipLevel,wgpu::Origin3D origin,wgpu::TextureAspect aspect)282 wgpu::TextureCopyView CreateTextureCopyView(wgpu::Texture texture, 283 uint32_t mipLevel, 284 wgpu::Origin3D origin, 285 wgpu::TextureAspect aspect) { 286 wgpu::TextureCopyView textureCopyView; 287 textureCopyView.texture = texture; 288 textureCopyView.mipLevel = mipLevel; 289 textureCopyView.origin = origin; 290 textureCopyView.aspect = aspect; 291 292 return textureCopyView; 293 } 294 CreateTextureDataLayout(uint64_t offset,uint32_t bytesPerRow,uint32_t rowsPerImage)295 wgpu::TextureDataLayout CreateTextureDataLayout(uint64_t offset, 296 uint32_t bytesPerRow, 297 uint32_t rowsPerImage) { 298 wgpu::TextureDataLayout textureDataLayout; 299 textureDataLayout.offset = offset; 300 textureDataLayout.bytesPerRow = bytesPerRow; 301 textureDataLayout.rowsPerImage = rowsPerImage; 302 303 return textureDataLayout; 304 } 305 GetDefaultSamplerDescriptor()306 wgpu::SamplerDescriptor GetDefaultSamplerDescriptor() { 307 wgpu::SamplerDescriptor desc = {}; 308 309 desc.minFilter = wgpu::FilterMode::Linear; 310 desc.magFilter = wgpu::FilterMode::Linear; 311 desc.mipmapFilter = wgpu::FilterMode::Linear; 312 desc.addressModeU = wgpu::AddressMode::Repeat; 313 desc.addressModeV = wgpu::AddressMode::Repeat; 314 desc.addressModeW = wgpu::AddressMode::Repeat; 315 316 return desc; 317 } 318 MakeBasicPipelineLayout(const wgpu::Device & device,const wgpu::BindGroupLayout * bindGroupLayout)319 wgpu::PipelineLayout MakeBasicPipelineLayout(const wgpu::Device& device, 320 const wgpu::BindGroupLayout* bindGroupLayout) { 321 wgpu::PipelineLayoutDescriptor descriptor; 322 if (bindGroupLayout != nullptr) { 323 descriptor.bindGroupLayoutCount = 1; 324 descriptor.bindGroupLayouts = bindGroupLayout; 325 } else { 326 descriptor.bindGroupLayoutCount = 0; 327 descriptor.bindGroupLayouts = nullptr; 328 } 329 return device.CreatePipelineLayout(&descriptor); 330 } 331 MakeBindGroupLayout(const wgpu::Device & device,std::initializer_list<wgpu::BindGroupLayoutEntry> entriesInitializer)332 wgpu::BindGroupLayout MakeBindGroupLayout( 333 const wgpu::Device& device, 334 std::initializer_list<wgpu::BindGroupLayoutEntry> entriesInitializer) { 335 std::vector<wgpu::BindGroupLayoutEntry> entries; 336 for (const wgpu::BindGroupLayoutEntry& entry : entriesInitializer) { 337 entries.push_back(entry); 338 } 339 340 wgpu::BindGroupLayoutDescriptor descriptor; 341 descriptor.entryCount = static_cast<uint32_t>(entries.size()); 342 descriptor.entries = entries.data(); 343 return device.CreateBindGroupLayout(&descriptor); 344 } 345 BindingInitializationHelper(uint32_t binding,const wgpu::Sampler & sampler)346 BindingInitializationHelper::BindingInitializationHelper(uint32_t binding, 347 const wgpu::Sampler& sampler) 348 : binding(binding), sampler(sampler) { 349 } 350 BindingInitializationHelper(uint32_t binding,const wgpu::TextureView & textureView)351 BindingInitializationHelper::BindingInitializationHelper(uint32_t binding, 352 const wgpu::TextureView& textureView) 353 : binding(binding), textureView(textureView) { 354 } 355 BindingInitializationHelper(uint32_t binding,const wgpu::Buffer & buffer,uint64_t offset,uint64_t size)356 BindingInitializationHelper::BindingInitializationHelper(uint32_t binding, 357 const wgpu::Buffer& buffer, 358 uint64_t offset, 359 uint64_t size) 360 : binding(binding), buffer(buffer), offset(offset), size(size) { 361 } 362 GetAsBinding() const363 wgpu::BindGroupEntry BindingInitializationHelper::GetAsBinding() const { 364 wgpu::BindGroupEntry result; 365 366 result.binding = binding; 367 result.sampler = sampler; 368 result.textureView = textureView; 369 result.buffer = buffer; 370 result.offset = offset; 371 result.size = size; 372 373 return result; 374 } 375 MakeBindGroup(const wgpu::Device & device,const wgpu::BindGroupLayout & layout,std::initializer_list<BindingInitializationHelper> entriesInitializer)376 wgpu::BindGroup MakeBindGroup( 377 const wgpu::Device& device, 378 const wgpu::BindGroupLayout& layout, 379 std::initializer_list<BindingInitializationHelper> entriesInitializer) { 380 std::vector<wgpu::BindGroupEntry> entries; 381 for (const BindingInitializationHelper& helper : entriesInitializer) { 382 entries.push_back(helper.GetAsBinding()); 383 } 384 385 wgpu::BindGroupDescriptor descriptor; 386 descriptor.layout = layout; 387 descriptor.entryCount = entries.size(); 388 descriptor.entries = entries.data(); 389 390 return device.CreateBindGroup(&descriptor); 391 } 392 393 } // namespace utils 394