blob: 51904bb495cd401ff3dbbfdf2bfad4f7943e9741 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "garnet/public/lib/escher/renderer/batch_gpu_uploader.h"
#include <thread>
#include "garnet/public/lib/escher/test/gtest_escher.h"
#include "garnet/public/lib/escher/test/vk/vulkan_tester.h"
#include "gtest/gtest.h"
#include "lib/escher/util/image_utils.h"
#include "lib/escher/vk/buffer_factory.h"
#include "lib/escher/vk/image_factory.h"
namespace escher {
VK_TEST(BatchGpuUploader, CreateDestroyUploader) {
auto escher = test::GetEscher()->GetWeakPtr();
{
std::unique_ptr<BatchGpuUploader> uploader = BatchGpuUploader::New(escher);
// BatchGpuUploader must be submitted before it is destroyed.
uploader->Submit();
}
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
}
VK_TEST(BatchGpuUploader, InvalidUploader) {
// A BatchGpuUploader without an escher should not be created.
auto uploader = BatchGpuUploader::New(EscherWeakPtr());
EXPECT_FALSE(uploader);
}
VK_TEST(BatchGpuUploader, AcquireSubmitWriter) {
auto escher = test::GetEscher()->GetWeakPtr();
std::unique_ptr<BatchGpuUploader> uploader = BatchGpuUploader::New(escher);
auto writer = uploader->AcquireWriter(256);
uploader->PostWriter(std::move(writer));
// BatchGpuUploader must be submitted before it is destroyed.
uploader->Submit();
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
}
VK_TEST(BatchGpuUploader, AcquireSubmitReader) {
auto escher = test::GetEscher()->GetWeakPtr();
std::unique_ptr<BatchGpuUploader> uploader = BatchGpuUploader::New(escher);
auto reader = uploader->AcquireReader(256);
uploader->PostReader(std::move(reader), [](BufferPtr) {});
// BatchGpuUploader must be submitted before it is destroyed.
uploader->Submit();
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
}
VK_TEST(BatchGpuUploader, AcquireSubmitMultipleWriters) {
auto escher = test::GetEscher()->GetWeakPtr();
std::unique_ptr<BatchGpuUploader> uploader = BatchGpuUploader::New(escher);
auto writer = uploader->AcquireWriter(256);
uploader->PostWriter(std::move(writer));
// CommandBuffer should not have been posted to the driver, cleanup should
// fail.
escher->vk_device().waitIdle();
EXPECT_FALSE(escher->Cleanup());
auto writer2 = uploader->AcquireWriter(256);
uploader->PostWriter(std::move(writer2));
// CommandBuffer should not have been posted to the driver, cleanup should
// fail.
escher->vk_device().waitIdle();
EXPECT_FALSE(escher->Cleanup());
bool batched_upload_done = false;
uploader->Submit([&batched_upload_done]() { batched_upload_done = true; });
// Trigger Cleanup, which triggers the callback on the submitted command
// buffer.
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
EXPECT_TRUE(batched_upload_done);
}
VK_TEST(BatchGpuUploader, AcquireSubmitMultipleReaders) {
auto escher = test::GetEscher()->GetWeakPtr();
std::unique_ptr<BatchGpuUploader> uploader = BatchGpuUploader::New(escher);
auto reader = uploader->AcquireReader(256);
uploader->PostReader(std::move(reader), [](BufferPtr) {});
// CommandBuffer should not have been posted to the driver, cleanup should
// fail.
escher->vk_device().waitIdle();
EXPECT_FALSE(escher->Cleanup());
auto reader2 = uploader->AcquireReader(256);
uploader->PostReader(std::move(reader2), [](BufferPtr) {});
// CommandBuffer should not have been posted to the driver, cleanup should
// fail.
escher->vk_device().waitIdle();
EXPECT_FALSE(escher->Cleanup());
bool batched_upload_done = false;
uploader->Submit([&batched_upload_done]() { batched_upload_done = true; });
// Trigger Cleanup, which triggers the callback on the submitted command
// buffer.
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
EXPECT_TRUE(batched_upload_done);
}
VK_TEST(BatchGpuUploader, WriteBuffer) {
auto escher = test::GetEscher()->GetWeakPtr();
auto uploader = BatchGpuUploader::New(escher);
const size_t buffer_size = 3 * sizeof(vec3);
auto writer = uploader->AcquireWriter(buffer_size);
// Create buffer to write to.
BufferFactoryAdapter buffer_factory(escher->gpu_allocator(),
escher->resource_recycler());
BufferPtr vertex_buffer =
buffer_factory.NewBuffer(buffer_size,
vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eTransferDst,
vk::MemoryPropertyFlagBits::eDeviceLocal);
// Do write.
void* host_ptr = writer->host_ptr();
vec3* const verts = static_cast<vec3*>(host_ptr);
verts[0] = vec3(0.f, 0.f, 0.f);
verts[1] = vec3(0.f, 1.f, 0.f);
verts[2] = vec3(1.f, 0.f, 0.f);
writer->WriteBuffer(vertex_buffer, {0, 0, vertex_buffer->size()});
// Posting and submitting should succeed.
uploader->PostWriter(std::move(writer));
// Verify that the "upload done" Semaphore was set on the buffer.
EXPECT_TRUE(vertex_buffer->HasWaitSemaphore());
// Submit the work.
uploader->Submit();
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
}
VK_TEST(BatchGpuUploader, WriteImage) {
auto escher = test::GetEscher()->GetWeakPtr();
auto uploader = BatchGpuUploader::New(escher);
const size_t image_size = sizeof(uint8_t) * 4;
auto writer = uploader->AcquireWriter(image_size);
// Create a 1x1 RGBA (8-bit channels) image to write to.
ImageFactoryAdapter image_factory(escher->gpu_allocator(),
escher->resource_recycler());
ImagePtr image =
image_utils::NewImage(&image_factory, vk::Format::eR8G8B8A8Unorm, 1, 1);
vk::BufferImageCopy region;
region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageExtent.width = 1;
region.imageExtent.height = 1;
region.imageExtent.depth = 1;
region.bufferOffset = 0;
// Do write.
void* host_ptr = writer->host_ptr();
uint8_t* const pixels = static_cast<uint8_t*>(host_ptr);
pixels[0] = 150;
pixels[1] = 88;
pixels[2] = 121;
pixels[3] = 255;
EXPECT_FALSE(image->HasWaitSemaphore());
writer->WriteImage(image, region);
// Posting and submitting should succeed.
uploader->PostWriter(std::move(writer));
// Verify that the "upload done" Semaphore was set on the image.
EXPECT_TRUE(image->HasWaitSemaphore());
// Submit the work.
uploader->Submit();
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
}
VK_TEST(BatchGpuUploader, DISABLED_WriterNotPostedFails) {
// This successfully tests death. However, when unsupported, death kills the
// test process. Disabled until EXPECT_DEATH_IF_SUPPORTED can graduate to
// EXPECT_DEATH.
auto escher = test::GetEscher()->GetWeakPtr();
auto uploader = BatchGpuUploader::New(escher);
auto writer = uploader->AcquireWriter(256);
// Submit should fail since it does not have the command buffer to submit.
EXPECT_DEATH_IF_SUPPORTED(uploader->Submit(), "");
}
VK_TEST(BatchGpuUploader, DISABLED_WriterPostedToWrongUploaderFails) {
// This successfully tests death. However, when unsupported, death kills the
// test process. Disabled until EXPECT_DEATH_IF_SUPPORTED can graduate to
// EXPECT_DEATH.
auto escher = test::GetEscher()->GetWeakPtr();
auto uploader = BatchGpuUploader::New(escher, 0);
auto writer = uploader->AcquireWriter(256);
// New uploader is created with a different backing frame. Posting the first
// uploader's writer to this should fail.
auto uploader2 = BatchGpuUploader::New(escher, 1);
EXPECT_DEATH_IF_SUPPORTED(uploader->PostWriter(std::move(writer)), "");
// New uploader should be able to be successfully submitted and cleaned up.
uploader2->Submit();
// Original uploader did not have writer posted, and should fail to submit or
// be destroyed.
EXPECT_DEATH_IF_SUPPORTED(uploader->Submit(), "");
}
VK_TEST(BatchGpuUploader, DISABLED_ReadAWriteSucceeds) {
// TODO (SCN-1197) Enable once memory barriers are added to the
// BatchGpuUploader and it can be used for reads and writes on the same
// resource.
auto escher = test::GetEscher()->GetWeakPtr();
auto uploader = BatchGpuUploader::New(escher);
const size_t buffer_size = 3 * sizeof(vec3);
auto writer = uploader->AcquireWriter(buffer_size);
// Create buffer to write to.
BufferFactoryAdapter buffer_factory(escher->gpu_allocator(),
escher->resource_recycler());
BufferPtr vertex_buffer =
buffer_factory.NewBuffer(buffer_size,
vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eTransferSrc |
vk::BufferUsageFlagBits::eTransferDst,
vk::MemoryPropertyFlagBits::eDeviceLocal);
EXPECT_FALSE(vertex_buffer->HasWaitSemaphore());
// Do write.
void* host_ptr = writer->host_ptr();
vec3* const write_verts = static_cast<vec3*>(host_ptr);
write_verts[0] = vec3(0.f, 0.f, 1.f);
write_verts[1] = vec3(0.f, 1.f, 0.f);
write_verts[2] = vec3(1.f, 0.f, 0.f);
writer->WriteBuffer(vertex_buffer, {0, 0, vertex_buffer->size()});
// Posting and submitting should succeed.
uploader->PostWriter(std::move(writer));
// Verify that the "upload done" Semaphore was set on the buffer.
EXPECT_TRUE(vertex_buffer->HasWaitSemaphore());
// Create reader to read from the buffer pending a write.
auto reader = uploader->AcquireReader(buffer_size);
reader->ReadBuffer(vertex_buffer, {0, 0, vertex_buffer->size()});
EXPECT_TRUE(vertex_buffer->HasWaitSemaphore());
bool read_buffer_done = false;
uploader->PostReader(std::move(reader),
[&read_buffer_done, &write_verts](BufferPtr buffer) {
void* host_ptr = buffer->host_ptr();
vec3* const read_verts = static_cast<vec3*>(host_ptr);
EXPECT_EQ(read_verts[0], write_verts[0]);
EXPECT_EQ(read_verts[1], write_verts[1]);
EXPECT_EQ(read_verts[2], write_verts[2]);
read_buffer_done = true;
});
// Submit all the work.
uploader->Submit();
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
EXPECT_TRUE(read_buffer_done);
}
VK_TEST(BatchGpuUploader, ReadImageTest) {
auto escher = test::GetEscher()->GetWeakPtr();
auto image = escher->NewNoiseImage(512, 512);
vk::BufferImageCopy region;
region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageExtent.width = image->width();
region.imageExtent.height = image->height();
region.imageExtent.depth = 1;
region.bufferOffset = 0;
BatchGpuUploader uploader(escher, 0);
auto reader = uploader.AcquireReader(image->size());
reader->ReadImage(image, region);
// Verify that the "upload done" Semaphore was set on the image.
EXPECT_TRUE(image->HasWaitSemaphore());
bool read_image_done = false;
uploader.PostReader(std::move(reader), [&read_image_done](BufferPtr buffer) {
read_image_done = true;
});
uploader.Submit([]() {});
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
EXPECT_TRUE(read_image_done);
}
VK_TEST(BatchGpuUploader, ReadBufferTest) {
auto escher = test::GetEscher()->GetWeakPtr();
// Create buffer to read from.
const size_t buffer_size = 3 * sizeof(vec3);
BufferFactoryAdapter buffer_factory(escher->gpu_allocator(),
escher->resource_recycler());
BufferPtr vertex_buffer =
buffer_factory.NewBuffer(buffer_size,
vk::BufferUsageFlagBits::eVertexBuffer |
vk::BufferUsageFlagBits::eTransferSrc |
vk::BufferUsageFlagBits::eTransferDst,
vk::MemoryPropertyFlagBits::eHostVisible);
void* host_ptr = vertex_buffer->host_ptr();
vec3* const verts = static_cast<vec3*>(host_ptr);
verts[0] = vec3(0.f, 0.f, 0.f);
verts[1] = vec3(0.f, 1.f, 0.f);
verts[2] = vec3(1.f, 0.f, 0.f);
// Do read.
std::unique_ptr<BatchGpuUploader> uploader = BatchGpuUploader::New(escher, 0);
auto reader = uploader->AcquireReader(buffer_size);
reader->ReadBuffer(vertex_buffer, {0, 0, vertex_buffer->size()});
// Verify that the "upload done" Semaphore was set on the buffer.
EXPECT_TRUE(vertex_buffer->HasWaitSemaphore());
bool read_buffer_done = false;
uploader->PostReader(std::move(reader),
[&read_buffer_done](BufferPtr buffer) {
void* host_ptr = buffer->host_ptr();
vec3* const verts = static_cast<vec3*>(host_ptr);
EXPECT_EQ(verts[0], vec3(0.f, 0.f, 0.f));
EXPECT_EQ(verts[1], vec3(0.f, 1.f, 0.f));
EXPECT_EQ(verts[2], vec3(1.f, 0.f, 0.f));
read_buffer_done = true;
});
uploader->Submit();
escher->vk_device().waitIdle();
EXPECT_TRUE(escher->Cleanup());
EXPECT_TRUE(read_buffer_done);
}
} // namespace escher