• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Amber 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 "src/dawn/engine_dawn.h"
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <cstdint>
20 #include <cstring>
21 #include <iostream>
22 #include <limits>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 
27 #include "amber/amber_dawn.h"
28 #include "dawn/dawncpp.h"
29 #include "src/dawn/pipeline_info.h"
30 #include "src/format.h"
31 #include "src/make_unique.h"
32 #include "src/sleep.h"
33 
34 namespace amber {
35 namespace dawn {
36 
37 namespace {
38 
39 // The minimum multiple row pitch observed on Dawn on Metal.  Increase this
40 // as needed for other Dawn backends.
41 static const uint32_t kMinimumImageRowPitch = 256;
42 static const float kLodMin = 0.0;
43 static const float kLodMax = 1000.0;
44 static const uint32_t kMaxColorAttachments = 4u;
45 static const uint32_t kMaxVertexInputs = 16u;
46 static const uint32_t kMaxVertexAttributes = 16u;
47 static const uint32_t kMaxDawnBindGroup = 4u;
48 
49 // A DS for creating and setting the defaults for VertexInputDescriptor
50 // Copied from Dawn utils source code.
51 struct ComboVertexInputDescriptor {
ComboVertexInputDescriptoramber::dawn::__anonb40c6e430111::ComboVertexInputDescriptor52   ComboVertexInputDescriptor() {
53     ::dawn::VertexInputDescriptor* descriptor =
54         reinterpret_cast<::dawn::VertexInputDescriptor*>(this);
55 
56     descriptor->indexFormat = ::dawn::IndexFormat::Uint32;
57     descriptor->bufferCount = 0;
58     descriptor->nextInChain = nullptr;
59 
60     // Fill the default values for vertexBuffers and vertexAttributes in
61     // buffers.
62     ::dawn::VertexAttributeDescriptor vertexAttribute;
63     vertexAttribute.shaderLocation = 0;
64     vertexAttribute.offset = 0;
65     vertexAttribute.format = ::dawn::VertexFormat::Float;
66     for (uint32_t i = 0; i < kMaxVertexAttributes; ++i) {
67       cAttributes[i] = vertexAttribute;
68     }
69     for (uint32_t i = 0; i < kMaxVertexBuffers; ++i) {
70       cBuffers[i].stride = 0;
71       cBuffers[i].stepMode = ::dawn::InputStepMode::Vertex;
72       cBuffers[i].attributeCount = 0;
73       cBuffers[i].attributes = nullptr;
74     }
75     // cBuffers[i].attributes points to somewhere in cAttributes.
76     // cBuffers[0].attributes points to &cAttributes[0] by default. Assuming
77     // cBuffers[0] has two attributes, then cBuffers[1].attributes should
78     // point to &cAttributes[2]. Likewise, if cBuffers[1] has 3 attributes,
79     // then cBuffers[2].attributes should point to &cAttributes[5].
80 
81     // In amber-dawn, the vertex input descriptor is always created assuming
82     // these relationships are one to one i.e. cBuffers[i].attributes is always
83     // pointing to &cAttributes[i] and cBuffers[i].attributeCount == 1
84     cBuffers[0].attributes = &cAttributes[0];
85     descriptor->buffers = &cBuffers[0];
86   }
87 
88   static const uint32_t kMaxVertexBuffers = 16u;
89   static const uint32_t kMaxVertexBufferStride = 2048u;
90   const void* nextInChain = nullptr;
91   ::dawn::IndexFormat indexFormat;
92   uint32_t bufferCount;
93   ::dawn::VertexBufferDescriptor const* buffers;
94 
95   std::array<::dawn::VertexBufferDescriptor, kMaxVertexBuffers> cBuffers;
96   std::array<::dawn::VertexAttributeDescriptor, kMaxVertexAttributes>
97       cAttributes;
98 };
99 
100 // This structure is a container for a few variables that are created during
101 // CreateRenderPipelineDescriptor and CreateRenderPassDescriptor and we want to
102 // make sure they don't go out of scope before we are done with them
103 struct DawnPipelineHelper {
104   Result CreateRenderPipelineDescriptor(
105       const RenderPipelineInfo& render_pipeline,
106       const ::dawn::Device& device,
107       const bool ignore_vertex_and_Index_buffers,
108       const PipelineData* pipeline_data);
109   Result CreateRenderPassDescriptor(
110       const RenderPipelineInfo& render_pipeline,
111       const ::dawn::Device& device,
112       const std::vector<::dawn::TextureView>& texture_view,
113       const ::dawn::LoadOp load_op);
114   ::dawn::RenderPipelineDescriptor renderPipelineDescriptor;
115   ::dawn::RenderPassDescriptor renderPassDescriptor;
116 
117   ComboVertexInputDescriptor vertexInputDescriptor;
118   ::dawn::RasterizationStateDescriptor rasterizationState;
119 
120  private:
121   ::dawn::ProgrammableStageDescriptor fragmentStage;
122   ::dawn::ProgrammableStageDescriptor vertexStage;
123   ::dawn::RenderPassColorAttachmentDescriptor
124       colorAttachmentsInfoPtr[kMaxColorAttachments];
125   ::dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachmentInfo;
126   std::array<::dawn::ColorStateDescriptor*, kMaxColorAttachments> colorStates;
127   ::dawn::DepthStencilStateDescriptor depthStencilState;
128   ::dawn::ColorStateDescriptor colorStatesDescriptor[kMaxColorAttachments];
129   ::dawn::ColorStateDescriptor colorStateDescriptor;
130   ::dawn::StencilStateFaceDescriptor stencil_front;
131   ::dawn::StencilStateFaceDescriptor stencil_back;
132   ::dawn::BlendDescriptor alpha_blend;
133   ::dawn::BlendDescriptor color_blend;
134   std::string vertexEntryPoint;
135   std::string fragmentEntryPoint;
136   std::array<::dawn::RenderPassColorAttachmentDescriptor, kMaxColorAttachments>
137       colorAttachmentsInfo;
138   ::dawn::TextureDescriptor depthStencilDescriptor;
139   ::dawn::Texture depthStencilTexture;
140   ::dawn::TextureView depthStencilView;
141 };
142 
143 // Creates a device-side texture, and returns it through |result_ptr|.
144 // Assumes the device exists and is valid.  Assumes result_ptr is not null.
145 // Returns a result code.
MakeTexture(const::dawn::Device & device,::dawn::TextureFormat format,uint32_t width,uint32_t height,::dawn::Texture * result_ptr)146 Result MakeTexture(const ::dawn::Device& device,
147                    ::dawn::TextureFormat format,
148                    uint32_t width,
149                    uint32_t height,
150                    ::dawn::Texture* result_ptr) {
151   assert(device);
152   assert(result_ptr);
153   assert(width * height > 0);
154   ::dawn::TextureDescriptor descriptor;
155   descriptor.dimension = ::dawn::TextureDimension::e2D;
156   descriptor.size.width = width;
157   descriptor.size.height = height;
158   descriptor.size.depth = 1;
159   descriptor.arrayLayerCount = 1;
160   descriptor.format = format;
161   descriptor.mipLevelCount = 1;
162   descriptor.sampleCount = 1;
163   descriptor.usage =
164       ::dawn::TextureUsage::CopySrc | ::dawn::TextureUsage::OutputAttachment;
165   // TODO(dneto): Get a better message by using the Dawn error callback.
166   *result_ptr = device.CreateTexture(&descriptor);
167   if (*result_ptr)
168     return {};
169   return Result("Dawn: Failed to allocate a framebuffer texture");
170 }
171 
172 // Creates a device-side texture, and returns it through |result_ptr|.
173 // Assumes the device exists and is valid.  Assumes result_ptr is not null.
174 // Returns a result code.
MakeDawnTexture(const::dawn::Device & device,::dawn::TextureFormat format,uint32_t width,uint32_t height)175 ::dawn::Texture MakeDawnTexture(const ::dawn::Device& device,
176                                 ::dawn::TextureFormat format,
177                                 uint32_t width,
178                                 uint32_t height) {
179   assert(device);
180   assert(width * height > 0);
181   ::dawn::TextureDescriptor descriptor;
182   descriptor.dimension = ::dawn::TextureDimension::e2D;
183   descriptor.size.width = width;
184   descriptor.size.height = height;
185   descriptor.size.depth = 1;
186   descriptor.arrayLayerCount = 1;
187   descriptor.format = format;
188   descriptor.mipLevelCount = 1;
189   descriptor.sampleCount = 1;
190   descriptor.usage =
191       ::dawn::TextureUsage::CopySrc | ::dawn::TextureUsage::OutputAttachment;
192 
193   return device.CreateTexture(&descriptor);
194 }
195 
196 // Result status object and data pointer resulting from a buffer mapping.
197 struct MapResult {
198   Result result;
199   const void* data = nullptr;
200   uint64_t dataLength = 0;
201 };
202 
203 // Handles the update from an asynchronous buffer map request, updating the
204 // state of the MapResult object hidden inside the |userdata| parameter.
205 // On a successful mapping outcome, set the data pointer in the map result.
206 // Otherwise set the map result object to an error, and the data member is
207 // not changed.
HandleBufferMapCallback(DawnBufferMapAsyncStatus status,const void * data,uint64_t dataLength,void * userdata)208 void HandleBufferMapCallback(DawnBufferMapAsyncStatus status,
209                              const void* data,
210                              uint64_t dataLength,
211                              void* userdata) {
212   MapResult& map_result = *reinterpret_cast<MapResult*>(userdata);
213   switch (status) {
214     case DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS:
215       map_result.data = data;
216       map_result.dataLength = dataLength;
217       break;
218     case DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR:
219       map_result.result = Result("Buffer map for reading failed: error");
220       break;
221     case DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN:
222     case DAWN_BUFFER_MAP_ASYNC_STATUS_FORCE32:
223       map_result.result = Result("Buffer map for reading failed: unknown");
224       break;
225     case DAWN_BUFFER_MAP_ASYNC_STATUS_DEVICE_LOST:
226       map_result.result = Result("Buffer map for reading failed: device lost");
227       break;
228   }
229 }
230 
231 // Returns |value| but rounded up to a multiple of |alignment|. |alignment| is
232 // assumed to be a power of 2.
Align(uint32_t value,size_t alignment)233 uint32_t Align(uint32_t value, size_t alignment) {
234   assert(alignment <= std::numeric_limits<uint32_t>::max());
235   assert(alignment != 0);
236   uint32_t alignment32 = static_cast<uint32_t>(alignment);
237   return (value + (alignment32 - 1)) & ~(alignment32 - 1);
238 }
239 
240 }  // namespace
241 
242 // Maps the given buffer.  Assumes the buffer has usage bit
243 // ::dawn::BufferUsage::MapRead set.  Returns a MapResult structure, with
244 // the status saved in the |result| member and the host pointer to the mapped
245 // data in the |data| member. Mapping a buffer can fail if the context is
246 // lost, for example. In the failure case, the |data| member will be null.
MapBuffer(const::dawn::Device & device,const::dawn::Buffer & buf)247 MapResult MapBuffer(const ::dawn::Device& device, const ::dawn::Buffer& buf) {
248   MapResult map_result;
249 
250   buf.MapReadAsync(
251       HandleBufferMapCallback,
252       reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(&map_result)));
253   device.Tick();
254   // Wait until the callback has been processed.  Use an exponential backoff
255   // interval, but cap it at one second intervals.  But never loop forever.
256   const int max_iters = 100;
257   const int one_second_in_us = 1000000;
258   for (int iters = 0, interval = 1;
259        !map_result.data && map_result.result.IsSuccess();
260        iters++, interval = std::min(2 * interval, one_second_in_us)) {
261     device.Tick();
262     if (iters > max_iters) {
263       map_result.result = Result("MapBuffer timed out after 100 iterations");
264       break;
265     }
266     USleep(uint32_t(interval));
267   }
268   return map_result;
269 }
270 
271 // Creates and returns a dawn BufferCopyView
272 // Copied from Dawn utils source code.
CreateBufferCopyView(::dawn::Buffer buffer,uint64_t offset,uint32_t rowPitch,uint32_t imageHeight)273 ::dawn::BufferCopyView CreateBufferCopyView(::dawn::Buffer buffer,
274                                             uint64_t offset,
275                                             uint32_t rowPitch,
276                                             uint32_t imageHeight) {
277   ::dawn::BufferCopyView bufferCopyView;
278   bufferCopyView.buffer = buffer;
279   bufferCopyView.offset = offset;
280   bufferCopyView.rowPitch = rowPitch;
281   bufferCopyView.imageHeight = imageHeight;
282 
283   return bufferCopyView;
284 }
285 
286 // Creates and returns a dawn TextureCopyView
287 // Copied from Dawn utils source code.
CreateTextureCopyView(::dawn::Texture texture,uint32_t mipLevel,uint32_t arrayLayer,::dawn::Origin3D origin)288 ::dawn::TextureCopyView CreateTextureCopyView(::dawn::Texture texture,
289                                               uint32_t mipLevel,
290                                               uint32_t arrayLayer,
291                                               ::dawn::Origin3D origin) {
292   ::dawn::TextureCopyView textureCopyView;
293   textureCopyView.texture = texture;
294   textureCopyView.mipLevel = mipLevel;
295   textureCopyView.arrayLayer = arrayLayer;
296   textureCopyView.origin = origin;
297 
298   return textureCopyView;
299 }
300 
MapDeviceTextureToHostBuffer(const RenderPipelineInfo & render_pipeline,const::dawn::Device & device)301 Result EngineDawn::MapDeviceTextureToHostBuffer(
302     const RenderPipelineInfo& render_pipeline,
303     const ::dawn::Device& device) {
304   const auto width = render_pipeline.pipeline->GetFramebufferWidth();
305   const auto height = render_pipeline.pipeline->GetFramebufferHeight();
306 
307   const auto pixelSize = render_pipeline.pipeline->GetColorAttachments()[0]
308                              .buffer->GetElementStride();
309   const auto dawn_row_pitch = Align(width * pixelSize, kMinimumImageRowPitch);
310   const auto size = height * dawn_row_pitch;
311   // Create a temporary buffer to hold the color attachment content and can
312   // be mapped
313   ::dawn::BufferDescriptor descriptor;
314   descriptor.size = size;
315   descriptor.usage =
316       ::dawn::BufferUsage::CopyDst | ::dawn::BufferUsage::MapRead;
317   ::dawn::Buffer copy_buffer = device.CreateBuffer(&descriptor);
318   ::dawn::BufferCopyView copy_buffer_view =
319       CreateBufferCopyView(copy_buffer, 0, dawn_row_pitch, 0);
320   ::dawn::Origin3D origin3D;
321   origin3D.x = 0;
322   origin3D.y = 0;
323   origin3D.z = 0;
324 
325   for (uint32_t i = 0;
326        i < render_pipeline.pipeline->GetColorAttachments().size(); i++) {
327     ::dawn::TextureCopyView device_texture_view =
328         CreateTextureCopyView(textures_[i], 0, 0, origin3D);
329     ::dawn::Extent3D copySize = {width, height, 1};
330     auto encoder = device.CreateCommandEncoder();
331     encoder.CopyTextureToBuffer(&device_texture_view, &copy_buffer_view,
332                                 &copySize);
333     auto commands = encoder.Finish();
334     auto queue = device.CreateQueue();
335     queue.Submit(1, &commands);
336 
337     MapResult mapped_device_texture = MapBuffer(device, copy_buffer);
338     if (!mapped_device_texture.result.IsSuccess())
339       return mapped_device_texture.result;
340 
341     auto& host_texture = render_pipeline.pipeline->GetColorAttachments()[i];
342     auto* values = host_texture.buffer->ValuePtr();
343     auto row_stride = pixelSize * width;
344     assert(row_stride * height == host_texture.buffer->GetSizeInBytes());
345     // Each Dawn row has enough data to fill the target row.
346     assert(dawn_row_pitch >= row_stride);
347     values->resize(host_texture.buffer->GetSizeInBytes());
348     // Copy the framebuffer contents back into the host-side
349     // framebuffer-buffer. In the Dawn buffer, the row stride is a multiple of
350     // kMinimumImageRowPitch bytes, so it might have padding therefore memcpy
351     // is done row by row.
352     for (uint h = 0; h < height; h++) {
353       std::memcpy(values->data() + h * row_stride,
354                   static_cast<const uint8_t*>(mapped_device_texture.data) +
355                       h * dawn_row_pitch,
356                   row_stride);
357     }
358     // Always unmap the buffer at the end of the engine's command.
359     copy_buffer.Unmap();
360   }
361   return {};
362 }
363 
MapDeviceBufferToHostBuffer(const ComputePipelineInfo & compute_pipeline,const::dawn::Device & device)364 Result EngineDawn::MapDeviceBufferToHostBuffer(
365     const ComputePipelineInfo& compute_pipeline,
366     const ::dawn::Device& device) {
367   for (uint32_t i = 0; i < compute_pipeline.pipeline->GetBuffers().size();
368        i++) {
369     auto& device_buffer = compute_pipeline.buffers[i];
370     auto& host_buffer = compute_pipeline.pipeline->GetBuffers()[i];
371 
372     // Create a copy of device buffer to use it in a map read operation.
373     // It's not possible to simply set this bit on the existing buffers since:
374     // Device error: Only CopyDst is allowed with MapRead
375     ::dawn::BufferDescriptor descriptor;
376     descriptor.size = host_buffer.buffer->GetSizeInBytes();
377     descriptor.usage =
378         ::dawn::BufferUsage::CopyDst | ::dawn::BufferUsage::MapRead;
379     const auto copy_device_buffer = device.CreateBuffer(&descriptor);
380     const uint64_t source_offset = 0;
381     const uint64_t destination_offset = 0;
382     const uint64_t copy_size =
383         static_cast<uint64_t>(host_buffer.buffer->GetSizeInBytes());
384     auto encoder = device.CreateCommandEncoder();
385     encoder.CopyBufferToBuffer(device_buffer, source_offset, copy_device_buffer,
386                                destination_offset, copy_size);
387     auto commands = encoder.Finish();
388     auto queue = device.CreateQueue();
389     queue.Submit(1, &commands);
390 
391     MapResult mapped_device_buffer = MapBuffer(device, copy_device_buffer);
392     auto* values = host_buffer.buffer->ValuePtr();
393     values->resize(host_buffer.buffer->GetSizeInBytes());
394     std::memcpy(values->data(),
395                 static_cast<const uint8_t*>(mapped_device_buffer.data),
396                 copy_size);
397 
398     copy_device_buffer.Unmap();
399     if (!mapped_device_buffer.result.IsSuccess())
400       return mapped_device_buffer.result;
401   }
402   return {};
403 }
404 
405 // Creates a dawn buffer of |size| bytes with TransferDst and the given usage
406 // copied from Dawn utils source code
CreateBufferFromData(const::dawn::Device & device,const void * data,uint64_t size,::dawn::BufferUsage usage)407 ::dawn::Buffer CreateBufferFromData(const ::dawn::Device& device,
408                                     const void* data,
409                                     uint64_t size,
410                                     ::dawn::BufferUsage usage) {
411   ::dawn::BufferDescriptor descriptor;
412   descriptor.size = size;
413   descriptor.usage = usage | ::dawn::BufferUsage::CopyDst;
414 
415   ::dawn::Buffer buffer = device.CreateBuffer(&descriptor);
416   if (data != nullptr)
417     buffer.SetSubData(0, size, reinterpret_cast<const uint8_t*>(data));
418   return buffer;
419 }
420 
421 // Creates a bind group.
422 // Helpers to make creating bind groups look nicer:
423 //
424 //   utils::MakeBindGroup(device, layout, {
425 //       {0, mySampler},
426 //       {1, myBuffer, offset, size},
427 //       {3, myTexture}
428 //   });
429 
430 // Structure with one constructor per-type of bindings, so that the
431 // initializer_list accepts bindings with the right type and no extra
432 // information.
433 struct BindingInitializationHelper {
BindingInitializationHelperamber::dawn::BindingInitializationHelper434   BindingInitializationHelper(uint32_t binding,
435                               const ::dawn::Buffer& buffer,
436                               uint64_t offset,
437                               uint64_t size)
438       : binding(binding), buffer(buffer), offset(offset), size(size) {}
439 
GetAsBindingamber::dawn::BindingInitializationHelper440   ::dawn::BindGroupBinding GetAsBinding() const {
441     ::dawn::BindGroupBinding result;
442     result.binding = binding;
443     result.sampler = sampler;
444     result.textureView = textureView;
445     result.buffer = buffer;
446     result.offset = offset;
447     result.size = size;
448     return result;
449   }
450 
451   uint32_t binding;
452   ::dawn::Sampler sampler;
453   ::dawn::TextureView textureView;
454   ::dawn::Buffer buffer;
455   uint64_t offset = 0;
456   uint64_t size = 0;
457 };
458 
MakeBindGroup(const::dawn::Device & device,const::dawn::BindGroupLayout & layout,const std::vector<BindingInitializationHelper> & bindingsInitializer)459 ::dawn::BindGroup MakeBindGroup(
460     const ::dawn::Device& device,
461     const ::dawn::BindGroupLayout& layout,
462     const std::vector<BindingInitializationHelper>& bindingsInitializer) {
463   std::vector<::dawn::BindGroupBinding> bindings;
464   for (const BindingInitializationHelper& helper : bindingsInitializer) {
465     bindings.push_back(helper.GetAsBinding());
466   }
467 
468   ::dawn::BindGroupDescriptor descriptor;
469   descriptor.layout = layout;
470   descriptor.bindingCount = bindings.size();
471   descriptor.bindings = bindings.data();
472 
473   return device.CreateBindGroup(&descriptor);
474 }
475 
476 // Creates a bind group layout.
477 // Copied from Dawn utils source code.
MakeBindGroupLayout(const::dawn::Device & device,const std::vector<::dawn::BindGroupLayoutBinding> & bindingsInitializer)478 ::dawn::BindGroupLayout MakeBindGroupLayout(
479     const ::dawn::Device& device,
480     const std::vector<::dawn::BindGroupLayoutBinding>& bindingsInitializer) {
481   constexpr ::dawn::ShaderStage kNoStages{};
482 
483   std::vector<::dawn::BindGroupLayoutBinding> bindings;
484   for (const ::dawn::BindGroupLayoutBinding& binding : bindingsInitializer) {
485     if (binding.visibility != kNoStages) {
486       bindings.push_back(binding);
487     }
488   }
489 
490   ::dawn::BindGroupLayoutDescriptor descriptor;
491   descriptor.bindingCount = static_cast<uint32_t>(bindings.size());
492   descriptor.bindings = bindings.data();
493   return device.CreateBindGroupLayout(&descriptor);
494 }
495 
496 // Creates a basic pipeline layout.
497 // Copied from Dawn utils source code.
MakeBasicPipelineLayout(const::dawn::Device & device,std::vector<::dawn::BindGroupLayout> bindingInitializer)498 ::dawn::PipelineLayout MakeBasicPipelineLayout(
499     const ::dawn::Device& device,
500     std::vector<::dawn::BindGroupLayout> bindingInitializer) {
501   ::dawn::PipelineLayoutDescriptor descriptor;
502   descriptor.bindGroupLayoutCount = bindingInitializer.size();
503   descriptor.bindGroupLayouts = bindingInitializer.data();
504   return device.CreatePipelineLayout(&descriptor);
505 }
506 
507 // Converts an Amber format to a Dawn texture format, and sends the result out
508 // through |dawn_format_ptr|.  If the conversion fails, return an error
509 // result.
GetDawnTextureFormat(const::amber::Format & amber_format,::dawn::TextureFormat * dawn_format_ptr)510 Result GetDawnTextureFormat(const ::amber::Format& amber_format,
511                             ::dawn::TextureFormat* dawn_format_ptr) {
512   if (!dawn_format_ptr)
513     return Result("Internal error: format pointer argument is null");
514   ::dawn::TextureFormat& dawn_format = *dawn_format_ptr;
515 
516   switch (amber_format.GetFormatType()) {
517     // TODO(dneto): These are all the formats that Dawn currently knows about.
518     case FormatType::kR8G8B8A8_UNORM:
519       dawn_format = ::dawn::TextureFormat::RGBA8Unorm;
520       break;
521     case FormatType::kR8G8_UNORM:
522       dawn_format = ::dawn::TextureFormat::RG8Unorm;
523       break;
524     case FormatType::kR8_UNORM:
525       dawn_format = ::dawn::TextureFormat::R8Unorm;
526       break;
527     case FormatType::kR8G8B8A8_UINT:
528       dawn_format = ::dawn::TextureFormat::RGBA8Uint;
529       break;
530     case FormatType::kR8G8_UINT:
531       dawn_format = ::dawn::TextureFormat::RG8Uint;
532       break;
533     case FormatType::kR8_UINT:
534       dawn_format = ::dawn::TextureFormat::R8Uint;
535       break;
536     case FormatType::kB8G8R8A8_UNORM:
537       dawn_format = ::dawn::TextureFormat::BGRA8Unorm;
538       break;
539     case FormatType::kD32_SFLOAT_S8_UINT:
540       dawn_format = ::dawn::TextureFormat::Depth24PlusStencil8;
541       break;
542     default:
543       return Result(
544           "Amber format " +
545           std::to_string(static_cast<uint32_t>(amber_format.GetFormatType())) +
546           " is invalid for Dawn");
547   }
548 
549   return {};
550 }
551 // Converts an Amber format to a Dawn Vertex format, and sends the result out
552 // through |dawn_format_ptr|.  If the conversion fails, return an error
553 // result.
554 // TODO(sarahM0): support other ::dawn::VertexFormat
GetDawnVertexFormat(const::amber::Format & amber_format,::dawn::VertexFormat * dawn_format_ptr)555 Result GetDawnVertexFormat(const ::amber::Format& amber_format,
556                            ::dawn::VertexFormat* dawn_format_ptr) {
557   ::dawn::VertexFormat& dawn_format = *dawn_format_ptr;
558   switch (amber_format.GetFormatType()) {
559     case FormatType::kR32_SFLOAT:
560       dawn_format = ::dawn::VertexFormat::Float;
561       break;
562     case FormatType::kR32G32_SFLOAT:
563       dawn_format = ::dawn::VertexFormat::Float2;
564       break;
565     case FormatType::kR32G32B32_SFLOAT:
566       dawn_format = ::dawn::VertexFormat::Float3;
567       break;
568     case FormatType::kR32G32B32A32_SFLOAT:
569       dawn_format = ::dawn::VertexFormat::Float4;
570       break;
571     case FormatType::kR8G8_SNORM:
572       dawn_format = ::dawn::VertexFormat::Char2Norm;
573       break;
574     case FormatType::kR8G8B8A8_UNORM:
575       dawn_format = ::dawn::VertexFormat::UChar4Norm;
576       break;
577     case FormatType::kR8G8B8A8_SNORM:
578       dawn_format = ::dawn::VertexFormat::Char4Norm;
579       break;
580     default:
581       return Result(
582           "Amber vertex format " +
583           std::to_string(static_cast<uint32_t>(amber_format.GetFormatType())) +
584           " is invalid for Dawn or is not supported in amber-dawn");
585   }
586   return {};
587 }
588 
589 // Converts an Amber format to a Dawn Index format, and sends the result out
590 // through |dawn_format_ptr|.  If the conversion fails, return an error
591 // result.
GetDawnIndexFormat(const::amber::Format & amber_format,::dawn::IndexFormat * dawn_format_ptr)592 Result GetDawnIndexFormat(const ::amber::Format& amber_format,
593                           ::dawn::IndexFormat* dawn_format_ptr) {
594   ::dawn::IndexFormat& dawn_format = *dawn_format_ptr;
595   switch (amber_format.GetFormatType()) {
596     case FormatType::kR16_UINT:
597       dawn_format = ::dawn::IndexFormat::Uint16;
598       break;
599     case FormatType::kR32_UINT:
600       dawn_format = ::dawn::IndexFormat::Uint32;
601       break;
602     default:
603       return Result(
604           "Amber index format " +
605           std::to_string(static_cast<uint32_t>(amber_format.GetFormatType())) +
606           " is invalid for Dawn");
607   }
608   return {};
609 }
610 
611 // Converts an Amber topology to a Dawn topology, and sends the result out
612 // through |dawn_topology_ptr|. It the conversion fails, return an error result.
GetDawnTopology(const::amber::Topology & amber_topology,::dawn::PrimitiveTopology * dawn_topology_ptr)613 Result GetDawnTopology(const ::amber::Topology& amber_topology,
614                        ::dawn::PrimitiveTopology* dawn_topology_ptr) {
615   ::dawn::PrimitiveTopology& dawn_topology = *dawn_topology_ptr;
616   switch (amber_topology) {
617     case Topology::kPointList:
618       dawn_topology = ::dawn::PrimitiveTopology::PointList;
619       break;
620     case Topology::kLineList:
621       dawn_topology = ::dawn::PrimitiveTopology::LineList;
622       break;
623     case Topology::kLineStrip:
624       dawn_topology = ::dawn::PrimitiveTopology::LineStrip;
625       break;
626     case Topology::kTriangleList:
627       dawn_topology = ::dawn::PrimitiveTopology::TriangleList;
628       break;
629     case Topology::kTriangleStrip:
630       dawn_topology = ::dawn::PrimitiveTopology::TriangleStrip;
631       break;
632     default:
633       return Result("Amber PrimitiveTopology " +
634                     std::to_string(static_cast<uint32_t>(amber_topology)) +
635                     " is not supported in Dawn");
636   }
637   return {};
638 }
639 
GetDawnCompareOp(::amber::CompareOp op)640 ::dawn::CompareFunction GetDawnCompareOp(::amber::CompareOp op) {
641   switch (op) {
642     case CompareOp::kNever:
643       return ::dawn::CompareFunction::Never;
644     case CompareOp::kLess:
645       return ::dawn::CompareFunction::Less;
646     case CompareOp::kEqual:
647       return ::dawn::CompareFunction::Equal;
648     case CompareOp::kLessOrEqual:
649       return ::dawn::CompareFunction::LessEqual;
650     case CompareOp::kGreater:
651       return ::dawn::CompareFunction::Greater;
652     case CompareOp::kNotEqual:
653       return ::dawn::CompareFunction::NotEqual;
654     case CompareOp::kGreaterOrEqual:
655       return ::dawn::CompareFunction::GreaterEqual;
656     case CompareOp::kAlways:
657       return ::dawn::CompareFunction::Always;
658     default:
659       return ::dawn::CompareFunction::Never;
660   }
661 }
662 
GetDawnStencilOp(::amber::StencilOp op)663 ::dawn::StencilOperation GetDawnStencilOp(::amber::StencilOp op) {
664   switch (op) {
665     case StencilOp::kKeep:
666       return ::dawn::StencilOperation::Keep;
667     case StencilOp::kZero:
668       return ::dawn::StencilOperation::Zero;
669     case StencilOp::kReplace:
670       return ::dawn::StencilOperation::Replace;
671     case StencilOp::kIncrementAndClamp:
672       return ::dawn::StencilOperation::IncrementClamp;
673     case StencilOp::kDecrementAndClamp:
674       return ::dawn::StencilOperation::DecrementClamp;
675     case StencilOp::kInvert:
676       return ::dawn::StencilOperation::Invert;
677     case StencilOp::kIncrementAndWrap:
678       return ::dawn::StencilOperation::IncrementWrap;
679     case StencilOp::kDecrementAndWrap:
680       return ::dawn::StencilOperation::DecrementWrap;
681     default:
682       return ::dawn::StencilOperation::Keep;
683   }
684 }
685 
GetDawnBlendFactor(::amber::BlendFactor factor)686 ::dawn::BlendFactor GetDawnBlendFactor(::amber::BlendFactor factor) {
687   switch (factor) {
688     case BlendFactor::kZero:
689       return ::dawn::BlendFactor::Zero;
690     case BlendFactor::kOne:
691       return ::dawn::BlendFactor::One;
692     case BlendFactor::kSrcColor:
693       return ::dawn::BlendFactor::SrcColor;
694     case BlendFactor::kOneMinusSrcColor:
695       return ::dawn::BlendFactor::OneMinusSrcColor;
696     case BlendFactor::kDstColor:
697       return ::dawn::BlendFactor::DstColor;
698     case BlendFactor::kOneMinusDstColor:
699       return ::dawn::BlendFactor::OneMinusDstColor;
700     case BlendFactor::kSrcAlpha:
701       return ::dawn::BlendFactor::SrcAlpha;
702     case BlendFactor::kOneMinusSrcAlpha:
703       return ::dawn::BlendFactor::OneMinusSrcAlpha;
704     case BlendFactor::kDstAlpha:
705       return ::dawn::BlendFactor::DstAlpha;
706     case BlendFactor::kOneMinusDstAlpha:
707       return ::dawn::BlendFactor::OneMinusDstAlpha;
708     case BlendFactor::kSrcAlphaSaturate:
709       return ::dawn::BlendFactor::SrcAlphaSaturated;
710     default:
711       assert(false && "Dawn::Unknown BlendFactor");
712       return ::dawn::BlendFactor::One;
713   }
714 }
715 
GetDawnBlendOperation(BlendOp op)716 ::dawn::BlendOperation GetDawnBlendOperation(BlendOp op) {
717   switch (op) {
718     case BlendOp::kAdd:
719       return ::dawn::BlendOperation::Add;
720     case BlendOp::kSubtract:
721       return ::dawn::BlendOperation::Subtract;
722     case BlendOp::kReverseSubtract:
723       return ::dawn::BlendOperation::ReverseSubtract;
724     case BlendOp::kMin:
725       return ::dawn::BlendOperation::Min;
726     case BlendOp::kMax:
727       return ::dawn::BlendOperation::Max;
728     default:
729       assert(false && "Dawn::Unknown BlendOp");
730       return ::dawn::BlendOperation::Add;
731   }
732 }
733 
GetDawnColorWriteMask(uint8_t amber_color_write_mask)734 ::dawn::ColorWriteMask GetDawnColorWriteMask(uint8_t amber_color_write_mask) {
735   if (amber_color_write_mask == 0x00000000)
736     return ::dawn::ColorWriteMask::None;
737   else if (amber_color_write_mask == 0x00000001)
738     return ::dawn::ColorWriteMask::Red;
739   else if (amber_color_write_mask == 0x00000002)
740     return ::dawn::ColorWriteMask::Green;
741   else if (amber_color_write_mask == 0x00000004)
742     return ::dawn::ColorWriteMask::Blue;
743   else if (amber_color_write_mask == 0x00000008)
744     return ::dawn::ColorWriteMask::Alpha;
745   else if (amber_color_write_mask == 0x0000000F)
746     return ::dawn::ColorWriteMask::All;
747   else
748     assert(false && "Dawn::Unknown ColorWriteMask");
749   return ::dawn::ColorWriteMask::All;
750 }
751 
GetDawnFrontFace(FrontFace amber_front_face)752 ::dawn::FrontFace GetDawnFrontFace(FrontFace amber_front_face) {
753   return amber_front_face == FrontFace::kClockwise ? ::dawn::FrontFace::CW
754                                                    : ::dawn::FrontFace::CCW;
755 }
756 
GetDawnCullMode(CullMode amber_cull_mode)757 ::dawn::CullMode GetDawnCullMode(CullMode amber_cull_mode) {
758   switch (amber_cull_mode) {
759     case CullMode::kNone:
760       return ::dawn::CullMode::None;
761     case CullMode::kFront:
762       return ::dawn::CullMode::Front;
763     case CullMode::kBack:
764       return ::dawn::CullMode::Back;
765     default:
766       assert(false && "Dawn::Unknown CullMode");
767       return ::dawn::CullMode::None;
768   }
769 }
770 
EngineDawn()771 EngineDawn::EngineDawn() : Engine() {}
772 
773 EngineDawn::~EngineDawn() = default;
774 
Initialize(EngineConfig * config,Delegate *,const std::vector<std::string> &,const std::vector<std::string> &,const std::vector<std::string> &)775 Result EngineDawn::Initialize(EngineConfig* config,
776                               Delegate*,
777                               const std::vector<std::string>&,
778                               const std::vector<std::string>&,
779                               const std::vector<std::string>&) {
780   if (device_)
781     return Result("Dawn:Initialize device_ already exists");
782 
783   if (!config)
784     return Result("Dawn::Initialize config is null");
785   DawnEngineConfig* dawn_config = static_cast<DawnEngineConfig*>(config);
786   if (dawn_config->device == nullptr)
787     return Result("Dawn:Initialize device is a null pointer");
788 
789   device_ = dawn_config->device;
790 
791   return {};
792 }
793 
CreatePipeline(::amber::Pipeline * pipeline)794 Result EngineDawn::CreatePipeline(::amber::Pipeline* pipeline) {
795   if (!device_) {
796     return Result("Dawn::CreatePipeline: device is not created");
797   }
798   std::unordered_map<ShaderType, ::dawn::ShaderModule, CastHash<ShaderType>>
799       module_for_type;
800   ::dawn::ShaderModuleDescriptor descriptor;
801   descriptor.nextInChain = nullptr;
802 
803   for (const auto& shader_info : pipeline->GetShaders()) {
804     ShaderType type = shader_info.GetShaderType();
805     const std::vector<uint32_t>& code = shader_info.GetData();
806     descriptor.code = code.data();
807     descriptor.codeSize = uint32_t(code.size());
808 
809     auto shader = device_->CreateShaderModule(&descriptor);
810     if (!shader) {
811       return Result("Dawn::CreatePipeline: failed to create shader");
812     }
813     if (module_for_type.count(type)) {
814       return Result("Dawn::CreatePipeline: module for type already exists");
815     }
816     module_for_type[type] = shader;
817   }
818 
819   switch (pipeline->GetType()) {
820     case PipelineType::kCompute: {
821       auto& module = module_for_type[kShaderTypeCompute];
822       if (!module)
823         return Result("Dawn::CreatePipeline: no compute shader provided");
824 
825       pipeline_map_[pipeline].compute_pipeline.reset(
826           new ComputePipelineInfo(pipeline, module));
827       Result result =
828           AttachBuffers(pipeline_map_[pipeline].compute_pipeline.get());
829       if (!result.IsSuccess())
830         return result;
831       break;
832     }
833 
834     case PipelineType::kGraphics: {
835       // TODO(dneto): Handle other shader types as well.  They are optional.
836       auto& vs = module_for_type[kShaderTypeVertex];
837       auto& fs = module_for_type[kShaderTypeFragment];
838       if (!vs) {
839         return Result(
840             "Dawn::CreatePipeline: no vertex shader provided for graphics "
841             "pipeline");
842       }
843       if (!fs) {
844         return Result(
845             "Dawn::CreatePipeline: no fragment shader provided for graphics "
846             "pipeline");
847       }
848 
849       pipeline_map_[pipeline].render_pipeline.reset(
850           new RenderPipelineInfo(pipeline, vs, fs));
851       Result result = AttachBuffersAndTextures(
852           pipeline_map_[pipeline].render_pipeline.get());
853       if (!result.IsSuccess())
854         return result;
855 
856       break;
857     }
858   }
859 
860   return {};
861 }
862 
DoClearColor(const ClearColorCommand * command)863 Result EngineDawn::DoClearColor(const ClearColorCommand* command) {
864   RenderPipelineInfo* render_pipeline = GetRenderPipeline(command);
865   if (!render_pipeline)
866     return Result("ClearColor invoked on invalid or missing render pipeline");
867 
868   render_pipeline->clear_color_value = ::dawn::Color{
869       command->GetR(), command->GetG(), command->GetB(), command->GetA()};
870 
871   return {};
872 }
873 
DoClearStencil(const ClearStencilCommand * command)874 Result EngineDawn::DoClearStencil(const ClearStencilCommand* command) {
875   RenderPipelineInfo* render_pipeline = GetRenderPipeline(command);
876   if (!render_pipeline)
877     return Result("ClearStencil invoked on invalid or missing render pipeline");
878 
879   render_pipeline->clear_stencil_value = command->GetValue();
880   return {};
881 }
882 
DoClearDepth(const ClearDepthCommand * command)883 Result EngineDawn::DoClearDepth(const ClearDepthCommand* command) {
884   RenderPipelineInfo* render_pipeline = GetRenderPipeline(command);
885   if (!render_pipeline)
886     return Result("ClearDepth invoked on invalid or missing render pipeline");
887 
888   render_pipeline->clear_depth_value = command->GetValue();
889   return {};
890 }
891 
DoClear(const ClearCommand * command)892 Result EngineDawn::DoClear(const ClearCommand* command) {
893   Result result;
894   RenderPipelineInfo* render_pipeline = GetRenderPipeline(command);
895   if (!render_pipeline)
896     return Result("Clear invoked on invalid or missing render pipeline");
897 
898   DawnPipelineHelper helper;
899   result = helper.CreateRenderPipelineDescriptor(*render_pipeline, *device_,
900                                                  false, nullptr);
901   if (!result.IsSuccess())
902     return result;
903   result = helper.CreateRenderPassDescriptor(
904       *render_pipeline, *device_, texture_views_, ::dawn::LoadOp::Clear);
905   if (!result.IsSuccess())
906     return result;
907 
908   ::dawn::RenderPassDescriptor* renderPassDescriptor =
909       &helper.renderPassDescriptor;
910   ::dawn::CommandEncoder encoder = device_->CreateCommandEncoder();
911   ::dawn::RenderPassEncoder pass =
912       encoder.BeginRenderPass(renderPassDescriptor);
913   pass.EndPass();
914 
915   ::dawn::CommandBuffer commands = encoder.Finish();
916   ::dawn::Queue queue = device_->CreateQueue();
917   queue.Submit(1, &commands);
918 
919   result = MapDeviceTextureToHostBuffer(*render_pipeline, *device_);
920 
921   return result;
922 }
923 
924 // Creates a Dawn render pipeline descriptor for the given pipeline on the given
925 // device. When |ignore_vertex_and_Index_buffers| is true, ignores the vertex
926 // and index buffers attached to |render_pipeline| and instead configures the
927 // resulting descriptor to have a single vertex buffer with an attribute format
928 // of Float4 and input stride of 4*sizeof(float)
CreateRenderPipelineDescriptor(const RenderPipelineInfo & render_pipeline,const::dawn::Device & device,const bool ignore_vertex_and_Index_buffers,const PipelineData * pipeline_data)929 Result DawnPipelineHelper::CreateRenderPipelineDescriptor(
930     const RenderPipelineInfo& render_pipeline,
931     const ::dawn::Device& device,
932     const bool ignore_vertex_and_Index_buffers,
933     const PipelineData* pipeline_data) {
934   Result result;
935 
936   auto* amber_format =
937       render_pipeline.pipeline->GetColorAttachments()[0].buffer->GetFormat();
938   if (!amber_format)
939     return Result("Color attachment 0 has no format!");
940   ::dawn::TextureFormat fb_format{};
941   result = GetDawnTextureFormat(*amber_format, &fb_format);
942   if (!result.IsSuccess())
943     return result;
944 
945   ::dawn::TextureFormat depth_stencil_format{};
946   auto* depthBuffer = render_pipeline.pipeline->GetDepthBuffer().buffer;
947   if (depthBuffer) {
948     auto* amber_depth_stencil_format = depthBuffer->GetFormat();
949     if (!amber_depth_stencil_format)
950       return Result("The depth/stencil attachment has no format!");
951     result = GetDawnTextureFormat(*amber_depth_stencil_format,
952                                   &depth_stencil_format);
953     if (!result.IsSuccess())
954       return result;
955   } else {
956     depth_stencil_format = ::dawn::TextureFormat::Depth24PlusStencil8;
957   }
958 
959   renderPipelineDescriptor.layout =
960       MakeBasicPipelineLayout(device, render_pipeline.bind_group_layouts);
961 
962   renderPipelineDescriptor.primitiveTopology =
963       ::dawn::PrimitiveTopology::TriangleList;
964   renderPipelineDescriptor.sampleCount = 1;
965 
966   // Lookup shaders' entrypoints
967   for (const auto& shader_info : render_pipeline.pipeline->GetShaders()) {
968     if (shader_info.GetShaderType() == kShaderTypeVertex) {
969       vertexEntryPoint = shader_info.GetEntryPoint();
970     } else if (shader_info.GetShaderType() == kShaderTypeFragment) {
971       fragmentEntryPoint = shader_info.GetEntryPoint();
972     } else {
973       return Result(
974           "CreateRenderPipelineDescriptor: An unknown shader is attached to "
975           "the render pipeline");
976     }
977   }
978   // Fill the default values for vertexInput (buffers and attributes).
979   // assuming #buffers == #attributes
980   vertexInputDescriptor.bufferCount =
981       render_pipeline.pipeline->GetVertexBuffers().size();
982 
983   for (uint32_t i = 0; i < kMaxVertexInputs; ++i) {
984     if (ignore_vertex_and_Index_buffers) {
985       if (i == 0) {
986         vertexInputDescriptor.bufferCount = 1;
987         vertexInputDescriptor.cBuffers[0].attributeCount = 1;
988         vertexInputDescriptor.cBuffers[0].stride = 4 * sizeof(float);
989         vertexInputDescriptor.cBuffers[0].attributes =
990             &vertexInputDescriptor.cAttributes[0];
991 
992         vertexInputDescriptor.cAttributes[0].shaderLocation = 0;
993         vertexInputDescriptor.cAttributes[0].format =
994             ::dawn::VertexFormat::Float4;
995       }
996     } else {
997       if (i < render_pipeline.pipeline->GetVertexBuffers().size()) {
998         vertexInputDescriptor.cBuffers[i].attributeCount = 1;
999         vertexInputDescriptor.cBuffers[i].stride =
1000             render_pipeline.pipeline->GetVertexBuffers()[i]
1001                 .buffer->GetElementStride();
1002         vertexInputDescriptor.cBuffers[i].stepMode =
1003             ::dawn::InputStepMode::Vertex;
1004         vertexInputDescriptor.cBuffers[i].attributes =
1005             &vertexInputDescriptor.cAttributes[i];
1006 
1007         vertexInputDescriptor.cAttributes[i].shaderLocation = i;
1008         auto* amber_vertex_format =
1009             render_pipeline.pipeline->GetVertexBuffers()[i].buffer->GetFormat();
1010         result = GetDawnVertexFormat(
1011             *amber_vertex_format, &vertexInputDescriptor.cAttributes[i].format);
1012         if (!result.IsSuccess())
1013           return result;
1014       }
1015     }
1016   }
1017 
1018   // set index buffer format
1019   if (render_pipeline.pipeline->GetIndexBuffer()) {
1020     auto* amber_index_format =
1021         render_pipeline.pipeline->GetIndexBuffer()->GetFormat();
1022     GetDawnIndexFormat(*amber_index_format, &vertexInputDescriptor.indexFormat);
1023     if (!result.IsSuccess())
1024       return result;
1025   }
1026 
1027   renderPipelineDescriptor.vertexInput =
1028       reinterpret_cast<::dawn::VertexInputDescriptor*>(&vertexInputDescriptor);
1029 
1030   // Set defaults for the vertex stage descriptor.
1031   vertexStage.module = render_pipeline.vertex_shader;
1032   vertexStage.entryPoint = vertexEntryPoint.c_str();
1033   renderPipelineDescriptor.vertexStage = vertexStage;
1034 
1035   // Set defaults for the fragment stage descriptor.
1036   fragmentStage.module = render_pipeline.fragment_shader;
1037   fragmentStage.entryPoint = fragmentEntryPoint.c_str();
1038   renderPipelineDescriptor.fragmentStage = std::move(&fragmentStage);
1039 
1040   // Set defaults for the rasterization state descriptor.
1041   if (pipeline_data == nullptr) {
1042     rasterizationState.frontFace = ::dawn::FrontFace::CCW;
1043     rasterizationState.cullMode = ::dawn::CullMode::None;
1044     rasterizationState.depthBias = 0;
1045     rasterizationState.depthBiasSlopeScale = 0.0;
1046     rasterizationState.depthBiasClamp = 0.0;
1047     renderPipelineDescriptor.rasterizationState = &rasterizationState;
1048   } else {
1049     rasterizationState.frontFace =
1050         GetDawnFrontFace(pipeline_data->GetFrontFace());
1051     rasterizationState.cullMode = GetDawnCullMode(pipeline_data->GetCullMode());
1052     rasterizationState.depthBias = pipeline_data->GetEnableDepthBias();
1053     rasterizationState.depthBiasSlopeScale =
1054         pipeline_data->GetDepthBiasSlopeFactor();
1055     rasterizationState.depthBiasClamp = pipeline_data->GetDepthBiasClamp();
1056     renderPipelineDescriptor.rasterizationState = &rasterizationState;
1057   }
1058 
1059   // Set defaults for the color state descriptors.
1060   if (pipeline_data == nullptr) {
1061     renderPipelineDescriptor.colorStateCount =
1062         render_pipeline.pipeline->GetColorAttachments().size();
1063     alpha_blend.operation = ::dawn::BlendOperation::Add;
1064     alpha_blend.srcFactor = ::dawn::BlendFactor::One;
1065     alpha_blend.dstFactor = ::dawn::BlendFactor::Zero;
1066     colorStateDescriptor.writeMask = ::dawn::ColorWriteMask::All;
1067     colorStateDescriptor.format = fb_format;
1068     colorStateDescriptor.alphaBlend = alpha_blend;
1069     colorStateDescriptor.colorBlend = alpha_blend;
1070   } else {
1071     renderPipelineDescriptor.colorStateCount =
1072         render_pipeline.pipeline->GetColorAttachments().size();
1073 
1074     alpha_blend.operation =
1075         GetDawnBlendOperation(pipeline_data->GetColorBlendOp());
1076     alpha_blend.srcFactor =
1077         GetDawnBlendFactor(pipeline_data->GetSrcAlphaBlendFactor());
1078     alpha_blend.dstFactor =
1079         GetDawnBlendFactor(pipeline_data->GetDstAlphaBlendFactor());
1080 
1081     color_blend.operation =
1082         GetDawnBlendOperation(pipeline_data->GetAlphaBlendOp());
1083     color_blend.srcFactor =
1084         GetDawnBlendFactor(pipeline_data->GetSrcColorBlendFactor());
1085     color_blend.dstFactor =
1086         GetDawnBlendFactor(pipeline_data->GetDstAlphaBlendFactor());
1087 
1088     colorStateDescriptor.writeMask =
1089         GetDawnColorWriteMask(pipeline_data->GetColorWriteMask());
1090 
1091     colorStateDescriptor.format = fb_format;
1092     colorStateDescriptor.alphaBlend = alpha_blend;
1093     colorStateDescriptor.colorBlend = color_blend;
1094   }
1095 
1096   for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
1097     ::dawn::TextureFormat fb_format{};
1098     {
1099       if (i < render_pipeline.pipeline->GetColorAttachments().size()) {
1100         auto* amber_format = render_pipeline.pipeline->GetColorAttachments()[i]
1101                                  .buffer->GetFormat();
1102         if (!amber_format)
1103           return Result(
1104               "AttachBuffersAndTextures: One Color attachment has no "
1105               "format!");
1106         result = GetDawnTextureFormat(*amber_format, &fb_format);
1107         if (!result.IsSuccess())
1108           return result;
1109       } else {
1110         fb_format = ::dawn::TextureFormat::RGBA8Unorm;
1111       }
1112     }
1113     colorStatesDescriptor[i] = colorStateDescriptor;
1114     colorStates[i] = &colorStatesDescriptor[i];
1115     colorStates[i]->format = fb_format;
1116   }
1117   renderPipelineDescriptor.colorStates = colorStates[0];
1118 
1119   // Set defaults for the depth stencil state descriptors.
1120   if (pipeline_data == nullptr) {
1121     stencil_front.compare = ::dawn::CompareFunction::Always;
1122     stencil_front.failOp = ::dawn::StencilOperation::Keep;
1123     stencil_front.depthFailOp = ::dawn::StencilOperation::Keep;
1124     stencil_front.passOp = ::dawn::StencilOperation::Keep;
1125     depthStencilState.depthWriteEnabled = false;
1126     depthStencilState.depthCompare = ::dawn::CompareFunction::Always;
1127     depthStencilState.stencilBack = stencil_front;
1128     depthStencilState.stencilFront = stencil_front;
1129     depthStencilState.stencilReadMask = 0xff;
1130     depthStencilState.stencilWriteMask = 0xff;
1131     depthStencilState.format = depth_stencil_format;
1132     renderPipelineDescriptor.depthStencilState = &depthStencilState;
1133   } else {
1134     stencil_front.compare =
1135         GetDawnCompareOp(pipeline_data->GetFrontCompareOp());
1136     stencil_front.failOp = GetDawnStencilOp(pipeline_data->GetFrontFailOp());
1137     stencil_front.depthFailOp =
1138         GetDawnStencilOp(pipeline_data->GetFrontDepthFailOp());
1139     stencil_front.passOp = GetDawnStencilOp(pipeline_data->GetFrontPassOp());
1140 
1141     stencil_back.compare = GetDawnCompareOp(pipeline_data->GetBackCompareOp());
1142     stencil_back.failOp = GetDawnStencilOp(pipeline_data->GetBackFailOp());
1143     stencil_back.depthFailOp =
1144         GetDawnStencilOp(pipeline_data->GetBackDepthFailOp());
1145     stencil_back.passOp = GetDawnStencilOp(pipeline_data->GetBackPassOp());
1146 
1147     depthStencilState.depthWriteEnabled = pipeline_data->GetEnableDepthWrite();
1148     depthStencilState.depthCompare =
1149         GetDawnCompareOp(pipeline_data->GetDepthCompareOp());
1150     depthStencilState.stencilFront = stencil_front;
1151     depthStencilState.stencilBack = stencil_back;
1152     // WebGPU doesn't support separate front and back stencil mask, they has to
1153     // be the same
1154     depthStencilState.stencilReadMask =
1155         (pipeline_data->GetFrontCompareMask() ==
1156          pipeline_data->GetBackCompareMask())
1157             ? pipeline_data->GetFrontCompareMask()
1158             : 0xff;
1159     depthStencilState.stencilWriteMask = (pipeline_data->GetBackWriteMask() ==
1160                                           pipeline_data->GetFrontWriteMask())
1161                                              ? pipeline_data->GetBackWriteMask()
1162                                              : 0xff;
1163     depthStencilState.format = depth_stencil_format;
1164     renderPipelineDescriptor.depthStencilState = &depthStencilState;
1165   }
1166 
1167   return {};
1168 }
1169 
CreateRenderPassDescriptor(const RenderPipelineInfo & render_pipeline,const::dawn::Device & device,const std::vector<::dawn::TextureView> & texture_view,const::dawn::LoadOp load_op)1170 Result DawnPipelineHelper::CreateRenderPassDescriptor(
1171     const RenderPipelineInfo& render_pipeline,
1172     const ::dawn::Device& device,
1173     const std::vector<::dawn::TextureView>& texture_view,
1174     const ::dawn::LoadOp load_op) {
1175   for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
1176     colorAttachmentsInfo[i].loadOp = load_op;
1177     colorAttachmentsInfo[i].storeOp = ::dawn::StoreOp::Store;
1178     colorAttachmentsInfo[i].clearColor = render_pipeline.clear_color_value;
1179   }
1180 
1181   depthStencilAttachmentInfo.clearDepth = render_pipeline.clear_depth_value;
1182   depthStencilAttachmentInfo.clearStencil = render_pipeline.clear_stencil_value;
1183   depthStencilAttachmentInfo.depthLoadOp = load_op;
1184   depthStencilAttachmentInfo.depthStoreOp = ::dawn::StoreOp::Store;
1185   depthStencilAttachmentInfo.stencilLoadOp = load_op;
1186   depthStencilAttachmentInfo.stencilStoreOp = ::dawn::StoreOp::Store;
1187 
1188   renderPassDescriptor.colorAttachmentCount =
1189       render_pipeline.pipeline->GetColorAttachments().size();
1190   uint32_t colorAttachmentIndex = 0;
1191   for (const ::dawn::TextureView& colorAttachment : texture_view) {
1192     if (colorAttachment.Get() != nullptr) {
1193       colorAttachmentsInfo[colorAttachmentIndex].attachment = colorAttachment;
1194       colorAttachmentsInfoPtr[colorAttachmentIndex] =
1195           colorAttachmentsInfo[colorAttachmentIndex];
1196     }
1197     ++colorAttachmentIndex;
1198   }
1199   renderPassDescriptor.colorAttachments = colorAttachmentsInfoPtr;
1200 
1201   ::dawn::TextureFormat depth_stencil_format{};
1202   auto* depthBuffer = render_pipeline.pipeline->GetDepthBuffer().buffer;
1203   if (depthBuffer) {
1204     auto* amber_depth_stencil_format = depthBuffer->GetFormat();
1205     if (!amber_depth_stencil_format)
1206       return Result("The depth/stencil attachment has no format!");
1207     Result result = GetDawnTextureFormat(*amber_depth_stencil_format,
1208                                          &depth_stencil_format);
1209     if (!result.IsSuccess())
1210       return result;
1211   } else {
1212     depth_stencil_format = ::dawn::TextureFormat::Depth24PlusStencil8;
1213   }
1214 
1215   depthStencilDescriptor.dimension = ::dawn::TextureDimension::e2D;
1216   depthStencilDescriptor.size.width =
1217       render_pipeline.pipeline->GetFramebufferWidth();
1218   depthStencilDescriptor.size.height =
1219       render_pipeline.pipeline->GetFramebufferHeight();
1220   depthStencilDescriptor.size.depth = 1;
1221   depthStencilDescriptor.arrayLayerCount = 1;
1222   depthStencilDescriptor.sampleCount = 1;
1223   depthStencilDescriptor.format = depth_stencil_format;
1224   depthStencilDescriptor.mipLevelCount = 1;
1225   depthStencilDescriptor.usage =
1226       ::dawn::TextureUsage::OutputAttachment | ::dawn::TextureUsage::CopySrc;
1227   depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
1228   depthStencilView = depthStencilTexture.CreateView();
1229 
1230   if (depthStencilView.Get() != nullptr) {
1231     depthStencilAttachmentInfo.attachment = depthStencilView;
1232     renderPassDescriptor.depthStencilAttachment = &depthStencilAttachmentInfo;
1233   } else {
1234     renderPassDescriptor.depthStencilAttachment = nullptr;
1235   }
1236 
1237   return {};
1238 }
1239 
DoDrawRect(const DrawRectCommand * command)1240 Result EngineDawn::DoDrawRect(const DrawRectCommand* command) {
1241   RenderPipelineInfo* render_pipeline = GetRenderPipeline(command);
1242   if (!render_pipeline)
1243     return Result("DrawRect invoked on invalid or missing render pipeline");
1244   if (render_pipeline->vertex_buffers.size() > 1)
1245     return Result(
1246         "DrawRect invoked on a render pipeline with more than one "
1247         "VERTEX_DATA attached");
1248 
1249   float x = command->GetX();
1250   float y = command->GetY();
1251   float rectangleWidth = command->GetWidth();
1252   float rectangleHeight = command->GetHeight();
1253 
1254   const uint32_t frameWidth = render_pipeline->pipeline->GetFramebufferWidth();
1255   const uint32_t frameHeight =
1256       render_pipeline->pipeline->GetFramebufferHeight();
1257 
1258   if (command->IsOrtho()) {
1259     x = ((x / frameWidth) * 2.0f) - 1.0f;
1260     y = ((y / frameHeight) * 2.0f) - 1.0f;
1261     rectangleWidth = (rectangleWidth / frameWidth) * 2.0f;
1262     rectangleHeight = (rectangleHeight / frameHeight) * 2.0f;
1263   }
1264 
1265   static const uint32_t indexData[3 * 2] = {
1266       0, 1, 2, 0, 2, 3,
1267   };
1268   auto index_buffer = CreateBufferFromData(
1269       *device_, indexData, sizeof(indexData), ::dawn::BufferUsage::Index);
1270 
1271   const float vertexData[4 * 4] = {
1272       // Bottom left
1273       x,
1274       y + rectangleHeight,
1275       0.0f,
1276       1.0f,
1277       // Top left
1278       x,
1279       y,
1280       0.0f,
1281       1.0f,
1282       // Top right
1283       x + rectangleWidth,
1284       y,
1285       0.0f,
1286       1.0f,
1287       // Bottom right
1288       x + rectangleWidth,
1289       y + rectangleHeight,
1290       0.0f,
1291       1.0f,
1292   };
1293 
1294   auto vertex_buffer = CreateBufferFromData(
1295       *device_, vertexData, sizeof(vertexData), ::dawn::BufferUsage::Vertex);
1296   DawnPipelineHelper helper;
1297   helper.CreateRenderPipelineDescriptor(*render_pipeline, *device_, true,
1298                                         command->GetPipelineData());
1299   helper.CreateRenderPassDescriptor(*render_pipeline, *device_, texture_views_,
1300                                     ::dawn::LoadOp::Load);
1301   ::dawn::RenderPipelineDescriptor* renderPipelineDescriptor =
1302       &helper.renderPipelineDescriptor;
1303   ::dawn::RenderPassDescriptor* renderPassDescriptor =
1304       &helper.renderPassDescriptor;
1305 
1306   const ::dawn::RenderPipeline pipeline =
1307       device_->CreateRenderPipeline(renderPipelineDescriptor);
1308   ::dawn::CommandEncoder encoder = device_->CreateCommandEncoder();
1309   ::dawn::RenderPassEncoder pass =
1310       encoder.BeginRenderPass(renderPassDescriptor);
1311   pass.SetPipeline(pipeline);
1312   for (uint32_t i = 0; i < render_pipeline->bind_groups.size(); i++) {
1313     if (render_pipeline->bind_groups[i]) {
1314       pass.SetBindGroup(i, render_pipeline->bind_groups[i], 0, nullptr);
1315     }
1316   }
1317   pass.SetVertexBuffer(0, vertex_buffer, 0);
1318   pass.SetIndexBuffer(index_buffer, 0);
1319   pass.DrawIndexed(6, 1, 0, 0, 0);
1320   pass.EndPass();
1321 
1322   ::dawn::CommandBuffer commands = encoder.Finish();
1323   ::dawn::Queue queue = device_->CreateQueue();
1324   queue.Submit(1, &commands);
1325 
1326   Result result = MapDeviceTextureToHostBuffer(*render_pipeline, *device_);
1327 
1328   return result;
1329 }
1330 
DoDrawGrid(const DrawGridCommand * command)1331 Result EngineDawn::DoDrawGrid(const DrawGridCommand* command) {
1332   return Result("DRAW_GRID not implemented on Dawn");
1333 }
1334 
DoDrawArrays(const DrawArraysCommand * command)1335 Result EngineDawn::DoDrawArrays(const DrawArraysCommand* command) {
1336   Result result;
1337 
1338   RenderPipelineInfo* render_pipeline = GetRenderPipeline(command);
1339   if (!render_pipeline)
1340     return Result("DrawArrays invoked on invalid or missing render pipeline");
1341 
1342   if (command->IsIndexed()) {
1343     if (!render_pipeline->index_buffer)
1344       return Result("DrawArrays: Draw indexed is used without given indices");
1345   } else {
1346     std::vector<uint32_t> indexData;
1347     for (uint32_t i = 0;
1348          i < command->GetFirstVertexIndex() + command->GetVertexCount(); i++) {
1349       indexData.emplace_back(i);
1350     }
1351     render_pipeline->index_buffer = CreateBufferFromData(
1352         *device_, indexData.data(), indexData.size() * sizeof(uint32_t),
1353         ::dawn::BufferUsage::Index);
1354   }
1355 
1356   uint32_t instance_count = command->GetInstanceCount();
1357   if (instance_count == 0 && command->GetVertexCount() != 0)
1358     instance_count = 1;
1359 
1360   DawnPipelineHelper helper;
1361   result = helper.CreateRenderPipelineDescriptor(
1362       *render_pipeline, *device_, false, command->GetPipelineData());
1363   if (!result.IsSuccess())
1364     return result;
1365   result = helper.CreateRenderPassDescriptor(
1366       *render_pipeline, *device_, texture_views_, ::dawn::LoadOp::Load);
1367   if (!result.IsSuccess())
1368     return result;
1369 
1370   ::dawn::RenderPipelineDescriptor* renderPipelineDescriptor =
1371       &helper.renderPipelineDescriptor;
1372   ::dawn::RenderPassDescriptor* renderPassDescriptor =
1373       &helper.renderPassDescriptor;
1374 
1375   result = GetDawnTopology(command->GetTopology(),
1376                            &renderPipelineDescriptor->primitiveTopology);
1377   if (!result.IsSuccess())
1378     return result;
1379 
1380   const ::dawn::RenderPipeline pipeline =
1381       device_->CreateRenderPipeline(renderPipelineDescriptor);
1382   ::dawn::CommandEncoder encoder = device_->CreateCommandEncoder();
1383   ::dawn::RenderPassEncoder pass =
1384       encoder.BeginRenderPass(renderPassDescriptor);
1385   pass.SetPipeline(pipeline);
1386   for (uint32_t i = 0; i < render_pipeline->bind_groups.size(); i++) {
1387     if (render_pipeline->bind_groups[i]) {
1388       pass.SetBindGroup(i, render_pipeline->bind_groups[i], 0, nullptr);
1389     }
1390   }
1391   // TODO(sarahM0): figure out what are startSlot, count and offsets
1392   for (uint32_t i = 0; i < render_pipeline->vertex_buffers.size(); i++) {
1393     pass.SetVertexBuffer(i,                                  /* slot */
1394                          render_pipeline->vertex_buffers[i], /* buffer */
1395                          0);                                 /* offsets */
1396   }
1397   // TODO(sarahM0): figure out what this offset means
1398   pass.SetIndexBuffer(render_pipeline->index_buffer, /* buffer */
1399                       0);                            /* offset*/
1400   pass.DrawIndexed(command->GetVertexCount(),        /* indexCount */
1401                    instance_count,                   /* instanceCount */
1402                    0,                                /* firstIndex */
1403                    command->GetFirstVertexIndex(),   /* baseVertex */
1404                    0 /* firstInstance */);
1405 
1406   pass.EndPass();
1407   ::dawn::CommandBuffer commands = encoder.Finish();
1408   ::dawn::Queue queue = device_->CreateQueue();
1409   queue.Submit(1, &commands);
1410 
1411   result = MapDeviceTextureToHostBuffer(*render_pipeline, *device_);
1412 
1413   return result;
1414 }
1415 
DoCompute(const ComputeCommand * command)1416 Result EngineDawn::DoCompute(const ComputeCommand* command) {
1417   Result result;
1418 
1419   ComputePipelineInfo* compute_pipeline = GetComputePipeline(command);
1420   if (!compute_pipeline)
1421     return Result("DoComput: invoked on invalid or missing compute pipeline");
1422 
1423   ::dawn::ComputePipelineDescriptor computePipelineDescriptor;
1424   computePipelineDescriptor.layout = MakeBasicPipelineLayout(
1425       device_->Get(), compute_pipeline->bind_group_layouts);
1426 
1427   ::dawn::ProgrammableStageDescriptor pipelineStageDescriptor;
1428   pipelineStageDescriptor.module = compute_pipeline->compute_shader;
1429   pipelineStageDescriptor.entryPoint = "main";
1430   computePipelineDescriptor.computeStage = pipelineStageDescriptor;
1431   ::dawn::ComputePipeline pipeline =
1432       device_->CreateComputePipeline(&computePipelineDescriptor);
1433   ::dawn::CommandEncoder encoder = device_->CreateCommandEncoder();
1434   ::dawn::ComputePassEncoder pass = encoder.BeginComputePass();
1435   pass.SetPipeline(pipeline);
1436   for (uint32_t i = 0; i < compute_pipeline->bind_groups.size(); i++) {
1437     if (compute_pipeline->bind_groups[i]) {
1438       pass.SetBindGroup(i, compute_pipeline->bind_groups[i], 0, nullptr);
1439     }
1440   }
1441   pass.Dispatch(command->GetX(), command->GetY(), command->GetZ());
1442   pass.EndPass();
1443   // Finish recording the command buffer.  It only has one command.
1444   auto command_buffer = encoder.Finish();
1445   // Submit the command.
1446   auto queue = device_->CreateQueue();
1447   queue.Submit(1, &command_buffer);
1448   // Copy result back
1449   result = MapDeviceBufferToHostBuffer(*compute_pipeline, *device_);
1450 
1451   return result;
1452 }
1453 
DoEntryPoint(const EntryPointCommand *)1454 Result EngineDawn::DoEntryPoint(const EntryPointCommand*) {
1455   return Result("Dawn: Entry point must be \"main\" in Dawn");
1456 }
1457 
DoPatchParameterVertices(const PatchParameterVerticesCommand *)1458 Result EngineDawn::DoPatchParameterVertices(
1459     const PatchParameterVerticesCommand*) {
1460   return Result("Dawn: PatchParameterVertices is not supported in Dawn");
1461 }
1462 
DoBuffer(const BufferCommand * command)1463 Result EngineDawn::DoBuffer(const BufferCommand* command) {
1464   Result result;
1465 
1466   ::dawn::Buffer* dawn_buffer = nullptr;
1467 
1468   const auto descriptor_set = command->GetDescriptorSet();
1469   const auto binding = command->GetBinding();
1470 
1471   RenderPipelineInfo* render_pipeline = GetRenderPipeline(command);
1472   if (render_pipeline) {
1473     auto where = render_pipeline->buffer_map.find({descriptor_set, binding});
1474     if (where != render_pipeline->buffer_map.end()) {
1475       const auto dawn_buffer_index = where->second;
1476       dawn_buffer = &render_pipeline->buffers[dawn_buffer_index];
1477     }
1478   }
1479 
1480   ComputePipelineInfo* compute_pipeline = GetComputePipeline(command);
1481   if (compute_pipeline) {
1482     auto where = compute_pipeline->buffer_map.find({descriptor_set, binding});
1483     if (where != compute_pipeline->buffer_map.end()) {
1484       const auto dawn_buffer_index = where->second;
1485       dawn_buffer = &compute_pipeline->buffers[dawn_buffer_index];
1486     }
1487   }
1488 
1489   if (!render_pipeline && !compute_pipeline)
1490     return Result("DoBuffer: invoked on invalid or missing pipeline");
1491   if (!command->IsSSBO() && !command->IsUniform())
1492     return Result("DoBuffer: only supports SSBO and uniform buffer type");
1493   if (!dawn_buffer) {
1494     return Result("DoBuffer: no Dawn buffer at descriptor set " +
1495                   std::to_string(descriptor_set) + " and binding " +
1496                   std::to_string(binding));
1497   }
1498 
1499   Buffer* amber_buffer = command->GetBuffer();
1500   if (amber_buffer) {
1501     amber_buffer->SetDataWithOffset(command->GetValues(), command->GetOffset());
1502 
1503     dawn_buffer->SetSubData(0, amber_buffer->GetMaxSizeInBytes(),
1504                             amber_buffer->ValuePtr()->data());
1505   }
1506 
1507   return {};
1508 }
1509 
AttachBuffersAndTextures(RenderPipelineInfo * render_pipeline)1510 Result EngineDawn::AttachBuffersAndTextures(
1511     RenderPipelineInfo* render_pipeline) {
1512   Result result;
1513   const uint32_t width = render_pipeline->pipeline->GetFramebufferWidth();
1514   const uint32_t height = render_pipeline->pipeline->GetFramebufferHeight();
1515 
1516   // Create textures and texture views if we haven't already
1517   std::vector<int32_t> seen_idx(
1518       render_pipeline->pipeline->GetColorAttachments().size(), -1);
1519   for (auto info : render_pipeline->pipeline->GetColorAttachments()) {
1520     if (info.location >=
1521         render_pipeline->pipeline->GetColorAttachments().size())
1522       return Result("color attachment locations must be sequential from 0");
1523     if (seen_idx[info.location] != -1) {
1524       return Result("duplicate attachment location: " +
1525                     std::to_string(info.location));
1526     }
1527     seen_idx[info.location] = static_cast<int32_t>(info.location);
1528   }
1529 
1530   if (textures_.size() == 0) {
1531     for (uint32_t i = 0; i < kMaxColorAttachments; i++) {
1532       ::dawn::TextureFormat fb_format{};
1533 
1534       if (i < render_pipeline->pipeline->GetColorAttachments().size()) {
1535         auto* amber_format = render_pipeline->pipeline->GetColorAttachments()[i]
1536                                  .buffer->GetFormat();
1537         if (!amber_format)
1538           return Result(
1539               "AttachBuffersAndTextures: One Color attachment has no "
1540               "format!");
1541         result = GetDawnTextureFormat(*amber_format, &fb_format);
1542         if (!result.IsSuccess())
1543           return result;
1544       } else {
1545         fb_format = ::dawn::TextureFormat::RGBA8Unorm;
1546       }
1547 
1548       textures_.emplace_back(
1549           MakeDawnTexture(*device_, fb_format, width, height));
1550       texture_views_.emplace_back(textures_.back().CreateView());
1551     }
1552   }
1553 
1554   // Attach depth-stencil texture
1555   auto* depthBuffer = render_pipeline->pipeline->GetDepthBuffer().buffer;
1556   if (depthBuffer) {
1557     if (!depth_stencil_texture_) {
1558       auto* amber_depth_stencil_format = depthBuffer->GetFormat();
1559       if (!amber_depth_stencil_format)
1560         return Result(
1561             "AttachBuffersAndTextures: The depth/stencil attachment has no "
1562             "format!");
1563       ::dawn::TextureFormat depth_stencil_format{};
1564       result = GetDawnTextureFormat(*amber_depth_stencil_format,
1565                                     &depth_stencil_format);
1566       if (!result.IsSuccess())
1567         return result;
1568 
1569       result = MakeTexture(*device_, depth_stencil_format, width, height,
1570                            &depth_stencil_texture_);
1571       if (!result.IsSuccess())
1572         return result;
1573       render_pipeline->depth_stencil_texture = depth_stencil_texture_;
1574     } else {
1575       render_pipeline->depth_stencil_texture = depth_stencil_texture_;
1576     }
1577   }
1578 
1579   // Attach index buffer
1580   if (render_pipeline->pipeline->GetIndexBuffer()) {
1581     render_pipeline->index_buffer = CreateBufferFromData(
1582         *device_,
1583         render_pipeline->pipeline->GetIndexBuffer()->ValuePtr()->data(),
1584         render_pipeline->pipeline->GetIndexBuffer()->GetSizeInBytes(),
1585         ::dawn::BufferUsage::Index);
1586   }
1587 
1588   // Attach vertex buffers
1589   for (auto& vertex_info : render_pipeline->pipeline->GetVertexBuffers()) {
1590     render_pipeline->vertex_buffers.emplace_back(CreateBufferFromData(
1591         *device_, vertex_info.buffer->ValuePtr()->data(),
1592         vertex_info.buffer->GetSizeInBytes(), ::dawn::BufferUsage::Vertex));
1593   }
1594 
1595   // Do not attach pushConstants
1596   if (render_pipeline->pipeline->GetPushConstantBuffer().buffer != nullptr) {
1597     return Result(
1598         "AttachBuffersAndTextures: Dawn does not support push constants!");
1599   }
1600 
1601   ::dawn::ShaderStage kAllStages =
1602       ::dawn::ShaderStage::Vertex | ::dawn::ShaderStage::Fragment;
1603   std::vector<std::vector<BindingInitializationHelper>> bindingInitalizerHelper(
1604       kMaxDawnBindGroup);
1605   std::vector<std::vector<::dawn::BindGroupLayoutBinding>> layouts_info(
1606       kMaxDawnBindGroup);
1607   uint32_t max_descriptor_set = 0;
1608 
1609   // Attach storage/uniform buffers
1610   ::dawn::BindGroupLayoutBinding empty_layout_info = {};
1611 
1612   if (!render_pipeline->pipeline->GetBuffers().empty()) {
1613     std::vector<uint32_t> max_binding_seen(kMaxDawnBindGroup, -1);
1614     for (auto& buf_info : render_pipeline->pipeline->GetBuffers()) {
1615       while (layouts_info[buf_info.descriptor_set].size() <= buf_info.binding)
1616         layouts_info[buf_info.descriptor_set].push_back(empty_layout_info);
1617     }
1618   }
1619 
1620   for (const auto& buf_info : render_pipeline->pipeline->GetBuffers()) {
1621     ::dawn::BufferUsage bufferUsage;
1622     ::dawn::BindingType bindingType;
1623     switch (buf_info.type) {
1624       case BufferType::kStorage: {
1625         bufferUsage = ::dawn::BufferUsage::Storage;
1626         bindingType = ::dawn::BindingType::StorageBuffer;
1627         break;
1628       }
1629       case BufferType::kUniform: {
1630         bufferUsage = ::dawn::BufferUsage::Uniform;
1631         bindingType = ::dawn::BindingType::UniformBuffer;
1632         break;
1633       }
1634       default: {
1635         return Result("AttachBuffersAndTextures: unknown buffer type: " +
1636                       std::to_string(static_cast<uint32_t>(buf_info.type)));
1637         break;
1638       }
1639     }
1640 
1641     if (buf_info.descriptor_set > kMaxDawnBindGroup - 1) {
1642       return Result("AttachBuffers: Dawn has a maximum of " +
1643                     std::to_string(kMaxDawnBindGroup) + " (descriptor sets)");
1644     }
1645 
1646     render_pipeline->buffers.emplace_back(
1647         CreateBufferFromData(*device_, buf_info.buffer->ValuePtr()->data(),
1648                              buf_info.buffer->GetMaxSizeInBytes(),
1649                              bufferUsage | ::dawn::BufferUsage::CopySrc |
1650                                  ::dawn::BufferUsage::CopyDst));
1651 
1652     render_pipeline->buffer_map[{buf_info.descriptor_set, buf_info.binding}] =
1653         render_pipeline->buffers.size() - 1;
1654 
1655     render_pipeline->used_descriptor_set.insert(buf_info.descriptor_set);
1656     max_descriptor_set = std::max(max_descriptor_set, buf_info.descriptor_set);
1657 
1658     ::dawn::BindGroupLayoutBinding layout_info;
1659     layout_info.binding = buf_info.binding;
1660     layout_info.visibility = kAllStages;
1661     layout_info.type = bindingType;
1662     layouts_info[buf_info.descriptor_set][buf_info.binding] = layout_info;
1663 
1664     BindingInitializationHelper tempBinding = BindingInitializationHelper(
1665         buf_info.binding, render_pipeline->buffers.back(), 0,
1666         buf_info.buffer->GetMaxSizeInBytes());
1667     bindingInitalizerHelper[buf_info.descriptor_set].push_back(tempBinding);
1668   }
1669 
1670   for (uint32_t i = 0; i < kMaxDawnBindGroup; i++) {
1671     if (layouts_info[i].size() > 0 && bindingInitalizerHelper[i].size() > 0) {
1672       ::dawn::BindGroupLayout bindGroupLayout =
1673           MakeBindGroupLayout(*device_, layouts_info[i]);
1674       render_pipeline->bind_group_layouts.push_back(bindGroupLayout);
1675 
1676       ::dawn::BindGroup bindGroup =
1677           MakeBindGroup(*device_, render_pipeline->bind_group_layouts[i],
1678                         bindingInitalizerHelper[i]);
1679       render_pipeline->bind_groups.push_back(bindGroup);
1680     } else if (i < max_descriptor_set) {
1681       ::dawn::BindGroupLayout bindGroupLayout =
1682           MakeBindGroupLayout(*device_, {});
1683       render_pipeline->bind_group_layouts.push_back(bindGroupLayout);
1684 
1685       ::dawn::BindGroup bindGroup =
1686           MakeBindGroup(*device_, render_pipeline->bind_group_layouts[i],
1687                         bindingInitalizerHelper[i]);
1688       render_pipeline->bind_groups.push_back(bindGroup);
1689     }
1690   }
1691   return {};
1692 }
1693 
AttachBuffers(ComputePipelineInfo * compute_pipeline)1694 Result EngineDawn::AttachBuffers(ComputePipelineInfo* compute_pipeline) {
1695   Result result;
1696 
1697   // Do not attach pushConstants
1698   if (compute_pipeline->pipeline->GetPushConstantBuffer().buffer != nullptr) {
1699     return Result("AttachBuffers: Dawn does not support push constants!");
1700   }
1701 
1702   std::vector<std::vector<BindingInitializationHelper>> bindingInitalizerHelper(
1703       kMaxDawnBindGroup);
1704   std::vector<std::vector<::dawn::BindGroupLayoutBinding>> layouts_info(
1705       kMaxDawnBindGroup);
1706   uint32_t max_descriptor_set = 0;
1707 
1708   // Attach storage/uniform buffers
1709   ::dawn::BindGroupLayoutBinding empty_layout_info = {};
1710 
1711   if (!compute_pipeline->pipeline->GetBuffers().empty()) {
1712     std::vector<uint32_t> max_binding_seen(kMaxDawnBindGroup, -1);
1713     for (auto& buf_info : compute_pipeline->pipeline->GetBuffers()) {
1714       while (layouts_info[buf_info.descriptor_set].size() <= buf_info.binding)
1715         layouts_info[buf_info.descriptor_set].push_back(empty_layout_info);
1716     }
1717   }
1718 
1719   for (const auto& buf_info : compute_pipeline->pipeline->GetBuffers()) {
1720     ::dawn::BufferUsage bufferUsage;
1721     ::dawn::BindingType bindingType;
1722     switch (buf_info.type) {
1723       case BufferType::kStorage: {
1724         bufferUsage = ::dawn::BufferUsage::Storage;
1725         bindingType = ::dawn::BindingType::StorageBuffer;
1726         break;
1727       }
1728       case BufferType::kUniform: {
1729         bufferUsage = ::dawn::BufferUsage::Uniform;
1730         bindingType = ::dawn::BindingType::UniformBuffer;
1731         break;
1732       }
1733       default: {
1734         return Result("AttachBuffers: unknown buffer type: " +
1735                       std::to_string(static_cast<uint32_t>(buf_info.type)));
1736         break;
1737       }
1738     }
1739 
1740     if (buf_info.descriptor_set > kMaxDawnBindGroup - 1) {
1741       return Result("AttachBuffers: Dawn has a maximum of " +
1742                     std::to_string(kMaxDawnBindGroup) + " (descriptor sets)");
1743     }
1744 
1745     compute_pipeline->buffers.emplace_back(
1746         CreateBufferFromData(*device_, buf_info.buffer->ValuePtr()->data(),
1747                              buf_info.buffer->GetMaxSizeInBytes(),
1748                              bufferUsage | ::dawn::BufferUsage::CopySrc |
1749                                  ::dawn::BufferUsage::CopyDst));
1750 
1751     compute_pipeline->buffer_map[{buf_info.descriptor_set, buf_info.binding}] =
1752         compute_pipeline->buffers.size() - 1;
1753 
1754     compute_pipeline->used_descriptor_set.insert(buf_info.descriptor_set);
1755     max_descriptor_set = std::max(max_descriptor_set, buf_info.descriptor_set);
1756 
1757     ::dawn::BindGroupLayoutBinding layout_info;
1758     layout_info.binding = buf_info.binding;
1759     layout_info.visibility = ::dawn::ShaderStage::Compute;
1760     layout_info.type = bindingType;
1761     layouts_info[buf_info.descriptor_set][buf_info.binding] = layout_info;
1762 
1763     BindingInitializationHelper tempBinding = BindingInitializationHelper(
1764         buf_info.binding, compute_pipeline->buffers.back(), 0,
1765         buf_info.buffer->GetMaxSizeInBytes());
1766     bindingInitalizerHelper[buf_info.descriptor_set].push_back(tempBinding);
1767   }
1768 
1769   for (uint32_t i = 0; i < kMaxDawnBindGroup; i++) {
1770     if (layouts_info[i].size() > 0 && bindingInitalizerHelper[i].size() > 0) {
1771       ::dawn::BindGroupLayout bindGroupLayout =
1772           MakeBindGroupLayout(*device_, layouts_info[i]);
1773       compute_pipeline->bind_group_layouts.push_back(bindGroupLayout);
1774 
1775       ::dawn::BindGroup bindGroup =
1776           MakeBindGroup(*device_, compute_pipeline->bind_group_layouts[i],
1777                         bindingInitalizerHelper[i]);
1778       compute_pipeline->bind_groups.push_back(bindGroup);
1779     } else if (i < max_descriptor_set) {
1780       ::dawn::BindGroupLayout bindGroupLayout =
1781           MakeBindGroupLayout(*device_, {});
1782       compute_pipeline->bind_group_layouts.push_back(bindGroupLayout);
1783 
1784       ::dawn::BindGroup bindGroup =
1785           MakeBindGroup(*device_, compute_pipeline->bind_group_layouts[i],
1786                         bindingInitalizerHelper[i]);
1787       compute_pipeline->bind_groups.push_back(bindGroup);
1788     }
1789   }
1790 
1791   return {};
1792 }
1793 
1794 }  // namespace dawn
1795 }  // namespace amber
1796