blob: 34bec35206c82eb663c1067ebdff447b901ce9ed [file] [log] [blame]
// Copyright 2017 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 "helper/command_buffer_helper.h"
#include "helper/platform_device_helper.h"
#include "magma_arm_mali_types.h"
#include "sys_driver/magma_driver.h"
#include "sys_driver/magma_system_connection.h"
#include "sys_driver/magma_system_context.h"
#include "gtest/gtest.h"
namespace {
class Test {
public:
void TestValidImmediate()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom[2];
atom[0].size = sizeof(atom[0]);
atom[0].atom_number = 1;
atom[0].flags = 1;
atom[0].dependencies[0].atom_number = 0;
atom[0].dependencies[1].atom_number = 0;
atom[1].size = sizeof(atom[1]);
atom[1].atom_number = 2;
atom[1].flags = 1;
atom[1].dependencies[0].atom_number = 1;
atom[1].dependencies[0].type = kArmMaliDependencyOrder;
atom[1].dependencies[1].atom_number = 0;
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), &atom, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_OK, status.get());
}
void TestValidLarger()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
uint8_t buffer[100];
ASSERT_GT(sizeof(buffer), sizeof(magma_arm_mali_atom));
auto atom = reinterpret_cast<magma_arm_mali_atom*>(buffer);
atom->size = sizeof(buffer);
atom->atom_number = 1;
atom->flags = 1;
atom->dependencies[0].atom_number = 0;
atom->dependencies[1].atom_number = 0;
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(buffer), buffer, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_OK, status.get());
}
void TestInvalidTooLarge()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
uint8_t buffer[100];
ASSERT_GT(sizeof(buffer), sizeof(magma_arm_mali_atom) + 1);
auto atom = reinterpret_cast<magma_arm_mali_atom*>(buffer);
atom->size = sizeof(buffer);
atom->atom_number = 1;
atom->flags = 1;
atom->dependencies[0].atom_number = 0;
atom->dependencies[1].atom_number = 0;
magma::Status status =
ctx->ExecuteImmediateCommands(sizeof(buffer) - 1, buffer, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestInvalidOverflow()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom[3];
for (uint32_t i = 0; i < 3; i++) {
atom[i].size = sizeof(atom[i]);
atom[i].atom_number = i + 1;
atom[i].flags = 1;
atom[i].dependencies[0].atom_number = 0;
atom[i].dependencies[1].atom_number = 0;
}
atom[2].size =
reinterpret_cast<uintptr_t>(&atom[1]) - reinterpret_cast<uintptr_t>(&atom[2]);
EXPECT_GE(atom[2].size, static_cast<uint64_t>(INT64_MAX));
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), atom, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestInvalidZeroSize()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom;
atom.size = 0;
atom.atom_number = 1;
atom.flags = 1;
atom.dependencies[0].atom_number = 0;
atom.dependencies[1].atom_number = 0;
// Shouldn't infinite loop, for example.
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), &atom, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestInvalidSmaller()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom;
atom.size = sizeof(atom) - 1;
atom.atom_number = 1;
atom.flags = 1;
atom.dependencies[0].atom_number = 0;
atom.dependencies[1].atom_number = 0;
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom) - 1, &atom, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestInvalidInUse()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom[2];
atom[0].size = sizeof(atom[0]);
atom[0].atom_number = 0;
atom[0].flags = 1;
atom[0].dependencies[0].atom_number = 0;
atom[0].dependencies[1].atom_number = 0;
atom[1].size = sizeof(atom[1]);
atom[1].atom_number = 0;
atom[1].flags = 1;
atom[1].dependencies[0].atom_number = 0;
atom[1].dependencies[1].atom_number = 0;
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), &atom, 0, nullptr);
// There's no device thread, so the atoms shouldn't be able to complete.
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestInvalidDependencyNotSubmitted()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom;
atom.size = sizeof(atom);
atom.atom_number = 1;
atom.flags = 1;
// Can't depend on self or on later atoms.
atom.dependencies[0].atom_number = 1;
atom.dependencies[0].type = kArmMaliDependencyOrder;
atom.dependencies[1].atom_number = 0;
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), &atom, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestInvalidDependencyType()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom[2];
atom[0].size = sizeof(atom[0]);
atom[0].atom_number = 1;
atom[0].flags = 1;
atom[0].dependencies[0].atom_number = 0;
atom[0].dependencies[1].atom_number = 0;
atom[1].size = sizeof(atom[1]);
atom[1].atom_number = 2;
atom[1].flags = 1;
atom[1].dependencies[0].atom_number = 1;
atom[1].dependencies[0].type = 5;
atom[1].dependencies[1].atom_number = 0;
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), &atom, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestInvalidSemaphoreImmediate()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
magma_arm_mali_atom atom;
atom.size = sizeof(atom);
atom.atom_number = 0;
atom.flags = kAtomFlagSemaphoreSet;
atom.dependencies[0].atom_number = 0;
atom.dependencies[1].atom_number = 0;
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), &atom, 0, nullptr);
EXPECT_EQ(MAGMA_STATUS_CONTEXT_KILLED, status.get());
}
void TestSemaphoreImmediate()
{
auto ctx = InitializeContext();
ASSERT_TRUE(ctx);
auto platform_semaphore = magma::PlatformSemaphore::Create();
uint32_t handle;
platform_semaphore->duplicate_handle(&handle);
connection_->ImportObject(handle, magma::PlatformObject::SEMAPHORE);
magma_arm_mali_atom atom;
atom.size = sizeof(atom);
atom.atom_number = 0;
atom.flags = kAtomFlagSemaphoreSet;
atom.dependencies[0].atom_number = 0;
atom.dependencies[1].atom_number = 0;
uint64_t semaphores[] = {platform_semaphore->id()};
magma::Status status = ctx->ExecuteImmediateCommands(sizeof(atom), &atom, 1, semaphores);
EXPECT_EQ(MAGMA_STATUS_OK, status.get());
}
private:
MagmaSystemContext* InitializeContext()
{
msd_drv_ = msd_driver_unique_ptr_t(msd_driver_create(), &msd_driver_destroy);
if (!msd_drv_)
return DRETP(nullptr, "failed to create msd driver");
msd_driver_configure(msd_drv_.get(), MSD_DRIVER_CONFIG_TEST_NO_DEVICE_THREAD);
platform_device_ = TestPlatformDevice::GetInstance();
if (!platform_device_)
DLOG("TestCommandBuffer: No platform device");
auto msd_dev = msd_driver_create_device(
msd_drv_.get(), platform_device_ ? platform_device_->GetDeviceHandle() : nullptr);
if (!msd_dev)
return DRETP(nullptr, "failed to create msd device");
system_dev_ = std::shared_ptr<MagmaSystemDevice>(
MagmaSystemDevice::Create(MsdDeviceUniquePtr(msd_dev)));
uint32_t ctx_id = 0;
auto msd_connection_t = msd_device_open(msd_dev, 0);
if (!msd_connection_t)
return DRETP(nullptr, "msd_device_open failed");
connection_ = std::unique_ptr<MagmaSystemConnection>(
new MagmaSystemConnection(system_dev_, MsdConnectionUniquePtr(msd_connection_t)));
if (!connection_)
return DRETP(nullptr, "failed to connect to msd device");
connection_->CreateContext(ctx_id);
auto ctx = connection_->LookupContext(ctx_id);
if (!ctx)
return DRETP(nullptr, "failed to create context");
return ctx;
}
msd_driver_unique_ptr_t msd_drv_;
magma::PlatformDevice* platform_device_;
std::shared_ptr<MagmaSystemDevice> system_dev_;
std::unique_ptr<MagmaSystemConnection> connection_;
};
TEST(CommandBuffer, TestInvalidSemaphoreImmediate) { ::Test().TestInvalidSemaphoreImmediate(); }
TEST(CommandBuffer, TestSemaphoreImmediate) { ::Test().TestSemaphoreImmediate(); }
TEST(CommandBuffer, TestValidImmediate) { ::Test().TestValidImmediate(); }
TEST(CommandBuffer, TestValidLarger) { ::Test().TestValidLarger(); }
TEST(CommandBuffer, TestInvalidTooLarge) { ::Test().TestInvalidTooLarge(); }
TEST(CommandBuffer, TestInvalidOverflow) { ::Test().TestInvalidOverflow(); }
TEST(CommandBuffer, TestInvalidZeroSize) { ::Test().TestInvalidZeroSize(); }
TEST(CommandBuffer, TestInvalidSmaller) { ::Test().TestInvalidSmaller(); }
TEST(CommandBuffer, TestInvalidInUse) { ::Test().TestInvalidInUse(); }
TEST(CommandBuffer, TestInvalidDependencyType) { ::Test().TestInvalidDependencyType(); }
TEST(CommandBuffer, TestInvalidDependencyNotSubmitted)
{
::Test().TestInvalidDependencyNotSubmitted();
}
} // namespace