1 // Copyright (C) 2024 The Android Open Source Project
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 <string>
16
17 #include "GfxstreamEnd2EndTestUtils.h"
18 #include "GfxstreamEnd2EndTests.h"
19 #include "gfxstream/RutabagaLayerTestUtils.h"
20
21 namespace gfxstream {
22 namespace tests {
23 namespace {
24
25 using testing::Eq;
26 using testing::Ge;
27 using testing::IsEmpty;
28 using testing::IsNull;
29 using testing::Not;
30 using testing::NotNull;
31
32 class GfxstreamEnd2EndVkSnapshotBufferTest : public GfxstreamEnd2EndTest {};
33
TEST_P(GfxstreamEnd2EndVkSnapshotBufferTest,DeviceLocalBufferContent)34 TEST_P(GfxstreamEnd2EndVkSnapshotBufferTest, DeviceLocalBufferContent) {
35 static constexpr vkhpp::DeviceSize kSize = 256;
36
37 std::vector<uint8_t> srcBufferContent(kSize);
38 for (size_t i = 0; i < kSize; i++) {
39 srcBufferContent[i] = static_cast<uint8_t>(i & 0xff);
40 }
41 auto [instance, physicalDevice, device, queue, queueFamilyIndex] =
42 VK_ASSERT(SetUpTypicalVkTestEnvironment());
43
44 // Staging buffer
45 const vkhpp::BufferCreateInfo stagingBufferCreateInfo = {
46 .size = static_cast<VkDeviceSize>(kSize),
47 .usage = vkhpp::BufferUsageFlagBits::eTransferSrc,
48 .sharingMode = vkhpp::SharingMode::eExclusive,
49 };
50 auto stagingBuffer = device->createBufferUnique(stagingBufferCreateInfo).value;
51 ASSERT_THAT(stagingBuffer, IsValidHandle());
52
53 vkhpp::MemoryRequirements stagingBufferMemoryRequirements{};
54 device->getBufferMemoryRequirements(*stagingBuffer, &stagingBufferMemoryRequirements);
55
56 const auto stagingBufferMemoryType = utils::getMemoryType(
57 physicalDevice, stagingBufferMemoryRequirements,
58 vkhpp::MemoryPropertyFlagBits::eHostVisible | vkhpp::MemoryPropertyFlagBits::eHostCoherent);
59
60 // Staging memory
61 const vkhpp::MemoryAllocateInfo stagingBufferMemoryAllocateInfo = {
62 .allocationSize = stagingBufferMemoryRequirements.size,
63 .memoryTypeIndex = stagingBufferMemoryType,
64 };
65 auto stagingBufferMemory = device->allocateMemoryUnique(stagingBufferMemoryAllocateInfo).value;
66 ASSERT_THAT(stagingBufferMemory, IsValidHandle());
67 ASSERT_THAT(device->bindBufferMemory(*stagingBuffer, *stagingBufferMemory, 0), IsVkSuccess());
68
69 // Fill memory content
70 void* mapped = nullptr;
71 auto mapResult =
72 device->mapMemory(*stagingBufferMemory, 0, VK_WHOLE_SIZE, vkhpp::MemoryMapFlags{}, &mapped);
73 ASSERT_THAT(mapResult, IsVkSuccess());
74 ASSERT_THAT(mapped, NotNull());
75
76 auto* bytes = reinterpret_cast<uint8_t*>(mapped);
77 std::memcpy(bytes, srcBufferContent.data(), kSize);
78
79 const vkhpp::MappedMemoryRange range = {
80 .memory = *stagingBufferMemory,
81 .offset = 0,
82 .size = kSize,
83 };
84 device->unmapMemory(*stagingBufferMemory);
85
86 // Vertex buffer
87 const vkhpp::BufferCreateInfo vertexBufferCreateInfo = {
88 .size = static_cast<VkDeviceSize>(kSize),
89 .usage = vkhpp::BufferUsageFlagBits::eVertexBuffer |
90 vkhpp::BufferUsageFlagBits::eTransferSrc |
91 vkhpp::BufferUsageFlagBits::eTransferDst,
92 .sharingMode = vkhpp::SharingMode::eExclusive,
93 };
94 auto vertexBuffer = device->createBufferUnique(vertexBufferCreateInfo).value;
95 ASSERT_THAT(vertexBuffer, IsValidHandle());
96
97 vkhpp::MemoryRequirements vertexBufferMemoryRequirements{};
98 device->getBufferMemoryRequirements(*vertexBuffer, &vertexBufferMemoryRequirements);
99
100 const auto vertexBufferMemoryType =
101 utils::getMemoryType(physicalDevice, vertexBufferMemoryRequirements,
102 vkhpp::MemoryPropertyFlagBits::eDeviceLocal);
103
104 // Vertex memory
105 const vkhpp::MemoryAllocateInfo vertexBufferMemoryAllocateInfo = {
106 .allocationSize = vertexBufferMemoryRequirements.size,
107 .memoryTypeIndex = vertexBufferMemoryType,
108 };
109 auto vertexBufferMemory = device->allocateMemoryUnique(vertexBufferMemoryAllocateInfo).value;
110 ASSERT_THAT(vertexBufferMemory, IsValidHandle());
111 ASSERT_THAT(device->bindBufferMemory(*vertexBuffer, *vertexBufferMemory, 0), IsVkSuccess());
112
113 // Command buffer
114 const vkhpp::CommandPoolCreateInfo commandPoolCreateInfo = {
115 .queueFamilyIndex = queueFamilyIndex,
116 };
117
118 auto commandPool = device->createCommandPoolUnique(commandPoolCreateInfo).value;
119 ASSERT_THAT(commandPool, IsValidHandle());
120
121 const vkhpp::CommandBufferAllocateInfo commandBufferAllocateInfo = {
122 .level = vkhpp::CommandBufferLevel::ePrimary,
123 .commandPool = *commandPool,
124 .commandBufferCount = 1,
125 };
126 auto commandBuffers = device->allocateCommandBuffersUnique(commandBufferAllocateInfo).value;
127 ASSERT_THAT(commandBuffers, Not(IsEmpty()));
128 auto commandBuffer = std::move(commandBuffers[0]);
129 ASSERT_THAT(commandBuffer, IsValidHandle());
130
131 const vkhpp::CommandBufferBeginInfo commandBufferBeginInfo = {
132 .flags = vkhpp::CommandBufferUsageFlagBits::eOneTimeSubmit,
133 };
134 commandBuffer->begin(commandBufferBeginInfo);
135 const vkhpp::BufferCopy bufferCopy = {
136 .size = kSize,
137 };
138 commandBuffer->copyBuffer(*stagingBuffer, *vertexBuffer, 1, &bufferCopy);
139 commandBuffer->end();
140
141 auto transferFence = device->createFenceUnique(vkhpp::FenceCreateInfo()).value;
142 ASSERT_THAT(transferFence, IsValidHandle());
143
144 // Execute the command to copy image
145 const vkhpp::SubmitInfo submitInfo = {
146 .commandBufferCount = 1,
147 .pCommandBuffers = &commandBuffer.get(),
148 };
149 queue.submit(submitInfo, *transferFence);
150
151 auto waitResult = device->waitForFences(*transferFence, VK_TRUE, 3000000000L);
152 ASSERT_THAT(waitResult, IsVkSuccess());
153
154 // Snapshot
155 SnapshotSaveAndLoad();
156
157 // Read-back buffer
158 const vkhpp::BufferCreateInfo readbackBufferCreateInfo = {
159 .size = static_cast<VkDeviceSize>(kSize),
160 .usage = vkhpp::BufferUsageFlagBits::eTransferDst,
161 .sharingMode = vkhpp::SharingMode::eExclusive,
162 };
163 auto readbackBuffer = device->createBufferUnique(readbackBufferCreateInfo).value;
164 ASSERT_THAT(readbackBuffer, IsValidHandle());
165
166 vkhpp::MemoryRequirements readbackBufferMemoryRequirements{};
167 device->getBufferMemoryRequirements(*readbackBuffer, &readbackBufferMemoryRequirements);
168
169 const auto readbackBufferMemoryType = utils::getMemoryType(
170 physicalDevice, readbackBufferMemoryRequirements,
171 vkhpp::MemoryPropertyFlagBits::eHostVisible | vkhpp::MemoryPropertyFlagBits::eHostCoherent);
172
173 // Read-back memory
174 const vkhpp::MemoryAllocateInfo readbackBufferMemoryAllocateInfo = {
175 .allocationSize = readbackBufferMemoryRequirements.size,
176 .memoryTypeIndex = readbackBufferMemoryType,
177 };
178 auto readbackBufferMemory =
179 device->allocateMemoryUnique(readbackBufferMemoryAllocateInfo).value;
180 ASSERT_THAT(readbackBufferMemory, IsValidHandle());
181 ASSERT_THAT(device->bindBufferMemory(*readbackBuffer, *readbackBufferMemory, 0), IsVkSuccess());
182
183 auto readbackCommandBuffers =
184 device->allocateCommandBuffersUnique(commandBufferAllocateInfo).value;
185 ASSERT_THAT(readbackCommandBuffers, Not(IsEmpty()));
186 auto readbackCommandBuffer = std::move(readbackCommandBuffers[0]);
187 ASSERT_THAT(readbackCommandBuffer, IsValidHandle());
188
189 readbackCommandBuffer->begin(commandBufferBeginInfo);
190 readbackCommandBuffer->copyBuffer(*vertexBuffer, *readbackBuffer, 1, &bufferCopy);
191 readbackCommandBuffer->end();
192
193 auto readbackFence = device->createFenceUnique(vkhpp::FenceCreateInfo()).value;
194 ASSERT_THAT(readbackCommandBuffer, IsValidHandle());
195
196 // Execute the command to copy image back to buffer
197 const vkhpp::SubmitInfo readbackSubmitInfo = {
198 .commandBufferCount = 1,
199 .pCommandBuffers = &readbackCommandBuffer.get(),
200 };
201 queue.submit(readbackSubmitInfo, *readbackFence);
202
203 auto readbackWaitResult = device->waitForFences(*readbackFence, VK_TRUE, 3000000000L);
204 ASSERT_THAT(readbackWaitResult, IsVkSuccess());
205
206 // Verify content
207 mapResult = device->mapMemory(*readbackBufferMemory, 0, VK_WHOLE_SIZE, vkhpp::MemoryMapFlags{},
208 &mapped);
209 ASSERT_THAT(mapResult, IsVkSuccess());
210 ASSERT_THAT(mapped, NotNull());
211 bytes = reinterpret_cast<uint8_t*>(mapped);
212
213 for (uint32_t i = 0; i < kSize; ++i) {
214 ASSERT_THAT(bytes[i], Eq(srcBufferContent[i]));
215 }
216 device->unmapMemory(*readbackBufferMemory);
217 }
218
TEST_P(GfxstreamEnd2EndVkSnapshotBufferTest,HostVisibleBufferContent)219 TEST_P(GfxstreamEnd2EndVkSnapshotBufferTest, HostVisibleBufferContent) {
220 static constexpr vkhpp::DeviceSize kSize = 256;
221
222 std::vector<uint8_t> srcBufferContent(kSize);
223 for (size_t i = 0; i < kSize; i++) {
224 srcBufferContent[i] = static_cast<uint8_t>(i & 0xff);
225 }
226 auto [instance, physicalDevice, device, queue, queueFamilyIndex] =
227 VK_ASSERT(SetUpTypicalVkTestEnvironment());
228
229 // Vertex buffer
230 const vkhpp::BufferCreateInfo uniformBufferCreateInfo = {
231 .size = static_cast<VkDeviceSize>(kSize),
232 .usage = vkhpp::BufferUsageFlagBits::eUniformBuffer,
233 .sharingMode = vkhpp::SharingMode::eExclusive,
234 };
235 auto uniformBuffer = device->createBufferUnique(uniformBufferCreateInfo).value;
236 ASSERT_THAT(uniformBuffer, IsValidHandle());
237
238 vkhpp::MemoryRequirements uniformBufferMemoryRequirements{};
239 device->getBufferMemoryRequirements(*uniformBuffer, &uniformBufferMemoryRequirements);
240
241 const auto uniformBufferMemoryType = utils::getMemoryType(
242 physicalDevice, uniformBufferMemoryRequirements,
243 vkhpp::MemoryPropertyFlagBits::eHostVisible | vkhpp::MemoryPropertyFlagBits::eHostCoherent);
244
245 // Vertex memory
246 const vkhpp::MemoryAllocateInfo uniformBufferMemoryAllocateInfo = {
247 .allocationSize = uniformBufferMemoryRequirements.size,
248 .memoryTypeIndex = uniformBufferMemoryType,
249 };
250 auto uniformBufferMemory = device->allocateMemoryUnique(uniformBufferMemoryAllocateInfo).value;
251 ASSERT_THAT(uniformBufferMemory, IsValidHandle());
252 ASSERT_THAT(device->bindBufferMemory(*uniformBuffer, *uniformBufferMemory, 0), IsVkSuccess());
253
254 // Fill memory content
255 void* mapped = nullptr;
256 auto mapResult =
257 device->mapMemory(*uniformBufferMemory, 0, VK_WHOLE_SIZE, vkhpp::MemoryMapFlags{}, &mapped);
258 ASSERT_THAT(mapResult, IsVkSuccess());
259 ASSERT_THAT(mapped, NotNull());
260
261 auto* bytes = reinterpret_cast<uint8_t*>(mapped);
262 std::memcpy(bytes, srcBufferContent.data(), kSize);
263
264 device->unmapMemory(*uniformBufferMemory);
265
266 // We need to unmap before snapshot due to limitations of the testing framework.
267 SnapshotSaveAndLoad();
268
269 // Verify content
270 mapResult =
271 device->mapMemory(*uniformBufferMemory, 0, VK_WHOLE_SIZE, vkhpp::MemoryMapFlags{}, &mapped);
272 ASSERT_THAT(mapResult, IsVkSuccess());
273 ASSERT_THAT(mapped, NotNull());
274 bytes = reinterpret_cast<uint8_t*>(mapped);
275
276 for (uint32_t i = 0; i < kSize; ++i) {
277 ASSERT_THAT(bytes[i], Eq(srcBufferContent[i]));
278 }
279 device->unmapMemory(*uniformBufferMemory);
280 }
281
282 INSTANTIATE_TEST_CASE_P(GfxstreamEnd2EndTests, GfxstreamEnd2EndVkSnapshotBufferTest,
283 ::testing::ValuesIn({
284 TestParams{
285 .with_gl = false,
286 .with_vk = true,
287 .with_features = {"VulkanSnapshots"},
288 },
289 }),
290 &GetTestName);
291
292 } // namespace
293 } // namespace tests
294 } // namespace gfxstream