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/graphics_pipeline.h"
16 
17 #include <cassert>
18 #include <cmath>
19 
20 #include "src/command.h"
21 #include "src/make_unique.h"
22 #include "src/vulkan/command_pool.h"
23 #include "src/vulkan/device.h"
24 
25 namespace amber {
26 namespace vulkan {
27 namespace {
28 
29 const VkAttachmentDescription kDefaultAttachmentDesc = {
30     0,                                    /* flags */
31     VK_FORMAT_UNDEFINED,                  /* format */
32     VK_SAMPLE_COUNT_1_BIT,                /* samples */
33     VK_ATTACHMENT_LOAD_OP_LOAD,           /* loadOp */
34     VK_ATTACHMENT_STORE_OP_STORE,         /* storeOp */
35     VK_ATTACHMENT_LOAD_OP_LOAD,           /* stencilLoadOp */
36     VK_ATTACHMENT_STORE_OP_STORE,         /* stencilStoreOp */
37     VK_IMAGE_LAYOUT_UNDEFINED,            /* initialLayout */
38     VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, /* finalLayout */
39 };
40 
41 const VkSampleMask kSampleMask = ~0U;
42 
ToVkTopology(Topology topology)43 VkPrimitiveTopology ToVkTopology(Topology topology) {
44   switch (topology) {
45     case Topology::kPointList:
46       return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
47     case Topology::kLineList:
48       return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
49     case Topology::kLineStrip:
50       return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
51     case Topology::kTriangleList:
52       return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
53     case Topology::kTriangleStrip:
54       return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
55     case Topology::kTriangleFan:
56       return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
57     case Topology::kLineListWithAdjacency:
58       return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY;
59     case Topology::kLineStripWithAdjacency:
60       return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
61     case Topology::kTriangleListWithAdjacency:
62       return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
63     case Topology::kTriangleStripWithAdjacency:
64       return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
65     case Topology::kPatchList:
66       return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
67     default:
68       break;
69   }
70 
71   assert(false && "Vulkan::Unknown topology");
72   return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
73 }
74 
ToVkStencilOp(StencilOp op)75 VkStencilOp ToVkStencilOp(StencilOp op) {
76   switch (op) {
77     case StencilOp::kKeep:
78       return VK_STENCIL_OP_KEEP;
79     case StencilOp::kZero:
80       return VK_STENCIL_OP_ZERO;
81     case StencilOp::kReplace:
82       return VK_STENCIL_OP_REPLACE;
83     case StencilOp::kIncrementAndClamp:
84       return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
85     case StencilOp::kDecrementAndClamp:
86       return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
87     case StencilOp::kInvert:
88       return VK_STENCIL_OP_INVERT;
89     case StencilOp::kIncrementAndWrap:
90       return VK_STENCIL_OP_INCREMENT_AND_WRAP;
91     case StencilOp::kDecrementAndWrap:
92       return VK_STENCIL_OP_DECREMENT_AND_WRAP;
93     case StencilOp::kUnknown:
94       break;
95   }
96   assert(false && "Vulkan::Unknown StencilOp");
97   return VK_STENCIL_OP_KEEP;
98 }
99 
ToVkCompareOp(CompareOp op)100 VkCompareOp ToVkCompareOp(CompareOp op) {
101   switch (op) {
102     case CompareOp::kNever:
103       return VK_COMPARE_OP_NEVER;
104     case CompareOp::kLess:
105       return VK_COMPARE_OP_LESS;
106     case CompareOp::kEqual:
107       return VK_COMPARE_OP_EQUAL;
108     case CompareOp::kLessOrEqual:
109       return VK_COMPARE_OP_LESS_OR_EQUAL;
110     case CompareOp::kGreater:
111       return VK_COMPARE_OP_GREATER;
112     case CompareOp::kNotEqual:
113       return VK_COMPARE_OP_NOT_EQUAL;
114     case CompareOp::kGreaterOrEqual:
115       return VK_COMPARE_OP_GREATER_OR_EQUAL;
116     case CompareOp::kAlways:
117       return VK_COMPARE_OP_ALWAYS;
118     case CompareOp::kUnknown:
119       break;
120   }
121   assert(false && "Vulkan::Unknown CompareOp");
122   return VK_COMPARE_OP_NEVER;
123 }
124 
ToVkPolygonMode(PolygonMode mode)125 VkPolygonMode ToVkPolygonMode(PolygonMode mode) {
126   switch (mode) {
127     case PolygonMode::kFill:
128       return VK_POLYGON_MODE_FILL;
129     case PolygonMode::kLine:
130       return VK_POLYGON_MODE_LINE;
131     case PolygonMode::kPoint:
132       return VK_POLYGON_MODE_POINT;
133   }
134   assert(false && "Vulkan::Unknown PolygonMode");
135   return VK_POLYGON_MODE_FILL;
136 }
137 
ToVkCullMode(CullMode mode)138 VkCullModeFlags ToVkCullMode(CullMode mode) {
139   switch (mode) {
140     case CullMode::kNone:
141       return VK_CULL_MODE_NONE;
142     case CullMode::kFront:
143       return VK_CULL_MODE_FRONT_BIT;
144     case CullMode::kBack:
145       return VK_CULL_MODE_BACK_BIT;
146     case CullMode::kFrontAndBack:
147       return VK_CULL_MODE_FRONT_AND_BACK;
148   }
149   assert(false && "Vulkan::Unknown CullMode");
150   return VK_CULL_MODE_NONE;
151 }
152 
ToVkFrontFace(FrontFace front_face)153 VkFrontFace ToVkFrontFace(FrontFace front_face) {
154   return front_face == FrontFace::kClockwise ? VK_FRONT_FACE_CLOCKWISE
155                                              : VK_FRONT_FACE_COUNTER_CLOCKWISE;
156 }
157 
ToVkLogicOp(LogicOp op)158 VkLogicOp ToVkLogicOp(LogicOp op) {
159   switch (op) {
160     case LogicOp::kClear:
161       return VK_LOGIC_OP_CLEAR;
162     case LogicOp::kAnd:
163       return VK_LOGIC_OP_AND;
164     case LogicOp::kAndReverse:
165       return VK_LOGIC_OP_AND_REVERSE;
166     case LogicOp::kCopy:
167       return VK_LOGIC_OP_COPY;
168     case LogicOp::kAndInverted:
169       return VK_LOGIC_OP_AND_INVERTED;
170     case LogicOp::kNoOp:
171       return VK_LOGIC_OP_NO_OP;
172     case LogicOp::kXor:
173       return VK_LOGIC_OP_XOR;
174     case LogicOp::kOr:
175       return VK_LOGIC_OP_OR;
176     case LogicOp::kNor:
177       return VK_LOGIC_OP_NOR;
178     case LogicOp::kEquivalent:
179       return VK_LOGIC_OP_EQUIVALENT;
180     case LogicOp::kInvert:
181       return VK_LOGIC_OP_INVERT;
182     case LogicOp::kOrReverse:
183       return VK_LOGIC_OP_OR_REVERSE;
184     case LogicOp::kCopyInverted:
185       return VK_LOGIC_OP_COPY_INVERTED;
186     case LogicOp::kOrInverted:
187       return VK_LOGIC_OP_OR_INVERTED;
188     case LogicOp::kNand:
189       return VK_LOGIC_OP_NAND;
190     case LogicOp::kSet:
191       return VK_LOGIC_OP_SET;
192   }
193   assert(false && "Vulkan::Unknown LogicOp");
194   return VK_LOGIC_OP_CLEAR;
195 }
196 
ToVkBlendFactor(BlendFactor factor)197 VkBlendFactor ToVkBlendFactor(BlendFactor factor) {
198   switch (factor) {
199     case BlendFactor::kZero:
200       return VK_BLEND_FACTOR_ZERO;
201     case BlendFactor::kOne:
202       return VK_BLEND_FACTOR_ONE;
203     case BlendFactor::kSrcColor:
204       return VK_BLEND_FACTOR_SRC_COLOR;
205     case BlendFactor::kOneMinusSrcColor:
206       return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
207     case BlendFactor::kDstColor:
208       return VK_BLEND_FACTOR_DST_COLOR;
209     case BlendFactor::kOneMinusDstColor:
210       return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
211     case BlendFactor::kSrcAlpha:
212       return VK_BLEND_FACTOR_SRC_ALPHA;
213     case BlendFactor::kOneMinusSrcAlpha:
214       return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
215     case BlendFactor::kDstAlpha:
216       return VK_BLEND_FACTOR_DST_ALPHA;
217     case BlendFactor::kOneMinusDstAlpha:
218       return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
219     case BlendFactor::kConstantColor:
220       return VK_BLEND_FACTOR_CONSTANT_COLOR;
221     case BlendFactor::kOneMinusConstantColor:
222       return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
223     case BlendFactor::kConstantAlpha:
224       return VK_BLEND_FACTOR_CONSTANT_ALPHA;
225     case BlendFactor::kOneMinusConstantAlpha:
226       return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
227     case BlendFactor::kSrcAlphaSaturate:
228       return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
229     case BlendFactor::kSrc1Color:
230       return VK_BLEND_FACTOR_SRC1_COLOR;
231     case BlendFactor::kOneMinusSrc1Color:
232       return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
233     case BlendFactor::kSrc1Alpha:
234       return VK_BLEND_FACTOR_SRC1_ALPHA;
235     case BlendFactor::kOneMinusSrc1Alpha:
236       return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
237     case BlendFactor::kUnknown:
238       break;
239   }
240   assert(false && "Vulkan::Unknown BlendFactor");
241   return VK_BLEND_FACTOR_ZERO;
242 }
243 
ToVkBlendOp(BlendOp op)244 VkBlendOp ToVkBlendOp(BlendOp op) {
245   switch (op) {
246     case BlendOp::kAdd:
247       return VK_BLEND_OP_ADD;
248     case BlendOp::kSubtract:
249       return VK_BLEND_OP_SUBTRACT;
250     case BlendOp::kReverseSubtract:
251       return VK_BLEND_OP_REVERSE_SUBTRACT;
252     case BlendOp::kMin:
253       return VK_BLEND_OP_MIN;
254     case BlendOp::kMax:
255       return VK_BLEND_OP_MAX;
256     case BlendOp::kZero:
257       return VK_BLEND_OP_ZERO_EXT;
258     case BlendOp::kSrc:
259       return VK_BLEND_OP_SRC_EXT;
260     case BlendOp::kDst:
261       return VK_BLEND_OP_DST_EXT;
262     case BlendOp::kSrcOver:
263       return VK_BLEND_OP_SRC_OVER_EXT;
264     case BlendOp::kDstOver:
265       return VK_BLEND_OP_DST_OVER_EXT;
266     case BlendOp::kSrcIn:
267       return VK_BLEND_OP_SRC_IN_EXT;
268     case BlendOp::kDstIn:
269       return VK_BLEND_OP_DST_IN_EXT;
270     case BlendOp::kSrcOut:
271       return VK_BLEND_OP_SRC_OUT_EXT;
272     case BlendOp::kDstOut:
273       return VK_BLEND_OP_DST_OUT_EXT;
274     case BlendOp::kSrcAtop:
275       return VK_BLEND_OP_SRC_ATOP_EXT;
276     case BlendOp::kDstAtop:
277       return VK_BLEND_OP_DST_ATOP_EXT;
278     case BlendOp::kXor:
279       return VK_BLEND_OP_XOR_EXT;
280     case BlendOp::kMultiply:
281       return VK_BLEND_OP_MULTIPLY_EXT;
282     case BlendOp::kScreen:
283       return VK_BLEND_OP_SCREEN_EXT;
284     case BlendOp::kOverlay:
285       return VK_BLEND_OP_OVERLAY_EXT;
286     case BlendOp::kDarken:
287       return VK_BLEND_OP_DARKEN_EXT;
288     case BlendOp::kLighten:
289       return VK_BLEND_OP_LIGHTEN_EXT;
290     case BlendOp::kColorDodge:
291       return VK_BLEND_OP_COLORDODGE_EXT;
292     case BlendOp::kColorBurn:
293       return VK_BLEND_OP_COLORBURN_EXT;
294     case BlendOp::kHardLight:
295       return VK_BLEND_OP_HARDLIGHT_EXT;
296     case BlendOp::kSoftLight:
297       return VK_BLEND_OP_SOFTLIGHT_EXT;
298     case BlendOp::kDifference:
299       return VK_BLEND_OP_DIFFERENCE_EXT;
300     case BlendOp::kExclusion:
301       return VK_BLEND_OP_EXCLUSION_EXT;
302     case BlendOp::kInvert:
303       return VK_BLEND_OP_INVERT_EXT;
304     case BlendOp::kInvertRGB:
305       return VK_BLEND_OP_INVERT_RGB_EXT;
306     case BlendOp::kLinearDodge:
307       return VK_BLEND_OP_LINEARDODGE_EXT;
308     case BlendOp::kLinearBurn:
309       return VK_BLEND_OP_LINEARBURN_EXT;
310     case BlendOp::kVividLight:
311       return VK_BLEND_OP_VIVIDLIGHT_EXT;
312     case BlendOp::kLinearLight:
313       return VK_BLEND_OP_LINEARLIGHT_EXT;
314     case BlendOp::kPinLight:
315       return VK_BLEND_OP_PINLIGHT_EXT;
316     case BlendOp::kHardMix:
317       return VK_BLEND_OP_HARDMIX_EXT;
318     case BlendOp::kHslHue:
319       return VK_BLEND_OP_HSL_HUE_EXT;
320     case BlendOp::kHslSaturation:
321       return VK_BLEND_OP_HSL_SATURATION_EXT;
322     case BlendOp::kHslColor:
323       return VK_BLEND_OP_HSL_COLOR_EXT;
324     case BlendOp::kHslLuminosity:
325       return VK_BLEND_OP_HSL_LUMINOSITY_EXT;
326     case BlendOp::kPlus:
327       return VK_BLEND_OP_PLUS_EXT;
328     case BlendOp::kPlusClamped:
329       return VK_BLEND_OP_PLUS_CLAMPED_EXT;
330     case BlendOp::kPlusClampedAlpha:
331       return VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT;
332     case BlendOp::kPlusDarker:
333       return VK_BLEND_OP_PLUS_DARKER_EXT;
334     case BlendOp::kMinus:
335       return VK_BLEND_OP_MINUS_EXT;
336     case BlendOp::kMinusClamped:
337       return VK_BLEND_OP_MINUS_CLAMPED_EXT;
338     case BlendOp::kContrast:
339       return VK_BLEND_OP_CONTRAST_EXT;
340     case BlendOp::kInvertOvg:
341       return VK_BLEND_OP_INVERT_OVG_EXT;
342     case BlendOp::kRed:
343       return VK_BLEND_OP_RED_EXT;
344     case BlendOp::kGreen:
345       return VK_BLEND_OP_GREEN_EXT;
346     case BlendOp::kBlue:
347       return VK_BLEND_OP_BLUE_EXT;
348     case BlendOp::kUnknown:
349       break;
350   }
351   assert(false && "Vulkan::Unknown BlendOp");
352   return VK_BLEND_OP_ADD;
353 }
354 
355 class RenderPassGuard {
356  public:
RenderPassGuard(GraphicsPipeline * pipeline)357   explicit RenderPassGuard(GraphicsPipeline* pipeline) : pipeline_(pipeline) {
358     auto* frame = pipeline_->GetFrameBuffer();
359     auto* cmd = pipeline_->GetCommandBuffer();
360     frame->ChangeFrameToDrawLayout(cmd);
361 
362     VkRenderPassBeginInfo render_begin_info = VkRenderPassBeginInfo();
363     render_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
364     render_begin_info.renderPass = pipeline_->GetVkRenderPass();
365     render_begin_info.framebuffer = frame->GetVkFrameBuffer();
366     render_begin_info.renderArea = {{0, 0},
367                                     {frame->GetWidth(), frame->GetHeight()}};
368     pipeline_->GetDevice()->GetPtrs()->vkCmdBeginRenderPass(
369         cmd->GetVkCommandBuffer(), &render_begin_info,
370         VK_SUBPASS_CONTENTS_INLINE);
371   }
372 
~RenderPassGuard()373   ~RenderPassGuard() {
374     auto* cmd = pipeline_->GetCommandBuffer();
375 
376     pipeline_->GetDevice()->GetPtrs()->vkCmdEndRenderPass(
377         cmd->GetVkCommandBuffer());
378 
379     auto* frame = pipeline_->GetFrameBuffer();
380     frame->ChangeFrameToProbeLayout(cmd);
381   }
382 
383  private:
384   GraphicsPipeline* pipeline_;
385 };
386 
387 }  // namespace
388 
GraphicsPipeline(Device * device,const std::vector<amber::Pipeline::BufferInfo> & color_buffers,amber::Pipeline::BufferInfo depth_stencil_buffer,const std::vector<amber::Pipeline::BufferInfo> & resolve_targets,uint32_t fence_timeout_ms,bool pipeline_runtime_layer_enabled,const std::vector<VkPipelineShaderStageCreateInfo> & shader_stage_info)389 GraphicsPipeline::GraphicsPipeline(
390     Device* device,
391     const std::vector<amber::Pipeline::BufferInfo>& color_buffers,
392     amber::Pipeline::BufferInfo depth_stencil_buffer,
393     const std::vector<amber::Pipeline::BufferInfo>& resolve_targets,
394     uint32_t fence_timeout_ms,
395     bool pipeline_runtime_layer_enabled,
396     const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info)
397     : Pipeline(PipelineType::kGraphics,
398                device,
399                fence_timeout_ms,
400                pipeline_runtime_layer_enabled,
401                shader_stage_info),
402       depth_stencil_buffer_(depth_stencil_buffer) {
403   for (const auto& info : color_buffers)
404     color_buffers_.push_back(&info);
405   for (const auto& info : resolve_targets)
406     resolve_targets_.push_back(&info);
407 }
408 
~GraphicsPipeline()409 GraphicsPipeline::~GraphicsPipeline() {
410   if (render_pass_) {
411     device_->GetPtrs()->vkDestroyRenderPass(device_->GetVkDevice(),
412                                             render_pass_, nullptr);
413   }
414 }
415 
CreateRenderPass()416 Result GraphicsPipeline::CreateRenderPass() {
417   VkSubpassDescription subpass_desc = VkSubpassDescription();
418   subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
419 
420   std::vector<VkAttachmentDescription> attachment_desc;
421 
422   std::vector<VkAttachmentReference> color_refer;
423   VkAttachmentReference depth_refer = VkAttachmentReference();
424   std::vector<VkAttachmentReference> resolve_refer;
425 
426   for (const auto* info : color_buffers_) {
427     attachment_desc.push_back(kDefaultAttachmentDesc);
428     attachment_desc.back().format =
429         device_->GetVkFormat(*info->buffer->GetFormat());
430     attachment_desc.back().initialLayout =
431         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
432     attachment_desc.back().finalLayout =
433         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
434     attachment_desc.back().samples =
435         static_cast<VkSampleCountFlagBits>(info->buffer->GetSamples());
436 
437     VkAttachmentReference ref = VkAttachmentReference();
438     ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
439     ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
440     color_refer.push_back(ref);
441   }
442   subpass_desc.colorAttachmentCount = static_cast<uint32_t>(color_refer.size());
443   subpass_desc.pColorAttachments = color_refer.data();
444 
445   if (depth_stencil_buffer_.buffer &&
446       depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
447     attachment_desc.push_back(kDefaultAttachmentDesc);
448     attachment_desc.back().format =
449         device_->GetVkFormat(*depth_stencil_buffer_.buffer->GetFormat());
450     attachment_desc.back().initialLayout =
451         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
452     attachment_desc.back().finalLayout =
453         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
454 
455     depth_refer.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
456     depth_refer.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
457 
458     subpass_desc.pDepthStencilAttachment = &depth_refer;
459   }
460 
461   for (const auto* info : resolve_targets_) {
462     attachment_desc.push_back(kDefaultAttachmentDesc);
463     attachment_desc.back().format =
464         device_->GetVkFormat(*info->buffer->GetFormat());
465     attachment_desc.back().initialLayout =
466         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
467     attachment_desc.back().finalLayout =
468         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
469 
470     VkAttachmentReference ref = VkAttachmentReference();
471     ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
472     ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
473     resolve_refer.push_back(ref);
474   }
475 
476   subpass_desc.pResolveAttachments = resolve_refer.data();
477 
478   VkRenderPassCreateInfo render_pass_info = VkRenderPassCreateInfo();
479   render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
480   render_pass_info.attachmentCount =
481       static_cast<uint32_t>(attachment_desc.size());
482   render_pass_info.pAttachments = attachment_desc.data();
483   render_pass_info.subpassCount = 1;
484   render_pass_info.pSubpasses = &subpass_desc;
485 
486   if (device_->GetPtrs()->vkCreateRenderPass(device_->GetVkDevice(),
487                                              &render_pass_info, nullptr,
488                                              &render_pass_) != VK_SUCCESS) {
489     return Result("Vulkan::Calling vkCreateRenderPass Fail");
490   }
491 
492   return {};
493 }
494 
495 VkPipelineDepthStencilStateCreateInfo
GetVkPipelineDepthStencilInfo(const PipelineData * pipeline_data)496 GraphicsPipeline::GetVkPipelineDepthStencilInfo(
497     const PipelineData* pipeline_data) {
498   VkPipelineDepthStencilStateCreateInfo depthstencil_info =
499       VkPipelineDepthStencilStateCreateInfo();
500   depthstencil_info.sType =
501       VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
502 
503   depthstencil_info.depthTestEnable = pipeline_data->GetEnableDepthTest();
504   depthstencil_info.depthWriteEnable = pipeline_data->GetEnableDepthWrite();
505   depthstencil_info.depthCompareOp =
506       ToVkCompareOp(pipeline_data->GetDepthCompareOp());
507   depthstencil_info.depthBoundsTestEnable =
508       pipeline_data->GetEnableDepthBoundsTest();
509   depthstencil_info.stencilTestEnable = pipeline_data->GetEnableStencilTest();
510 
511   depthstencil_info.front.failOp =
512       ToVkStencilOp(pipeline_data->GetFrontFailOp());
513   depthstencil_info.front.passOp =
514       ToVkStencilOp(pipeline_data->GetFrontPassOp());
515   depthstencil_info.front.depthFailOp =
516       ToVkStencilOp(pipeline_data->GetFrontDepthFailOp());
517   depthstencil_info.front.compareOp =
518       ToVkCompareOp(pipeline_data->GetFrontCompareOp());
519   depthstencil_info.front.compareMask = pipeline_data->GetFrontCompareMask();
520   depthstencil_info.front.writeMask = pipeline_data->GetFrontWriteMask();
521   depthstencil_info.front.reference = pipeline_data->GetFrontReference();
522 
523   depthstencil_info.back.failOp = ToVkStencilOp(pipeline_data->GetBackFailOp());
524   depthstencil_info.back.passOp = ToVkStencilOp(pipeline_data->GetBackPassOp());
525   depthstencil_info.back.depthFailOp =
526       ToVkStencilOp(pipeline_data->GetBackDepthFailOp());
527   depthstencil_info.back.compareOp =
528       ToVkCompareOp(pipeline_data->GetBackCompareOp());
529   depthstencil_info.back.compareMask = pipeline_data->GetBackCompareMask();
530   depthstencil_info.back.writeMask = pipeline_data->GetBackWriteMask();
531   depthstencil_info.back.reference = pipeline_data->GetBackReference();
532 
533   depthstencil_info.minDepthBounds = pipeline_data->GetMinDepthBounds();
534   depthstencil_info.maxDepthBounds = pipeline_data->GetMaxDepthBounds();
535 
536   return depthstencil_info;
537 }
538 
539 std::vector<VkPipelineColorBlendAttachmentState>
GetVkPipelineColorBlendAttachmentState(const PipelineData * pipeline_data)540 GraphicsPipeline::GetVkPipelineColorBlendAttachmentState(
541     const PipelineData* pipeline_data) {
542   std::vector<VkPipelineColorBlendAttachmentState> states;
543 
544   for (size_t i = 0; i < color_buffers_.size(); ++i) {
545     VkPipelineColorBlendAttachmentState colorblend_attachment =
546         VkPipelineColorBlendAttachmentState();
547     colorblend_attachment.blendEnable = pipeline_data->GetEnableBlend();
548     colorblend_attachment.srcColorBlendFactor =
549         ToVkBlendFactor(pipeline_data->GetSrcColorBlendFactor());
550     colorblend_attachment.dstColorBlendFactor =
551         ToVkBlendFactor(pipeline_data->GetDstColorBlendFactor());
552     colorblend_attachment.colorBlendOp =
553         ToVkBlendOp(pipeline_data->GetColorBlendOp());
554     colorblend_attachment.srcAlphaBlendFactor =
555         ToVkBlendFactor(pipeline_data->GetSrcAlphaBlendFactor());
556     colorblend_attachment.dstAlphaBlendFactor =
557         ToVkBlendFactor(pipeline_data->GetDstAlphaBlendFactor());
558     colorblend_attachment.alphaBlendOp =
559         ToVkBlendOp(pipeline_data->GetAlphaBlendOp());
560     colorblend_attachment.colorWriteMask = pipeline_data->GetColorWriteMask();
561     states.push_back(colorblend_attachment);
562   }
563   return states;
564 }
565 
CreateVkGraphicsPipeline(const PipelineData * pipeline_data,VkPrimitiveTopology topology,const VertexBuffer * vertex_buffer,const VkPipelineLayout & pipeline_layout,VkPipeline * pipeline)566 Result GraphicsPipeline::CreateVkGraphicsPipeline(
567     const PipelineData* pipeline_data,
568     VkPrimitiveTopology topology,
569     const VertexBuffer* vertex_buffer,
570     const VkPipelineLayout& pipeline_layout,
571     VkPipeline* pipeline) {
572   if (!pipeline_data) {
573     return Result(
574         "Vulkan: GraphicsPipeline::CreateVkGraphicsPipeline PipelineData is "
575         "null");
576   }
577 
578   std::vector<VkVertexInputBindingDescription> vertex_bindings;
579   std::vector<VkVertexInputAttributeDescription> vertex_attribs;
580   if (vertex_buffer != nullptr) {
581     vertex_bindings = vertex_buffer->GetVkVertexInputBinding();
582     vertex_attribs = vertex_buffer->GetVkVertexInputAttr();
583   }
584 
585   VkPipelineVertexInputStateCreateInfo vertex_input_info =
586       VkPipelineVertexInputStateCreateInfo();
587   vertex_input_info.sType =
588       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
589   vertex_input_info.vertexBindingDescriptionCount =
590       static_cast<uint32_t>(vertex_bindings.size());
591   vertex_input_info.pVertexBindingDescriptions =
592       vertex_bindings.empty() ? nullptr : vertex_bindings.data();
593   vertex_input_info.vertexAttributeDescriptionCount =
594       static_cast<uint32_t>(vertex_attribs.size());
595   vertex_input_info.pVertexAttributeDescriptions =
596       vertex_attribs.empty() ? nullptr : vertex_attribs.data();
597 
598   VkPipelineInputAssemblyStateCreateInfo input_assembly_info =
599       VkPipelineInputAssemblyStateCreateInfo();
600   input_assembly_info.sType =
601       VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
602   // TODO(jaebaek): Handle the given index if exists.
603   input_assembly_info.topology = topology;
604   input_assembly_info.primitiveRestartEnable =
605       pipeline_data->GetEnablePrimitiveRestart();
606 
607   VkViewport viewport = {
608       0, 0, static_cast<float>(frame_width_), static_cast<float>(frame_height_),
609       0, 1};
610 
611   if (pipeline_data->HasViewportData()) {
612     Viewport vp = pipeline_data->GetViewport();
613     viewport.x = vp.x;
614     viewport.y = vp.y;
615     viewport.width = vp.w;
616     viewport.height = vp.h;
617     viewport.minDepth = vp.mind;
618     viewport.maxDepth = vp.maxd;
619   }
620 
621   VkRect2D scissor = {{0, 0}, {frame_width_, frame_height_}};
622 
623   VkPipelineViewportStateCreateInfo viewport_info =
624       VkPipelineViewportStateCreateInfo();
625   viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
626   viewport_info.viewportCount = 1;
627   viewport_info.pViewports = &viewport;
628   viewport_info.scissorCount = 1;
629   viewport_info.pScissors = &scissor;
630 
631   auto shader_stage_info = GetVkShaderStageInfo();
632   bool is_tessellation_needed = false;
633   for (auto& info : shader_stage_info) {
634     info.pName = GetEntryPointName(info.stage);
635     if (info.stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
636         info.stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
637       is_tessellation_needed = true;
638     }
639   }
640 
641   VkPipelineMultisampleStateCreateInfo multisampleInfo = {
642       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, /* sType */
643       nullptr,                                                  /* pNext */
644       0,                                                        /* flags */
645       kDefaultAttachmentDesc.samples, /* rasterizationSamples */
646       VK_FALSE,                       /* sampleShadingEnable */
647       0,                              /* minSampleShading */
648       &kSampleMask,                   /* pSampleMask */
649       VK_FALSE,                       /* alphaToCoverageEnable */
650       VK_FALSE,                       /* alphaToOneEnable */
651   };
652 
653   // Search for multisampled color buffers and adjust the rasterization samples
654   // to match.
655   for (const auto& cb : color_buffers_) {
656     uint32_t samples = cb->buffer->GetSamples();
657     assert(static_cast<VkSampleCountFlagBits>(samples) >=
658            multisampleInfo.rasterizationSamples);
659     multisampleInfo.rasterizationSamples =
660         static_cast<VkSampleCountFlagBits>(samples);
661   }
662 
663   VkGraphicsPipelineCreateInfo pipeline_info = VkGraphicsPipelineCreateInfo();
664   pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
665   pipeline_info.stageCount = static_cast<uint32_t>(shader_stage_info.size());
666   pipeline_info.pStages = shader_stage_info.data();
667   pipeline_info.pVertexInputState = &vertex_input_info;
668   pipeline_info.pInputAssemblyState = &input_assembly_info;
669   pipeline_info.pViewportState = &viewport_info;
670   pipeline_info.pMultisampleState = &multisampleInfo;
671 
672   VkPipelineRasterizationStateCreateInfo rasterization_info =
673       VkPipelineRasterizationStateCreateInfo();
674   rasterization_info.sType =
675       VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
676   rasterization_info.depthClampEnable = pipeline_data->GetEnableDepthClamp();
677   rasterization_info.rasterizerDiscardEnable =
678       pipeline_data->GetEnableRasterizerDiscard();
679   rasterization_info.polygonMode =
680       ToVkPolygonMode(pipeline_data->GetPolygonMode());
681   rasterization_info.cullMode = ToVkCullMode(pipeline_data->GetCullMode());
682   rasterization_info.frontFace = ToVkFrontFace(pipeline_data->GetFrontFace());
683   rasterization_info.depthBiasEnable = pipeline_data->GetEnableDepthBias();
684   rasterization_info.depthBiasConstantFactor =
685       pipeline_data->GetDepthBiasConstantFactor();
686   rasterization_info.depthBiasClamp = pipeline_data->GetDepthBiasClamp();
687   rasterization_info.depthBiasSlopeFactor =
688       pipeline_data->GetDepthBiasSlopeFactor();
689   rasterization_info.lineWidth = pipeline_data->GetLineWidth();
690   pipeline_info.pRasterizationState = &rasterization_info;
691 
692   VkPipelineTessellationStateCreateInfo tess_info =
693       VkPipelineTessellationStateCreateInfo();
694   if (is_tessellation_needed) {
695     tess_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
696     tess_info.patchControlPoints = patch_control_points_;
697     pipeline_info.pTessellationState = &tess_info;
698   }
699 
700   VkPipelineDepthStencilStateCreateInfo depthstencil_info;
701   if (depth_stencil_buffer_.buffer &&
702       depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
703     depthstencil_info = GetVkPipelineDepthStencilInfo(pipeline_data);
704     pipeline_info.pDepthStencilState = &depthstencil_info;
705   }
706 
707   VkPipelineColorBlendStateCreateInfo colorblend_info =
708       VkPipelineColorBlendStateCreateInfo();
709 
710   auto colorblend_attachment =
711       GetVkPipelineColorBlendAttachmentState(pipeline_data);
712 
713   colorblend_info.sType =
714       VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
715   colorblend_info.logicOpEnable = pipeline_data->GetEnableLogicOp();
716   colorblend_info.logicOp = ToVkLogicOp(pipeline_data->GetLogicOp());
717   colorblend_info.attachmentCount =
718       static_cast<uint32_t>(colorblend_attachment.size());
719   colorblend_info.pAttachments = colorblend_attachment.data();
720   pipeline_info.pColorBlendState = &colorblend_info;
721 
722   pipeline_info.layout = pipeline_layout;
723   pipeline_info.renderPass = render_pass_;
724   pipeline_info.subpass = 0;
725 
726   if (device_->GetPtrs()->vkCreateGraphicsPipelines(
727           device_->GetVkDevice(), VK_NULL_HANDLE, 1, &pipeline_info, nullptr,
728           pipeline) != VK_SUCCESS) {
729     return Result("Vulkan::Calling vkCreateGraphicsPipelines Fail");
730   }
731 
732   return {};
733 }
734 
Initialize(uint32_t width,uint32_t height,CommandPool * pool)735 Result GraphicsPipeline::Initialize(uint32_t width,
736                                     uint32_t height,
737                                     CommandPool* pool) {
738   Result r = Pipeline::Initialize(pool);
739   if (!r.IsSuccess())
740     return r;
741 
742   r = CreateRenderPass();
743   if (!r.IsSuccess())
744     return r;
745 
746   frame_ =
747       MakeUnique<FrameBuffer>(device_, color_buffers_, depth_stencil_buffer_,
748                               resolve_targets_, width, height);
749   r = frame_->Initialize(render_pass_);
750   if (!r.IsSuccess())
751     return r;
752 
753   frame_width_ = width;
754   frame_height_ = height;
755 
756   return {};
757 }
758 
SendVertexBufferDataIfNeeded(VertexBuffer * vertex_buffer)759 Result GraphicsPipeline::SendVertexBufferDataIfNeeded(
760     VertexBuffer* vertex_buffer) {
761   if (!vertex_buffer || vertex_buffer->VertexDataSent())
762     return {};
763   return vertex_buffer->SendVertexData(command_.get());
764 }
765 
SetIndexBuffer(Buffer * buffer)766 Result GraphicsPipeline::SetIndexBuffer(Buffer* buffer) {
767   if (index_buffer_) {
768     return Result(
769         "GraphicsPipeline::SetIndexBuffer must be called once when "
770         "index_buffer_ is created");
771   }
772 
773   index_buffer_ = MakeUnique<IndexBuffer>(device_);
774 
775   CommandBufferGuard guard(GetCommandBuffer());
776   if (!guard.IsRecording())
777     return guard.GetResult();
778 
779   Result r = index_buffer_->SendIndexData(command_.get(), buffer);
780   if (!r.IsSuccess())
781     return r;
782 
783   return guard.Submit(GetFenceTimeout(), GetPipelineRuntimeLayerEnabled());
784 }
785 
SetClearColor(float r,float g,float b,float a)786 Result GraphicsPipeline::SetClearColor(float r, float g, float b, float a) {
787   clear_color_r_ = r;
788   clear_color_g_ = g;
789   clear_color_b_ = b;
790   clear_color_a_ = a;
791   return {};
792 }
793 
SetClearStencil(uint32_t stencil)794 Result GraphicsPipeline::SetClearStencil(uint32_t stencil) {
795   if (!depth_stencil_buffer_.buffer ||
796       !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
797     return Result(
798         "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer "
799         "Exists");
800   }
801 
802   clear_stencil_ = stencil;
803   return {};
804 }
805 
SetClearDepth(float depth)806 Result GraphicsPipeline::SetClearDepth(float depth) {
807   if (!depth_stencil_buffer_.buffer ||
808       !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
809     return Result(
810         "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer "
811         "Exists");
812   }
813 
814   clear_depth_ = depth;
815   return {};
816 }
817 
Clear()818 Result GraphicsPipeline::Clear() {
819   VkClearValue colour_clear;
820   colour_clear.color = {
821       {clear_color_r_, clear_color_g_, clear_color_b_, clear_color_a_}};
822 
823   CommandBufferGuard cmd_buf_guard(GetCommandBuffer());
824   if (!cmd_buf_guard.IsRecording())
825     return cmd_buf_guard.GetResult();
826 
827   frame_->ChangeFrameToWriteLayout(GetCommandBuffer());
828   frame_->CopyBuffersToImages();
829   frame_->TransferImagesToDevice(GetCommandBuffer());
830 
831   {
832     RenderPassGuard render_pass_guard(this);
833 
834     std::vector<VkClearAttachment> clears;
835     for (size_t i = 0; i < color_buffers_.size(); ++i) {
836       VkClearAttachment clear_attachment = VkClearAttachment();
837       clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
838       clear_attachment.colorAttachment = static_cast<uint32_t>(i);
839       clear_attachment.clearValue = colour_clear;
840 
841       clears.push_back(clear_attachment);
842     }
843 
844     if (depth_stencil_buffer_.buffer &&
845         depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
846       VkClearValue depth_stencil_clear;
847       depth_stencil_clear.depthStencil = {clear_depth_, clear_stencil_};
848 
849       VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
850       if (depth_stencil_buffer_.buffer->GetFormat()->HasStencilComponent())
851         aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
852 
853       VkClearAttachment clear_attachment = VkClearAttachment();
854       clear_attachment.aspectMask = aspect;
855       clear_attachment.colorAttachment =
856           static_cast<uint32_t>(color_buffers_.size());
857       clear_attachment.clearValue = depth_stencil_clear;
858 
859       clears.push_back(clear_attachment);
860     }
861 
862     VkClearRect clear_rect;
863     clear_rect.rect = {{0, 0}, {frame_width_, frame_height_}};
864     clear_rect.baseArrayLayer = 0;
865     clear_rect.layerCount = 1;
866 
867     device_->GetPtrs()->vkCmdClearAttachments(
868         command_->GetVkCommandBuffer(), static_cast<uint32_t>(clears.size()),
869         clears.data(), 1, &clear_rect);
870   }
871 
872   frame_->TransferImagesToHost(command_.get());
873 
874   Result r = cmd_buf_guard.Submit(GetFenceTimeout(),
875                                   GetPipelineRuntimeLayerEnabled());
876   if (!r.IsSuccess())
877     return r;
878 
879   frame_->CopyImagesToBuffers();
880   return {};
881 }
882 
Draw(const DrawArraysCommand * command,VertexBuffer * vertex_buffer)883 Result GraphicsPipeline::Draw(const DrawArraysCommand* command,
884                               VertexBuffer* vertex_buffer) {
885   Result r = SendDescriptorDataToDeviceIfNeeded();
886   if (!r.IsSuccess())
887     return r;
888 
889   VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
890   r = CreateVkPipelineLayout(&pipeline_layout);
891   if (!r.IsSuccess())
892     return r;
893 
894   VkPipeline pipeline = VK_NULL_HANDLE;
895   r = CreateVkGraphicsPipeline(command->GetPipelineData(),
896                                ToVkTopology(command->GetTopology()),
897                                vertex_buffer, pipeline_layout, &pipeline);
898   if (!r.IsSuccess())
899     return r;
900 
901   // Note that a command updating a descriptor set and a command using
902   // it must be submitted separately, because using a descriptor set
903   // while updating it is not safe.
904   UpdateDescriptorSetsIfNeeded();
905 
906   {
907     CommandBufferGuard cmd_buf_guard(GetCommandBuffer());
908     if (!cmd_buf_guard.IsRecording())
909       return cmd_buf_guard.GetResult();
910 
911     r = SendVertexBufferDataIfNeeded(vertex_buffer);
912     if (!r.IsSuccess())
913       return r;
914 
915     frame_->ChangeFrameToWriteLayout(GetCommandBuffer());
916     frame_->CopyBuffersToImages();
917     frame_->TransferImagesToDevice(GetCommandBuffer());
918 
919     {
920       RenderPassGuard render_pass_guard(this);
921 
922       BindVkDescriptorSets(pipeline_layout);
923 
924       r = RecordPushConstant(pipeline_layout);
925       if (!r.IsSuccess())
926         return r;
927 
928       device_->GetPtrs()->vkCmdBindPipeline(command_->GetVkCommandBuffer(),
929                                             VK_PIPELINE_BIND_POINT_GRAPHICS,
930                                             pipeline);
931 
932       if (vertex_buffer != nullptr)
933         vertex_buffer->BindToCommandBuffer(command_.get());
934 
935       if (command->IsIndexed()) {
936         if (!index_buffer_)
937           return Result("Vulkan: Draw indexed is used without given indices");
938 
939         r = index_buffer_->BindToCommandBuffer(command_.get());
940         if (!r.IsSuccess())
941           return r;
942 
943         // VkRunner spec says
944         //   "vertexCount will be used as the index count, firstVertex
945         //    becomes the vertex offset and firstIndex will always be zero."
946         device_->GetPtrs()->vkCmdDrawIndexed(
947             command_->GetVkCommandBuffer(),
948             command->GetVertexCount(),   /* indexCount */
949             command->GetInstanceCount(), /* instanceCount */
950             0,                           /* firstIndex */
951             static_cast<int32_t>(
952                 command->GetFirstVertexIndex()), /* vertexOffset */
953             command->GetFirstInstance());        /* firstInstance */
954       } else {
955         device_->GetPtrs()->vkCmdDraw(
956             command_->GetVkCommandBuffer(), command->GetVertexCount(),
957             command->GetInstanceCount(), command->GetFirstVertexIndex(),
958             command->GetFirstInstance());
959       }
960     }
961 
962     frame_->TransferImagesToHost(command_.get());
963 
964     r = cmd_buf_guard.Submit(GetFenceTimeout(),
965                              GetPipelineRuntimeLayerEnabled());
966     if (!r.IsSuccess())
967       return r;
968   }
969 
970   r = ReadbackDescriptorsToHostDataQueue();
971   if (!r.IsSuccess())
972     return r;
973 
974   frame_->CopyImagesToBuffers();
975 
976   device_->GetPtrs()->vkDestroyPipeline(device_->GetVkDevice(), pipeline,
977                                         nullptr);
978   device_->GetPtrs()->vkDestroyPipelineLayout(device_->GetVkDevice(),
979                                               pipeline_layout, nullptr);
980   return {};
981 }
982 
983 }  // namespace vulkan
984 }  // namespace amber
985