GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
77 / 83
92.8%
Branches:
28 / 58
48.3%
Functions:
8 / 11
72.7%

device/image.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file image.cpp
3 /// @brief Allocating images through VMA, their views and samplers.
4 #include "ernie/device/image.h"
5
6 #include "ernie/util/on_failure.h"
7
8 #include <array>
9
10 namespace ernie {
11 namespace {
12
13 struct FormatInfo {
14 VkFormat vk;
15 std::uint32_t bytes;
16 };
17
18 17 FormatInfo Info(ImageFormat format) {
19 17 static constexpr std::array kFormats{
20 FormatInfo{VK_FORMAT_R8G8B8A8_UNORM, 4},
21 FormatInfo{VK_FORMAT_R8G8B8A8_SRGB, 4},
22 FormatInfo{VK_FORMAT_R32_SFLOAT, 4},
23 FormatInfo{VK_FORMAT_R32G32_SFLOAT, 8},
24 FormatInfo{VK_FORMAT_R16G16B16A16_SFLOAT, 8},
25 FormatInfo{VK_FORMAT_R32G32B32A32_SFLOAT, 16},
26 FormatInfo{VK_FORMAT_R32_UINT, 4},
27 };
28 17 return kFormats[static_cast<std::size_t>(format)];
29 }
30
31 15 VkImageUsageFlags ToVkUsage(ImageUsage usage) {
32 15 VkImageUsageFlags flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
33
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (Any(usage, ImageUsage::Sampled)) {
34 15 flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
35 }
36
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 if (Any(usage, ImageUsage::Storage)) {
37 10 flags |= VK_IMAGE_USAGE_STORAGE_BIT;
38 }
39
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 13 times.
15 if (Any(usage, ImageUsage::Attachment)) {
40 2 flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
41 }
42 15 return flags;
43 }
44
45 } // namespace
46
47 ✗ std::uint32_t TexelBytes(ImageFormat format) {
48 ✗ return Info(format).bytes;
49 }
50
51 17 VkFormat ToVkFormat(ImageFormat format) {
52 17 return Info(format).vk;
53 }
54
55 15 DeviceImage::DeviceImage(DeviceContext& context, const ImageDescription& description,
56 15 std::string_view name)
57
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 : context_(context), description_(description) {
58 15 const bool volume = description.extent.z > 1;
59 15 const VkImageCreateInfo info{
60 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
61
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 .imageType = volume ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D,
62 15 .format = ToVkFormat(description.format),
63 15 .extent = {description.extent.x, description.extent.y, description.extent.z},
64 15 .mipLevels = description.mips,
65 .arrayLayers = 1,
66 .samples = VK_SAMPLE_COUNT_1_BIT,
67 .tiling = VK_IMAGE_TILING_OPTIMAL,
68 15 .usage = ToVkUsage(description.usage),
69 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
70 15 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED};
71 15 const VkPhysicalDeviceImageFormatInfo2 query{
72 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
73 .format = info.format,
74 .type = info.imageType,
75 .tiling = info.tiling,
76 15 .usage = info.usage};
77 15 VkImageFormatProperties2 supported{.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2};
78 15 const VkImageFormatProperties& limits = supported.imageFormatProperties;
79
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (description.mips == 0 ||
80 15 vkGetPhysicalDeviceImageFormatProperties2(context.Physical(), &query, &supported) !=
81 15 VK_SUCCESS ||
82
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 description.mips > limits.maxMipLevels || description.extent.x > limits.maxExtent.width ||
83
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 description.extent.y > limits.maxExtent.height ||
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 description.extent.z > limits.maxExtent.depth) {
85 ✗ throw DeviceError(DeviceErrorKind::Unsupported,
86
0/6
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ context.Info().name + " has no such image as " + std::string(name));
87 }
88 15 const VmaAllocationCreateInfo allocation{.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE};
89
2/4
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 CheckVk(vmaCreateImage(context.Allocator(), &info, &allocation, &image_, &allocation_, nullptr),
90
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
30 "Allocating image " + std::string(name));
91 ✗ const OnFailure freeImage([&] { vmaDestroyImage(context.Allocator(), image_, allocation_); });
92 15 const VkImageSubresourceRange all{
93 15 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .levelCount = description.mips, .layerCount = 1};
94 15 const VkImageViewCreateInfo view{.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
95 15 .image = image_,
96 .viewType =
97 volume ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D,
98 15 .format = info.format,
99 15 .subresourceRange = all};
100
3/6
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
30 CheckVk(vkCreateImageView(context.Device(), &view, nullptr, &view_),
101
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
30 "Viewing image " + std::string(name));
102 ✗ const OnFailure freeView([&] { vkDestroyImageView(context.Device(), view_, nullptr); });
103
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 context.Name(VK_OBJECT_TYPE_IMAGE, reinterpret_cast<std::uint64_t>(image_), name);
104
105
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 ready_ = context.Main().Submit([&](VkCommandBuffer commands) {
106 15 const VkImageMemoryBarrier2 barrier{.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
107 .dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
108 .dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT |
109 VK_ACCESS_2_MEMORY_WRITE_BIT,
110 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
111 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
112 15 .image = image_,
113 15 .subresourceRange = all};
114 15 const VkDependencyInfo dependency{.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
115 .imageMemoryBarrierCount = 1,
116 15 .pImageMemoryBarriers = &barrier};
117 15 vkCmdPipelineBarrier2(commands, &dependency);
118 15 });
119
2/4
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
60 }
120
121 15 DeviceImage::~DeviceImage() {
122 15 vkDestroyImageView(context_.Device(), view_, nullptr);
123 15 vmaDestroyImage(context_.Allocator(), image_, allocation_);
124 15 }
125
126 3 Sampler::Sampler(DeviceContext& context, const SamplerDescription& description,
127
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 std::string_view name)
128 3 : device_(context.Device()) {
129 6 const VkFilter filter =
130
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 description.filter == Filter::Linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
131 3 static constexpr std::array kAddress{VK_SAMPLER_ADDRESS_MODE_REPEAT,
132 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
133 VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT};
134
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 const VkSamplerAddressMode address = kAddress[static_cast<std::size_t>(description.address)];
135 3 const VkSamplerCreateInfo info{.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
136 .magFilter = filter,
137 .minFilter = filter,
138 3 .mipmapMode = description.filter == Filter::Linear
139 3 ? VK_SAMPLER_MIPMAP_MODE_LINEAR
140 : VK_SAMPLER_MIPMAP_MODE_NEAREST,
141 .addressModeU = address,
142 .addressModeV = address,
143 .addressModeW = address,
144
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 .maxLod = VK_LOD_CLAMP_NONE};
145 3 CheckVk(vkCreateSampler(device_, &info, nullptr, &sampler_), "Creating a sampler");
146 3 context.Name(VK_OBJECT_TYPE_SAMPLER, reinterpret_cast<std::uint64_t>(sampler_), name);
147 3 }
148
149 3 Sampler::~Sampler() {
150 3 vkDestroySampler(device_, sampler_, nullptr);
151 3 }
152
153 } // namespace ernie
154