| // 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 "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 |