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