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