blob: 1bd3f3a7facaa9323bab2c20d9668d3765a1c6f1 [file] [log] [blame]
// Copyright 2021 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 <fcntl.h>
#include <fuchsia/gpu/magma/cpp/fidl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <fuchsia/vulkan/loader/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <zircon/types.h>
#include <filesystem>
#include <gtest/gtest.h>
// This is the first and only ICD loaded, so it should have a "0-" prepended.
const char* kIcdFilename = "0-libvulkan_fake.so";
zx_status_t ForceWaitForIdle(fuchsia::vulkan::loader::LoaderSyncPtr& loader) {
zx::vmo vmo;
// manifest.json remaps this to bin/pkg-server.
return loader->Get(kIcdFilename, &vmo);
}
TEST(VulkanLoader, ManifestLoad) {
fuchsia::vulkan::loader::LoaderSyncPtr loader;
EXPECT_EQ(ZX_OK, fdio_service_connect("/svc/fuchsia.vulkan.loader.Loader",
loader.NewRequest().TakeChannel().release()));
zx::vmo vmo_out;
// manifest.json remaps this to bin/pkg-server.
EXPECT_EQ(ZX_OK, loader->Get(kIcdFilename, &vmo_out));
EXPECT_TRUE(vmo_out.is_valid());
zx_info_handle_basic_t handle_info;
EXPECT_EQ(ZX_OK, vmo_out.get_info(ZX_INFO_HANDLE_BASIC, &handle_info, sizeof(handle_info),
nullptr, nullptr));
EXPECT_TRUE(handle_info.rights & ZX_RIGHT_EXECUTE);
EXPECT_FALSE(handle_info.rights & ZX_RIGHT_WRITE);
EXPECT_EQ(ZX_OK, loader->Get("not-present", &vmo_out));
EXPECT_FALSE(vmo_out.is_valid());
}
// Check that writes to one VMO returned by the server will not modify a separate VMO returned by
// the service.
TEST(VulkanLoader, VmosIndependent) {
fuchsia::vulkan::loader::LoaderSyncPtr loader;
EXPECT_EQ(ZX_OK, fdio_service_connect("/svc/fuchsia.vulkan.loader.Loader",
loader.NewRequest().TakeChannel().release()));
zx::vmo vmo_out;
// manifest.json remaps this to bin/pkg-server.
EXPECT_EQ(ZX_OK, loader->Get(kIcdFilename, &vmo_out));
EXPECT_TRUE(vmo_out.is_valid());
fzl::VmoMapper mapper;
EXPECT_EQ(ZX_OK, mapper.Map(vmo_out, 0, 0, ZX_VM_PERM_EXECUTE | ZX_VM_PERM_READ));
uint8_t original_value = *static_cast<uint8_t*>(mapper.start());
uint8_t byte_to_write = original_value + 1;
size_t actual;
// zx_process_write_memory can write to memory mapped without ZX_VM_PERM_WRITE. If that ever
// changes, this test can probably be removed.
zx_status_t status = zx::process::self()->write_memory(
reinterpret_cast<uint64_t>(mapper.start()), &byte_to_write, sizeof(byte_to_write), &actual);
// zx_process_write_memory may be disabled using a kernel command-line flag.
if (status == ZX_ERR_NOT_SUPPORTED) {
EXPECT_EQ(original_value, *static_cast<uint8_t*>(mapper.start()));
} else {
EXPECT_EQ(ZX_OK, status);
EXPECT_EQ(byte_to_write, *static_cast<uint8_t*>(mapper.start()));
}
// Ensure that the new clone is unaffected.
zx::vmo vmo2;
EXPECT_EQ(ZX_OK, loader->Get(kIcdFilename, &vmo2));
EXPECT_TRUE(vmo2.is_valid());
fzl::VmoMapper mapper2;
EXPECT_EQ(ZX_OK, mapper2.Map(vmo2, 0, 0, ZX_VM_PERM_EXECUTE | ZX_VM_PERM_READ));
EXPECT_EQ(original_value, *static_cast<uint8_t*>(mapper2.start()));
}
TEST(VulkanLoader, DeviceFs) {
fuchsia::vulkan::loader::LoaderSyncPtr loader;
EXPECT_EQ(ZX_OK, fdio_service_connect("/svc/fuchsia.vulkan.loader.Loader",
loader.NewRequest().TakeChannel().release()));
fidl::InterfaceHandle<fuchsia::io::Directory> dir;
EXPECT_EQ(ZX_OK, loader->ConnectToDeviceFs(dir.NewRequest().TakeChannel()));
ForceWaitForIdle(loader);
fuchsia::gpu::magma::DeviceSyncPtr device_ptr;
EXPECT_EQ(ZX_OK, fdio_service_connect_at(dir.channel().get(), "class/gpu/000",
device_ptr.NewRequest().TakeChannel().release()));
fuchsia::gpu::magma::Device_Query2_Result query_result;
EXPECT_EQ(ZX_OK, device_ptr->Query2(0u, &query_result));
ASSERT_TRUE(query_result.is_response());
EXPECT_EQ(5u, query_result.response().result);
}
TEST(VulkanLoader, Features) {
fuchsia::vulkan::loader::LoaderSyncPtr loader;
EXPECT_EQ(ZX_OK, fdio_service_connect("/svc/fuchsia.vulkan.loader.Loader",
loader.NewRequest().TakeChannel().release()));
fuchsia::vulkan::loader::Features features;
EXPECT_EQ(ZX_OK, loader->GetSupportedFeatures(&features));
constexpr fuchsia::vulkan::loader::Features kExpectedFeatures =
fuchsia::vulkan::loader::Features::CONNECT_TO_DEVICE_FS |
fuchsia::vulkan::loader::Features::GET |
fuchsia::vulkan::loader::Features::CONNECT_TO_MANIFEST_FS;
EXPECT_EQ(kExpectedFeatures, features);
}
TEST(VulkanLoader, ManifestFs) {
fuchsia::vulkan::loader::LoaderSyncPtr loader;
EXPECT_EQ(ZX_OK, fdio_service_connect("/svc/fuchsia.vulkan.loader.Loader",
loader.NewRequest().TakeChannel().release()));
fidl::InterfaceHandle<fuchsia::io::Directory> dir;
EXPECT_EQ(ZX_OK, loader->ConnectToManifestFs(
fuchsia::vulkan::loader::ConnectToManifestOptions::WAIT_FOR_IDLE,
dir.NewRequest().TakeChannel()));
int dir_fd;
EXPECT_EQ(ZX_OK, fdio_fd_create(dir.TakeChannel().release(), &dir_fd));
int manifest_fd = openat(dir_fd, (std::string(kIcdFilename) + ".json").c_str(), O_RDONLY);
EXPECT_LE(0, manifest_fd);
constexpr int kManifestFileSize = 135;
char manifest_data[kManifestFileSize + 1];
ssize_t read_size = read(manifest_fd, manifest_data, sizeof(manifest_data) - 1);
EXPECT_EQ(kManifestFileSize, read_size);
close(manifest_fd);
close(dir_fd);
}
TEST(VulkanLoader, GoldfishSyncDeviceFs) {
fuchsia::vulkan::loader::LoaderSyncPtr loader;
EXPECT_EQ(ZX_OK, fdio_service_connect("/svc/fuchsia.vulkan.loader.Loader",
loader.NewRequest().TakeChannel().release()));
fidl::InterfaceHandle<fuchsia::io::Directory> dir;
EXPECT_EQ(ZX_OK, loader->ConnectToDeviceFs(dir.NewRequest().TakeChannel()));
ForceWaitForIdle(loader);
const char* kDeviceClassList[] = {
"class/goldfish-sync",
"class/goldfish-pipe",
"class/goldfish-address-space",
};
for (auto& device_class : kDeviceClassList) {
fuchsia::io::NodeSyncPtr device_ptr;
EXPECT_EQ(ZX_OK, fdio_service_connect_at(dir.channel().get(), device_class,
device_ptr.NewRequest().TakeChannel().release()));
// Check that the directory is connected to something.
fuchsia::io::NodeInfo result;
EXPECT_EQ(ZX_OK, device_ptr->Describe(&result)) << " class " << device_class;
}
}
TEST(VulkanLoader, DebugFilesystems) {
fuchsia::vulkan::loader::LoaderSyncPtr loader;
EXPECT_EQ(ZX_OK, fdio_service_connect("/svc/fuchsia.vulkan.loader.Loader",
loader.NewRequest().TakeChannel().release()));
ForceWaitForIdle(loader);
const std::string debug_path("/parent_hub/children/vulkan_loader/exec/out/debug/");
EXPECT_TRUE(std::filesystem::exists(debug_path + "device-fs/class/gpu/000"));
EXPECT_TRUE(std::filesystem::exists(debug_path + "manifest-fs/" + kIcdFilename + ".json"));
}