blob: ac475cf56c4b03df40dc84791485f270ab4ab622 [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/lib/ui/gfx/resources/host_image.h"
#include "garnet/lib/ui/gfx/tests/session_test.h"
#include "garnet/lib/ui/gfx/tests/vk_session_test.h"
#include "gtest/gtest.h"
#include "lib/images/cpp/images.h"
#include "lib/ui/scenic/cpp/commands.h"
#include "src/ui/lib/escher/test/gtest_vulkan.h"
#include "src/ui/lib/escher/vk/vulkan_device_queues.h"
using namespace escher;
namespace {
const uint32_t kVmoSize = 65536;
// If you change the size of this buffer, make sure that the YUV test in
// scenic_pixel_test.cc is also updated. Unlike this unit test,
// scenic_pixel_test.cc has no way to confirm that it is going through the
// direct-to-GPU path.
// TODO(SCN-1387): This number needs to be queried via sysmem or vulkan.
const uint32_t kSize = 64;
const uint32_t kMemoryId = 1;
const uint32_t kImageId = 2;
const uint32_t kImagePipeId = 3;
class ImageFactoryListener : public ImageFactory {
public:
ImageFactoryListener(ImageFactory* factory) : factory_(factory) {}
ImagePtr NewImage(const ImageInfo& info, GpuMemPtr* out_ptr = nullptr) {
++images_created_;
return factory_->NewImage(info, out_ptr);
}
uint32_t images_created_ = 0;
ImageFactory* factory_;
};
} // namespace
namespace scenic_impl {
namespace gfx {
namespace test {
class HostImageTest : public VkSessionTest {
public:
void OnSessionContextCreated(SessionContext* context) override {
ASSERT_FALSE(listener);
listener =
std::make_unique<ImageFactoryListener>(context->escher_image_factory);
context->escher_image_factory = listener.get();
}
std::unique_ptr<ImageFactoryListener> listener;
};
VK_TEST_F(HostImageTest, FindResource) {
zx::vmo vmo;
zx_status_t status = zx::vmo::create(kVmoSize, 0u, &vmo);
ASSERT_EQ(ZX_OK, status);
ASSERT_TRUE(Apply(
scenic::NewCreateMemoryCmd(kMemoryId, std::move(vmo), kVmoSize,
fuchsia::images::MemoryType::HOST_MEMORY)));
fuchsia::images::ImageInfo image_info{
.width = kSize,
.height = kSize,
.stride = static_cast<uint32_t>(
kSize * images::StrideBytesPerWidthPixel(
fuchsia::images::PixelFormat::BGRA_8)),
.pixel_format = fuchsia::images::PixelFormat::BGRA_8,
};
ASSERT_TRUE(
Apply(scenic::NewCreateImageCmd(kImageId, kMemoryId, 0, image_info)));
fidl::InterfacePtr<fuchsia::images::ImagePipe> image_pipe;
ASSERT_TRUE(Apply(
scenic::NewCreateImagePipeCmd(kImagePipeId, image_pipe.NewRequest())));
// Host images should be findable as their concrete sub-class.
auto host_image_resource = FindResource<HostImage>(kImageId);
EXPECT_TRUE(host_image_resource);
// Host images should also be findable as their base class (i.e., Image).
auto image_resource = FindResource<Image>(kImageId);
EXPECT_TRUE(image_resource);
// Memory should not be findable as the same base class.
auto memory_as_image_resource = FindResource<Image>(kMemoryId);
EXPECT_FALSE(memory_as_image_resource);
// Image pipes should not be findable as the Image class (even though they are
// an ImageBase, the next class down).
auto image_pipe_as_image_resource = FindResource<Image>(kImagePipeId);
EXPECT_FALSE(image_pipe_as_image_resource);
}
VK_TEST_F(HostImageTest, RgbaImport) {
zx::vmo vmo;
zx_status_t status = zx::vmo::create(kVmoSize, 0u, &vmo);
ASSERT_EQ(ZX_OK, status);
ASSERT_TRUE(Apply(
scenic::NewCreateMemoryCmd(kMemoryId, std::move(vmo), kVmoSize,
fuchsia::images::MemoryType::HOST_MEMORY)));
fuchsia::images::ImageInfo image_info{
.width = kSize,
.height = kSize,
.stride = static_cast<uint32_t>(
kSize * images::StrideBytesPerWidthPixel(
fuchsia::images::PixelFormat::BGRA_8)),
.pixel_format = fuchsia::images::PixelFormat::BGRA_8,
};
ASSERT_TRUE(
Apply(scenic::NewCreateImageCmd(kImageId, kMemoryId, 0, image_info)));
auto image_resource = FindResource<HostImage>(kImageId);
ASSERT_TRUE(image_resource);
EXPECT_FALSE(image_resource->IsDirectlyMapped());
// Before updating pixels, image resources should never return a valid Escher
// image.
EXPECT_FALSE(image_resource->GetEscherImage());
// Updating shouldn't crash when passesd a null gpu_uploader, but it should
// also keep the image dirty, because the copy from CPU to GPU memory has not
// occured yet.
image_resource->UpdateEscherImage(nullptr);
// Because we did not provide a valid batch uploader, the image is still dirty
// and in need of an update. Until that succeeds, GetEscherImage() should not
// return a valid image.
EXPECT_FALSE(image_resource->GetEscherImage());
// A backing image should have been constructed through the image factory.
EXPECT_EQ(1u, listener->images_created_);
}
VK_TEST_F(HostImageTest, YuvImportOnUmaPlatform) {
auto vulkan_queues = CreateVulkanDeviceQueues();
auto device = vulkan_queues->vk_device();
auto physical_device = vulkan_queues->vk_physical_device();
if (!Memory::HasSharedMemoryPools(device, physical_device)) {
FXL_LOG(INFO)
<< "Could not find UMA compatible memory pool, aborting test.";
}
zx::vmo vmo;
zx_status_t status = zx::vmo::create(kVmoSize, 0u, &vmo);
ASSERT_EQ(ZX_OK, status);
ASSERT_TRUE(Apply(
scenic::NewCreateMemoryCmd(kMemoryId, std::move(vmo), kVmoSize,
fuchsia::images::MemoryType::HOST_MEMORY)));
fuchsia::images::ImageInfo image_info{
.width = kSize,
.height = kSize,
.stride = static_cast<uint32_t>(
kSize *
images::StrideBytesPerWidthPixel(fuchsia::images::PixelFormat::NV12)),
.pixel_format = fuchsia::images::PixelFormat::NV12,
};
ASSERT_TRUE(
Apply(scenic::NewCreateImageCmd(kImageId, kMemoryId, 0, image_info)));
auto image_resource = FindResource<HostImage>(kImageId);
ASSERT_TRUE(image_resource);
EXPECT_TRUE(image_resource->IsDirectlyMapped());
// Even direct mapped images don't return a valid Escher image until at least
// one call to UpdatePixels has occured.
EXPECT_FALSE(image_resource->GetEscherImage());
// Updating should be a no-op, so it shouldn't crash when passesd a null
// gpu_uploader, but it should also remove the dirty bit, meaning there is no
// additional work to do.
image_resource->UpdateEscherImage(nullptr);
// Despite not updating, the resource should have a valid Escher image, since
// we mapped it directly with zero copies.
EXPECT_TRUE(image_resource->GetEscherImage());
// The images should have been constructed directly, not through the image
// factory.
EXPECT_EQ(0u, listener->images_created_);
}
} // namespace test
} // namespace gfx
} // namespace scenic_impl