• 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/vulkan/engine_vulkan.h"
16 
17 #include <algorithm>
18 #include <set>
19 #include <utility>
20 
21 #include "amber/amber_vulkan.h"
22 #include "src/make_unique.h"
23 #include "src/type_parser.h"
24 #include "src/vulkan/compute_pipeline.h"
25 #include "src/vulkan/graphics_pipeline.h"
26 
27 namespace amber {
28 namespace vulkan {
29 namespace {
30 
31 const uint32_t kTrianglesPerCell = 2;
32 const uint32_t kVerticesPerTriangle = 3;
33 
ToVkShaderStage(ShaderType type,VkShaderStageFlagBits * ret)34 Result ToVkShaderStage(ShaderType type, VkShaderStageFlagBits* ret) {
35   switch (type) {
36     case kShaderTypeGeometry:
37       *ret = VK_SHADER_STAGE_GEOMETRY_BIT;
38       break;
39     case kShaderTypeFragment:
40       *ret = VK_SHADER_STAGE_FRAGMENT_BIT;
41       break;
42     case kShaderTypeVertex:
43       *ret = VK_SHADER_STAGE_VERTEX_BIT;
44       break;
45     case kShaderTypeTessellationControl:
46       *ret = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
47       break;
48     case kShaderTypeTessellationEvaluation:
49       *ret = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
50       break;
51     case kShaderTypeCompute:
52       *ret = VK_SHADER_STAGE_COMPUTE_BIT;
53       break;
54     case kShaderTypeMulti:
55       *ret = VK_SHADER_STAGE_FRAGMENT_BIT;
56       return Result("Vulkan::Unknown shader stage");
57   }
58 
59   return {};
60 }
61 
AreAllExtensionsSupported(const std::vector<std::string> & available_extensions,const std::vector<std::string> & required_extensions)62 bool AreAllExtensionsSupported(
63     const std::vector<std::string>& available_extensions,
64     const std::vector<std::string>& required_extensions) {
65   if (required_extensions.empty())
66     return true;
67 
68   std::set<std::string> required_extension_set(required_extensions.begin(),
69                                                required_extensions.end());
70   for (const auto& extension : available_extensions) {
71     required_extension_set.erase(extension);
72   }
73 
74   return required_extension_set.empty();
75 }
76 
77 }  // namespace
78 
EngineVulkan()79 EngineVulkan::EngineVulkan() : Engine() {}
80 
~EngineVulkan()81 EngineVulkan::~EngineVulkan() {
82   auto vk_device = device_->GetVkDevice();
83   if (vk_device != VK_NULL_HANDLE) {
84     for (auto shader : shaders_) {
85       device_->GetPtrs()->vkDestroyShaderModule(vk_device, shader.second,
86                                                 nullptr);
87     }
88   }
89 }
90 
Initialize(EngineConfig * config,Delegate * delegate,const std::vector<std::string> & features,const std::vector<std::string> & instance_extensions,const std::vector<std::string> & device_extensions)91 Result EngineVulkan::Initialize(
92     EngineConfig* config,
93     Delegate* delegate,
94     const std::vector<std::string>& features,
95     const std::vector<std::string>& instance_extensions,
96     const std::vector<std::string>& device_extensions) {
97   if (device_)
98     return Result("Vulkan::Initialize device_ already exists");
99 
100   VulkanEngineConfig* vk_config = static_cast<VulkanEngineConfig*>(config);
101   if (!vk_config || vk_config->vkGetInstanceProcAddr == VK_NULL_HANDLE)
102     return Result("Vulkan::Initialize vkGetInstanceProcAddr must be provided.");
103   if (vk_config->device == VK_NULL_HANDLE)
104     return Result("Vulkan::Initialize device must be provided");
105   if (vk_config->physical_device == VK_NULL_HANDLE)
106     return Result("Vulkan::Initialize physical device handle is null.");
107   if (vk_config->queue == VK_NULL_HANDLE)
108     return Result("Vulkan::Initialize queue handle is null.");
109 
110   // Validate instance extensions
111   if (!AreAllExtensionsSupported(vk_config->available_instance_extensions,
112                                  instance_extensions)) {
113     return Result("Vulkan::Initialize not all instance extensions supported");
114   }
115 
116   device_ = MakeUnique<Device>(vk_config->instance, vk_config->physical_device,
117                                vk_config->queue_family_index, vk_config->device,
118                                vk_config->queue);
119 
120   Result r = device_->Initialize(
121       vk_config->vkGetInstanceProcAddr, delegate, features, device_extensions,
122       vk_config->available_features, vk_config->available_features2,
123       vk_config->available_device_extensions);
124   if (!r.IsSuccess())
125     return r;
126 
127   if (!pool_) {
128     pool_ = MakeUnique<CommandPool>(device_.get());
129     r = pool_->Initialize();
130     if (!r.IsSuccess())
131       return r;
132   }
133 
134   return {};
135 }
136 
CreatePipeline(amber::Pipeline * pipeline)137 Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) {
138   // Create the pipeline data early so we can access them as needed.
139   pipeline_map_[pipeline] = PipelineInfo();
140   auto& info = pipeline_map_[pipeline];
141 
142   for (const auto& shader_info : pipeline->GetShaders()) {
143     Result r = SetShader(pipeline, shader_info);
144     if (!r.IsSuccess())
145       return r;
146   }
147 
148   for (const auto& colour_info : pipeline->GetColorAttachments()) {
149     auto fmt = colour_info.buffer->GetFormat();
150     if (!device_->IsFormatSupportedByPhysicalDevice(*fmt, colour_info.type))
151       return Result("Vulkan color attachment format is not supported");
152   }
153 
154   if (pipeline->GetDepthStencilBuffer().buffer) {
155     const auto& depth_stencil_info = pipeline->GetDepthStencilBuffer();
156 
157     auto fmt = depth_stencil_info.buffer->GetFormat();
158     if (!device_->IsFormatSupportedByPhysicalDevice(*fmt,
159                                                     depth_stencil_info.type)) {
160       return Result("Vulkan depth attachment format is not supported");
161     }
162   }
163 
164   std::vector<VkPipelineShaderStageCreateInfo> stage_create_info;
165   Result r = GetVkShaderStageInfo(pipeline, &stage_create_info);
166   if (!r.IsSuccess())
167     return r;
168 
169   const auto& engine_data = GetEngineData();
170   std::unique_ptr<Pipeline> vk_pipeline;
171   if (pipeline->GetType() == PipelineType::kCompute) {
172     vk_pipeline = MakeUnique<ComputePipeline>(
173         device_.get(), engine_data.fence_timeout_ms, stage_create_info);
174     r = vk_pipeline->AsCompute()->Initialize(pool_.get());
175     if (!r.IsSuccess())
176       return r;
177   } else {
178     vk_pipeline = MakeUnique<GraphicsPipeline>(
179         device_.get(), pipeline->GetColorAttachments(),
180         pipeline->GetDepthStencilBuffer(), pipeline->GetResolveTargets(),
181         engine_data.fence_timeout_ms, stage_create_info);
182 
183     vk_pipeline->AsGraphics()->SetPatchControlPoints(
184         pipeline->GetPipelineData()->GetPatchControlPoints());
185 
186     r = vk_pipeline->AsGraphics()->Initialize(pipeline->GetFramebufferWidth(),
187                                               pipeline->GetFramebufferHeight(),
188                                               pool_.get());
189     if (!r.IsSuccess())
190       return r;
191   }
192 
193   info.vk_pipeline = std::move(vk_pipeline);
194 
195   // Set the entry point names for the pipeline.
196   for (const auto& shader_info : pipeline->GetShaders()) {
197     VkShaderStageFlagBits stage = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
198     r = ToVkShaderStage(shader_info.GetShaderType(), &stage);
199     if (!r.IsSuccess())
200       return r;
201     const auto& name = shader_info.GetEntryPoint();
202     if (!name.empty()) {
203       info.vk_pipeline->SetEntryPointName(stage, name);
204     }
205   }
206 
207   for (const auto& vtex_info : pipeline->GetVertexBuffers()) {
208     auto fmt = vtex_info.buffer->GetFormat();
209     if (!device_->IsFormatSupportedByPhysicalDevice(*fmt, vtex_info.type))
210       return Result("Vulkan vertex buffer format is not supported");
211     if (!info.vertex_buffer)
212       info.vertex_buffer = MakeUnique<VertexBuffer>(device_.get());
213 
214     info.vertex_buffer->SetData(static_cast<uint8_t>(vtex_info.location),
215                                 vtex_info.buffer, vtex_info.input_rate,
216                                 vtex_info.format, vtex_info.offset,
217                                 vtex_info.stride);
218   }
219 
220   if (pipeline->GetIndexBuffer()) {
221     auto* buf = pipeline->GetIndexBuffer();
222     info.vk_pipeline->AsGraphics()->SetIndexBuffer(buf);
223   }
224 
225   if (pipeline->GetPushConstantBuffer().buffer != nullptr) {
226     r = info.vk_pipeline->AddPushConstantBuffer(
227         pipeline->GetPushConstantBuffer().buffer, 0);
228     if (!r.IsSuccess())
229       return r;
230   }
231 
232   for (const auto& buf_info : pipeline->GetBuffers()) {
233     auto type = BufferCommand::BufferType::kSSBO;
234     if (buf_info.type == BufferType::kStorageImage) {
235       type = BufferCommand::BufferType::kStorageImage;
236     } else if (buf_info.type == BufferType::kSampledImage) {
237       type = BufferCommand::BufferType::kSampledImage;
238     } else if (buf_info.type == BufferType::kCombinedImageSampler) {
239       type = BufferCommand::BufferType::kCombinedImageSampler;
240     } else if (buf_info.type == BufferType::kUniformTexelBuffer) {
241       type = BufferCommand::BufferType::kUniformTexelBuffer;
242     } else if (buf_info.type == BufferType::kStorageTexelBuffer) {
243       type = BufferCommand::BufferType::kStorageTexelBuffer;
244     } else if (buf_info.type == BufferType::kUniform) {
245       type = BufferCommand::BufferType::kUniform;
246     } else if (buf_info.type == BufferType::kUniformDynamic) {
247       type = BufferCommand::BufferType::kUniformDynamic;
248     } else if (buf_info.type == BufferType::kStorageDynamic) {
249       type = BufferCommand::BufferType::kSSBODynamic;
250     } else if (buf_info.type != BufferType::kStorage) {
251       return Result("Vulkan: CreatePipeline - unknown buffer type: " +
252                     std::to_string(static_cast<uint32_t>(buf_info.type)));
253     }
254 
255     auto cmd = MakeUnique<BufferCommand>(type, pipeline);
256     cmd->SetDescriptorSet(buf_info.descriptor_set);
257     cmd->SetBinding(buf_info.binding);
258     cmd->SetBaseMipLevel(buf_info.base_mip_level);
259     cmd->SetDynamicOffset(buf_info.dynamic_offset);
260     cmd->SetDescriptorOffset(buf_info.descriptor_offset);
261     cmd->SetDescriptorRange(buf_info.descriptor_range);
262     cmd->SetBuffer(buf_info.buffer);
263     cmd->SetSampler(buf_info.sampler);
264 
265     if (cmd->GetValues().empty()) {
266       cmd->GetBuffer()->SetSizeInElements(cmd->GetBuffer()->ElementCount());
267     } else {
268       cmd->GetBuffer()->SetDataWithOffset(cmd->GetValues(), cmd->GetOffset());
269     }
270 
271     r = info.vk_pipeline->AddBufferDescriptor(cmd.get());
272     if (!r.IsSuccess())
273       return r;
274   }
275 
276   for (const auto& sampler_info : pipeline->GetSamplers()) {
277     auto cmd = MakeUnique<SamplerCommand>(pipeline);
278     cmd->SetDescriptorSet(sampler_info.descriptor_set);
279     cmd->SetBinding(sampler_info.binding);
280     cmd->SetSampler(sampler_info.sampler);
281 
282     r = info.vk_pipeline->AddSamplerDescriptor(cmd.get());
283     if (!r.IsSuccess())
284       return r;
285   }
286 
287   return {};
288 }
289 
SetShader(amber::Pipeline * pipeline,const amber::Pipeline::ShaderInfo & shader)290 Result EngineVulkan::SetShader(amber::Pipeline* pipeline,
291                                const amber::Pipeline::ShaderInfo& shader) {
292   const auto type = shader.GetShaderType();
293   const auto& data = shader.GetData();
294   const auto shader_name = shader.GetShader()->GetName();
295   auto& info = pipeline_map_[pipeline];
296 
297   auto it = info.shader_info.find(type);
298   if (it != info.shader_info.end())
299     return Result("Vulkan::Setting Duplicated Shader Types Fail");
300 
301   VkShaderModule shader_module;
302   if (shaders_.find(shader_name) != shaders_.end()) {
303     shader_module = shaders_[shader_name];
304   } else {
305     VkShaderModuleCreateInfo create_info = VkShaderModuleCreateInfo();
306     create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
307     create_info.codeSize = data.size() * sizeof(uint32_t);
308     create_info.pCode = data.data();
309 
310     if (device_->GetPtrs()->vkCreateShaderModule(
311             device_->GetVkDevice(), &create_info, nullptr, &shader_module) !=
312         VK_SUCCESS) {
313       return Result("Vulkan::Calling vkCreateShaderModule Fail");
314     }
315 
316     shaders_[shader_name] = shader_module;
317   }
318 
319   info.shader_info[type].shader = shader_module;
320 
321   for (auto& shader_info : pipeline->GetShaders()) {
322     if (shader_info.GetShaderType() != type)
323       continue;
324 
325     const auto required_subgroup_size_setting =
326         shader_info.GetRequiredSubgroupSizeSetting();
327     uint32_t required_subgroup_size_uint = 0;
328     switch (required_subgroup_size_setting) {
329       case amber::Pipeline::ShaderInfo::RequiredSubgroupSizeSetting::
330           kSetToMinimumSize:
331         required_subgroup_size_uint = device_->GetMinSubgroupSize();
332         break;
333       case amber::Pipeline::ShaderInfo::RequiredSubgroupSizeSetting::
334           kSetToMaximumSize:
335         required_subgroup_size_uint = device_->GetMaxSubgroupSize();
336         break;
337       default:
338         required_subgroup_size_uint = shader_info.GetRequiredSubgroupSize();
339         break;
340     }
341     if (required_subgroup_size_uint > 0) {
342       if (!device_->IsRequiredSubgroupSizeSupported(
343               type, required_subgroup_size_uint)) {
344         return Result(
345             "Vulkan::Setting Required subgroup size is not supported by the "
346             "device.");
347       }
348     }
349     info.shader_info[type].required_subgroup_size = required_subgroup_size_uint;
350 
351     info.shader_info[type].create_flags = 0;
352     if (shader_info.GetVaryingSubgroupSize()) {
353       info.shader_info[type].create_flags |=
354           VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT;
355     }
356     if (shader_info.GetRequireFullSubgroups()) {
357       info.shader_info[type].create_flags |=
358           VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT;
359     }
360 
361     const auto& shader_spec_info = shader_info.GetSpecialization();
362     if (shader_spec_info.empty())
363       continue;
364 
365     auto& entries = info.shader_info[type].specialization_entries;
366     entries.reset(new std::vector<VkSpecializationMapEntry>());
367     auto& entry_data = info.shader_info[type].specialization_data;
368     entry_data.reset(new std::vector<uint32_t>());
369     uint32_t i = 0;
370     for (auto pair : shader_spec_info) {
371       entries->push_back({pair.first,
372                           static_cast<uint32_t>(i * sizeof(uint32_t)),
373                           static_cast<uint32_t>(sizeof(uint32_t))});
374       entry_data->push_back(pair.second);
375       ++i;
376     }
377     auto& spec_info = info.shader_info[type].specialization_info;
378     spec_info.reset(new VkSpecializationInfo());
379     spec_info->mapEntryCount = static_cast<uint32_t>(shader_spec_info.size());
380     spec_info->pMapEntries = entries->data();
381     spec_info->dataSize = sizeof(uint32_t) * shader_spec_info.size();
382     spec_info->pData = entry_data->data();
383   }
384 
385   return {};
386 }
387 
GetVkShaderStageInfo(amber::Pipeline * pipeline,std::vector<VkPipelineShaderStageCreateInfo> * out)388 Result EngineVulkan::GetVkShaderStageInfo(
389     amber::Pipeline* pipeline,
390     std::vector<VkPipelineShaderStageCreateInfo>* out) {
391   auto& info = pipeline_map_[pipeline];
392 
393   std::vector<VkPipelineShaderStageCreateInfo> stage_info(
394       info.shader_info.size());
395   uint32_t stage_count = 0;
396   for (auto& it : info.shader_info) {
397     VkShaderStageFlagBits stage = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
398     Result r = ToVkShaderStage(it.first, &stage);
399     if (!r.IsSuccess())
400       return r;
401 
402     stage_info[stage_count] = VkPipelineShaderStageCreateInfo();
403     stage_info[stage_count].sType =
404         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
405     stage_info[stage_count].flags = it.second.create_flags;
406     stage_info[stage_count].stage = stage;
407     stage_info[stage_count].module = it.second.shader;
408     stage_info[stage_count].pName = nullptr;
409     if (it.second.specialization_entries &&
410         !it.second.specialization_entries->empty()) {
411       stage_info[stage_count].pSpecializationInfo =
412           it.second.specialization_info.get();
413     }
414 
415     if (stage == VK_SHADER_STAGE_COMPUTE_BIT &&
416         it.second.required_subgroup_size > 0) {
417       VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT* pSubgroupSize =
418           new VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT();
419       pSubgroupSize->sType =
420           VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT;  // NOLINT(whitespace/line_length)
421       pSubgroupSize->pNext = nullptr;
422       pSubgroupSize->requiredSubgroupSize = it.second.required_subgroup_size;
423       stage_info[stage_count].pNext = pSubgroupSize;
424     }
425     ++stage_count;
426   }
427   *out = stage_info;
428   return {};
429 }
430 
DoClearColor(const ClearColorCommand * command)431 Result EngineVulkan::DoClearColor(const ClearColorCommand* command) {
432   auto& info = pipeline_map_[command->GetPipeline()];
433   if (!info.vk_pipeline->IsGraphics())
434     return Result("Vulkan::Clear Color Command for Non-Graphics Pipeline");
435 
436   return info.vk_pipeline->AsGraphics()->SetClearColor(
437       command->GetR(), command->GetG(), command->GetB(), command->GetA());
438 }
439 
DoClearStencil(const ClearStencilCommand * command)440 Result EngineVulkan::DoClearStencil(const ClearStencilCommand* command) {
441   auto& info = pipeline_map_[command->GetPipeline()];
442   if (!info.vk_pipeline->IsGraphics())
443     return Result("Vulkan::Clear Stencil Command for Non-Graphics Pipeline");
444 
445   return info.vk_pipeline->AsGraphics()->SetClearStencil(command->GetValue());
446 }
447 
DoClearDepth(const ClearDepthCommand * command)448 Result EngineVulkan::DoClearDepth(const ClearDepthCommand* command) {
449   auto& info = pipeline_map_[command->GetPipeline()];
450   if (!info.vk_pipeline->IsGraphics())
451     return Result("Vulkan::Clear Depth Command for Non-Graphics Pipeline");
452 
453   return info.vk_pipeline->AsGraphics()->SetClearDepth(command->GetValue());
454 }
455 
DoClear(const ClearCommand * command)456 Result EngineVulkan::DoClear(const ClearCommand* command) {
457   auto& info = pipeline_map_[command->GetPipeline()];
458   if (!info.vk_pipeline->IsGraphics())
459     return Result("Vulkan::Clear Command for Non-Graphics Pipeline");
460 
461   return info.vk_pipeline->AsGraphics()->Clear();
462 }
463 
DoDrawRect(const DrawRectCommand * command)464 Result EngineVulkan::DoDrawRect(const DrawRectCommand* command) {
465   auto& info = pipeline_map_[command->GetPipeline()];
466   if (!info.vk_pipeline->IsGraphics())
467     return Result("Vulkan::DrawRect for Non-Graphics Pipeline");
468 
469   auto* graphics = info.vk_pipeline->AsGraphics();
470 
471   float x = command->GetX();
472   float y = command->GetY();
473   float width = command->GetWidth();
474   float height = command->GetHeight();
475 
476   if (command->IsOrtho()) {
477     const float frame_width = static_cast<float>(graphics->GetWidth());
478     const float frame_height = static_cast<float>(graphics->GetHeight());
479     x = ((x / frame_width) * 2.0f) - 1.0f;
480     y = ((y / frame_height) * 2.0f) - 1.0f;
481     width = (width / frame_width) * 2.0f;
482     height = (height / frame_height) * 2.0f;
483   }
484 
485   std::vector<Value> values(8);
486   // Bottom left
487   values[0].SetDoubleValue(static_cast<double>(x));
488   values[1].SetDoubleValue(static_cast<double>(y + height));
489   // Top left
490   values[2].SetDoubleValue(static_cast<double>(x));
491   values[3].SetDoubleValue(static_cast<double>(y));
492   // Bottom right
493   values[4].SetDoubleValue(static_cast<double>(x + width));
494   values[5].SetDoubleValue(static_cast<double>(y + height));
495   // Top right
496   values[6].SetDoubleValue(static_cast<double>(x + width));
497   values[7].SetDoubleValue(static_cast<double>(y));
498 
499   // |format| is not Format for frame buffer but for vertex buffer.
500   // Since draw rect command contains its vertex information and it
501   // does not include a format of vertex buffer, we can choose any
502   // one that is suitable. We use VK_FORMAT_R32G32_SFLOAT for it.
503   TypeParser parser;
504   auto type = parser.Parse("R32G32_SFLOAT");
505   Format fmt(type.get());
506 
507   auto buf = MakeUnique<Buffer>();
508   buf->SetFormat(&fmt);
509   buf->SetData(std::move(values));
510 
511   auto vertex_buffer = MakeUnique<VertexBuffer>(device_.get());
512   vertex_buffer->SetData(0, buf.get(), InputRate::kVertex, buf->GetFormat(), 0,
513                          buf->GetFormat()->SizeInBytes());
514 
515   DrawArraysCommand draw(command->GetPipeline(), *command->GetPipelineData());
516   draw.SetTopology(command->IsPatch() ? Topology::kPatchList
517                                       : Topology::kTriangleStrip);
518   draw.SetFirstVertexIndex(0);
519   draw.SetVertexCount(4);
520   draw.SetInstanceCount(1);
521 
522   Result r = graphics->Draw(&draw, vertex_buffer.get());
523   if (!r.IsSuccess())
524     return r;
525 
526   return {};
527 }
528 
DoDrawGrid(const DrawGridCommand * command)529 Result EngineVulkan::DoDrawGrid(const DrawGridCommand* command) {
530   auto& info = pipeline_map_[command->GetPipeline()];
531   if (!info.vk_pipeline->IsGraphics())
532     return Result("Vulkan::DrawGrid for Non-Graphics Pipeline");
533 
534   auto* graphics = info.vk_pipeline->AsGraphics();
535 
536   float x = command->GetX();
537   float y = command->GetY();
538   float width = command->GetWidth();
539   float height = command->GetHeight();
540   const uint32_t columns = command->GetColumns();
541   const uint32_t rows = command->GetRows();
542   const uint32_t vertices =
543       columns * rows * kVerticesPerTriangle * kTrianglesPerCell;
544 
545   // Ortho calculation
546   const float frame_width = static_cast<float>(graphics->GetWidth());
547   const float frame_height = static_cast<float>(graphics->GetHeight());
548   x = ((x / frame_width) * 2.0f) - 1.0f;
549   y = ((y / frame_height) * 2.0f) - 1.0f;
550   width = (width / frame_width) * 2.0f;
551   height = (height / frame_height) * 2.0f;
552 
553   std::vector<Value> values(vertices * 2);
554 
555   const float cell_width = width / static_cast<float>(columns);
556   const float cell_height = height / static_cast<float>(rows);
557 
558   for (uint32_t i = 0, c = 0; i < rows; i++) {
559     for (uint32_t j = 0; j < columns; j++, c += 12) {
560       // Calculate corners
561       float x0 = x + cell_width * static_cast<float>(j);
562       float y0 = y + cell_height * static_cast<float>(i);
563       float x1 = x + cell_width * static_cast<float>(j + 1);
564       float y1 = y + cell_height * static_cast<float>(i + 1);
565 
566       // Bottom right
567       values[c + 0].SetDoubleValue(static_cast<double>(x1));
568       values[c + 1].SetDoubleValue(static_cast<double>(y1));
569       // Bottom left
570       values[c + 2].SetDoubleValue(static_cast<double>(x0));
571       values[c + 3].SetDoubleValue(static_cast<double>(y1));
572       // Top left
573       values[c + 4].SetDoubleValue(static_cast<double>(x0));
574       values[c + 5].SetDoubleValue(static_cast<double>(y0));
575       // Bottom right
576       values[c + 6].SetDoubleValue(static_cast<double>(x1));
577       values[c + 7].SetDoubleValue(static_cast<double>(y1));
578       // Top left
579       values[c + 8].SetDoubleValue(static_cast<double>(x0));
580       values[c + 9].SetDoubleValue(static_cast<double>(y0));
581       // Top right
582       values[c + 10].SetDoubleValue(static_cast<double>(x1));
583       values[c + 11].SetDoubleValue(static_cast<double>(y0));
584     }
585   }
586 
587   // |format| is not Format for frame buffer but for vertex buffer.
588   // Since draw rect command contains its vertex information and it
589   // does not include a format of vertex buffer, we can choose any
590   // one that is suitable. We use VK_FORMAT_R32G32_SFLOAT for it.
591   TypeParser parser;
592   auto type = parser.Parse("R32G32_SFLOAT");
593   Format fmt(type.get());
594 
595   auto buf = MakeUnique<Buffer>();
596   buf->SetFormat(&fmt);
597   buf->SetData(std::move(values));
598 
599   auto vertex_buffer = MakeUnique<VertexBuffer>(device_.get());
600   vertex_buffer->SetData(0, buf.get(), InputRate::kVertex, buf->GetFormat(), 0,
601                          buf->GetFormat()->SizeInBytes());
602 
603   DrawArraysCommand draw(command->GetPipeline(), *command->GetPipelineData());
604   draw.SetTopology(Topology::kTriangleList);
605   draw.SetFirstVertexIndex(0);
606   draw.SetVertexCount(vertices);
607   draw.SetInstanceCount(1);
608 
609   Result r = graphics->Draw(&draw, vertex_buffer.get());
610   if (!r.IsSuccess())
611     return r;
612 
613   return {};
614 }
615 
DoDrawArrays(const DrawArraysCommand * command)616 Result EngineVulkan::DoDrawArrays(const DrawArraysCommand* command) {
617   auto& info = pipeline_map_[command->GetPipeline()];
618   if (!info.vk_pipeline)
619     return Result("Vulkan::DrawArrays for Non-Graphics Pipeline");
620 
621   return info.vk_pipeline->AsGraphics()->Draw(command,
622                                               info.vertex_buffer.get());
623 }
624 
DoCompute(const ComputeCommand * command)625 Result EngineVulkan::DoCompute(const ComputeCommand* command) {
626   auto& info = pipeline_map_[command->GetPipeline()];
627   if (info.vk_pipeline->IsGraphics())
628     return Result("Vulkan: Compute called for graphics pipeline.");
629 
630   return info.vk_pipeline->AsCompute()->Compute(
631       command->GetX(), command->GetY(), command->GetZ());
632 }
633 
DoEntryPoint(const EntryPointCommand * command)634 Result EngineVulkan::DoEntryPoint(const EntryPointCommand* command) {
635   auto& info = pipeline_map_[command->GetPipeline()];
636   if (!info.vk_pipeline)
637     return Result("Vulkan::DoEntryPoint no Pipeline exists");
638 
639   VkShaderStageFlagBits stage = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
640   Result r = ToVkShaderStage(command->GetShaderType(), &stage);
641   if (!r.IsSuccess())
642     return r;
643 
644   info.vk_pipeline->SetEntryPointName(stage, command->GetEntryPointName());
645   return {};
646 }
647 
DoPatchParameterVertices(const PatchParameterVerticesCommand * command)648 Result EngineVulkan::DoPatchParameterVertices(
649     const PatchParameterVerticesCommand* command) {
650   auto& info = pipeline_map_[command->GetPipeline()];
651   if (!info.vk_pipeline->IsGraphics())
652     return Result("Vulkan::DoPatchParameterVertices for Non-Graphics Pipeline");
653 
654   info.vk_pipeline->AsGraphics()->SetPatchControlPoints(
655       command->GetControlPointCount());
656   return {};
657 }
658 
DoBuffer(const BufferCommand * cmd)659 Result EngineVulkan::DoBuffer(const BufferCommand* cmd) {
660   if (!device_->IsDescriptorSetInBounds(cmd->GetDescriptorSet())) {
661     return Result(
662         "Vulkan::DoBuffer exceed maxBoundDescriptorSets limit of physical "
663         "device");
664   }
665   if (cmd->GetValues().empty()) {
666     cmd->GetBuffer()->SetSizeInElements(cmd->GetBuffer()->ElementCount());
667   } else {
668     cmd->GetBuffer()->SetDataWithOffset(cmd->GetValues(), cmd->GetOffset());
669   }
670   if (cmd->IsPushConstant()) {
671     auto& info = pipeline_map_[cmd->GetPipeline()];
672     return info.vk_pipeline->AddPushConstantBuffer(cmd->GetBuffer(),
673                                                    cmd->GetOffset());
674   }
675   return {};
676 }
677 
678 }  // namespace vulkan
679 }  // namespace amber
680