• 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   }
238   assert(false && "Vulkan::Unknown BlendFactor");
239   return VK_BLEND_FACTOR_ZERO;
240 }
241 
ToVkBlendOp(BlendOp op)242 VkBlendOp ToVkBlendOp(BlendOp op) {
243   switch (op) {
244     case BlendOp::kAdd:
245       return VK_BLEND_OP_ADD;
246     case BlendOp::kSubtract:
247       return VK_BLEND_OP_SUBTRACT;
248     case BlendOp::kReverseSubtract:
249       return VK_BLEND_OP_REVERSE_SUBTRACT;
250     case BlendOp::kMin:
251       return VK_BLEND_OP_MIN;
252     case BlendOp::kMax:
253       return VK_BLEND_OP_MAX;
254     case BlendOp::kZero:
255       return VK_BLEND_OP_ZERO_EXT;
256     case BlendOp::kSrc:
257       return VK_BLEND_OP_SRC_EXT;
258     case BlendOp::kDst:
259       return VK_BLEND_OP_DST_EXT;
260     case BlendOp::kSrcOver:
261       return VK_BLEND_OP_SRC_OVER_EXT;
262     case BlendOp::kDstOver:
263       return VK_BLEND_OP_DST_OVER_EXT;
264     case BlendOp::kSrcIn:
265       return VK_BLEND_OP_SRC_IN_EXT;
266     case BlendOp::kDstIn:
267       return VK_BLEND_OP_DST_IN_EXT;
268     case BlendOp::kSrcOut:
269       return VK_BLEND_OP_SRC_OUT_EXT;
270     case BlendOp::kDstOut:
271       return VK_BLEND_OP_DST_OUT_EXT;
272     case BlendOp::kSrcAtop:
273       return VK_BLEND_OP_SRC_ATOP_EXT;
274     case BlendOp::kDstAtop:
275       return VK_BLEND_OP_DST_ATOP_EXT;
276     case BlendOp::kXor:
277       return VK_BLEND_OP_XOR_EXT;
278     case BlendOp::kMultiply:
279       return VK_BLEND_OP_MULTIPLY_EXT;
280     case BlendOp::kScreen:
281       return VK_BLEND_OP_SCREEN_EXT;
282     case BlendOp::kOverlay:
283       return VK_BLEND_OP_OVERLAY_EXT;
284     case BlendOp::kDarken:
285       return VK_BLEND_OP_DARKEN_EXT;
286     case BlendOp::kLighten:
287       return VK_BLEND_OP_LIGHTEN_EXT;
288     case BlendOp::kColorDodge:
289       return VK_BLEND_OP_COLORDODGE_EXT;
290     case BlendOp::kColorBurn:
291       return VK_BLEND_OP_COLORBURN_EXT;
292     case BlendOp::kHardLight:
293       return VK_BLEND_OP_HARDLIGHT_EXT;
294     case BlendOp::kSoftLight:
295       return VK_BLEND_OP_SOFTLIGHT_EXT;
296     case BlendOp::kDifference:
297       return VK_BLEND_OP_DIFFERENCE_EXT;
298     case BlendOp::kExclusion:
299       return VK_BLEND_OP_EXCLUSION_EXT;
300     case BlendOp::kInvert:
301       return VK_BLEND_OP_INVERT_EXT;
302     case BlendOp::kInvertRGB:
303       return VK_BLEND_OP_INVERT_RGB_EXT;
304     case BlendOp::kLinearDodge:
305       return VK_BLEND_OP_LINEARDODGE_EXT;
306     case BlendOp::kLinearBurn:
307       return VK_BLEND_OP_LINEARBURN_EXT;
308     case BlendOp::kVividLight:
309       return VK_BLEND_OP_VIVIDLIGHT_EXT;
310     case BlendOp::kLinearLight:
311       return VK_BLEND_OP_LINEARLIGHT_EXT;
312     case BlendOp::kPinLight:
313       return VK_BLEND_OP_PINLIGHT_EXT;
314     case BlendOp::kHardMix:
315       return VK_BLEND_OP_HARDMIX_EXT;
316     case BlendOp::kHslHue:
317       return VK_BLEND_OP_HSL_HUE_EXT;
318     case BlendOp::kHslSaturation:
319       return VK_BLEND_OP_HSL_SATURATION_EXT;
320     case BlendOp::kHslColor:
321       return VK_BLEND_OP_HSL_COLOR_EXT;
322     case BlendOp::kHslLuminosity:
323       return VK_BLEND_OP_HSL_LUMINOSITY_EXT;
324     case BlendOp::kPlus:
325       return VK_BLEND_OP_PLUS_EXT;
326     case BlendOp::kPlusClamped:
327       return VK_BLEND_OP_PLUS_CLAMPED_EXT;
328     case BlendOp::kPlusClampedAlpha:
329       return VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT;
330     case BlendOp::kPlusDarker:
331       return VK_BLEND_OP_PLUS_DARKER_EXT;
332     case BlendOp::kMinus:
333       return VK_BLEND_OP_MINUS_EXT;
334     case BlendOp::kMinusClamped:
335       return VK_BLEND_OP_MINUS_CLAMPED_EXT;
336     case BlendOp::kContrast:
337       return VK_BLEND_OP_CONTRAST_EXT;
338     case BlendOp::kInvertOvg:
339       return VK_BLEND_OP_INVERT_OVG_EXT;
340     case BlendOp::kRed:
341       return VK_BLEND_OP_RED_EXT;
342     case BlendOp::kGreen:
343       return VK_BLEND_OP_GREEN_EXT;
344     case BlendOp::kBlue:
345       return VK_BLEND_OP_BLUE_EXT;
346   }
347   assert(false && "Vulkan::Unknown BlendOp");
348   return VK_BLEND_OP_ADD;
349 }
350 
351 class RenderPassGuard {
352  public:
RenderPassGuard(GraphicsPipeline * pipeline)353   explicit RenderPassGuard(GraphicsPipeline* pipeline) : pipeline_(pipeline) {
354     auto* frame = pipeline_->GetFrameBuffer();
355     auto* cmd = pipeline_->GetCommandBuffer();
356     frame->ChangeFrameToDrawLayout(cmd);
357 
358     VkRenderPassBeginInfo render_begin_info = VkRenderPassBeginInfo();
359     render_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
360     render_begin_info.renderPass = pipeline_->GetVkRenderPass();
361     render_begin_info.framebuffer = frame->GetVkFrameBuffer();
362     render_begin_info.renderArea = {{0, 0},
363                                     {frame->GetWidth(), frame->GetHeight()}};
364     pipeline_->GetDevice()->GetPtrs()->vkCmdBeginRenderPass(
365         cmd->GetVkCommandBuffer(), &render_begin_info,
366         VK_SUBPASS_CONTENTS_INLINE);
367   }
368 
~RenderPassGuard()369   ~RenderPassGuard() {
370     auto* cmd = pipeline_->GetCommandBuffer();
371 
372     pipeline_->GetDevice()->GetPtrs()->vkCmdEndRenderPass(
373         cmd->GetVkCommandBuffer());
374 
375     auto* frame = pipeline_->GetFrameBuffer();
376     frame->ChangeFrameToProbeLayout(cmd);
377   }
378 
379  private:
380   GraphicsPipeline* pipeline_;
381 };
382 
383 }  // namespace
384 
GraphicsPipeline(Device * device,const std::vector<amber::Pipeline::BufferInfo> & color_buffers,amber::Pipeline::BufferInfo depth_stencil_buffer,uint32_t fence_timeout_ms,const std::vector<VkPipelineShaderStageCreateInfo> & shader_stage_info)385 GraphicsPipeline::GraphicsPipeline(
386     Device* device,
387     const std::vector<amber::Pipeline::BufferInfo>& color_buffers,
388     amber::Pipeline::BufferInfo depth_stencil_buffer,
389     uint32_t fence_timeout_ms,
390     const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info)
391     : Pipeline(PipelineType::kGraphics,
392                device,
393                fence_timeout_ms,
394                shader_stage_info),
395       depth_stencil_buffer_(depth_stencil_buffer) {
396   for (const auto& info : color_buffers)
397     color_buffers_.push_back(&info);
398 }
399 
~GraphicsPipeline()400 GraphicsPipeline::~GraphicsPipeline() {
401   if (render_pass_) {
402     device_->GetPtrs()->vkDestroyRenderPass(device_->GetVkDevice(),
403                                             render_pass_, nullptr);
404   }
405 }
406 
CreateRenderPass()407 Result GraphicsPipeline::CreateRenderPass() {
408   VkSubpassDescription subpass_desc = VkSubpassDescription();
409   subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
410 
411   std::vector<VkAttachmentDescription> attachment_desc;
412 
413   std::vector<VkAttachmentReference> color_refer;
414   VkAttachmentReference depth_refer = VkAttachmentReference();
415 
416   for (const auto* info : color_buffers_) {
417     attachment_desc.push_back(kDefaultAttachmentDesc);
418     attachment_desc.back().format =
419         device_->GetVkFormat(*info->buffer->GetFormat());
420     attachment_desc.back().initialLayout =
421         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
422     attachment_desc.back().finalLayout =
423         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
424 
425     VkAttachmentReference ref = VkAttachmentReference();
426     ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
427     ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
428     color_refer.push_back(ref);
429   }
430   subpass_desc.colorAttachmentCount = static_cast<uint32_t>(color_refer.size());
431   subpass_desc.pColorAttachments = color_refer.data();
432 
433   if (depth_stencil_buffer_.buffer &&
434       depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
435     attachment_desc.push_back(kDefaultAttachmentDesc);
436     attachment_desc.back().format =
437         device_->GetVkFormat(*depth_stencil_buffer_.buffer->GetFormat());
438     attachment_desc.back().initialLayout =
439         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
440     attachment_desc.back().finalLayout =
441         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
442 
443     depth_refer.attachment = static_cast<uint32_t>(attachment_desc.size() - 1);
444     depth_refer.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
445 
446     subpass_desc.pDepthStencilAttachment = &depth_refer;
447   }
448 
449   VkRenderPassCreateInfo render_pass_info = VkRenderPassCreateInfo();
450   render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
451   render_pass_info.attachmentCount =
452       static_cast<uint32_t>(attachment_desc.size());
453   render_pass_info.pAttachments = attachment_desc.data();
454   render_pass_info.subpassCount = 1;
455   render_pass_info.pSubpasses = &subpass_desc;
456 
457   if (device_->GetPtrs()->vkCreateRenderPass(device_->GetVkDevice(),
458                                              &render_pass_info, nullptr,
459                                              &render_pass_) != VK_SUCCESS) {
460     return Result("Vulkan::Calling vkCreateRenderPass Fail");
461   }
462 
463   return {};
464 }
465 
466 VkPipelineDepthStencilStateCreateInfo
GetVkPipelineDepthStencilInfo(const PipelineData * pipeline_data)467 GraphicsPipeline::GetVkPipelineDepthStencilInfo(
468     const PipelineData* pipeline_data) {
469   VkPipelineDepthStencilStateCreateInfo depthstencil_info =
470       VkPipelineDepthStencilStateCreateInfo();
471   depthstencil_info.sType =
472       VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
473 
474   depthstencil_info.depthTestEnable = pipeline_data->GetEnableDepthTest();
475   depthstencil_info.depthWriteEnable = pipeline_data->GetEnableDepthWrite();
476   depthstencil_info.depthCompareOp =
477       ToVkCompareOp(pipeline_data->GetDepthCompareOp());
478   depthstencil_info.depthBoundsTestEnable =
479       pipeline_data->GetEnableDepthBoundsTest();
480   depthstencil_info.stencilTestEnable = pipeline_data->GetEnableStencilTest();
481 
482   depthstencil_info.front.failOp =
483       ToVkStencilOp(pipeline_data->GetFrontFailOp());
484   depthstencil_info.front.passOp =
485       ToVkStencilOp(pipeline_data->GetFrontPassOp());
486   depthstencil_info.front.depthFailOp =
487       ToVkStencilOp(pipeline_data->GetFrontDepthFailOp());
488   depthstencil_info.front.compareOp =
489       ToVkCompareOp(pipeline_data->GetFrontCompareOp());
490   depthstencil_info.front.compareMask = pipeline_data->GetFrontCompareMask();
491   depthstencil_info.front.writeMask = pipeline_data->GetFrontWriteMask();
492   depthstencil_info.front.reference = pipeline_data->GetFrontReference();
493 
494   depthstencil_info.back.failOp = ToVkStencilOp(pipeline_data->GetBackFailOp());
495   depthstencil_info.back.passOp = ToVkStencilOp(pipeline_data->GetBackPassOp());
496   depthstencil_info.back.depthFailOp =
497       ToVkStencilOp(pipeline_data->GetBackDepthFailOp());
498   depthstencil_info.back.compareOp =
499       ToVkCompareOp(pipeline_data->GetBackCompareOp());
500   depthstencil_info.back.compareMask = pipeline_data->GetBackCompareMask();
501   depthstencil_info.back.writeMask = pipeline_data->GetBackWriteMask();
502   depthstencil_info.back.reference = pipeline_data->GetBackReference();
503 
504   depthstencil_info.minDepthBounds = pipeline_data->GetMinDepthBounds();
505   depthstencil_info.maxDepthBounds = pipeline_data->GetMaxDepthBounds();
506 
507   return depthstencil_info;
508 }
509 
510 std::vector<VkPipelineColorBlendAttachmentState>
GetVkPipelineColorBlendAttachmentState(const PipelineData * pipeline_data)511 GraphicsPipeline::GetVkPipelineColorBlendAttachmentState(
512     const PipelineData* pipeline_data) {
513   std::vector<VkPipelineColorBlendAttachmentState> states;
514 
515   for (size_t i = 0; i < color_buffers_.size(); ++i) {
516     VkPipelineColorBlendAttachmentState colorblend_attachment =
517         VkPipelineColorBlendAttachmentState();
518     colorblend_attachment.blendEnable = pipeline_data->GetEnableBlend();
519     colorblend_attachment.srcColorBlendFactor =
520         ToVkBlendFactor(pipeline_data->GetSrcColorBlendFactor());
521     colorblend_attachment.dstColorBlendFactor =
522         ToVkBlendFactor(pipeline_data->GetDstColorBlendFactor());
523     colorblend_attachment.colorBlendOp =
524         ToVkBlendOp(pipeline_data->GetColorBlendOp());
525     colorblend_attachment.srcAlphaBlendFactor =
526         ToVkBlendFactor(pipeline_data->GetSrcAlphaBlendFactor());
527     colorblend_attachment.dstAlphaBlendFactor =
528         ToVkBlendFactor(pipeline_data->GetDstAlphaBlendFactor());
529     colorblend_attachment.alphaBlendOp =
530         ToVkBlendOp(pipeline_data->GetAlphaBlendOp());
531     colorblend_attachment.colorWriteMask = pipeline_data->GetColorWriteMask();
532     states.push_back(colorblend_attachment);
533   }
534   return states;
535 }
536 
CreateVkGraphicsPipeline(const PipelineData * pipeline_data,VkPrimitiveTopology topology,const VertexBuffer * vertex_buffer,const VkPipelineLayout & pipeline_layout,VkPipeline * pipeline)537 Result GraphicsPipeline::CreateVkGraphicsPipeline(
538     const PipelineData* pipeline_data,
539     VkPrimitiveTopology topology,
540     const VertexBuffer* vertex_buffer,
541     const VkPipelineLayout& pipeline_layout,
542     VkPipeline* pipeline) {
543   if (!pipeline_data) {
544     return Result(
545         "Vulkan: GraphicsPipeline::CreateVkGraphicsPipeline PipelineData is "
546         "null");
547   }
548 
549   std::vector<VkVertexInputBindingDescription> vertex_bindings;
550   std::vector<VkVertexInputAttributeDescription> vertex_attribs;
551   if (vertex_buffer != nullptr) {
552     vertex_bindings = vertex_buffer->GetVkVertexInputBinding();
553     vertex_attribs = vertex_buffer->GetVkVertexInputAttr();
554   }
555 
556   VkPipelineVertexInputStateCreateInfo vertex_input_info =
557       VkPipelineVertexInputStateCreateInfo();
558   vertex_input_info.sType =
559       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
560   vertex_input_info.vertexBindingDescriptionCount =
561       static_cast<uint32_t>(vertex_bindings.size());
562   vertex_input_info.pVertexBindingDescriptions =
563       vertex_bindings.empty() ? nullptr : vertex_bindings.data();
564   vertex_input_info.vertexAttributeDescriptionCount =
565       static_cast<uint32_t>(vertex_attribs.size());
566   vertex_input_info.pVertexAttributeDescriptions =
567       vertex_attribs.empty() ? nullptr : vertex_attribs.data();
568 
569   VkPipelineInputAssemblyStateCreateInfo input_assembly_info =
570       VkPipelineInputAssemblyStateCreateInfo();
571   input_assembly_info.sType =
572       VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
573   // TODO(jaebaek): Handle the given index if exists.
574   input_assembly_info.topology = topology;
575   input_assembly_info.primitiveRestartEnable =
576       pipeline_data->GetEnablePrimitiveRestart();
577 
578   VkViewport viewport = {
579       0, 0, static_cast<float>(frame_width_), static_cast<float>(frame_height_),
580       0, 1};
581 
582   VkRect2D scissor = {{0, 0}, {frame_width_, frame_height_}};
583 
584   VkPipelineViewportStateCreateInfo viewport_info =
585       VkPipelineViewportStateCreateInfo();
586   viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
587   viewport_info.viewportCount = 1;
588   viewport_info.pViewports = &viewport;
589   viewport_info.scissorCount = 1;
590   viewport_info.pScissors = &scissor;
591 
592   auto shader_stage_info = GetVkShaderStageInfo();
593   bool is_tessellation_needed = false;
594   for (auto& info : shader_stage_info) {
595     info.pName = GetEntryPointName(info.stage);
596     if (info.stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
597         info.stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
598       is_tessellation_needed = true;
599     }
600   }
601 
602   VkPipelineMultisampleStateCreateInfo multisampleInfo = {
603       VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, /* sType */
604       nullptr,                                                  /* pNext */
605       0,                                                        /* flags */
606       kDefaultAttachmentDesc.samples, /* rasterizationSamples */
607       VK_FALSE,                       /* sampleShadingEnable */
608       0,                              /* minSampleShading */
609       &kSampleMask,                   /* pSampleMask */
610       VK_FALSE,                       /* alphaToCoverageEnable */
611       VK_FALSE,                       /* alphaToOneEnable */
612   };
613 
614   VkGraphicsPipelineCreateInfo pipeline_info = VkGraphicsPipelineCreateInfo();
615   pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
616   pipeline_info.stageCount = static_cast<uint32_t>(shader_stage_info.size());
617   pipeline_info.pStages = shader_stage_info.data();
618   pipeline_info.pVertexInputState = &vertex_input_info;
619   pipeline_info.pInputAssemblyState = &input_assembly_info;
620   pipeline_info.pViewportState = &viewport_info;
621   pipeline_info.pMultisampleState = &multisampleInfo;
622 
623   VkPipelineRasterizationStateCreateInfo rasterization_info =
624       VkPipelineRasterizationStateCreateInfo();
625   rasterization_info.sType =
626       VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
627   rasterization_info.depthClampEnable = pipeline_data->GetEnableDepthClamp();
628   rasterization_info.rasterizerDiscardEnable =
629       pipeline_data->GetEnableRasterizerDiscard();
630   rasterization_info.polygonMode =
631       ToVkPolygonMode(pipeline_data->GetPolygonMode());
632   rasterization_info.cullMode = ToVkCullMode(pipeline_data->GetCullMode());
633   rasterization_info.frontFace = ToVkFrontFace(pipeline_data->GetFrontFace());
634   rasterization_info.depthBiasEnable = pipeline_data->GetEnableDepthBias();
635   rasterization_info.depthBiasConstantFactor =
636       pipeline_data->GetDepthBiasConstantFactor();
637   rasterization_info.depthBiasClamp = pipeline_data->GetDepthBiasClamp();
638   rasterization_info.depthBiasSlopeFactor =
639       pipeline_data->GetDepthBiasSlopeFactor();
640   rasterization_info.lineWidth = pipeline_data->GetLineWidth();
641   pipeline_info.pRasterizationState = &rasterization_info;
642 
643   VkPipelineTessellationStateCreateInfo tess_info =
644       VkPipelineTessellationStateCreateInfo();
645   if (is_tessellation_needed) {
646     tess_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
647     tess_info.patchControlPoints = patch_control_points_;
648     pipeline_info.pTessellationState = &tess_info;
649   }
650 
651   VkPipelineDepthStencilStateCreateInfo depthstencil_info;
652   if (depth_stencil_buffer_.buffer &&
653       depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
654     depthstencil_info = GetVkPipelineDepthStencilInfo(pipeline_data);
655     pipeline_info.pDepthStencilState = &depthstencil_info;
656   }
657 
658   VkPipelineColorBlendStateCreateInfo colorblend_info =
659       VkPipelineColorBlendStateCreateInfo();
660 
661   auto colorblend_attachment =
662       GetVkPipelineColorBlendAttachmentState(pipeline_data);
663 
664   colorblend_info.sType =
665       VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
666   colorblend_info.logicOpEnable = pipeline_data->GetEnableLogicOp();
667   colorblend_info.logicOp = ToVkLogicOp(pipeline_data->GetLogicOp());
668   colorblend_info.attachmentCount =
669       static_cast<uint32_t>(colorblend_attachment.size());
670   colorblend_info.pAttachments = colorblend_attachment.data();
671   pipeline_info.pColorBlendState = &colorblend_info;
672 
673   pipeline_info.layout = pipeline_layout;
674   pipeline_info.renderPass = render_pass_;
675   pipeline_info.subpass = 0;
676 
677   if (device_->GetPtrs()->vkCreateGraphicsPipelines(
678           device_->GetVkDevice(), VK_NULL_HANDLE, 1, &pipeline_info, nullptr,
679           pipeline) != VK_SUCCESS) {
680     return Result("Vulkan::Calling vkCreateGraphicsPipelines Fail");
681   }
682 
683   return {};
684 }
685 
Initialize(uint32_t width,uint32_t height,CommandPool * pool)686 Result GraphicsPipeline::Initialize(uint32_t width,
687                                     uint32_t height,
688                                     CommandPool* pool) {
689   Result r = Pipeline::Initialize(pool);
690   if (!r.IsSuccess())
691     return r;
692 
693   r = CreateRenderPass();
694   if (!r.IsSuccess())
695     return r;
696 
697   frame_ = MakeUnique<FrameBuffer>(device_, color_buffers_,
698                                    depth_stencil_buffer_, width, height);
699   r = frame_->Initialize(render_pass_);
700   if (!r.IsSuccess())
701     return r;
702 
703   frame_width_ = width;
704   frame_height_ = height;
705 
706   return {};
707 }
708 
SendVertexBufferDataIfNeeded(VertexBuffer * vertex_buffer)709 Result GraphicsPipeline::SendVertexBufferDataIfNeeded(
710     VertexBuffer* vertex_buffer) {
711   if (!vertex_buffer || vertex_buffer->VertexDataSent())
712     return {};
713   return vertex_buffer->SendVertexData(command_.get());
714 }
715 
SetIndexBuffer(Buffer * buffer)716 Result GraphicsPipeline::SetIndexBuffer(Buffer* buffer) {
717   if (index_buffer_) {
718     return Result(
719         "GraphicsPipeline::SetIndexBuffer must be called once when "
720         "index_buffer_ is created");
721   }
722 
723   index_buffer_ = MakeUnique<IndexBuffer>(device_);
724 
725   CommandBufferGuard guard(GetCommandBuffer());
726   if (!guard.IsRecording())
727     return guard.GetResult();
728 
729   Result r = index_buffer_->SendIndexData(command_.get(), buffer);
730   if (!r.IsSuccess())
731     return r;
732 
733   return guard.Submit(GetFenceTimeout());
734 }
735 
SetClearColor(float r,float g,float b,float a)736 Result GraphicsPipeline::SetClearColor(float r, float g, float b, float a) {
737   clear_color_r_ = r;
738   clear_color_g_ = g;
739   clear_color_b_ = b;
740   clear_color_a_ = a;
741   return {};
742 }
743 
SetClearStencil(uint32_t stencil)744 Result GraphicsPipeline::SetClearStencil(uint32_t stencil) {
745   if (!depth_stencil_buffer_.buffer ||
746       !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
747     return Result(
748         "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer "
749         "Exists");
750   }
751 
752   clear_stencil_ = stencil;
753   return {};
754 }
755 
SetClearDepth(float depth)756 Result GraphicsPipeline::SetClearDepth(float depth) {
757   if (!depth_stencil_buffer_.buffer ||
758       !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
759     return Result(
760         "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer "
761         "Exists");
762   }
763 
764   clear_depth_ = depth;
765   return {};
766 }
767 
Clear()768 Result GraphicsPipeline::Clear() {
769   VkClearValue colour_clear;
770   colour_clear.color = {
771       {clear_color_r_, clear_color_g_, clear_color_b_, clear_color_a_}};
772 
773   CommandBufferGuard cmd_buf_guard(GetCommandBuffer());
774   if (!cmd_buf_guard.IsRecording())
775     return cmd_buf_guard.GetResult();
776 
777   frame_->ChangeFrameToWriteLayout(GetCommandBuffer());
778   frame_->CopyBuffersToImages();
779   frame_->TransferImagesToDevice(GetCommandBuffer());
780 
781   {
782     RenderPassGuard render_pass_guard(this);
783 
784     std::vector<VkClearAttachment> clears;
785     for (size_t i = 0; i < color_buffers_.size(); ++i) {
786       VkClearAttachment clear_attachment = VkClearAttachment();
787       clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
788       clear_attachment.colorAttachment = static_cast<uint32_t>(i);
789       clear_attachment.clearValue = colour_clear;
790 
791       clears.push_back(clear_attachment);
792     }
793 
794     if (depth_stencil_buffer_.buffer &&
795         depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) {
796       VkClearValue depth_stencil_clear;
797       depth_stencil_clear.depthStencil = {clear_depth_, clear_stencil_};
798 
799       VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
800       if (depth_stencil_buffer_.buffer->GetFormat()->HasStencilComponent())
801         aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
802 
803       VkClearAttachment clear_attachment = VkClearAttachment();
804       clear_attachment.aspectMask = aspect;
805       clear_attachment.colorAttachment =
806           static_cast<uint32_t>(color_buffers_.size());
807       clear_attachment.clearValue = depth_stencil_clear;
808 
809       clears.push_back(clear_attachment);
810     }
811 
812     VkClearRect clear_rect;
813     clear_rect.rect = {{0, 0}, {frame_width_, frame_height_}};
814     clear_rect.baseArrayLayer = 0;
815     clear_rect.layerCount = 1;
816 
817     device_->GetPtrs()->vkCmdClearAttachments(
818         command_->GetVkCommandBuffer(), static_cast<uint32_t>(clears.size()),
819         clears.data(), 1, &clear_rect);
820   }
821 
822   frame_->TransferImagesToHost(command_.get());
823 
824   Result r = cmd_buf_guard.Submit(GetFenceTimeout());
825   if (!r.IsSuccess())
826     return r;
827 
828   frame_->CopyImagesToBuffers();
829   return {};
830 }
831 
Draw(const DrawArraysCommand * command,VertexBuffer * vertex_buffer)832 Result GraphicsPipeline::Draw(const DrawArraysCommand* command,
833                               VertexBuffer* vertex_buffer) {
834   Result r = SendDescriptorDataToDeviceIfNeeded();
835   if (!r.IsSuccess())
836     return r;
837 
838   VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
839   r = CreateVkPipelineLayout(&pipeline_layout);
840   if (!r.IsSuccess())
841     return r;
842 
843   VkPipeline pipeline = VK_NULL_HANDLE;
844   r = CreateVkGraphicsPipeline(command->GetPipelineData(),
845                                ToVkTopology(command->GetTopology()),
846                                vertex_buffer, pipeline_layout, &pipeline);
847   if (!r.IsSuccess())
848     return r;
849 
850   // Note that a command updating a descriptor set and a command using
851   // it must be submitted separately, because using a descriptor set
852   // while updating it is not safe.
853   UpdateDescriptorSetsIfNeeded();
854 
855   {
856     CommandBufferGuard cmd_buf_guard(GetCommandBuffer());
857     if (!cmd_buf_guard.IsRecording())
858       return cmd_buf_guard.GetResult();
859 
860     r = SendVertexBufferDataIfNeeded(vertex_buffer);
861     if (!r.IsSuccess())
862       return r;
863 
864     frame_->ChangeFrameToWriteLayout(GetCommandBuffer());
865     frame_->CopyBuffersToImages();
866     frame_->TransferImagesToDevice(GetCommandBuffer());
867 
868     {
869       RenderPassGuard render_pass_guard(this);
870 
871       BindVkDescriptorSets(pipeline_layout);
872 
873       r = RecordPushConstant(pipeline_layout);
874       if (!r.IsSuccess())
875         return r;
876 
877       device_->GetPtrs()->vkCmdBindPipeline(command_->GetVkCommandBuffer(),
878                                             VK_PIPELINE_BIND_POINT_GRAPHICS,
879                                             pipeline);
880 
881       if (vertex_buffer != nullptr)
882         vertex_buffer->BindToCommandBuffer(command_.get());
883 
884       if (command->IsIndexed()) {
885         if (!index_buffer_)
886           return Result("Vulkan: Draw indexed is used without given indices");
887 
888         r = index_buffer_->BindToCommandBuffer(command_.get());
889         if (!r.IsSuccess())
890           return r;
891 
892         // VkRunner spec says
893         //   "vertexCount will be used as the index count, firstVertex
894         //    becomes the vertex offset and firstIndex will always be zero."
895         device_->GetPtrs()->vkCmdDrawIndexed(
896             command_->GetVkCommandBuffer(),
897             command->GetVertexCount(),   /* indexCount */
898             command->GetInstanceCount(), /* instanceCount */
899             0,                           /* firstIndex */
900             static_cast<int32_t>(
901                 command->GetFirstVertexIndex()), /* vertexOffset */
902             command->GetFirstInstance());        /* firstInstance */
903       } else {
904         device_->GetPtrs()->vkCmdDraw(
905             command_->GetVkCommandBuffer(), command->GetVertexCount(),
906             command->GetInstanceCount(), command->GetFirstVertexIndex(),
907             command->GetFirstInstance());
908       }
909     }
910 
911     frame_->TransferImagesToHost(command_.get());
912 
913     r = cmd_buf_guard.Submit(GetFenceTimeout());
914     if (!r.IsSuccess())
915       return r;
916   }
917 
918   r = ReadbackDescriptorsToHostDataQueue();
919   if (!r.IsSuccess())
920     return r;
921 
922   frame_->CopyImagesToBuffers();
923 
924   device_->GetPtrs()->vkDestroyPipeline(device_->GetVkDevice(), pipeline,
925                                         nullptr);
926   device_->GetPtrs()->vkDestroyPipelineLayout(device_->GetVkDevice(),
927                                               pipeline_layout, nullptr);
928   return {};
929 }
930 
931 }  // namespace vulkan
932 }  // namespace amber
933