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