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