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