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