blob: dbc043aa06d8a4e67df7cf25996ca84051845f21 [file] [log] [blame]
// Copyright (C) 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include "GfxstreamEnd2EndTestUtils.h"
#include "GfxstreamEnd2EndTests.h"
#include "gfxstream/RutabagaLayerTestUtils.h"
namespace gfxstream {
namespace tests {
namespace {
using testing::Eq;
using testing::Ge;
using testing::IsEmpty;
using testing::IsNull;
using testing::Not;
using testing::NotNull;
class GfxstreamEnd2EndVkSnapshotBufferTest : public GfxstreamEnd2EndTest {};
TEST_P(GfxstreamEnd2EndVkSnapshotBufferTest, BufferContent) {
static constexpr vkhpp::DeviceSize kSize = 256;
std::vector<uint8_t> srcBufferContent(kSize);
for (size_t i = 0; i < kSize; i++) {
srcBufferContent[i] = static_cast<uint8_t>(i & 0xff);
}
auto [instance, physicalDevice, device, queue, queueFamilyIndex] =
VK_ASSERT(SetUpTypicalVkTestEnvironment());
// Staging buffer
const vkhpp::BufferCreateInfo stagingBufferCreateInfo = {
.size = static_cast<VkDeviceSize>(kSize),
.usage = vkhpp::BufferUsageFlagBits::eTransferSrc,
.sharingMode = vkhpp::SharingMode::eExclusive,
};
auto stagingBuffer = device->createBufferUnique(stagingBufferCreateInfo).value;
ASSERT_THAT(stagingBuffer, IsValidHandle());
vkhpp::MemoryRequirements stagingBufferMemoryRequirements{};
device->getBufferMemoryRequirements(*stagingBuffer, &stagingBufferMemoryRequirements);
const auto stagingBufferMemoryType = utils::getMemoryType(
physicalDevice, stagingBufferMemoryRequirements,
vkhpp::MemoryPropertyFlagBits::eHostVisible | vkhpp::MemoryPropertyFlagBits::eHostCoherent);
// Staging memory
const vkhpp::MemoryAllocateInfo stagingBufferMemoryAllocateInfo = {
.allocationSize = stagingBufferMemoryRequirements.size,
.memoryTypeIndex = stagingBufferMemoryType,
};
auto stagingBufferMemory = device->allocateMemoryUnique(stagingBufferMemoryAllocateInfo).value;
ASSERT_THAT(stagingBufferMemory, IsValidHandle());
ASSERT_THAT(device->bindBufferMemory(*stagingBuffer, *stagingBufferMemory, 0), IsVkSuccess());
// Fill memory content
void* mapped = nullptr;
auto mapResult =
device->mapMemory(*stagingBufferMemory, 0, VK_WHOLE_SIZE, vkhpp::MemoryMapFlags{}, &mapped);
ASSERT_THAT(mapResult, IsVkSuccess());
ASSERT_THAT(mapped, NotNull());
auto* bytes = reinterpret_cast<uint8_t*>(mapped);
std::memcpy(bytes, srcBufferContent.data(), kSize);
const vkhpp::MappedMemoryRange range = {
.memory = *stagingBufferMemory,
.offset = 0,
.size = kSize,
};
device->unmapMemory(*stagingBufferMemory);
// Vertex buffer
const vkhpp::BufferCreateInfo vertexBufferCreateInfo = {
.size = static_cast<VkDeviceSize>(kSize),
.usage = vkhpp::BufferUsageFlagBits::eVertexBuffer,
.sharingMode = vkhpp::SharingMode::eExclusive,
};
auto vertexBuffer = device->createBufferUnique(vertexBufferCreateInfo).value;
ASSERT_THAT(vertexBuffer, IsValidHandle());
vkhpp::MemoryRequirements vertexBufferMemoryRequirements{};
device->getBufferMemoryRequirements(*vertexBuffer, &vertexBufferMemoryRequirements);
const auto vertexBufferMemoryType = utils::getMemoryType(
physicalDevice, vertexBufferMemoryRequirements,
vkhpp::MemoryPropertyFlagBits::eHostVisible | vkhpp::MemoryPropertyFlagBits::eHostCoherent);
// Vertex memory
const vkhpp::MemoryAllocateInfo vertexBufferMemoryAllocateInfo = {
.allocationSize = vertexBufferMemoryRequirements.size,
.memoryTypeIndex = vertexBufferMemoryType,
};
auto vertexBufferMemory = device->allocateMemoryUnique(vertexBufferMemoryAllocateInfo).value;
ASSERT_THAT(vertexBufferMemory, IsValidHandle());
ASSERT_THAT(device->bindBufferMemory(*vertexBuffer, *vertexBufferMemory, 0), IsVkSuccess());
// Command buffer
const vkhpp::CommandPoolCreateInfo commandPoolCreateInfo = {
.queueFamilyIndex = queueFamilyIndex,
};
auto commandPool = device->createCommandPoolUnique(commandPoolCreateInfo).value;
ASSERT_THAT(commandPool, IsValidHandle());
const vkhpp::CommandBufferAllocateInfo commandBufferAllocateInfo = {
.level = vkhpp::CommandBufferLevel::ePrimary,
.commandPool = *commandPool,
.commandBufferCount = 1,
};
auto commandBuffers = device->allocateCommandBuffersUnique(commandBufferAllocateInfo).value;
ASSERT_THAT(commandBuffers, Not(IsEmpty()));
auto commandBuffer = std::move(commandBuffers[0]);
ASSERT_THAT(commandBuffer, IsValidHandle());
const vkhpp::CommandBufferBeginInfo commandBufferBeginInfo = {
.flags = vkhpp::CommandBufferUsageFlagBits::eOneTimeSubmit,
};
commandBuffer->begin(commandBufferBeginInfo);
const vkhpp::BufferCopy bufferCopy = {
.size = kSize,
};
commandBuffer->copyBuffer(*stagingBuffer, *vertexBuffer, 1, &bufferCopy);
commandBuffer->end();
auto transferFence = device->createFenceUnique(vkhpp::FenceCreateInfo()).value;
ASSERT_THAT(transferFence, IsValidHandle());
// Execute the command to copy image
const vkhpp::SubmitInfo submitInfo = {
.commandBufferCount = 1,
.pCommandBuffers = &commandBuffer.get(),
};
queue.submit(submitInfo, *transferFence);
auto waitResult = device->waitForFences(*transferFence, VK_TRUE, 3000000000L);
ASSERT_THAT(waitResult, IsVkSuccess());
// Snapshot
SnapshotSaveAndLoad();
// Read-back buffer
const vkhpp::BufferCreateInfo readbackBufferCreateInfo = {
.size = static_cast<VkDeviceSize>(kSize),
.usage = vkhpp::BufferUsageFlagBits::eTransferDst,
.sharingMode = vkhpp::SharingMode::eExclusive,
};
auto readbackBuffer = device->createBufferUnique(readbackBufferCreateInfo).value;
ASSERT_THAT(readbackBuffer, IsValidHandle());
vkhpp::MemoryRequirements readbackBufferMemoryRequirements{};
device->getBufferMemoryRequirements(*readbackBuffer, &readbackBufferMemoryRequirements);
const auto readbackBufferMemoryType = utils::getMemoryType(
physicalDevice, readbackBufferMemoryRequirements,
vkhpp::MemoryPropertyFlagBits::eHostVisible | vkhpp::MemoryPropertyFlagBits::eHostCoherent);
// Read-back memory
const vkhpp::MemoryAllocateInfo readbackBufferMemoryAllocateInfo = {
.allocationSize = readbackBufferMemoryRequirements.size,
.memoryTypeIndex = readbackBufferMemoryType,
};
auto readbackBufferMemory =
device->allocateMemoryUnique(readbackBufferMemoryAllocateInfo).value;
ASSERT_THAT(readbackBufferMemory, IsValidHandle());
ASSERT_THAT(device->bindBufferMemory(*readbackBuffer, *readbackBufferMemory, 0), IsVkSuccess());
auto readbackCommandBuffers =
device->allocateCommandBuffersUnique(commandBufferAllocateInfo).value;
ASSERT_THAT(readbackCommandBuffers, Not(IsEmpty()));
auto readbackCommandBuffer = std::move(readbackCommandBuffers[0]);
ASSERT_THAT(readbackCommandBuffer, IsValidHandle());
readbackCommandBuffer->begin(commandBufferBeginInfo);
readbackCommandBuffer->copyBuffer(*vertexBuffer, *readbackBuffer, 1, &bufferCopy);
readbackCommandBuffer->end();
auto readbackFence = device->createFenceUnique(vkhpp::FenceCreateInfo()).value;
ASSERT_THAT(readbackCommandBuffer, IsValidHandle());
// Execute the command to copy image back to buffer
const vkhpp::SubmitInfo readbackSubmitInfo = {
.commandBufferCount = 1,
.pCommandBuffers = &readbackCommandBuffer.get(),
};
queue.submit(readbackSubmitInfo, *readbackFence);
auto readbackWaitResult = device->waitForFences(*readbackFence, VK_TRUE, 3000000000L);
ASSERT_THAT(readbackWaitResult, IsVkSuccess());
// Verify content
mapResult = device->mapMemory(*readbackBufferMemory, 0, VK_WHOLE_SIZE, vkhpp::MemoryMapFlags{},
&mapped);
ASSERT_THAT(mapResult, IsVkSuccess());
ASSERT_THAT(mapped, NotNull());
bytes = reinterpret_cast<uint8_t*>(mapped);
for (uint32_t i = 0; i < kSize; ++i) {
ASSERT_THAT(bytes[i], Eq(srcBufferContent[i]));
}
device->unmapMemory(*readbackBufferMemory);
}
INSTANTIATE_TEST_CASE_P(GfxstreamEnd2EndTests, GfxstreamEnd2EndVkSnapshotBufferTest,
::testing::ValuesIn({
TestParams{
.with_gl = false,
.with_vk = true,
.with_features = {"VulkanSnapshots"},
},
}),
&GetTestName);
} // namespace
} // namespace tests
} // namespace gfxstream