blob: 878a03a682cea4e0904264202a5d1a3c3e18f009 [file] [log] [blame]
// Copyright 2022 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 <drm_fourcc.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <gtest/gtest.h>
#include "gbm.h"
class GbmDevice {
public:
void SetUp() {
fd_ = open("/dev/magma0", O_RDWR | O_CLOEXEC);
ASSERT_GE(fd_, 0);
device_ = gbm_create_device(fd_);
ASSERT_TRUE(device_);
}
void TearDown() {
gbm_device_destroy(device_);
device_ = nullptr;
close(fd_);
fd_ = -1;
}
struct gbm_device *device() { return device_; }
int fd_ = -1;
struct gbm_device *device_ = nullptr;
};
class MagmaGbmTest : public testing::Test {
public:
void SetUp() override { gbm_.SetUp(); }
void TearDown() override { gbm_.TearDown(); }
struct gbm_device *device() { return gbm_.device(); }
GbmDevice gbm_;
};
constexpr uint32_t kDefaultWidth = 1920;
constexpr uint32_t kDefaultHeight = 1080;
constexpr uint32_t kDefaultFormat = GBM_FORMAT_ARGB8888;
TEST_F(MagmaGbmTest, CreateLinear) {
std::vector<uint64_t> modifiers{DRM_FORMAT_MOD_LINEAR};
struct gbm_bo *bo =
gbm_bo_create_with_modifiers(device(), kDefaultWidth, kDefaultHeight, kDefaultFormat,
modifiers.data(), static_cast<uint32_t>(modifiers.size()));
ASSERT_TRUE(bo);
EXPECT_EQ(DRM_FORMAT_MOD_LINEAR, gbm_bo_get_modifier(bo));
gbm_bo_destroy(bo);
}
TEST_F(MagmaGbmTest, CreateIntelX) {
std::vector<uint64_t> modifiers{I915_FORMAT_MOD_X_TILED};
struct gbm_bo *bo =
gbm_bo_create_with_modifiers(device(), kDefaultWidth, kDefaultHeight, kDefaultFormat,
modifiers.data(), static_cast<uint32_t>(modifiers.size()));
ASSERT_TRUE(bo);
EXPECT_EQ(I915_FORMAT_MOD_X_TILED, gbm_bo_get_modifier(bo));
gbm_bo_destroy(bo);
}
TEST_F(MagmaGbmTest, CreateIntelY) {
std::vector<uint64_t> modifiers{I915_FORMAT_MOD_Y_TILED};
struct gbm_bo *bo =
gbm_bo_create_with_modifiers(device(), kDefaultWidth, kDefaultHeight, kDefaultFormat,
modifiers.data(), static_cast<uint32_t>(modifiers.size()));
ASSERT_TRUE(bo);
EXPECT_EQ(I915_FORMAT_MOD_Y_TILED, gbm_bo_get_modifier(bo));
gbm_bo_destroy(bo);
}
TEST_F(MagmaGbmTest, CreateIntelBest) {
std::vector<uint64_t> modifiers{DRM_FORMAT_MOD_LINEAR, I915_FORMAT_MOD_X_TILED,
I915_FORMAT_MOD_Y_TILED};
struct gbm_bo *bo =
gbm_bo_create_with_modifiers(device(), kDefaultWidth, kDefaultHeight, kDefaultFormat,
modifiers.data(), static_cast<uint32_t>(modifiers.size()));
ASSERT_TRUE(bo);
EXPECT_EQ(I915_FORMAT_MOD_Y_TILED, gbm_bo_get_modifier(bo));
gbm_bo_destroy(bo);
}
class MagmaGbmTestWithUsage : public MagmaGbmTest, public testing::WithParamInterface<uint32_t> {};
TEST_P(MagmaGbmTestWithUsage, Create) {
uint32_t usage = GetParam();
struct gbm_bo *bo = gbm_bo_create(device(), kDefaultWidth, kDefaultHeight, kDefaultFormat, usage);
ASSERT_TRUE(bo);
if (usage & GBM_BO_USE_LINEAR) {
EXPECT_EQ(DRM_FORMAT_MOD_LINEAR, gbm_bo_get_modifier(bo));
} else if (usage & GBM_BO_USE_SCANOUT) {
EXPECT_EQ(I915_FORMAT_MOD_Y_TILED, gbm_bo_get_modifier(bo));
} else {
EXPECT_EQ(I915_FORMAT_MOD_Y_TILED_CCS, gbm_bo_get_modifier(bo));
}
gbm_bo_destroy(bo);
}
TEST_P(MagmaGbmTestWithUsage, Write) {
uint32_t usage = GetParam();
struct gbm_bo *bo = gbm_bo_create(device(), kDefaultWidth, kDefaultHeight, kDefaultFormat, usage);
ASSERT_TRUE(bo);
if (usage & GBM_BO_USE_LINEAR) {
EXPECT_EQ(DRM_FORMAT_MOD_LINEAR, gbm_bo_get_modifier(bo));
} else if (usage & GBM_BO_USE_SCANOUT) {
EXPECT_EQ(I915_FORMAT_MOD_Y_TILED, gbm_bo_get_modifier(bo));
} else {
GTEST_SKIP();
}
{
size_t size = kDefaultHeight * gbm_bo_get_stride(bo);
void *transfer = malloc(size);
ASSERT_TRUE(transfer != nullptr);
// Write first line - zeros
for (uint32_t i = 0; i < kDefaultWidth; i++) {
reinterpret_cast<uint32_t *>(transfer)[i] = 0;
}
// Write remainder of lines
for (uint32_t i = kDefaultWidth; i < kDefaultWidth * kDefaultHeight; i++) {
reinterpret_cast<uint32_t *>(transfer)[i] = i;
}
gbm_bo_write(bo, transfer, size);
free(transfer);
}
{
uint32_t stride;
void *map_data;
void *addr = gbm_bo_map(bo, 0, 0, kDefaultWidth, 1, GBM_BO_TRANSFER_READ, &stride, &map_data);
ASSERT_NE(addr, MAP_FAILED);
for (uint32_t i = 0; i < kDefaultWidth; i++) {
EXPECT_EQ(reinterpret_cast<uint32_t *>(addr)[i], 0u);
}
gbm_bo_unmap(bo, map_data);
}
{
uint32_t stride;
void *map_data;
void *addr = gbm_bo_map(bo, 0, 1, kDefaultWidth, kDefaultHeight - 1, GBM_BO_TRANSFER_READ,
&stride, &map_data);
ASSERT_NE(addr, MAP_FAILED);
for (uint32_t i = 0; i < kDefaultWidth * (kDefaultHeight - 1); i++) {
EXPECT_EQ(reinterpret_cast<uint32_t *>(addr)[i], kDefaultWidth + i);
}
gbm_bo_unmap(bo, map_data);
}
gbm_bo_destroy(bo);
}
TEST_P(MagmaGbmTestWithUsage, Import) {
GbmDevice gbm2;
gbm2.SetUp();
constexpr uint32_t kPattern = 0xabcd1234;
struct gbm_bo *bo =
gbm_bo_create(device(), kDefaultWidth, kDefaultHeight, kDefaultFormat, GetParam());
ASSERT_TRUE(bo);
{
uint32_t stride;
void *map_data;
void *addr = gbm_bo_map(bo, 0, 0, kDefaultWidth, kDefaultHeight, GBM_BO_TRANSFER_WRITE, &stride,
&map_data);
ASSERT_NE(addr, MAP_FAILED);
*reinterpret_cast<uint32_t *>(addr) = kPattern;
gbm_bo_unmap(bo, map_data);
}
{
// Import with specified stride (could be incorrect)
constexpr uint32_t kImportStride = 123;
// Import usage doesn't matter
constexpr uint32_t kImportUsage = GBM_BO_USE_RENDERING;
struct gbm_import_fd_data import;
import.fd = gbm_bo_get_fd(bo);
import.format = gbm_bo_get_format(bo);
import.width = gbm_bo_get_width(bo);
import.height = gbm_bo_get_height(bo);
import.stride = kImportStride;
EXPECT_GE(import.fd, 0);
EXPECT_EQ(import.width, kDefaultWidth);
EXPECT_EQ(import.height, kDefaultHeight);
EXPECT_EQ(import.format, kDefaultFormat);
struct gbm_bo *bo2 = gbm_bo_import(gbm2.device(), GBM_BO_IMPORT_FD, &import, kImportUsage);
ASSERT_TRUE(bo2);
EXPECT_EQ(gbm_bo_get_width(bo), gbm_bo_get_width(bo2));
EXPECT_EQ(gbm_bo_get_height(bo), gbm_bo_get_height(bo2));
EXPECT_EQ(gbm_bo_get_stride(bo), gbm_bo_get_stride(bo2));
EXPECT_EQ(gbm_bo_get_format(bo), gbm_bo_get_format(bo2));
EXPECT_EQ(gbm_bo_get_modifier(bo), gbm_bo_get_modifier(bo2));
EXPECT_NE(DRM_FORMAT_MOD_INVALID, gbm_bo_get_modifier(bo2));
{
uint32_t stride;
void *map_data;
void *addr = gbm_bo_map(bo2, 0, 0, kDefaultWidth, kDefaultHeight, GBM_BO_TRANSFER_READ,
&stride, &map_data);
ASSERT_NE(addr, MAP_FAILED);
EXPECT_EQ(*reinterpret_cast<uint32_t *>(addr), kPattern);
gbm_bo_unmap(bo, map_data);
}
gbm_bo_destroy(bo2);
}
{
// Import with 0 stride
constexpr uint32_t kImportStride = 0;
// Import usage doesn't matter
constexpr uint32_t kImportUsage = GBM_BO_USE_RENDERING;
struct gbm_import_fd_data import;
import.format = gbm_bo_get_format(bo);
import.fd = gbm_bo_get_fd(bo);
import.width = gbm_bo_get_width(bo);
import.height = gbm_bo_get_height(bo);
import.stride = kImportStride;
EXPECT_GE(import.fd, 0);
EXPECT_EQ(import.width, kDefaultWidth);
EXPECT_EQ(import.height, kDefaultHeight);
EXPECT_EQ(import.format, kDefaultFormat);
struct gbm_bo *bo2 = gbm_bo_import(gbm2.device(), GBM_BO_IMPORT_FD, &import, kImportUsage);
ASSERT_TRUE(bo2);
EXPECT_EQ(gbm_bo_get_width(bo), gbm_bo_get_width(bo2));
EXPECT_EQ(gbm_bo_get_height(bo), gbm_bo_get_height(bo2));
EXPECT_EQ(gbm_bo_get_stride(bo), gbm_bo_get_stride(bo2));
EXPECT_EQ(gbm_bo_get_format(bo), gbm_bo_get_format(bo2));
EXPECT_EQ(gbm_bo_get_modifier(bo), gbm_bo_get_modifier(bo2));
EXPECT_NE(DRM_FORMAT_MOD_INVALID, gbm_bo_get_modifier(bo2));
{
uint32_t stride;
void *map_data;
void *addr = gbm_bo_map(bo2, 0, 0, kDefaultWidth, kDefaultHeight, GBM_BO_TRANSFER_READ,
&stride, &map_data);
ASSERT_NE(addr, MAP_FAILED);
EXPECT_EQ(*reinterpret_cast<uint32_t *>(addr), kPattern);
gbm_bo_unmap(bo, map_data);
}
gbm_bo_destroy(bo2);
}
gbm_bo_destroy(bo);
gbm2.TearDown();
}
INSTANTIATE_TEST_SUITE_P(
MagmaGbmTestWithUsage, MagmaGbmTestWithUsage,
::testing::Values(GBM_BO_USE_RENDERING, GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT,
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT,
GBM_BO_USE_LINEAR),
[](testing::TestParamInfo<MagmaGbmTestWithUsage::ParamType> info) {
if (info.param == GBM_BO_USE_RENDERING)
return "GBM_BO_USE_RENDERING";
if (info.param == (GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR))
return "GBM_BO_USE_RENDERING_GBM_BO_USE_LINEAR";
if (info.param == (GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT))
return "GBM_BO_USE_RENDERING_GBM_BO_USE_SCANOUT";
if (info.param == (GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT))
return "GBM_BO_USE_RENDERING_GBM_BO_USE_LINEAR_GBM_BO_USE_SCANOUT";
if (info.param == GBM_BO_USE_LINEAR)
return "GBM_BO_USE_LINEAR";
return "Unknown";
});