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 "GfxstreamEnd2EndTestUtils.h"
16 
17 namespace gfxstream {
18 namespace tests {
19 namespace utils {
20 
21 using testing::Eq;
22 using testing::Ge;
23 using testing::IsEmpty;
24 using testing::IsNull;
25 using testing::Not;
26 using testing::NotNull;
27 
getMemoryType(const vkhpp::PhysicalDevice & physicalDevice,const vkhpp::MemoryRequirements & memoryRequirements,vkhpp::MemoryPropertyFlags memoryProperties)28 uint32_t getMemoryType(const vkhpp::PhysicalDevice& physicalDevice,
29                        const vkhpp::MemoryRequirements& memoryRequirements,
30                        vkhpp::MemoryPropertyFlags memoryProperties) {
31     const auto props = physicalDevice.getMemoryProperties();
32     for (uint32_t i = 0; i < props.memoryTypeCount; i++) {
33         if (!(memoryRequirements.memoryTypeBits & (1 << i))) {
34             continue;
35         }
36         if ((props.memoryTypes[i].propertyFlags & memoryProperties) != memoryProperties) {
37             continue;
38         }
39         return i;
40     }
41     return -1;
42 }
43 
readImageData(vkhpp::Image image,uint32_t width,uint32_t height,vkhpp::ImageLayout currentLayout,void * dst,uint64_t dstSize,const GfxstreamEnd2EndTest::TypicalVkTestEnvironment & testEnvironment)44 void readImageData(vkhpp::Image image, uint32_t width, uint32_t height,
45                    vkhpp::ImageLayout currentLayout, void* dst, uint64_t dstSize,
46                    const GfxstreamEnd2EndTest::TypicalVkTestEnvironment& testEnvironment) {
47     auto& instance = testEnvironment.instance;
48     auto& physicalDevice = testEnvironment.physicalDevice;
49     auto& device = testEnvironment.device;
50     auto& queue = testEnvironment.queue;
51     auto queueFamilyIndex = testEnvironment.queueFamilyIndex;
52 
53     // Read-back buffer
54     const vkhpp::BufferCreateInfo readbackBufferCreateInfo = {
55         .size = static_cast<VkDeviceSize>(dstSize),
56         .usage = vkhpp::BufferUsageFlagBits::eTransferDst,
57         .sharingMode = vkhpp::SharingMode::eExclusive,
58     };
59     auto readbackBuffer = device->createBufferUnique(readbackBufferCreateInfo).value;
60     ASSERT_THAT(readbackBuffer, IsValidHandle());
61 
62     vkhpp::MemoryRequirements readbackBufferMemoryRequirements{};
63     device->getBufferMemoryRequirements(*readbackBuffer, &readbackBufferMemoryRequirements);
64 
65     const auto readbackBufferMemoryType = getMemoryType(
66         physicalDevice, readbackBufferMemoryRequirements,
67         vkhpp::MemoryPropertyFlagBits::eHostVisible | vkhpp::MemoryPropertyFlagBits::eHostCoherent);
68 
69     // Read-back memory
70     const vkhpp::MemoryAllocateInfo readbackBufferMemoryAllocateInfo = {
71         .allocationSize = readbackBufferMemoryRequirements.size,
72         .memoryTypeIndex = readbackBufferMemoryType,
73     };
74     auto readbackBufferMemory =
75         device->allocateMemoryUnique(readbackBufferMemoryAllocateInfo).value;
76     ASSERT_THAT(readbackBufferMemory, IsValidHandle());
77     ASSERT_THAT(device->bindBufferMemory(*readbackBuffer, *readbackBufferMemory, 0), IsVkSuccess());
78 
79     // Command buffer
80     const vkhpp::CommandPoolCreateInfo commandPoolCreateInfo = {
81         .queueFamilyIndex = queueFamilyIndex,
82     };
83 
84     auto commandPool = device->createCommandPoolUnique(commandPoolCreateInfo).value;
85     ASSERT_THAT(commandPool, IsValidHandle());
86     const vkhpp::CommandBufferAllocateInfo commandBufferAllocateInfo = {
87         .level = vkhpp::CommandBufferLevel::ePrimary,
88         .commandPool = *commandPool,
89         .commandBufferCount = 1,
90     };
91     auto readbackCommandBuffers =
92         device->allocateCommandBuffersUnique(commandBufferAllocateInfo).value;
93     ASSERT_THAT(readbackCommandBuffers, Not(IsEmpty()));
94     auto readbackCommandBuffer = std::move(readbackCommandBuffers[0]);
95     ASSERT_THAT(readbackCommandBuffer, IsValidHandle());
96 
97     const vkhpp::CommandBufferBeginInfo commandBufferBeginInfo = {
98         .flags = vkhpp::CommandBufferUsageFlagBits::eOneTimeSubmit,
99     };
100     readbackCommandBuffer->begin(commandBufferBeginInfo);
101     const vkhpp::ImageMemoryBarrier readbackBarrier{
102         .oldLayout = currentLayout,
103         .newLayout = vkhpp::ImageLayout::eTransferSrcOptimal,
104         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
105         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
106         .image = image,
107         .subresourceRange =
108             {
109                 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
110                 .levelCount = 1,
111                 .layerCount = 1,
112             },
113     };
114 
115     readbackCommandBuffer->pipelineBarrier(
116         vkhpp::PipelineStageFlagBits::eAllCommands, vkhpp::PipelineStageFlagBits::eAllCommands,
117         vkhpp::DependencyFlags(), nullptr, nullptr, readbackBarrier);
118 
119     const vkhpp::BufferImageCopy bufferImageCopy = {
120         .imageSubresource =
121             {
122                 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
123                 .layerCount = 1,
124             },
125         .imageExtent =
126             {
127                 .width = width,
128                 .height = height,
129                 .depth = 1,
130             },
131     };
132     readbackCommandBuffer->copyImageToBuffer(image, vkhpp::ImageLayout::eTransferSrcOptimal,
133                                              *readbackBuffer, 1, &bufferImageCopy);
134 
135     const vkhpp::ImageMemoryBarrier restoreBarrier{
136         .oldLayout = vkhpp::ImageLayout::eTransferSrcOptimal,
137         .newLayout = currentLayout,
138         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
139         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
140         .image = image,
141         .subresourceRange =
142             {
143                 .aspectMask = vkhpp::ImageAspectFlagBits::eColor,
144                 .levelCount = 1,
145                 .layerCount = 1,
146             },
147     };
148 
149     readbackCommandBuffer->pipelineBarrier(
150         vkhpp::PipelineStageFlagBits::eAllCommands, vkhpp::PipelineStageFlagBits::eAllCommands,
151         vkhpp::DependencyFlags(), nullptr, nullptr, restoreBarrier);
152 
153     readbackCommandBuffer->end();
154 
155     auto readbackFence = device->createFenceUnique(vkhpp::FenceCreateInfo()).value;
156     ASSERT_THAT(readbackCommandBuffer, IsValidHandle());
157 
158     // Execute the command to copy image back to buffer
159     const vkhpp::SubmitInfo readbackSubmitInfo = {
160         .commandBufferCount = 1,
161         .pCommandBuffers = &readbackCommandBuffer.get(),
162     };
163     queue.submit(readbackSubmitInfo, *readbackFence);
164 
165     auto readbackWaitResult = device->waitForFences(*readbackFence, VK_TRUE, 3000000000L);
166     ASSERT_THAT(readbackWaitResult, IsVkSuccess());
167 
168     // Verify content
169     void* mapped;
170     auto mapResult = device->mapMemory(*readbackBufferMemory, 0, VK_WHOLE_SIZE,
171                                        vkhpp::MemoryMapFlags{}, &mapped);
172     ASSERT_THAT(mapResult, IsVkSuccess());
173     ASSERT_THAT(mapped, NotNull());
174     memcpy(dst, mapped, dstSize);
175     device->unmapMemory(*readbackBufferMemory);
176 }
177 
178 }  // namespace utils
179 }  // namespace tests
180 }  // namespace gfxstream