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