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