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