• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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