blob: 1174fdb6b4820e79356c9b5e052ec827220e54e8 [file]
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <webgpu/webgpu_cpp.h>
#include <array>
#include <string>
#include <utility>
#include <vector>
#include "src/utils/compiler.h"
// This must be included instead of vulkan.h so that we can wrap it with vulkan_platform.h.
#include "src/dawn/common/DRMUtils.h"
#include "src/dawn/common/vulkan_platform.h"
#include "src/dawn/tests/GBMUtils.h"
#include "src/dawn/tests/white_box/SharedTextureMemoryTests.h"
namespace dawn {
namespace {
template <wgpu::FeatureName FenceFeature>
class Backend : public SharedTextureMemoryTestVulkanBackend {
public:
static SharedTextureMemoryTestBackend* GetInstance() {
static Backend b;
return &b;
}
std::string Name() const override {
switch (FenceFeature) {
case wgpu::FeatureName::SharedFenceVkSemaphoreOpaqueFD:
return "dma buf, opaque fd";
case wgpu::FeatureName::SharedFenceSyncFD:
return "dma buf, sync fd";
default:
DAWN_UNREACHABLE();
}
}
std::vector<wgpu::FeatureName> RequiredFeatures(const wgpu::Adapter&) const override {
return {wgpu::FeatureName::SharedTextureMemoryDmaBuf,
wgpu::FeatureName::DawnMultiPlanarFormats, wgpu::FeatureName::AdapterPropertiesDrm,
FenceFeature};
}
static std::string MakeLabel(const wgpu::SharedTextureMemoryDmaBufDescriptor& desc) {
// Internally, the GBM enums are defined as their fourcc values. Cast to that and use
// it as the label. The fourcc value is a four-character name that can be
// interpreted as a 32-bit integer enum ('ABGR', 'r011', etc.)
return std::string(reinterpret_cast<const char*>(&desc.drmFormat), 4) + " " +
"modifier:" + std::to_string(desc.drmModifier) + " " +
std::to_string(desc.size.width) + "x" + std::to_string(desc.size.height);
}
template <typename CreateFn>
auto CreateSharedTextureMemoryHelper(uint32_t size,
uint32_t format,
uint32_t usage,
CreateFn createFn) {
OwnedGbmBo bo(gbm_bo_create(mGbmDevice.get(), size, size, format, usage));
EXPECT_NE(bo, nullptr) << "Failed to create GBM buffer object";
wgpu::SharedTextureMemoryDmaBufDescriptor dmaBufDesc;
dmaBufDesc.size = {size, size};
dmaBufDesc.drmFormat = format;
dmaBufDesc.drmModifier = gbm_bo_get_modifier(bo.get());
std::array<wgpu::SharedTextureMemoryDmaBufPlane, GBM_MAX_PLANES> planes = {};
const int gbmPlaneCount = gbm_bo_get_plane_count(bo.get());
DAWN_ASSERT(gbmPlaneCount > 0);
const size_t planeCount = static_cast<size_t>(gbmPlaneCount);
DAWN_ASSERT(planeCount <= planes.size());
dmaBufDesc.planeCount = planeCount;
dmaBufDesc.planes = planes.data();
std::array<SystemHandle, GBM_MAX_PLANES> planeFDs;
for (size_t plane = 0; plane < planeCount; ++plane) {
const int gbmPlane = static_cast<int>(plane);
planeFDs[plane] = SystemHandle::Acquire(gbm_bo_get_fd(bo.get()));
EXPECT_TRUE(planeFDs[plane].IsValid());
planes[plane].fd = planeFDs[plane].Get();
planes[plane].stride = gbm_bo_get_stride_for_plane(bo.get(), gbmPlane);
planes[plane].offset = gbm_bo_get_offset(bo.get(), gbmPlane);
}
std::string label = MakeLabel(dmaBufDesc);
wgpu::SharedTextureMemoryDescriptor desc;
desc.label = label.c_str();
desc.nextInChain = &dmaBufDesc;
return createFn(desc);
}
// Create one basic shared texture memory. It should support most operations.
wgpu::SharedTextureMemory CreateSharedTextureMemory(const wgpu::Device& device,
int layerCount) override {
auto format = GBM_FORMAT_ABGR8888;
auto usage = GBM_BO_USE_LINEAR;
DAWN_ASSERT(gbm_device_is_format_supported(mGbmDevice.get(), format, usage));
return CreateSharedTextureMemoryHelper(
16, format, usage, [&](const wgpu::SharedTextureMemoryDescriptor& desc) {
return device.ImportSharedTextureMemory(&desc);
});
}
std::vector<std::vector<wgpu::SharedTextureMemory>> CreatePerDeviceSharedTextureMemories(
const std::vector<wgpu::Device>& devices,
int layerCount) override {
std::vector<std::vector<wgpu::SharedTextureMemory>> memories;
for (uint32_t format : {
GBM_FORMAT_R8,
GBM_FORMAT_GR88,
GBM_FORMAT_ABGR8888,
GBM_FORMAT_ARGB8888,
GBM_FORMAT_XBGR8888,
GBM_FORMAT_XRGB8888,
GBM_FORMAT_ABGR2101010,
GBM_FORMAT_NV12,
}) {
for (gbm_bo_flags usage : {
gbm_bo_flags(0),
GBM_BO_USE_LINEAR,
GBM_BO_USE_RENDERING,
gbm_bo_flags(GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR),
}) {
if (!gbm_device_is_format_supported(mGbmDevice.get(), format, usage)) {
continue;
}
for (uint32_t size : {4, 64}) {
CreateSharedTextureMemoryHelper(
size, format, usage, [&](const wgpu::SharedTextureMemoryDescriptor& desc) {
std::vector<wgpu::SharedTextureMemory> perDeviceMemories;
for (auto& device : devices) {
perDeviceMemories.push_back(
device.ImportSharedTextureMemory(&desc));
}
memories.push_back(std::move(perDeviceMemories));
return true;
});
}
}
}
return memories;
}
private:
void SetUp(const wgpu::Device& device) override {
wgpu::AdapterPropertiesDrm drmProperties;
wgpu::AdapterInfo adapterInfo;
adapterInfo.nextInChain = &drmProperties;
DAWN_TEST_UNSUPPORTED_IF(device.GetAdapter().GetInfo(&adapterInfo) !=
wgpu::Status::Success ||
!drmProperties.hasRender);
SystemHandle renderNode =
OpenDRMRenderNode(drmProperties.renderMajor, drmProperties.renderMinor);
DAWN_TEST_UNSUPPORTED_IF(!renderNode.IsValid());
OwnedGbmDevice gbmDevice(gbm_create_device(renderNode.Get()));
DAWN_TEST_UNSUPPORTED_IF(gbmDevice == nullptr);
// Make sure we can successfully create a basic buffer object.
OwnedGbmBo bo(
gbm_bo_create(gbmDevice.get(), 16, 16, GBM_FORMAT_XBGR8888, GBM_BO_USE_LINEAR));
DAWN_TEST_UNSUPPORTED_IF(bo == nullptr);
mGbmDevice = std::move(gbmDevice);
mRenderNode = std::move(renderNode);
}
// Declare first so the render node outlives the GBM device.
SystemHandle mRenderNode;
OwnedGbmDevice mGbmDevice;
};
DAWN_INSTANTIATE_PREFIXED_TEST_P(
Vulkan,
SharedTextureMemoryNoFeatureTests,
{VulkanBackend()},
{Backend<wgpu::FeatureName::SharedFenceVkSemaphoreOpaqueFD>::GetInstance(),
Backend<wgpu::FeatureName::SharedFenceSyncFD>::GetInstance()},
{1});
DAWN_INSTANTIATE_PREFIXED_TEST_P(
Vulkan,
SharedTextureMemoryTests,
{VulkanBackend()},
{Backend<wgpu::FeatureName::SharedFenceVkSemaphoreOpaqueFD>::GetInstance(),
Backend<wgpu::FeatureName::SharedFenceSyncFD>::GetInstance()},
{1});
} // anonymous namespace
} // namespace dawn