• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/vulkan/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,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     const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info)
396     : Pipeline(PipelineType::kGraphics,
397                device,
398                fence_timeout_ms,
399                shader_stage_info),
400       depth_stencil_buffer_(depth_stencil_buffer) {
401   for (const auto& info : color_buffers)
402     color_buffers_.push_back(&info);
403   for (const auto& info : resolve_targets)
404     resolve_targets_.push_back(&info);
405 }
406 
~GraphicsPipeline()407 GraphicsPipeline::~GraphicsPipeline() {
408   if (render_pass_) {
409     device_->GetPtrs()->vkDestroyRenderPass(device_->GetVkDevice(),
410                                             render_pass_, nullptr);
411   }
412 }
413 
CreateRenderPass()414 Result GraphicsPipeline::CreateRenderPass() {
415   VkSubpassDescription subpass_desc = VkSubpassDescription();
416   subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
417 
418   std::vector<VkAttachmentDescription> attachment_desc;
419 
420   std::vector<VkAttachmentReference> color_refer;
421   VkAttachmentReference depth_refer = VkAttachmentReference();
422   std::vector<VkAttachmentReference> resolve_refer;
423 
424   for (const auto* info : color_buffers_) {
425     attachment_desc.push_back(kDefaultAttachmentDesc);
426     attachment_desc.back().format =
427         device_->GetVkFormat(*info->buffer->GetFormat());
428     attachment_desc.back().initialLayout =
429         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
430     attachment_desc.back().finalLayout =
431         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
432     attachment_desc.back().samples =
433         static_cast<VkSampleCountFlagBits>(info->buffer->GetSamples());
434 
435     VkAttachmentReference ref = VkAttachmentReference();
436     ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
437     ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
438     color_refer.push_back(ref);
439   }
440   subpass_desc.colorAttachmentCount = static_cast<uint32_t>(color_refer.size());
441   subpass_desc.pColorAttachments = color_refer.data();
442 
443   if (depth_stencil_buffer_.buffer &&
444       depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
445     attachment_desc.push_back(kDefaultAttachmentDesc);
446     attachment_desc.back().format =
447         device_->GetVkFormat(*depth_stencil_buffer_.buffer->GetFormat());
448     attachment_desc.back().initialLayout =
449         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
450     attachment_desc.back().finalLayout =
451         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
452 
453     depth_refer.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
454     depth_refer.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
455 
456     subpass_desc.pDepthStencilAttachment = &depth_refer;
457   }
458 
459   for (const auto* info : resolve_targets_) {
460     attachment_desc.push_back(kDefaultAttachmentDesc);
461     attachment_desc.back().format =
462         device_->GetVkFormat(*info->buffer->GetFormat());
463     attachment_desc.back().initialLayout =
464         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
465     attachment_desc.back().finalLayout =
466         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
467 
468     VkAttachmentReference ref = VkAttachmentReference();
469     ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
470     ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
471     resolve_refer.push_back(ref);
472   }
473 
474   subpass_desc.pResolveAttachments = resolve_refer.data();
475 
476   VkRenderPassCreateInfo render_pass_info = VkRenderPassCreateInfo();
477   render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
478   render_pass_info.attachmentCount =
479       static_cast<uint32_t>(attachment_desc.size());
480   render_pass_info.pAttachments = attachment_desc.data();
481   render_pass_info.subpassCount = 1;
482   render_pass_info.pSubpasses = &subpass_desc;
483 
484   if (device_->GetPtrs()->vkCreateRenderPass(device_->GetVkDevice(),
485                                              &render_pass_info, nullptr,
486                                              &render_pass_) != VK_SUCCESS) {
487     return Result("Vulkan::Calling vkCreateRenderPass Fail");
488   }
489 
490   return {};
491 }
492 
493 VkPipelineDepthStencilStateCreateInfo
GetVkPipelineDepthStencilInfo(const PipelineData * pipeline_data)494 GraphicsPipeline::GetVkPipelineDepthStencilInfo(
495     const PipelineData* pipeline_data) {
496   VkPipelineDepthStencilStateCreateInfo depthstencil_info =
497       VkPipelineDepthStencilStateCreateInfo();
498   depthstencil_info.sType =
499       VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
500 
501   depthstencil_info.depthTestEnable = pipeline_data->GetEnableDepthTest();
502   depthstencil_info.depthWriteEnable = pipeline_data->GetEnableDepthWrite();
503   depthstencil_info.depthCompareOp =
504       ToVkCompareOp(pipeline_data->GetDepthCompareOp());
505   depthstencil_info.depthBoundsTestEnable =
506       pipeline_data->GetEnableDepthBoundsTest();
507   depthstencil_info.stencilTestEnable = pipeline_data->GetEnableStencilTest();
508 
509   depthstencil_info.front.failOp =
510       ToVkStencilOp(pipeline_data->GetFrontFailOp());
511   depthstencil_info.front.passOp =
512       ToVkStencilOp(pipeline_data->GetFrontPassOp());
513   depthstencil_info.front.depthFailOp =
514       ToVkStencilOp(pipeline_data->GetFrontDepthFailOp());
515   depthstencil_info.front.compareOp =
516       ToVkCompareOp(pipeline_data->GetFrontCompareOp());
517   depthstencil_info.front.compareMask = pipeline_data->GetFrontCompareMask();
518   depthstencil_info.front.writeMask = pipeline_data->GetFrontWriteMask();
519   depthstencil_info.front.reference = pipeline_data->GetFrontReference();
520 
521   depthstencil_info.back.failOp = ToVkStencilOp(pipeline_data->GetBackFailOp());
522   depthstencil_info.back.passOp = ToVkStencilOp(pipeline_data->GetBackPassOp());
523   depthstencil_info.back.depthFailOp =
524       ToVkStencilOp(pipeline_data->GetBackDepthFailOp());
525   depthstencil_info.back.compareOp =
526       ToVkCompareOp(pipeline_data->GetBackCompareOp());
527   depthstencil_info.back.compareMask = pipeline_data->GetBackCompareMask();
528   depthstencil_info.back.writeMask = pipeline_data->GetBackWriteMask();
529   depthstencil_info.back.reference = pipeline_data->GetBackReference();
530 
531   depthstencil_info.minDepthBounds = pipeline_data->GetMinDepthBounds();
532   depthstencil_info.maxDepthBounds = pipeline_data->GetMaxDepthBounds();
533 
534   return depthstencil_info;
535 }
536 
537 std::vector<VkPipelineColorBlendAttachmentState>
GetVkPipelineColorBlendAttachmentState(const PipelineData * pipeline_data)538 GraphicsPipeline::GetVkPipelineColorBlendAttachmentState(
539     const PipelineData* pipeline_data) {
540   std::vector<VkPipelineColorBlendAttachmentState> states;
541 
542   for (size_t i = 0; i < color_buffers_.size(); ++i) {
543     VkPipelineColorBlendAttachmentState colorblend_attachment =
544         VkPipelineColorBlendAttachmentState();
545     colorblend_attachment.blendEnable = pipeline_data->GetEnableBlend();
546     colorblend_attachment.srcColorBlendFactor =
547         ToVkBlendFactor(pipeline_data->GetSrcColorBlendFactor());
548     colorblend_attachment.dstColorBlendFactor =
549         ToVkBlendFactor(pipeline_data->GetDstColorBlendFactor());
550     colorblend_attachment.colorBlendOp =
551         ToVkBlendOp(pipeline_data->GetColorBlendOp());
552     colorblend_attachment.srcAlphaBlendFactor =
553         ToVkBlendFactor(pipeline_data->GetSrcAlphaBlendFactor());
554     colorblend_attachment.dstAlphaBlendFactor =
555         ToVkBlendFactor(pipeline_data->GetDstAlphaBlendFactor());
556     colorblend_attachment.alphaBlendOp =
557         ToVkBlendOp(pipeline_data->GetAlphaBlendOp());
558     colorblend_attachment.colorWriteMask = pipeline_data->GetColorWriteMask();
559     states.push_back(colorblend_attachment);
560   }
561   return states;
562 }
563 
CreateVkGraphicsPipeline(const PipelineData * pipeline_data,VkPrimitiveTopology topology,const VertexBuffer * vertex_buffer,const VkPipelineLayout & pipeline_layout,VkPipeline * pipeline)564 Result GraphicsPipeline::CreateVkGraphicsPipeline(
565     const PipelineData* pipeline_data,
566     VkPrimitiveTopology topology,
567     const VertexBuffer* vertex_buffer,
568     const VkPipelineLayout& pipeline_layout,
569     VkPipeline* pipeline) {
570   if (!pipeline_data) {
571     return Result(
572         "Vulkan: GraphicsPipeline::CreateVkGraphicsPipeline PipelineData is "
573         "null");
574   }
575 
576   std::vector<VkVertexInputBindingDescription> vertex_bindings;
577   std::vector<VkVertexInputAttributeDescription> vertex_attribs;
578   if (vertex_buffer != nullptr) {
579     vertex_bindings = vertex_buffer->GetVkVertexInputBinding();
580     vertex_attribs = vertex_buffer->GetVkVertexInputAttr();
581   }
582 
583   VkPipelineVertexInputStateCreateInfo vertex_input_info =
584       VkPipelineVertexInputStateCreateInfo();
585   vertex_input_info.sType =
586       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
587   vertex_input_info.vertexBindingDescriptionCount =
588       static_cast<uint32_t>(vertex_bindings.size());
589   vertex_input_info.pVertexBindingDescriptions =
590       vertex_bindings.empty() ? nullptr : vertex_bindings.data();
591   vertex_input_info.vertexAttributeDescriptionCount =
592       static_cast<uint32_t>(vertex_attribs.size());
593   vertex_input_info.pVertexAttributeDescriptions =
594       vertex_attribs.empty() ? nullptr : vertex_attribs.data();
595 
596   VkPipelineInputAssemblyStateCreateInfo input_assembly_info =
597       VkPipelineInputAssemblyStateCreateInfo();
598   input_assembly_info.sType =
599       VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
600   // TODO(jaebaek): Handle the given index if exists.
601   input_assembly_info.topology = topology;
602   input_assembly_info.primitiveRestartEnable =
603       pipeline_data->GetEnablePrimitiveRestart();
604 
605   VkViewport viewport = {
606       0, 0, static_cast<float>(frame_width_), static_cast<float>(frame_height_),
607       0, 1};
608 
609   if (pipeline_data->HasViewportData()) {
610     Viewport vp = pipeline_data->GetViewport();
611     viewport.x = vp.x;
612     viewport.y = vp.y;
613     viewport.width = vp.w;
614     viewport.height = vp.h;
615     viewport.minDepth = vp.mind;
616     viewport.maxDepth = vp.maxd;
617   }
618 
619   VkRect2D scissor = {{0, 0}, {frame_width_, frame_height_}};
620 
621   VkPipelineViewportStateCreateInfo viewport_info =
622       VkPipelineViewportStateCreateInfo();
623   viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
624   viewport_info.viewportCount = 1;
625   viewport_info.pViewports = &viewport;
626   viewport_info.scissorCount = 1;
627   viewport_info.pScissors = &scissor;
628 
629   auto shader_stage_info = GetVkShaderStageInfo();
630   bool is_tessellation_needed = false;
631   for (auto& info : shader_stage_info) {
632     info.pName = GetEntryPointName(info.stage);
633     if (info.stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
634         info.stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
635       is_tessellation_needed = true;
636     }
637   }
638 
639   VkPipelineMultisampleStateCreateInfo multisampleInfo = {
640       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, /* sType */
641       nullptr,                                                  /* pNext */
642       0,                                                        /* flags */
643       kDefaultAttachmentDesc.samples, /* rasterizationSamples */
644       VK_FALSE,                       /* sampleShadingEnable */
645       0,                              /* minSampleShading */
646       &kSampleMask,                   /* pSampleMask */
647       VK_FALSE,                       /* alphaToCoverageEnable */
648       VK_FALSE,                       /* alphaToOneEnable */
649   };
650 
651   // Search for multisampled color buffers and adjust the rasterization samples
652   // to match.
653   for (const auto& cb : color_buffers_) {
654     uint32_t samples = cb->buffer->GetSamples();
655     assert(static_cast<VkSampleCountFlagBits>(samples) >=
656            multisampleInfo.rasterizationSamples);
657     multisampleInfo.rasterizationSamples =
658         static_cast<VkSampleCountFlagBits>(samples);
659   }
660 
661   VkGraphicsPipelineCreateInfo pipeline_info = VkGraphicsPipelineCreateInfo();
662   pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
663   pipeline_info.stageCount = static_cast<uint32_t>(shader_stage_info.size());
664   pipeline_info.pStages = shader_stage_info.data();
665   pipeline_info.pVertexInputState = &vertex_input_info;
666   pipeline_info.pInputAssemblyState = &input_assembly_info;
667   pipeline_info.pViewportState = &viewport_info;
668   pipeline_info.pMultisampleState = &multisampleInfo;
669 
670   VkPipelineRasterizationStateCreateInfo rasterization_info =
671       VkPipelineRasterizationStateCreateInfo();
672   rasterization_info.sType =
673       VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
674   rasterization_info.depthClampEnable = pipeline_data->GetEnableDepthClamp();
675   rasterization_info.rasterizerDiscardEnable =
676       pipeline_data->GetEnableRasterizerDiscard();
677   rasterization_info.polygonMode =
678       ToVkPolygonMode(pipeline_data->GetPolygonMode());
679   rasterization_info.cullMode = ToVkCullMode(pipeline_data->GetCullMode());
680   rasterization_info.frontFace = ToVkFrontFace(pipeline_data->GetFrontFace());
681   rasterization_info.depthBiasEnable = pipeline_data->GetEnableDepthBias();
682   rasterization_info.depthBiasConstantFactor =
683       pipeline_data->GetDepthBiasConstantFactor();
684   rasterization_info.depthBiasClamp = pipeline_data->GetDepthBiasClamp();
685   rasterization_info.depthBiasSlopeFactor =
686       pipeline_data->GetDepthBiasSlopeFactor();
687   rasterization_info.lineWidth = pipeline_data->GetLineWidth();
688   pipeline_info.pRasterizationState = &rasterization_info;
689 
690   VkPipelineTessellationStateCreateInfo tess_info =
691       VkPipelineTessellationStateCreateInfo();
692   if (is_tessellation_needed) {
693     tess_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
694     tess_info.patchControlPoints = patch_control_points_;
695     pipeline_info.pTessellationState = &tess_info;
696   }
697 
698   VkPipelineDepthStencilStateCreateInfo depthstencil_info;
699   if (depth_stencil_buffer_.buffer &&
700       depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
701     depthstencil_info = GetVkPipelineDepthStencilInfo(pipeline_data);
702     pipeline_info.pDepthStencilState = &depthstencil_info;
703   }
704 
705   VkPipelineColorBlendStateCreateInfo colorblend_info =
706       VkPipelineColorBlendStateCreateInfo();
707 
708   auto colorblend_attachment =
709       GetVkPipelineColorBlendAttachmentState(pipeline_data);
710 
711   colorblend_info.sType =
712       VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
713   colorblend_info.logicOpEnable = pipeline_data->GetEnableLogicOp();
714   colorblend_info.logicOp = ToVkLogicOp(pipeline_data->GetLogicOp());
715   colorblend_info.attachmentCount =
716       static_cast<uint32_t>(colorblend_attachment.size());
717   colorblend_info.pAttachments = colorblend_attachment.data();
718   pipeline_info.pColorBlendState = &colorblend_info;
719 
720   pipeline_info.layout = pipeline_layout;
721   pipeline_info.renderPass = render_pass_;
722   pipeline_info.subpass = 0;
723 
724   if (device_->GetPtrs()->vkCreateGraphicsPipelines(
725           device_->GetVkDevice(), VK_NULL_HANDLE, 1, &pipeline_info, nullptr,
726           pipeline) != VK_SUCCESS) {
727     return Result("Vulkan::Calling vkCreateGraphicsPipelines Fail");
728   }
729 
730   return {};
731 }
732 
Initialize(uint32_t width,uint32_t height,CommandPool * pool)733 Result GraphicsPipeline::Initialize(uint32_t width,
734                                     uint32_t height,
735                                     CommandPool* pool) {
736   Result r = Pipeline::Initialize(pool);
737   if (!r.IsSuccess())
738     return r;
739 
740   r = CreateRenderPass();
741   if (!r.IsSuccess())
742     return r;
743 
744   frame_ =
745       MakeUnique<FrameBuffer>(device_, color_buffers_, depth_stencil_buffer_,
746                               resolve_targets_, width, height);
747   r = frame_->Initialize(render_pass_);
748   if (!r.IsSuccess())
749     return r;
750 
751   frame_width_ = width;
752   frame_height_ = height;
753 
754   return {};
755 }
756 
SendVertexBufferDataIfNeeded(VertexBuffer * vertex_buffer)757 Result GraphicsPipeline::SendVertexBufferDataIfNeeded(
758     VertexBuffer* vertex_buffer) {
759   if (!vertex_buffer || vertex_buffer->VertexDataSent())
760     return {};
761   return vertex_buffer->SendVertexData(command_.get());
762 }
763 
SetIndexBuffer(Buffer * buffer)764 Result GraphicsPipeline::SetIndexBuffer(Buffer* buffer) {
765   if (index_buffer_) {
766     return Result(
767         "GraphicsPipeline::SetIndexBuffer must be called once when "
768         "index_buffer_ is created");
769   }
770 
771   index_buffer_ = MakeUnique<IndexBuffer>(device_);
772 
773   CommandBufferGuard guard(GetCommandBuffer());
774   if (!guard.IsRecording())
775     return guard.GetResult();
776 
777   Result r = index_buffer_->SendIndexData(command_.get(), buffer);
778   if (!r.IsSuccess())
779     return r;
780 
781   return guard.Submit(GetFenceTimeout());
782 }
783 
SetClearColor(float r,float g,float b,float a)784 Result GraphicsPipeline::SetClearColor(float r, float g, float b, float a) {
785   clear_color_r_ = r;
786   clear_color_g_ = g;
787   clear_color_b_ = b;
788   clear_color_a_ = a;
789   return {};
790 }
791 
SetClearStencil(uint32_t stencil)792 Result GraphicsPipeline::SetClearStencil(uint32_t stencil) {
793   if (!depth_stencil_buffer_.buffer ||
794       !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
795     return Result(
796         "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer "
797         "Exists");
798   }
799 
800   clear_stencil_ = stencil;
801   return {};
802 }
803 
SetClearDepth(float depth)804 Result GraphicsPipeline::SetClearDepth(float depth) {
805   if (!depth_stencil_buffer_.buffer ||
806       !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
807     return Result(
808         "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer "
809         "Exists");
810   }
811 
812   clear_depth_ = depth;
813   return {};
814 }
815 
Clear()816 Result GraphicsPipeline::Clear() {
817   VkClearValue colour_clear;
818   colour_clear.color = {
819       {clear_color_r_, clear_color_g_, clear_color_b_, clear_color_a_}};
820 
821   CommandBufferGuard cmd_buf_guard(GetCommandBuffer());
822   if (!cmd_buf_guard.IsRecording())
823     return cmd_buf_guard.GetResult();
824 
825   frame_->ChangeFrameToWriteLayout(GetCommandBuffer());
826   frame_->CopyBuffersToImages();
827   frame_->TransferImagesToDevice(GetCommandBuffer());
828 
829   {
830     RenderPassGuard render_pass_guard(this);
831 
832     std::vector<VkClearAttachment> clears;
833     for (size_t i = 0; i < color_buffers_.size(); ++i) {
834       VkClearAttachment clear_attachment = VkClearAttachment();
835       clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
836       clear_attachment.colorAttachment = static_cast<uint32_t>(i);
837       clear_attachment.clearValue = colour_clear;
838 
839       clears.push_back(clear_attachment);
840     }
841 
842     if (depth_stencil_buffer_.buffer &&
843         depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
844       VkClearValue depth_stencil_clear;
845       depth_stencil_clear.depthStencil = {clear_depth_, clear_stencil_};
846 
847       VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
848       if (depth_stencil_buffer_.buffer->GetFormat()->HasStencilComponent())
849         aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
850 
851       VkClearAttachment clear_attachment = VkClearAttachment();
852       clear_attachment.aspectMask = aspect;
853       clear_attachment.colorAttachment =
854           static_cast<uint32_t>(color_buffers_.size());
855       clear_attachment.clearValue = depth_stencil_clear;
856 
857       clears.push_back(clear_attachment);
858     }
859 
860     VkClearRect clear_rect;
861     clear_rect.rect = {{0, 0}, {frame_width_, frame_height_}};
862     clear_rect.baseArrayLayer = 0;
863     clear_rect.layerCount = 1;
864 
865     device_->GetPtrs()->vkCmdClearAttachments(
866         command_->GetVkCommandBuffer(), static_cast<uint32_t>(clears.size()),
867         clears.data(), 1, &clear_rect);
868   }
869 
870   frame_->TransferImagesToHost(command_.get());
871 
872   Result r = cmd_buf_guard.Submit(GetFenceTimeout());
873   if (!r.IsSuccess())
874     return r;
875 
876   frame_->CopyImagesToBuffers();
877   return {};
878 }
879 
Draw(const DrawArraysCommand * command,VertexBuffer * vertex_buffer)880 Result GraphicsPipeline::Draw(const DrawArraysCommand* command,
881                               VertexBuffer* vertex_buffer) {
882   Result r = SendDescriptorDataToDeviceIfNeeded();
883   if (!r.IsSuccess())
884     return r;
885 
886   VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
887   r = CreateVkPipelineLayout(&pipeline_layout);
888   if (!r.IsSuccess())
889     return r;
890 
891   VkPipeline pipeline = VK_NULL_HANDLE;
892   r = CreateVkGraphicsPipeline(command->GetPipelineData(),
893                                ToVkTopology(command->GetTopology()),
894                                vertex_buffer, pipeline_layout, &pipeline);
895   if (!r.IsSuccess())
896     return r;
897 
898   // Note that a command updating a descriptor set and a command using
899   // it must be submitted separately, because using a descriptor set
900   // while updating it is not safe.
901   UpdateDescriptorSetsIfNeeded();
902 
903   {
904     CommandBufferGuard cmd_buf_guard(GetCommandBuffer());
905     if (!cmd_buf_guard.IsRecording())
906       return cmd_buf_guard.GetResult();
907 
908     r = SendVertexBufferDataIfNeeded(vertex_buffer);
909     if (!r.IsSuccess())
910       return r;
911 
912     frame_->ChangeFrameToWriteLayout(GetCommandBuffer());
913     frame_->CopyBuffersToImages();
914     frame_->TransferImagesToDevice(GetCommandBuffer());
915 
916     {
917       RenderPassGuard render_pass_guard(this);
918 
919       BindVkDescriptorSets(pipeline_layout);
920 
921       r = RecordPushConstant(pipeline_layout);
922       if (!r.IsSuccess())
923         return r;
924 
925       device_->GetPtrs()->vkCmdBindPipeline(command_->GetVkCommandBuffer(),
926                                             VK_PIPELINE_BIND_POINT_GRAPHICS,
927                                             pipeline);
928 
929       if (vertex_buffer != nullptr)
930         vertex_buffer->BindToCommandBuffer(command_.get());
931 
932       if (command->IsIndexed()) {
933         if (!index_buffer_)
934           return Result("Vulkan: Draw indexed is used without given indices");
935 
936         r = index_buffer_->BindToCommandBuffer(command_.get());
937         if (!r.IsSuccess())
938           return r;
939 
940         // VkRunner spec says
941         //   "vertexCount will be used as the index count, firstVertex
942         //    becomes the vertex offset and firstIndex will always be zero."
943         device_->GetPtrs()->vkCmdDrawIndexed(
944             command_->GetVkCommandBuffer(),
945             command->GetVertexCount(),   /* indexCount */
946             command->GetInstanceCount(), /* instanceCount */
947             0,                           /* firstIndex */
948             static_cast<int32_t>(
949                 command->GetFirstVertexIndex()), /* vertexOffset */
950             command->GetFirstInstance());        /* firstInstance */
951       } else {
952         device_->GetPtrs()->vkCmdDraw(
953             command_->GetVkCommandBuffer(), command->GetVertexCount(),
954             command->GetInstanceCount(), command->GetFirstVertexIndex(),
955             command->GetFirstInstance());
956       }
957     }
958 
959     frame_->TransferImagesToHost(command_.get());
960 
961     r = cmd_buf_guard.Submit(GetFenceTimeout());
962     if (!r.IsSuccess())
963       return r;
964   }
965 
966   r = ReadbackDescriptorsToHostDataQueue();
967   if (!r.IsSuccess())
968     return r;
969 
970   frame_->CopyImagesToBuffers();
971 
972   device_->GetPtrs()->vkDestroyPipeline(device_->GetVkDevice(), pipeline,
973                                         nullptr);
974   device_->GetPtrs()->vkDestroyPipelineLayout(device_->GetVkDevice(),
975                                               pipeline_layout, nullptr);
976   return {};
977 }
978 
979 }  // namespace vulkan
980 }  // namespace amber
981