blob: 167cf3c420da01bf7047e83a562eccd4fe29f73b [file] [log] [blame]
// Copyright 2016 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 <thread>
#include <fuchsia/gpu/magma/c/fidl.h>
#include <lib/fdio/unsafe.h>
#include "magma.h"
#include "magma_util/inflight_list.h"
#include "magma_util/macros.h"
#include "gtest/gtest.h"
namespace {
class TestBase {
public:
TestBase() { fd_ = open("/dev/class/gpu/000", O_RDONLY); }
int fd() { return fd_; }
~TestBase() { close(fd_); }
private:
int fd_;
};
class TestConnection : public TestBase {
public:
TestConnection() { magma_create_connection(fd(), &connection_); }
~TestConnection()
{
if (connection_)
magma_release_connection(connection_);
}
int32_t Test()
{
DASSERT(connection_);
uint32_t context_id;
magma_create_context(connection_, &context_id);
int32_t result = magma_get_error(connection_);
if (result != 0)
return DRET(result);
uint64_t size;
magma_buffer_t batch_buffer, command_buffer;
result = magma_create_buffer(connection_, PAGE_SIZE, &size, &batch_buffer);
if (result != 0)
return DRET(result);
result = magma_create_command_buffer(connection_, PAGE_SIZE, &command_buffer);
if (result != 0)
return DRET(result);
EXPECT_TRUE(InitBatchBuffer(batch_buffer, size));
EXPECT_TRUE(InitCommandBuffer(command_buffer, batch_buffer, size));
magma_submit_command_buffer(connection_, command_buffer, context_id);
magma::InflightList list(connection_);
EXPECT_TRUE(list.WaitForCompletion(1000));
magma_release_context(connection_, context_id);
magma_release_buffer(connection_, batch_buffer);
result = magma_get_error(connection_);
return DRET(result);
}
bool InitBatchBuffer(magma_buffer_t buffer, uint64_t size)
{
void* vaddr;
if (magma_map(connection_, buffer, &vaddr) != 0)
return DRETF(false, "couldn't map batch buffer");
memset(vaddr, 0, size);
// Intel end-of-batch
*reinterpret_cast<uint32_t*>(vaddr) = 0xA << 23;
EXPECT_EQ(magma_unmap(connection_, buffer), 0);
return true;
}
bool InitCommandBuffer(magma_buffer_t buffer, magma_buffer_t batch_buffer,
uint64_t batch_buffer_length)
{
void* vaddr;
if (magma_map(connection_, buffer, &vaddr) != 0)
return DRETF(false, "couldn't map command buffer");
auto command_buffer = reinterpret_cast<struct magma_system_command_buffer*>(vaddr);
command_buffer->batch_buffer_resource_index = 0;
command_buffer->batch_start_offset = 0;
command_buffer->num_resources = 1;
auto exec_resource =
reinterpret_cast<struct magma_system_exec_resource*>(command_buffer + 1);
exec_resource->buffer_id = magma_get_buffer_id(batch_buffer);
exec_resource->num_relocations = 0;
exec_resource->offset = 0;
exec_resource->length = batch_buffer_length;
EXPECT_EQ(magma_unmap(connection_, buffer), 0);
return true;
}
private:
magma_connection_t connection_;
};
constexpr uint32_t kMaxCount = 100;
constexpr uint32_t kRestartCount = kMaxCount / 10;
static std::atomic_uint complete_count;
static void looper_thread_entry()
{
std::unique_ptr<TestConnection> test(new TestConnection());
while (complete_count < kMaxCount) {
int32_t result = test->Test();
if (result == 0) {
complete_count++;
} else {
// Wait rendering can't pass back a proper error yet
EXPECT_TRUE(result == MAGMA_STATUS_CONNECTION_LOST ||
result == MAGMA_STATUS_INTERNAL_ERROR);
test.reset(new TestConnection());
}
}
}
static void test_shutdown(uint32_t iters)
{
for (uint32_t i = 0; i < iters; i++) {
complete_count = 0;
TestBase test_base;
{
uint64_t is_supported = 0;
fdio_t* fdio = fdio_unsafe_fd_to_io(test_base.fd());
zx_status_t status =
fuchsia_gpu_magma_DeviceQuery(fdio_unsafe_borrow_channel(fdio),
MAGMA_QUERY_IS_TEST_RESTART_SUPPORTED, &is_supported);
fdio_unsafe_release(fdio);
if (status != ZX_OK || !is_supported) {
printf("Test restart not supported: status %d is_supported %lu\n", status,
is_supported);
return;
}
}
std::thread looper(looper_thread_entry);
std::thread looper2(looper_thread_entry);
uint32_t count = kRestartCount;
while (complete_count < kMaxCount) {
if (complete_count > count) {
fdio_t* fdio = fdio_unsafe_fd_to_io(test_base.fd());
// TODO(MA-518) replace this with a request to devmgr to restart the driver
EXPECT_EQ(ZX_OK,
fuchsia_gpu_magma_DeviceTestRestart(fdio_unsafe_borrow_channel(fdio)));
fdio_unsafe_release(fdio);
count += kRestartCount;
}
std::this_thread::yield();
}
looper.join();
looper2.join();
}
}
} // namespace
TEST(Shutdown, Test) { test_shutdown(1); }
TEST(Shutdown, DISABLED_Stress) { test_shutdown(1000); }