• 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(), engine_data.fence_timeout_ms,
181         stage_create_info);
182 
183     r = vk_pipeline->AsGraphics()->Initialize(pipeline->GetFramebufferWidth(),
184                                               pipeline->GetFramebufferHeight(),
185                                               pool_.get());
186     if (!r.IsSuccess())
187       return r;
188   }
189 
190   info.vk_pipeline = std::move(vk_pipeline);
191 
192   // Set the entry point names for the pipeline.
193   for (const auto& shader_info : pipeline->GetShaders()) {
194     VkShaderStageFlagBits stage = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
195     r = ToVkShaderStage(shader_info.GetShaderType(), &stage);
196     if (!r.IsSuccess())
197       return r;
198     const auto& name = shader_info.GetEntryPoint();
199     if (!name.empty()) {
200       info.vk_pipeline->SetEntryPointName(stage, name);
201     }
202   }
203 
204   for (const auto& vtex_info : pipeline->GetVertexBuffers()) {
205     auto fmt = vtex_info.buffer->GetFormat();
206     if (!device_->IsFormatSupportedByPhysicalDevice(*fmt, vtex_info.type))
207       return Result("Vulkan vertex buffer format is not supported");
208     if (!info.vertex_buffer)
209       info.vertex_buffer = MakeUnique<VertexBuffer>(device_.get());
210 
211     info.vertex_buffer->SetData(static_cast<uint8_t>(vtex_info.location),
212                                 vtex_info.buffer, vtex_info.input_rate,
213                                 vtex_info.format, vtex_info.offset,
214                                 vtex_info.stride);
215   }
216 
217   if (pipeline->GetIndexBuffer()) {
218     auto* buf = pipeline->GetIndexBuffer();
219     info.vk_pipeline->AsGraphics()->SetIndexBuffer(buf);
220   }
221 
222   if (pipeline->GetPushConstantBuffer().buffer != nullptr) {
223     r = info.vk_pipeline->AddPushConstantBuffer(
224         pipeline->GetPushConstantBuffer().buffer, 0);
225     if (!r.IsSuccess())
226       return r;
227   }
228 
229   for (const auto& buf_info : pipeline->GetBuffers()) {
230     auto type = BufferCommand::BufferType::kSSBO;
231     if (buf_info.type == BufferType::kStorageImage) {
232       type = BufferCommand::BufferType::kStorageImage;
233     } else if (buf_info.type == BufferType::kSampledImage) {
234       type = BufferCommand::BufferType::kSampledImage;
235     } else if (buf_info.type == BufferType::kCombinedImageSampler) {
236       type = BufferCommand::BufferType::kCombinedImageSampler;
237     } else if (buf_info.type == BufferType::kUniformTexelBuffer) {
238       type = BufferCommand::BufferType::kUniformTexelBuffer;
239     } else if (buf_info.type == BufferType::kStorageTexelBuffer) {
240       type = BufferCommand::BufferType::kStorageTexelBuffer;
241     } else if (buf_info.type == BufferType::kUniform) {
242       type = BufferCommand::BufferType::kUniform;
243     } else if (buf_info.type == BufferType::kUniformDynamic) {
244       type = BufferCommand::BufferType::kUniformDynamic;
245     } else if (buf_info.type == BufferType::kStorageDynamic) {
246       type = BufferCommand::BufferType::kSSBODynamic;
247     } else if (buf_info.type != BufferType::kStorage) {
248       return Result("Vulkan: CreatePipeline - unknown buffer type: " +
249                     std::to_string(static_cast<uint32_t>(buf_info.type)));
250     }
251 
252     auto cmd = MakeUnique<BufferCommand>(type, pipeline);
253     cmd->SetDescriptorSet(buf_info.descriptor_set);
254     cmd->SetBinding(buf_info.binding);
255     cmd->SetBaseMipLevel(buf_info.base_mip_level);
256     cmd->SetDynamicOffset(buf_info.dynamic_offset);
257     cmd->SetBuffer(buf_info.buffer);
258     cmd->SetSampler(buf_info.sampler);
259 
260     if (cmd->GetValues().empty()) {
261       cmd->GetBuffer()->SetSizeInElements(cmd->GetBuffer()->ElementCount());
262     } else {
263       cmd->GetBuffer()->SetDataWithOffset(cmd->GetValues(), cmd->GetOffset());
264     }
265 
266     r = info.vk_pipeline->AddBufferDescriptor(cmd.get());
267     if (!r.IsSuccess())
268       return r;
269   }
270 
271   for (const auto& sampler_info : pipeline->GetSamplers()) {
272     auto cmd = MakeUnique<SamplerCommand>(pipeline);
273     cmd->SetDescriptorSet(sampler_info.descriptor_set);
274     cmd->SetBinding(sampler_info.binding);
275     cmd->SetSampler(sampler_info.sampler);
276 
277     r = info.vk_pipeline->AddSamplerDescriptor(cmd.get());
278     if (!r.IsSuccess())
279       return r;
280   }
281 
282   return {};
283 }
284 
SetShader(amber::Pipeline * pipeline,const amber::Pipeline::ShaderInfo & shader)285 Result EngineVulkan::SetShader(amber::Pipeline* pipeline,
286                                const amber::Pipeline::ShaderInfo& shader) {
287   const auto type = shader.GetShaderType();
288   const auto& data = shader.GetData();
289   const auto shader_name = shader.GetShader()->GetName();
290   auto& info = pipeline_map_[pipeline];
291 
292   auto it = info.shader_info.find(type);
293   if (it != info.shader_info.end())
294     return Result("Vulkan::Setting Duplicated Shader Types Fail");
295 
296   VkShaderModule shader_module;
297   if (shaders_.find(shader_name) != shaders_.end()) {
298     shader_module = shaders_[shader_name];
299   } else {
300     VkShaderModuleCreateInfo create_info = VkShaderModuleCreateInfo();
301     create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
302     create_info.codeSize = data.size() * sizeof(uint32_t);
303     create_info.pCode = data.data();
304 
305     if (device_->GetPtrs()->vkCreateShaderModule(
306             device_->GetVkDevice(), &create_info, nullptr, &shader_module) !=
307         VK_SUCCESS) {
308       return Result("Vulkan::Calling vkCreateShaderModule Fail");
309     }
310 
311     shaders_[shader_name] = shader_module;
312   }
313 
314   info.shader_info[type].shader = shader_module;
315 
316   for (auto& shader_info : pipeline->GetShaders()) {
317     if (shader_info.GetShaderType() != type)
318       continue;
319 
320     const auto required_subgroup_size_setting =
321         shader_info.GetRequiredSubgroupSizeSetting();
322     uint32_t required_subgroup_size_uint = 0;
323     switch (required_subgroup_size_setting) {
324       case amber::Pipeline::ShaderInfo::RequiredSubgroupSizeSetting::
325           kSetToMinimumSize:
326         required_subgroup_size_uint = device_->GetMinSubgroupSize();
327         break;
328       case amber::Pipeline::ShaderInfo::RequiredSubgroupSizeSetting::
329           kSetToMaximumSize:
330         required_subgroup_size_uint = device_->GetMaxSubgroupSize();
331         break;
332       default:
333         required_subgroup_size_uint = shader_info.GetRequiredSubgroupSize();
334         break;
335     }
336     if (required_subgroup_size_uint > 0) {
337       if (!device_->IsRequiredSubgroupSizeSupported(
338               type, required_subgroup_size_uint)) {
339         return Result(
340             "Vulkan::Setting Required subgroup size is not supported by the "
341             "device.");
342       }
343     }
344     info.shader_info[type].required_subgroup_size = required_subgroup_size_uint;
345 
346     info.shader_info[type].create_flags = 0;
347     if (shader_info.GetVaryingSubgroupSize()) {
348       info.shader_info[type].create_flags |=
349           VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT;
350     }
351     if (shader_info.GetRequireFullSubgroups()) {
352       info.shader_info[type].create_flags |=
353           VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT;
354     }
355 
356     const auto& shader_spec_info = shader_info.GetSpecialization();
357     if (shader_spec_info.empty())
358       continue;
359 
360     auto& entries = info.shader_info[type].specialization_entries;
361     entries.reset(new std::vector<VkSpecializationMapEntry>());
362     auto& entry_data = info.shader_info[type].specialization_data;
363     entry_data.reset(new std::vector<uint32_t>());
364     uint32_t i = 0;
365     for (auto pair : shader_spec_info) {
366       entries->push_back({pair.first,
367                           static_cast<uint32_t>(i * sizeof(uint32_t)),
368                           static_cast<uint32_t>(sizeof(uint32_t))});
369       entry_data->push_back(pair.second);
370       ++i;
371     }
372     auto& spec_info = info.shader_info[type].specialization_info;
373     spec_info.reset(new VkSpecializationInfo());
374     spec_info->mapEntryCount = static_cast<uint32_t>(shader_spec_info.size());
375     spec_info->pMapEntries = entries->data();
376     spec_info->dataSize = sizeof(uint32_t) * shader_spec_info.size();
377     spec_info->pData = entry_data->data();
378   }
379 
380   return {};
381 }
382 
GetVkShaderStageInfo(amber::Pipeline * pipeline,std::vector<VkPipelineShaderStageCreateInfo> * out)383 Result EngineVulkan::GetVkShaderStageInfo(
384     amber::Pipeline* pipeline,
385     std::vector<VkPipelineShaderStageCreateInfo>* out) {
386   auto& info = pipeline_map_[pipeline];
387 
388   std::vector<VkPipelineShaderStageCreateInfo> stage_info(
389       info.shader_info.size());
390   uint32_t stage_count = 0;
391   for (auto& it : info.shader_info) {
392     VkShaderStageFlagBits stage = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
393     Result r = ToVkShaderStage(it.first, &stage);
394     if (!r.IsSuccess())
395       return r;
396 
397     stage_info[stage_count] = VkPipelineShaderStageCreateInfo();
398     stage_info[stage_count].sType =
399         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
400     stage_info[stage_count].flags = it.second.create_flags;
401     stage_info[stage_count].stage = stage;
402     stage_info[stage_count].module = it.second.shader;
403     stage_info[stage_count].pName = nullptr;
404     if (it.second.specialization_entries &&
405         !it.second.specialization_entries->empty()) {
406       stage_info[stage_count].pSpecializationInfo =
407           it.second.specialization_info.get();
408     }
409 
410     if (stage == VK_SHADER_STAGE_COMPUTE_BIT &&
411         it.second.required_subgroup_size > 0) {
412       VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT* pSubgroupSize =
413           new VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT();
414       pSubgroupSize->sType =
415           VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT;  // NOLINT(whitespace/line_length)
416       pSubgroupSize->pNext = nullptr;
417       pSubgroupSize->requiredSubgroupSize = it.second.required_subgroup_size;
418       stage_info[stage_count].pNext = pSubgroupSize;
419     }
420     ++stage_count;
421   }
422   *out = stage_info;
423   return {};
424 }
425 
DoClearColor(const ClearColorCommand * command)426 Result EngineVulkan::DoClearColor(const ClearColorCommand* command) {
427   auto& info = pipeline_map_[command->GetPipeline()];
428   if (!info.vk_pipeline->IsGraphics())
429     return Result("Vulkan::Clear Color Command for Non-Graphics Pipeline");
430 
431   return info.vk_pipeline->AsGraphics()->SetClearColor(
432       command->GetR(), command->GetG(), command->GetB(), command->GetA());
433 }
434 
DoClearStencil(const ClearStencilCommand * command)435 Result EngineVulkan::DoClearStencil(const ClearStencilCommand* command) {
436   auto& info = pipeline_map_[command->GetPipeline()];
437   if (!info.vk_pipeline->IsGraphics())
438     return Result("Vulkan::Clear Stencil Command for Non-Graphics Pipeline");
439 
440   return info.vk_pipeline->AsGraphics()->SetClearStencil(command->GetValue());
441 }
442 
DoClearDepth(const ClearDepthCommand * command)443 Result EngineVulkan::DoClearDepth(const ClearDepthCommand* command) {
444   auto& info = pipeline_map_[command->GetPipeline()];
445   if (!info.vk_pipeline->IsGraphics())
446     return Result("Vulkan::Clear Depth Command for Non-Graphics Pipeline");
447 
448   return info.vk_pipeline->AsGraphics()->SetClearDepth(command->GetValue());
449 }
450 
DoClear(const ClearCommand * command)451 Result EngineVulkan::DoClear(const ClearCommand* command) {
452   auto& info = pipeline_map_[command->GetPipeline()];
453   if (!info.vk_pipeline->IsGraphics())
454     return Result("Vulkan::Clear Command for Non-Graphics Pipeline");
455 
456   return info.vk_pipeline->AsGraphics()->Clear();
457 }
458 
DoDrawRect(const DrawRectCommand * command)459 Result EngineVulkan::DoDrawRect(const DrawRectCommand* command) {
460   auto& info = pipeline_map_[command->GetPipeline()];
461   if (!info.vk_pipeline->IsGraphics())
462     return Result("Vulkan::DrawRect for Non-Graphics Pipeline");
463 
464   auto* graphics = info.vk_pipeline->AsGraphics();
465 
466   float x = command->GetX();
467   float y = command->GetY();
468   float width = command->GetWidth();
469   float height = command->GetHeight();
470 
471   if (command->IsOrtho()) {
472     const float frame_width = static_cast<float>(graphics->GetWidth());
473     const float frame_height = static_cast<float>(graphics->GetHeight());
474     x = ((x / frame_width) * 2.0f) - 1.0f;
475     y = ((y / frame_height) * 2.0f) - 1.0f;
476     width = (width / frame_width) * 2.0f;
477     height = (height / frame_height) * 2.0f;
478   }
479 
480   std::vector<Value> values(8);
481   // Bottom left
482   values[0].SetDoubleValue(static_cast<double>(x));
483   values[1].SetDoubleValue(static_cast<double>(y + height));
484   // Top left
485   values[2].SetDoubleValue(static_cast<double>(x));
486   values[3].SetDoubleValue(static_cast<double>(y));
487   // Bottom right
488   values[4].SetDoubleValue(static_cast<double>(x + width));
489   values[5].SetDoubleValue(static_cast<double>(y + height));
490   // Top right
491   values[6].SetDoubleValue(static_cast<double>(x + width));
492   values[7].SetDoubleValue(static_cast<double>(y));
493 
494   // |format| is not Format for frame buffer but for vertex buffer.
495   // Since draw rect command contains its vertex information and it
496   // does not include a format of vertex buffer, we can choose any
497   // one that is suitable. We use VK_FORMAT_R32G32_SFLOAT for it.
498   TypeParser parser;
499   auto type = parser.Parse("R32G32_SFLOAT");
500   Format fmt(type.get());
501 
502   auto buf = MakeUnique<Buffer>();
503   buf->SetFormat(&fmt);
504   buf->SetData(std::move(values));
505 
506   auto vertex_buffer = MakeUnique<VertexBuffer>(device_.get());
507   vertex_buffer->SetData(0, buf.get(), InputRate::kVertex, buf->GetFormat(), 0,
508                          buf->GetFormat()->SizeInBytes());
509 
510   DrawArraysCommand draw(command->GetPipeline(), *command->GetPipelineData());
511   draw.SetTopology(command->IsPatch() ? Topology::kPatchList
512                                       : Topology::kTriangleStrip);
513   draw.SetFirstVertexIndex(0);
514   draw.SetVertexCount(4);
515   draw.SetInstanceCount(1);
516 
517   Result r = graphics->Draw(&draw, vertex_buffer.get());
518   if (!r.IsSuccess())
519     return r;
520 
521   return {};
522 }
523 
DoDrawGrid(const DrawGridCommand * command)524 Result EngineVulkan::DoDrawGrid(const DrawGridCommand* command) {
525   auto& info = pipeline_map_[command->GetPipeline()];
526   if (!info.vk_pipeline->IsGraphics())
527     return Result("Vulkan::DrawGrid for Non-Graphics Pipeline");
528 
529   auto* graphics = info.vk_pipeline->AsGraphics();
530 
531   float x = command->GetX();
532   float y = command->GetY();
533   float width = command->GetWidth();
534   float height = command->GetHeight();
535   const uint32_t columns = command->GetColumns();
536   const uint32_t rows = command->GetRows();
537   const uint32_t vertices =
538       columns * rows * kVerticesPerTriangle * kTrianglesPerCell;
539 
540   // Ortho calculation
541   const float frame_width = static_cast<float>(graphics->GetWidth());
542   const float frame_height = static_cast<float>(graphics->GetHeight());
543   x = ((x / frame_width) * 2.0f) - 1.0f;
544   y = ((y / frame_height) * 2.0f) - 1.0f;
545   width = (width / frame_width) * 2.0f;
546   height = (height / frame_height) * 2.0f;
547 
548   std::vector<Value> values(vertices * 2);
549 
550   const float cell_width = width / static_cast<float>(columns);
551   const float cell_height = height / static_cast<float>(rows);
552 
553   for (uint32_t i = 0, c = 0; i < rows; i++) {
554     for (uint32_t j = 0; j < columns; j++, c += 12) {
555       // Calculate corners
556       float x0 = x + cell_width * static_cast<float>(j);
557       float y0 = y + cell_height * static_cast<float>(i);
558       float x1 = x + cell_width * static_cast<float>(j + 1);
559       float y1 = y + cell_height * static_cast<float>(i + 1);
560 
561       // Bottom right
562       values[c + 0].SetDoubleValue(static_cast<double>(x1));
563       values[c + 1].SetDoubleValue(static_cast<double>(y1));
564       // Bottom left
565       values[c + 2].SetDoubleValue(static_cast<double>(x0));
566       values[c + 3].SetDoubleValue(static_cast<double>(y1));
567       // Top left
568       values[c + 4].SetDoubleValue(static_cast<double>(x0));
569       values[c + 5].SetDoubleValue(static_cast<double>(y0));
570       // Bottom right
571       values[c + 6].SetDoubleValue(static_cast<double>(x1));
572       values[c + 7].SetDoubleValue(static_cast<double>(y1));
573       // Top left
574       values[c + 8].SetDoubleValue(static_cast<double>(x0));
575       values[c + 9].SetDoubleValue(static_cast<double>(y0));
576       // Top right
577       values[c + 10].SetDoubleValue(static_cast<double>(x1));
578       values[c + 11].SetDoubleValue(static_cast<double>(y0));
579     }
580   }
581 
582   // |format| is not Format for frame buffer but for vertex buffer.
583   // Since draw rect command contains its vertex information and it
584   // does not include a format of vertex buffer, we can choose any
585   // one that is suitable. We use VK_FORMAT_R32G32_SFLOAT for it.
586   TypeParser parser;
587   auto type = parser.Parse("R32G32_SFLOAT");
588   Format fmt(type.get());
589 
590   auto buf = MakeUnique<Buffer>();
591   buf->SetFormat(&fmt);
592   buf->SetData(std::move(values));
593 
594   auto vertex_buffer = MakeUnique<VertexBuffer>(device_.get());
595   vertex_buffer->SetData(0, buf.get(), InputRate::kVertex, buf->GetFormat(), 0,
596                          buf->GetFormat()->SizeInBytes());
597 
598   DrawArraysCommand draw(command->GetPipeline(), *command->GetPipelineData());
599   draw.SetTopology(Topology::kTriangleList);
600   draw.SetFirstVertexIndex(0);
601   draw.SetVertexCount(vertices);
602   draw.SetInstanceCount(1);
603 
604   Result r = graphics->Draw(&draw, vertex_buffer.get());
605   if (!r.IsSuccess())
606     return r;
607 
608   return {};
609 }
610 
DoDrawArrays(const DrawArraysCommand * command)611 Result EngineVulkan::DoDrawArrays(const DrawArraysCommand* command) {
612   auto& info = pipeline_map_[command->GetPipeline()];
613   if (!info.vk_pipeline)
614     return Result("Vulkan::DrawArrays for Non-Graphics Pipeline");
615 
616   return info.vk_pipeline->AsGraphics()->Draw(command,
617                                               info.vertex_buffer.get());
618 }
619 
DoCompute(const ComputeCommand * command)620 Result EngineVulkan::DoCompute(const ComputeCommand* command) {
621   auto& info = pipeline_map_[command->GetPipeline()];
622   if (info.vk_pipeline->IsGraphics())
623     return Result("Vulkan: Compute called for graphics pipeline.");
624 
625   return info.vk_pipeline->AsCompute()->Compute(
626       command->GetX(), command->GetY(), command->GetZ());
627 }
628 
DoEntryPoint(const EntryPointCommand * command)629 Result EngineVulkan::DoEntryPoint(const EntryPointCommand* command) {
630   auto& info = pipeline_map_[command->GetPipeline()];
631   if (!info.vk_pipeline)
632     return Result("Vulkan::DoEntryPoint no Pipeline exists");
633 
634   VkShaderStageFlagBits stage = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
635   Result r = ToVkShaderStage(command->GetShaderType(), &stage);
636   if (!r.IsSuccess())
637     return r;
638 
639   info.vk_pipeline->SetEntryPointName(stage, command->GetEntryPointName());
640   return {};
641 }
642 
DoPatchParameterVertices(const PatchParameterVerticesCommand * command)643 Result EngineVulkan::DoPatchParameterVertices(
644     const PatchParameterVerticesCommand* command) {
645   auto& info = pipeline_map_[command->GetPipeline()];
646   if (!info.vk_pipeline->IsGraphics())
647     return Result("Vulkan::DoPatchParameterVertices for Non-Graphics Pipeline");
648 
649   info.vk_pipeline->AsGraphics()->SetPatchControlPoints(
650       command->GetControlPointCount());
651   return {};
652 }
653 
DoBuffer(const BufferCommand * cmd)654 Result EngineVulkan::DoBuffer(const BufferCommand* cmd) {
655   if (!device_->IsDescriptorSetInBounds(cmd->GetDescriptorSet())) {
656     return Result(
657         "Vulkan::DoBuffer exceed maxBoundDescriptorSets limit of physical "
658         "device");
659   }
660   if (cmd->GetValues().empty()) {
661     cmd->GetBuffer()->SetSizeInElements(cmd->GetBuffer()->ElementCount());
662   } else {
663     cmd->GetBuffer()->SetDataWithOffset(cmd->GetValues(), cmd->GetOffset());
664   }
665   if (cmd->IsPushConstant()) {
666     auto& info = pipeline_map_[cmd->GetPipeline()];
667     return info.vk_pipeline->AddPushConstantBuffer(cmd->GetBuffer(),
668                                                    cmd->GetOffset());
669   }
670   return {};
671 }
672 
673 }  // namespace vulkan
674 }  // namespace amber
675