blob: 6c54924dad512798a71fb470d0f477b0029418a0 [file] [log] [blame]
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/tests/white_box/VulkanImageWrappingTests.h"
#include <fcntl.h>
#include <gbm.h>
#include <gtest/gtest.h>
#include <unistd.h>
namespace dawn::native::vulkan {
ExternalImageDescriptorVkForTesting::ExternalImageDescriptorVkForTesting()
: ExternalImageDescriptorVk(ExternalImageType::DmaBuf) {
}
ExternalImageExportInfoVkForTesting::ExternalImageExportInfoVkForTesting()
: ExternalImageExportInfoVk(ExternalImageType::DmaBuf) {
}
class ExternalSemaphoreDmaBuf : public VulkanImageWrappingTestBackend::ExternalSemaphore {
public:
ExternalSemaphoreDmaBuf(int handle) : mHandle(handle) {
}
~ExternalSemaphoreDmaBuf() override {
if (mHandle != -1) {
close(mHandle);
}
}
int AcquireHandle() {
int handle = mHandle;
mHandle = -1;
return handle;
}
private:
int mHandle = -1;
};
class ExternalTextureDmaBuf : public VulkanImageWrappingTestBackend::ExternalTexture {
public:
ExternalTextureDmaBuf(gbm_bo* bo, int fd, uint32_t stride, uint64_t drmModifier)
: mGbmBo(bo), mFd(fd), stride(stride), drmModifier(drmModifier) {
}
~ExternalTextureDmaBuf() override {
if (mFd != -1) {
close(mFd);
}
if (mGbmBo != nullptr) {
gbm_bo_destroy(mGbmBo);
}
}
int Dup() const {
return dup(mFd);
}
private:
gbm_bo* mGbmBo = nullptr;
int mFd = -1;
public:
const uint32_t stride;
const uint64_t drmModifier;
};
class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBackend {
public:
VulkanImageWrappingTestBackendDmaBuf(const wgpu::Device& device) {
}
~VulkanImageWrappingTestBackendDmaBuf() {
if (mGbmDevice != nullptr) {
gbm_device_destroy(mGbmDevice);
mGbmDevice = nullptr;
}
}
std::unique_ptr<ExternalTexture> CreateTexture(uint32_t width,
uint32_t height,
wgpu::TextureFormat format,
wgpu::TextureUsage usage) override {
EXPECT_EQ(format, wgpu::TextureFormat::RGBA8Unorm);
gbm_bo* bo = CreateGbmBo(width, height, true);
return std::make_unique<ExternalTextureDmaBuf>(
bo, gbm_bo_get_fd(bo), gbm_bo_get_stride_for_plane(bo, 0), gbm_bo_get_modifier(bo));
}
wgpu::Texture WrapImage(
const wgpu::Device& device,
const ExternalTexture* texture,
const ExternalImageDescriptorVkForTesting& descriptor,
std::vector<std::unique_ptr<ExternalSemaphore>> semaphores) override {
const ExternalTextureDmaBuf* textureDmaBuf =
static_cast<const ExternalTextureDmaBuf*>(texture);
std::vector<int> waitFDs;
for (auto& semaphore : semaphores) {
waitFDs.push_back(
static_cast<ExternalSemaphoreDmaBuf*>(semaphore.get())->AcquireHandle());
}
ExternalImageDescriptorDmaBuf descriptorDmaBuf;
*static_cast<ExternalImageDescriptorVk*>(&descriptorDmaBuf) = descriptor;
descriptorDmaBuf.memoryFD = textureDmaBuf->Dup();
descriptorDmaBuf.waitFDs = std::move(waitFDs);
descriptorDmaBuf.stride = textureDmaBuf->stride;
descriptorDmaBuf.drmModifier = textureDmaBuf->drmModifier;
return dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorDmaBuf);
}
bool ExportImage(const wgpu::Texture& texture,
VkImageLayout layout,
ExternalImageExportInfoVkForTesting* exportInfo) override {
ExternalImageExportInfoDmaBuf infoDmaBuf;
bool success = ExportVulkanImage(texture.Get(), layout, &infoDmaBuf);
*static_cast<ExternalImageExportInfoVk*>(exportInfo) = infoDmaBuf;
for (int fd : infoDmaBuf.semaphoreHandles) {
EXPECT_NE(fd, -1);
exportInfo->semaphores.push_back(std::make_unique<ExternalSemaphoreDmaBuf>(fd));
}
return success;
}
void CreateGbmDevice() {
// Render nodes [1] are the primary interface for communicating with the GPU on
// devices that support DRM. The actual filename of the render node is
// implementation-specific, so we must scan through all possible filenames to find
// one that we can use [2].
//
// [1] https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#render-nodes
// [2]
// https://cs.chromium.org/chromium/src/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc
const uint32_t kRenderNodeStart = 128;
const uint32_t kRenderNodeEnd = kRenderNodeStart + 16;
const std::string kRenderNodeTemplate = "/dev/dri/renderD";
int renderNodeFd = -1;
for (uint32_t i = kRenderNodeStart; i < kRenderNodeEnd; i++) {
std::string renderNode = kRenderNodeTemplate + std::to_string(i);
renderNodeFd = open(renderNode.c_str(), O_RDWR);
if (renderNodeFd >= 0)
break;
}
EXPECT_GE(renderNodeFd, 0) << "Failed to get file descriptor for render node";
gbm_device* gbmDevice = gbm_create_device(renderNodeFd);
EXPECT_NE(gbmDevice, nullptr) << "Failed to create GBM device";
mGbmDevice = gbmDevice;
}
private:
gbm_bo* CreateGbmBo(uint32_t width, uint32_t height, bool linear) {
uint32_t flags = GBM_BO_USE_RENDERING;
if (linear)
flags |= GBM_BO_USE_LINEAR;
gbm_bo* gbmBo = gbm_bo_create(mGbmDevice, width, height, GBM_FORMAT_XBGR8888, flags);
EXPECT_NE(gbmBo, nullptr) << "Failed to create GBM buffer object";
return gbmBo;
}
gbm_device* mGbmDevice = nullptr;
};
// static
std::unique_ptr<VulkanImageWrappingTestBackend> VulkanImageWrappingTestBackend::Create(
const wgpu::Device& device) {
auto backend = std::make_unique<VulkanImageWrappingTestBackendDmaBuf>(device);
backend->CreateGbmDevice();
return backend;
}
} // namespace dawn::native::vulkan