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