blob: 7c43df648479e274ee2b245a446ac8efee583131 [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 <virtio/gpu.h>
#include "garnet/bin/guest/vmm/device/gpu.h"
#include "garnet/bin/guest/vmm/device/test_with_device.h"
#include "garnet/bin/guest/vmm/device/virtio_queue_fake.h"
static constexpr char kVirtioGpuUrl[] =
"fuchsia-pkg://fuchsia.com/virtio_gpu#meta/virtio_gpu.cmx";
static constexpr uint16_t kNumQueues = 2;
static constexpr uint16_t kQueueSize = 16;
static constexpr uint32_t kPixelFormat = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
static constexpr uint32_t kResourceId = 0;
static constexpr uint32_t kScanoutId = 0;
class VirtioGpuTest : public TestWithDevice {
protected:
VirtioGpuTest()
: control_queue_(phys_mem_, PAGE_SIZE * kNumQueues, kQueueSize),
cursor_queue_(phys_mem_, control_queue_.end(), kQueueSize) {}
void SetUp() override {
// Launch device process.
fuchsia::guest::device::StartInfo start_info;
zx_status_t status =
LaunchDevice(kVirtioGpuUrl, cursor_queue_.end(), &start_info);
ASSERT_EQ(ZX_OK, status);
// Start device execution.
services.ConnectToService(gpu_.NewRequest());
status = gpu_->Start(std::move(start_info), nullptr);
ASSERT_EQ(ZX_OK, status);
// Configure device queues.
VirtioQueueFake* queues[kNumQueues] = {&control_queue_, &cursor_queue_};
for (size_t i = 0; i < kNumQueues; i++) {
auto q = queues[i];
q->Configure(PAGE_SIZE * i, PAGE_SIZE);
status =
gpu_->ConfigureQueue(i, q->size(), q->desc(), q->avail(), q->used());
ASSERT_EQ(ZX_OK, status);
}
}
void ResourceCreate2d() {
virtio_gpu_resource_create_2d_t request = {
.hdr = {.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D},
.format = kPixelFormat,
.resource_id = kResourceId,
.width = kGpuStartupWidth,
.height = kGpuStartupHeight,
};
virtio_gpu_ctrl_hdr_t* response;
zx_status_t status =
DescriptorChainBuilder(control_queue_)
.AppendReadableDescriptor(&request, sizeof(request))
.AppendWritableDescriptor(&response, sizeof(*response))
.Build();
ASSERT_EQ(ZX_OK, status);
status = gpu_->NotifyQueue(0);
ASSERT_EQ(ZX_OK, status);
status = WaitOnInterrupt();
ASSERT_EQ(ZX_OK, status);
ASSERT_EQ(VIRTIO_GPU_RESP_OK_NODATA, response->type);
}
void ResourceAttachBacking() {
virtio_gpu_resource_attach_backing_t request = {
.hdr = {.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING},
.resource_id = kResourceId,
.nr_entries = 0,
};
virtio_gpu_ctrl_hdr_t* response;
zx_status_t status =
DescriptorChainBuilder(control_queue_)
.AppendReadableDescriptor(&request, sizeof(request))
.AppendWritableDescriptor(&response, sizeof(*response))
.Build();
ASSERT_EQ(ZX_OK, status);
status = gpu_->NotifyQueue(0);
ASSERT_EQ(ZX_OK, status);
status = WaitOnInterrupt();
ASSERT_EQ(ZX_OK, status);
ASSERT_EQ(VIRTIO_GPU_RESP_OK_NODATA, response->type);
}
void SetScanout(uint32_t resource_id, uint32_t response_type) {
virtio_gpu_set_scanout_t request = {
.hdr = {.type = VIRTIO_GPU_CMD_SET_SCANOUT},
.resource_id = resource_id,
.scanout_id = kScanoutId,
.r = {.x = 0,
.y = 0,
.width = kGpuStartupWidth,
.height = kGpuStartupHeight},
};
virtio_gpu_ctrl_hdr_t* response;
zx_status_t status =
DescriptorChainBuilder(control_queue_)
.AppendReadableDescriptor(&request, sizeof(request))
.AppendWritableDescriptor(&response, sizeof(*response))
.Build();
ASSERT_EQ(ZX_OK, status);
status = gpu_->NotifyQueue(0);
ASSERT_EQ(ZX_OK, status);
status = WaitOnInterrupt();
ASSERT_EQ(ZX_OK, status);
EXPECT_EQ(response_type, response->type);
}
fuchsia::guest::device::VirtioGpuSyncPtr gpu_;
VirtioQueueFake control_queue_;
VirtioQueueFake cursor_queue_;
};
TEST_F(VirtioGpuTest, GetDisplayInfo) {
virtio_gpu_ctrl_hdr_t request = {
.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO,
};
virtio_gpu_resp_display_info_t* response;
zx_status_t status =
DescriptorChainBuilder(control_queue_)
.AppendReadableDescriptor(&request, sizeof(request))
.AppendWritableDescriptor(&response, sizeof(*response))
.Build();
ASSERT_EQ(ZX_OK, status);
status = gpu_->NotifyQueue(0);
ASSERT_EQ(ZX_OK, status);
status = WaitOnInterrupt();
ASSERT_EQ(ZX_OK, status);
EXPECT_EQ(response->hdr.type, VIRTIO_GPU_RESP_OK_DISPLAY_INFO);
EXPECT_EQ(response->pmodes[0].r.x, 0u);
EXPECT_EQ(response->pmodes[0].r.y, 0u);
EXPECT_EQ(response->pmodes[0].r.width, kGpuStartupWidth);
EXPECT_EQ(response->pmodes[0].r.height, kGpuStartupHeight);
}
TEST_F(VirtioGpuTest, SetScanout) {
ResourceCreate2d();
ResourceAttachBacking();
SetScanout(kResourceId, VIRTIO_GPU_RESP_OK_NODATA);
}
TEST_F(VirtioGpuTest, SetScanoutWithInvalidResourceId) {
ResourceCreate2d();
ResourceAttachBacking();
SetScanout(UINT32_MAX, VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID);
}