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 "spirv-tools/optimizer.hpp" 21 22 #include <cstring> 23 #include <iomanip> 24 #include <limits> 25 #include <mutex> 26 #include <sstream> 27 28 namespace utils { CreateShaderModuleFromASM(const wgpu::Device & device,const char * source)29 wgpu::ShaderModule CreateShaderModuleFromASM(const wgpu::Device& device, const char* source) { 30 // Use SPIRV-Tools's C API to assemble the SPIR-V assembly text to binary. Because the types 31 // aren't RAII, we don't return directly on success and instead always go through the code 32 // path that destroys the SPIRV-Tools objects. 33 wgpu::ShaderModule result = nullptr; 34 35 spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3); 36 ASSERT(context != nullptr); 37 38 spv_binary spirv = nullptr; 39 spv_diagnostic diagnostic = nullptr; 40 if (spvTextToBinary(context, source, strlen(source), &spirv, &diagnostic) == SPV_SUCCESS) { 41 ASSERT(spirv != nullptr); 42 ASSERT(spirv->wordCount <= std::numeric_limits<uint32_t>::max()); 43 44 wgpu::ShaderModuleSPIRVDescriptor spirvDesc; 45 spirvDesc.codeSize = static_cast<uint32_t>(spirv->wordCount); 46 spirvDesc.code = spirv->code; 47 48 wgpu::ShaderModuleDescriptor descriptor; 49 descriptor.nextInChain = &spirvDesc; 50 result = device.CreateShaderModule(&descriptor); 51 } else { 52 ASSERT(diagnostic != nullptr); 53 dawn::WarningLog() << "CreateShaderModuleFromASM SPIRV assembly error:" 54 << diagnostic->position.line + 1 << ":" 55 << diagnostic->position.column + 1 << ": " << diagnostic->error; 56 } 57 58 spvDiagnosticDestroy(diagnostic); 59 spvBinaryDestroy(spirv); 60 spvContextDestroy(context); 61 62 return result; 63 } 64 CreateShaderModule(const wgpu::Device & device,const char * source)65 wgpu::ShaderModule CreateShaderModule(const wgpu::Device& device, const char* source) { 66 wgpu::ShaderModuleWGSLDescriptor wgslDesc; 67 wgslDesc.source = source; 68 wgpu::ShaderModuleDescriptor descriptor; 69 descriptor.nextInChain = &wgslDesc; 70 return device.CreateShaderModule(&descriptor); 71 } 72 CreateBufferFromData(const wgpu::Device & device,const void * data,uint64_t size,wgpu::BufferUsage usage)73 wgpu::Buffer CreateBufferFromData(const wgpu::Device& device, 74 const void* data, 75 uint64_t size, 76 wgpu::BufferUsage usage) { 77 wgpu::BufferDescriptor descriptor; 78 descriptor.size = size; 79 descriptor.usage = usage | wgpu::BufferUsage::CopyDst; 80 wgpu::Buffer buffer = device.CreateBuffer(&descriptor); 81 82 device.GetQueue().WriteBuffer(buffer, 0, data, size); 83 return buffer; 84 } 85 ComboRenderPassDescriptor(std::initializer_list<wgpu::TextureView> colorAttachmentInfo,wgpu::TextureView depthStencil)86 ComboRenderPassDescriptor::ComboRenderPassDescriptor( 87 std::initializer_list<wgpu::TextureView> colorAttachmentInfo, 88 wgpu::TextureView depthStencil) { 89 for (uint32_t i = 0; i < kMaxColorAttachments; ++i) { 90 cColorAttachments[i].loadOp = wgpu::LoadOp::Clear; 91 cColorAttachments[i].storeOp = wgpu::StoreOp::Store; 92 cColorAttachments[i].clearColor = {0.0f, 0.0f, 0.0f, 0.0f}; 93 } 94 95 cDepthStencilAttachmentInfo.clearDepth = 1.0f; 96 cDepthStencilAttachmentInfo.clearStencil = 0; 97 cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Clear; 98 cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store; 99 cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear; 100 cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store; 101 102 colorAttachmentCount = static_cast<uint32_t>(colorAttachmentInfo.size()); 103 uint32_t colorAttachmentIndex = 0; 104 for (const wgpu::TextureView& colorAttachment : colorAttachmentInfo) { 105 if (colorAttachment.Get() != nullptr) { 106 cColorAttachments[colorAttachmentIndex].view = colorAttachment; 107 } 108 ++colorAttachmentIndex; 109 } 110 colorAttachments = cColorAttachments.data(); 111 112 if (depthStencil.Get() != nullptr) { 113 cDepthStencilAttachmentInfo.view = depthStencil; 114 depthStencilAttachment = &cDepthStencilAttachmentInfo; 115 } else { 116 depthStencilAttachment = nullptr; 117 } 118 } 119 ComboRenderPassDescriptor(const ComboRenderPassDescriptor & other)120 ComboRenderPassDescriptor::ComboRenderPassDescriptor(const ComboRenderPassDescriptor& other) { 121 *this = other; 122 } 123 operator =(const ComboRenderPassDescriptor & otherRenderPass)124 const ComboRenderPassDescriptor& ComboRenderPassDescriptor::operator=( 125 const ComboRenderPassDescriptor& otherRenderPass) { 126 cDepthStencilAttachmentInfo = otherRenderPass.cDepthStencilAttachmentInfo; 127 cColorAttachments = otherRenderPass.cColorAttachments; 128 colorAttachmentCount = otherRenderPass.colorAttachmentCount; 129 130 colorAttachments = cColorAttachments.data(); 131 132 if (otherRenderPass.depthStencilAttachment != nullptr) { 133 // Assign desc.depthStencilAttachment to this->depthStencilAttachmentInfo; 134 depthStencilAttachment = &cDepthStencilAttachmentInfo; 135 } else { 136 depthStencilAttachment = nullptr; 137 } 138 139 return *this; 140 } 141 BasicRenderPass()142 BasicRenderPass::BasicRenderPass() 143 : width(0), 144 height(0), 145 color(nullptr), 146 colorFormat(wgpu::TextureFormat::RGBA8Unorm), 147 renderPassInfo({}) { 148 } 149 BasicRenderPass(uint32_t texWidth,uint32_t texHeight,wgpu::Texture colorAttachment,wgpu::TextureFormat textureFormat)150 BasicRenderPass::BasicRenderPass(uint32_t texWidth, 151 uint32_t texHeight, 152 wgpu::Texture colorAttachment, 153 wgpu::TextureFormat textureFormat) 154 : width(texWidth), 155 height(texHeight), 156 color(colorAttachment), 157 colorFormat(textureFormat), 158 renderPassInfo({colorAttachment.CreateView()}) { 159 } 160 CreateBasicRenderPass(const wgpu::Device & device,uint32_t width,uint32_t height,wgpu::TextureFormat format)161 BasicRenderPass CreateBasicRenderPass(const wgpu::Device& device, 162 uint32_t width, 163 uint32_t height, 164 wgpu::TextureFormat format) { 165 DAWN_ASSERT(width > 0 && height > 0); 166 167 wgpu::TextureDescriptor descriptor; 168 descriptor.dimension = wgpu::TextureDimension::e2D; 169 descriptor.size.width = width; 170 descriptor.size.height = height; 171 descriptor.size.depthOrArrayLayers = 1; 172 descriptor.sampleCount = 1; 173 descriptor.format = format; 174 descriptor.mipLevelCount = 1; 175 descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc; 176 wgpu::Texture color = device.CreateTexture(&descriptor); 177 178 return BasicRenderPass(width, height, color); 179 } 180 CreateImageCopyBuffer(wgpu::Buffer buffer,uint64_t offset,uint32_t bytesPerRow,uint32_t rowsPerImage)181 wgpu::ImageCopyBuffer CreateImageCopyBuffer(wgpu::Buffer buffer, 182 uint64_t offset, 183 uint32_t bytesPerRow, 184 uint32_t rowsPerImage) { 185 wgpu::ImageCopyBuffer imageCopyBuffer = {}; 186 imageCopyBuffer.buffer = buffer; 187 imageCopyBuffer.layout = CreateTextureDataLayout(offset, bytesPerRow, rowsPerImage); 188 189 return imageCopyBuffer; 190 } 191 CreateImageCopyTexture(wgpu::Texture texture,uint32_t mipLevel,wgpu::Origin3D origin,wgpu::TextureAspect aspect)192 wgpu::ImageCopyTexture CreateImageCopyTexture(wgpu::Texture texture, 193 uint32_t mipLevel, 194 wgpu::Origin3D origin, 195 wgpu::TextureAspect aspect) { 196 wgpu::ImageCopyTexture imageCopyTexture; 197 imageCopyTexture.texture = texture; 198 imageCopyTexture.mipLevel = mipLevel; 199 imageCopyTexture.origin = origin; 200 imageCopyTexture.aspect = aspect; 201 202 return imageCopyTexture; 203 } 204 CreateTextureDataLayout(uint64_t offset,uint32_t bytesPerRow,uint32_t rowsPerImage)205 wgpu::TextureDataLayout CreateTextureDataLayout(uint64_t offset, 206 uint32_t bytesPerRow, 207 uint32_t rowsPerImage) { 208 wgpu::TextureDataLayout textureDataLayout; 209 textureDataLayout.offset = offset; 210 textureDataLayout.bytesPerRow = bytesPerRow; 211 textureDataLayout.rowsPerImage = rowsPerImage; 212 213 return textureDataLayout; 214 } 215 MakeBasicPipelineLayout(const wgpu::Device & device,const wgpu::BindGroupLayout * bindGroupLayout)216 wgpu::PipelineLayout MakeBasicPipelineLayout(const wgpu::Device& device, 217 const wgpu::BindGroupLayout* bindGroupLayout) { 218 wgpu::PipelineLayoutDescriptor descriptor; 219 if (bindGroupLayout != nullptr) { 220 descriptor.bindGroupLayoutCount = 1; 221 descriptor.bindGroupLayouts = bindGroupLayout; 222 } else { 223 descriptor.bindGroupLayoutCount = 0; 224 descriptor.bindGroupLayouts = nullptr; 225 } 226 return device.CreatePipelineLayout(&descriptor); 227 } 228 MakePipelineLayout(const wgpu::Device & device,std::vector<wgpu::BindGroupLayout> bgls)229 wgpu::PipelineLayout MakePipelineLayout(const wgpu::Device& device, 230 std::vector<wgpu::BindGroupLayout> bgls) { 231 wgpu::PipelineLayoutDescriptor descriptor; 232 descriptor.bindGroupLayoutCount = uint32_t(bgls.size()); 233 descriptor.bindGroupLayouts = bgls.data(); 234 return device.CreatePipelineLayout(&descriptor); 235 } 236 MakeBindGroupLayout(const wgpu::Device & device,std::initializer_list<BindingLayoutEntryInitializationHelper> entriesInitializer)237 wgpu::BindGroupLayout MakeBindGroupLayout( 238 const wgpu::Device& device, 239 std::initializer_list<BindingLayoutEntryInitializationHelper> entriesInitializer) { 240 std::vector<wgpu::BindGroupLayoutEntry> entries; 241 for (const BindingLayoutEntryInitializationHelper& entry : entriesInitializer) { 242 entries.push_back(entry); 243 } 244 245 wgpu::BindGroupLayoutDescriptor descriptor; 246 descriptor.entryCount = static_cast<uint32_t>(entries.size()); 247 descriptor.entries = entries.data(); 248 return device.CreateBindGroupLayout(&descriptor); 249 } 250 BindingLayoutEntryInitializationHelper(uint32_t entryBinding,wgpu::ShaderStage entryVisibility,wgpu::BufferBindingType bufferType,bool bufferHasDynamicOffset,uint64_t bufferMinBindingSize)251 BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper( 252 uint32_t entryBinding, 253 wgpu::ShaderStage entryVisibility, 254 wgpu::BufferBindingType bufferType, 255 bool bufferHasDynamicOffset, 256 uint64_t bufferMinBindingSize) { 257 binding = entryBinding; 258 visibility = entryVisibility; 259 buffer.type = bufferType; 260 buffer.hasDynamicOffset = bufferHasDynamicOffset; 261 buffer.minBindingSize = bufferMinBindingSize; 262 } 263 BindingLayoutEntryInitializationHelper(uint32_t entryBinding,wgpu::ShaderStage entryVisibility,wgpu::SamplerBindingType samplerType)264 BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper( 265 uint32_t entryBinding, 266 wgpu::ShaderStage entryVisibility, 267 wgpu::SamplerBindingType samplerType) { 268 binding = entryBinding; 269 visibility = entryVisibility; 270 sampler.type = samplerType; 271 } 272 BindingLayoutEntryInitializationHelper(uint32_t entryBinding,wgpu::ShaderStage entryVisibility,wgpu::TextureSampleType textureSampleType,wgpu::TextureViewDimension textureViewDimension,bool textureMultisampled)273 BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper( 274 uint32_t entryBinding, 275 wgpu::ShaderStage entryVisibility, 276 wgpu::TextureSampleType textureSampleType, 277 wgpu::TextureViewDimension textureViewDimension, 278 bool textureMultisampled) { 279 binding = entryBinding; 280 visibility = entryVisibility; 281 texture.sampleType = textureSampleType; 282 texture.viewDimension = textureViewDimension; 283 texture.multisampled = textureMultisampled; 284 } 285 BindingLayoutEntryInitializationHelper(uint32_t entryBinding,wgpu::ShaderStage entryVisibility,wgpu::StorageTextureAccess storageTextureAccess,wgpu::TextureFormat format,wgpu::TextureViewDimension textureViewDimension)286 BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper( 287 uint32_t entryBinding, 288 wgpu::ShaderStage entryVisibility, 289 wgpu::StorageTextureAccess storageTextureAccess, 290 wgpu::TextureFormat format, 291 wgpu::TextureViewDimension textureViewDimension) { 292 binding = entryBinding; 293 visibility = entryVisibility; 294 storageTexture.access = storageTextureAccess; 295 storageTexture.format = format; 296 storageTexture.viewDimension = textureViewDimension; 297 } 298 299 // ExternalTextureBindingLayout never contains data, so just make one that can be reused instead 300 // of declaring a new one every time it's needed. 301 wgpu::ExternalTextureBindingLayout kExternalTextureBindingLayout = {}; 302 BindingLayoutEntryInitializationHelper(uint32_t entryBinding,wgpu::ShaderStage entryVisibility,wgpu::ExternalTextureBindingLayout * bindingLayout)303 BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper( 304 uint32_t entryBinding, 305 wgpu::ShaderStage entryVisibility, 306 wgpu::ExternalTextureBindingLayout* bindingLayout) { 307 binding = entryBinding; 308 visibility = entryVisibility; 309 nextInChain = bindingLayout; 310 } 311 BindingLayoutEntryInitializationHelper(const wgpu::BindGroupLayoutEntry & entry)312 BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper( 313 const wgpu::BindGroupLayoutEntry& entry) 314 : wgpu::BindGroupLayoutEntry(entry) { 315 } 316 BindingInitializationHelper(uint32_t binding,const wgpu::Sampler & sampler)317 BindingInitializationHelper::BindingInitializationHelper(uint32_t binding, 318 const wgpu::Sampler& sampler) 319 : binding(binding), sampler(sampler) { 320 } 321 BindingInitializationHelper(uint32_t binding,const wgpu::TextureView & textureView)322 BindingInitializationHelper::BindingInitializationHelper(uint32_t binding, 323 const wgpu::TextureView& textureView) 324 : binding(binding), textureView(textureView) { 325 } 326 BindingInitializationHelper(uint32_t binding,const wgpu::ExternalTexture & externalTexture)327 BindingInitializationHelper::BindingInitializationHelper( 328 uint32_t binding, 329 const wgpu::ExternalTexture& externalTexture) 330 : binding(binding) { 331 externalTextureBindingEntry.externalTexture = externalTexture; 332 } 333 BindingInitializationHelper(uint32_t binding,const wgpu::Buffer & buffer,uint64_t offset,uint64_t size)334 BindingInitializationHelper::BindingInitializationHelper(uint32_t binding, 335 const wgpu::Buffer& buffer, 336 uint64_t offset, 337 uint64_t size) 338 : binding(binding), buffer(buffer), offset(offset), size(size) { 339 } 340 GetAsBinding() const341 wgpu::BindGroupEntry BindingInitializationHelper::GetAsBinding() const { 342 wgpu::BindGroupEntry result; 343 344 result.binding = binding; 345 result.sampler = sampler; 346 result.textureView = textureView; 347 result.buffer = buffer; 348 result.offset = offset; 349 result.size = size; 350 if (externalTextureBindingEntry.externalTexture != nullptr) { 351 result.nextInChain = &externalTextureBindingEntry; 352 } 353 354 return result; 355 } 356 MakeBindGroup(const wgpu::Device & device,const wgpu::BindGroupLayout & layout,std::initializer_list<BindingInitializationHelper> entriesInitializer)357 wgpu::BindGroup MakeBindGroup( 358 const wgpu::Device& device, 359 const wgpu::BindGroupLayout& layout, 360 std::initializer_list<BindingInitializationHelper> entriesInitializer) { 361 std::vector<wgpu::BindGroupEntry> entries; 362 for (const BindingInitializationHelper& helper : entriesInitializer) { 363 entries.push_back(helper.GetAsBinding()); 364 } 365 366 wgpu::BindGroupDescriptor descriptor; 367 descriptor.layout = layout; 368 descriptor.entryCount = entries.size(); 369 descriptor.entries = entries.data(); 370 371 return device.CreateBindGroup(&descriptor); 372 } 373 374 } // namespace utils 375