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