Wrap multiplanar iosurface in wgpuTexture
This CL supports wrapping multiplanar iosurface in wgpuTexture. It also provides mechanism to create TextureView on each planes. Bug:1307194 Change-Id: I5e82f47944fdea542abba097240c880628b1181f Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/81482 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
This commit is contained in:
parent
6cacdc460a
commit
0a6c2b0f99
|
@ -43,6 +43,8 @@ namespace dawn::native::metal {
|
|||
ExternalImageDescriptorIOSurface();
|
||||
|
||||
IOSurfaceRef ioSurface;
|
||||
|
||||
// This has been deprecated.
|
||||
uint32_t plane;
|
||||
};
|
||||
|
||||
|
|
|
@ -358,6 +358,12 @@ namespace dawn::native::metal {
|
|||
mSupportedFeatures.EnableFeature(Feature::Depth32FloatStencil8);
|
||||
}
|
||||
|
||||
// Uses newTextureWithDescriptor::iosurface::plane which is available
|
||||
// on ios 11.0+ and macOS 11.0+
|
||||
if (@available(macOS 10.11, iOS 11.0, *)) {
|
||||
mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats);
|
||||
}
|
||||
|
||||
#if defined(DAWN_PLATFORM_MACOS)
|
||||
// MTLPixelFormatDepth24Unorm_Stencil8 is only available on macOS 10.11+
|
||||
if ([*mDevice isDepth24Stencil8PixelFormatSupported]) {
|
||||
|
|
|
@ -54,8 +54,7 @@ namespace dawn::native::metal {
|
|||
MaybeError SubmitPendingCommandBuffer();
|
||||
|
||||
Ref<Texture> CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane);
|
||||
IOSurfaceRef ioSurface);
|
||||
void WaitForCommandsToBeScheduled();
|
||||
|
||||
ResultOrError<std::unique_ptr<StagingBufferBase>> CreateStagingBuffer(size_t size) override;
|
||||
|
|
|
@ -432,21 +432,18 @@ namespace dawn::native::metal {
|
|||
}
|
||||
|
||||
Ref<Texture> Device::CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane) {
|
||||
IOSurfaceRef ioSurface) {
|
||||
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
|
||||
|
||||
if (ConsumedError(ValidateTextureDescriptor(this, textureDescriptor))) {
|
||||
return nullptr;
|
||||
}
|
||||
if (ConsumedError(
|
||||
ValidateIOSurfaceCanBeWrapped(this, textureDescriptor, ioSurface, plane))) {
|
||||
if (ConsumedError(ValidateIOSurfaceCanBeWrapped(this, textureDescriptor, ioSurface))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Ref<Texture> result;
|
||||
if (ConsumedError(Texture::CreateFromIOSurface(this, descriptor, ioSurface, plane),
|
||||
&result)) {
|
||||
if (ConsumedError(Texture::CreateFromIOSurface(this, descriptor, ioSurface), &result)) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace dawn::native::metal {
|
|||
WGPUTexture WrapIOSurface(WGPUDevice device,
|
||||
const ExternalImageDescriptorIOSurface* cDescriptor) {
|
||||
Device* backendDevice = ToBackend(FromAPI(device));
|
||||
Ref<TextureBase> texture = backendDevice->CreateTextureWrappingIOSurface(
|
||||
cDescriptor, cDescriptor->ioSurface, cDescriptor->plane);
|
||||
Ref<TextureBase> texture =
|
||||
backendDevice->CreateTextureWrappingIOSurface(cDescriptor, cDescriptor->ioSurface);
|
||||
return ToAPI(texture.Detach());
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "dawn/native/Texture.h"
|
||||
|
||||
#include "dawn/common/CoreFoundationRef.h"
|
||||
#include "dawn/common/NSRef.h"
|
||||
#include "dawn/native/DawnNative.h"
|
||||
|
||||
|
@ -31,8 +32,7 @@ namespace dawn::native::metal {
|
|||
MTLPixelFormat MetalPixelFormat(wgpu::TextureFormat format);
|
||||
MaybeError ValidateIOSurfaceCanBeWrapped(const DeviceBase* device,
|
||||
const TextureDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane);
|
||||
IOSurfaceRef ioSurface);
|
||||
|
||||
class Texture final : public TextureBase {
|
||||
public:
|
||||
|
@ -41,13 +41,13 @@ namespace dawn::native::metal {
|
|||
static ResultOrError<Ref<Texture>> CreateFromIOSurface(
|
||||
Device* device,
|
||||
const ExternalImageDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane);
|
||||
IOSurfaceRef ioSurface);
|
||||
static Ref<Texture> CreateWrapping(Device* device,
|
||||
const TextureDescriptor* descriptor,
|
||||
NSPRef<id<MTLTexture>> wrapped);
|
||||
|
||||
id<MTLTexture> GetMTLTexture();
|
||||
IOSurfaceRef GetIOSurface();
|
||||
NSPRef<id<MTLTexture>> CreateFormatView(wgpu::TextureFormat format);
|
||||
|
||||
void EnsureSubresourceContentInitialized(CommandRecordingContext* commandContext,
|
||||
|
@ -62,8 +62,7 @@ namespace dawn::native::metal {
|
|||
MaybeError InitializeAsInternalTexture(const TextureDescriptor* descriptor);
|
||||
MaybeError InitializeFromIOSurface(const ExternalImageDescriptor* descriptor,
|
||||
const TextureDescriptor* textureDescriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane);
|
||||
IOSurfaceRef ioSurface);
|
||||
void InitializeAsWrapping(const TextureDescriptor* descriptor,
|
||||
NSPRef<id<MTLTexture>> wrapped);
|
||||
|
||||
|
@ -74,7 +73,9 @@ namespace dawn::native::metal {
|
|||
TextureBase::ClearValue clearValue);
|
||||
|
||||
NSPRef<id<MTLTexture>> mMtlTexture;
|
||||
|
||||
MTLTextureUsage mMtlUsage;
|
||||
CFRef<IOSurfaceRef> mIOSurface = nullptr;
|
||||
};
|
||||
|
||||
class TextureView final : public TextureViewBase {
|
||||
|
|
|
@ -181,12 +181,25 @@ namespace dawn::native::metal {
|
|||
return wgpu::TextureFormat::RG8Unorm;
|
||||
case kCVPixelFormatType_OneComponent8:
|
||||
return wgpu::TextureFormat::R8Unorm;
|
||||
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
|
||||
return wgpu::TextureFormat::R8BG8Biplanar420Unorm;
|
||||
default:
|
||||
return DAWN_FORMAT_VALIDATION_ERROR("Unsupported IOSurface format (%x).",
|
||||
format);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetIOSurfacePlane(wgpu::TextureAspect aspect) {
|
||||
switch (aspect) {
|
||||
case wgpu::TextureAspect::Plane0Only:
|
||||
return 0;
|
||||
case wgpu::TextureAspect::Plane1Only:
|
||||
return 1;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DAWN_PLATFORM_MACOS)
|
||||
MTLStorageMode kIOSurfaceStorageMode = MTLStorageModeManaged;
|
||||
#elif defined(DAWN_PLATFORM_IOS)
|
||||
|
@ -392,15 +405,7 @@ namespace dawn::native::metal {
|
|||
|
||||
MaybeError ValidateIOSurfaceCanBeWrapped(const DeviceBase*,
|
||||
const TextureDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane) {
|
||||
// IOSurfaceGetPlaneCount can return 0 for non-planar IOSurfaces but we will treat
|
||||
// non-planar like it is a single plane.
|
||||
size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
|
||||
DAWN_INVALID_IF(plane >= surfacePlaneCount,
|
||||
"IOSurface plane (%u) exceeds the surface's plane count (%u).", plane,
|
||||
surfacePlaneCount);
|
||||
|
||||
IOSurfaceRef ioSurface) {
|
||||
DAWN_INVALID_IF(descriptor->dimension != wgpu::TextureDimension::e2D,
|
||||
"Texture dimension (%s) is not %s.", descriptor->dimension,
|
||||
wgpu::TextureDimension::e2D);
|
||||
|
@ -414,8 +419,8 @@ namespace dawn::native::metal {
|
|||
DAWN_INVALID_IF(descriptor->sampleCount != 1, "Sample count (%u) is not 1.",
|
||||
descriptor->sampleCount);
|
||||
|
||||
uint32_t surfaceWidth = IOSurfaceGetWidthOfPlane(ioSurface, plane);
|
||||
uint32_t surfaceHeight = IOSurfaceGetHeightOfPlane(ioSurface, plane);
|
||||
uint32_t surfaceWidth = IOSurfaceGetWidth(ioSurface);
|
||||
uint32_t surfaceHeight = IOSurfaceGetHeight(ioSurface);
|
||||
|
||||
DAWN_INVALID_IF(
|
||||
descriptor->size.width != surfaceWidth || descriptor->size.height != surfaceHeight ||
|
||||
|
@ -497,13 +502,12 @@ namespace dawn::native::metal {
|
|||
ResultOrError<Ref<Texture>> Texture::CreateFromIOSurface(
|
||||
Device* device,
|
||||
const ExternalImageDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane) {
|
||||
IOSurfaceRef ioSurface) {
|
||||
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
|
||||
|
||||
Ref<Texture> texture =
|
||||
AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedInternal));
|
||||
DAWN_TRY(texture->InitializeFromIOSurface(descriptor, textureDescriptor, ioSurface, plane));
|
||||
AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedExternal));
|
||||
DAWN_TRY(texture->InitializeFromIOSurface(descriptor, textureDescriptor, ioSurface));
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
@ -546,20 +550,28 @@ namespace dawn::native::metal {
|
|||
|
||||
MaybeError Texture::InitializeFromIOSurface(const ExternalImageDescriptor* descriptor,
|
||||
const TextureDescriptor* textureDescriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane) {
|
||||
Device* device = ToBackend(GetDevice());
|
||||
IOSurfaceRef ioSurface) {
|
||||
mIOSurface = ioSurface;
|
||||
|
||||
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
|
||||
[*mtlDesc setStorageMode:kIOSurfaceStorageMode];
|
||||
// Uses WGPUTexture which wraps multiplanar ioSurface needs to create
|
||||
// texture view explicitly. Wrap the ioSurface and delay to extract
|
||||
// MTLTexture from the plane of it when creating texture view.
|
||||
// WGPUTexture which wraps non-multplanar ioSurface needs to support
|
||||
// ops that doesn't require creating texture view(e.g. copy). Extract
|
||||
// MTLTexture from such ioSurface to support this.
|
||||
if (!GetFormat().IsMultiPlanar()) {
|
||||
Device* device = ToBackend(GetDevice());
|
||||
|
||||
mMtlUsage = [*mtlDesc usage];
|
||||
mMtlTexture = AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()
|
||||
iosurface:ioSurface
|
||||
plane:plane]);
|
||||
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor();
|
||||
[*mtlDesc setStorageMode:kIOSurfaceStorageMode];
|
||||
|
||||
mMtlUsage = [*mtlDesc usage];
|
||||
mMtlTexture =
|
||||
AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()
|
||||
iosurface:ioSurface
|
||||
plane:0]);
|
||||
}
|
||||
SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -569,12 +581,17 @@ namespace dawn::native::metal {
|
|||
void Texture::DestroyImpl() {
|
||||
TextureBase::DestroyImpl();
|
||||
mMtlTexture = nullptr;
|
||||
mIOSurface = nullptr;
|
||||
}
|
||||
|
||||
id<MTLTexture> Texture::GetMTLTexture() {
|
||||
return mMtlTexture.Get();
|
||||
}
|
||||
|
||||
IOSurfaceRef Texture::GetIOSurface() {
|
||||
return mIOSurface.Get();
|
||||
}
|
||||
|
||||
NSPRef<id<MTLTexture>> Texture::CreateFormatView(wgpu::TextureFormat format) {
|
||||
if (GetFormat().format == format) {
|
||||
return mMtlTexture;
|
||||
|
@ -821,6 +838,37 @@ namespace dawn::native::metal {
|
|||
mMtlTextureView = nullptr;
|
||||
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
|
||||
mMtlTextureView = mtlTexture;
|
||||
} else if (texture->GetFormat().IsMultiPlanar()) {
|
||||
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
|
||||
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
|
||||
|
||||
mtlDesc.sampleCount = texture->GetSampleCount();
|
||||
mtlDesc.usage = MetalTextureUsage(texture->GetFormat(), texture->GetInternalUsage(),
|
||||
texture->GetSampleCount());
|
||||
mtlDesc.pixelFormat = MetalPixelFormat(descriptor->format);
|
||||
mtlDesc.mipmapLevelCount = texture->GetNumMipLevels();
|
||||
mtlDesc.storageMode = kIOSurfaceStorageMode;
|
||||
|
||||
uint32_t plane = GetIOSurfacePlane(descriptor->aspect);
|
||||
mtlDesc.width = IOSurfaceGetWidthOfPlane(texture->GetIOSurface(), plane);
|
||||
mtlDesc.height = IOSurfaceGetHeightOfPlane(texture->GetIOSurface(), plane);
|
||||
|
||||
// Multiplanar texture is validated to only have single layer, single mipLevel
|
||||
// and 2d textures (depth == 1)
|
||||
ASSERT(texture->GetArrayLayers() == 1 &&
|
||||
texture->GetDimension() == wgpu::TextureDimension::e2D &&
|
||||
texture->GetNumMipLevels() == 1);
|
||||
mtlDesc.arrayLength = 1;
|
||||
mtlDesc.depth = 1;
|
||||
|
||||
mMtlTextureView = AcquireNSPRef([ToBackend(GetDevice())->GetMTLDevice()
|
||||
newTextureWithDescriptor:mtlDesc
|
||||
iosurface:texture->GetIOSurface()
|
||||
plane:plane]);
|
||||
if (mMtlTextureView == nil) {
|
||||
return DAWN_INTERNAL_ERROR(
|
||||
"Failed to create MTLTexture view for external texture.");
|
||||
}
|
||||
} else {
|
||||
MTLPixelFormat format = MetalPixelFormat(descriptor->format);
|
||||
if (descriptor->aspect == wgpu::TextureAspect::StencilOnly) {
|
||||
|
|
|
@ -451,7 +451,10 @@ source_set("end2end_tests_sources") {
|
|||
}
|
||||
|
||||
if (dawn_enable_metal) {
|
||||
sources += [ "end2end/IOSurfaceWrappingTests.cpp" ]
|
||||
sources += [
|
||||
"end2end/IOSurfaceWrappingTests.cpp",
|
||||
"end2end/VideoViewsTests_mac.cpp",
|
||||
]
|
||||
frameworks = [ "IOSurface.framework" ]
|
||||
}
|
||||
|
||||
|
@ -468,7 +471,8 @@ source_set("end2end_tests_sources") {
|
|||
deps += [ "${dawn_root}/src/dawn/utils:glfw" ]
|
||||
}
|
||||
|
||||
if (dawn_enable_d3d12 || (dawn_enable_vulkan && is_chromeos)) {
|
||||
if (dawn_enable_d3d12 || (dawn_enable_vulkan && is_chromeos) ||
|
||||
dawn_enable_metal) {
|
||||
sources += [
|
||||
"end2end/VideoViewsTests.cpp",
|
||||
"end2end/VideoViewsTests.h",
|
||||
|
|
|
@ -96,13 +96,11 @@ namespace {
|
|||
public:
|
||||
wgpu::Texture WrapIOSurface(const wgpu::TextureDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
uint32_t plane,
|
||||
bool isInitialized = true) {
|
||||
dawn::native::metal::ExternalImageDescriptorIOSurface externDesc;
|
||||
externDesc.cTextureDescriptor =
|
||||
reinterpret_cast<const WGPUTextureDescriptor*>(descriptor);
|
||||
externDesc.ioSurface = ioSurface;
|
||||
externDesc.plane = plane;
|
||||
externDesc.isInitialized = isInitialized;
|
||||
WGPUTexture texture = dawn::native::metal::WrapIOSurface(device.Get(), &externDesc);
|
||||
return wgpu::Texture::Acquire(texture);
|
||||
|
@ -134,7 +132,7 @@ class IOSurfaceValidationTests : public IOSurfaceTestBase {
|
|||
// Test a successful wrapping of an IOSurface in a texture
|
||||
TEST_P(IOSurfaceValidationTests, Success) {
|
||||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get(), 0);
|
||||
wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get());
|
||||
ASSERT_NE(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -145,16 +143,7 @@ TEST_P(IOSurfaceValidationTests, InvalidTextureDescriptor) {
|
|||
wgpu::ChainedStruct chainedDescriptor;
|
||||
descriptor.nextInChain = &chainedDescriptor;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
// Test an error occurs if the plane is too large
|
||||
TEST_P(IOSurfaceValidationTests, PlaneTooLarge) {
|
||||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 1));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -164,8 +153,7 @@ TEST_P(IOSurfaceValidationTests, InvalidTextureDimension) {
|
|||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
descriptor.dimension = wgpu::TextureDimension::e3D;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -174,8 +162,7 @@ TEST_P(IOSurfaceValidationTests, InvalidMipLevelCount) {
|
|||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
descriptor.mipLevelCount = 2;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -184,8 +171,7 @@ TEST_P(IOSurfaceValidationTests, InvalidDepth) {
|
|||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
descriptor.size.depthOrArrayLayers = 2;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -194,8 +180,7 @@ TEST_P(IOSurfaceValidationTests, InvalidSampleCount) {
|
|||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
descriptor.sampleCount = 4;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -204,8 +189,7 @@ TEST_P(IOSurfaceValidationTests, InvalidWidth) {
|
|||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
descriptor.size.width = 11;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -214,8 +198,7 @@ TEST_P(IOSurfaceValidationTests, InvalidHeight) {
|
|||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
descriptor.size.height = 11;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -224,8 +207,7 @@ TEST_P(IOSurfaceValidationTests, InvalidFormat) {
|
|||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
||||
descriptor.format = wgpu::TextureFormat::R8Unorm;
|
||||
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture =
|
||||
WrapIOSurface(&descriptor, defaultIOSurface.get(), 0));
|
||||
ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapIOSurface(&descriptor, defaultIOSurface.get()));
|
||||
ASSERT_EQ(texture.Get(), nullptr);
|
||||
}
|
||||
|
||||
|
@ -305,7 +287,7 @@ class IOSurfaceUsageTests : public IOSurfaceTestBase {
|
|||
textureDescriptor.sampleCount = 1;
|
||||
textureDescriptor.mipLevelCount = 1;
|
||||
textureDescriptor.usage = wgpu::TextureUsage::TextureBinding;
|
||||
wgpu::Texture wrappingTexture = WrapIOSurface(&textureDescriptor, ioSurface, 0);
|
||||
wgpu::Texture wrappingTexture = WrapIOSurface(&textureDescriptor, ioSurface);
|
||||
|
||||
wgpu::TextureView textureView = wrappingTexture.CreateView();
|
||||
|
||||
|
@ -345,7 +327,7 @@ class IOSurfaceUsageTests : public IOSurfaceTestBase {
|
|||
textureDescriptor.sampleCount = 1;
|
||||
textureDescriptor.mipLevelCount = 1;
|
||||
textureDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
|
||||
wgpu::Texture ioSurfaceTexture = WrapIOSurface(&textureDescriptor, ioSurface, 0);
|
||||
wgpu::Texture ioSurfaceTexture = WrapIOSurface(&textureDescriptor, ioSurface);
|
||||
|
||||
wgpu::TextureView ioSurfaceView = ioSurfaceTexture.CreateView();
|
||||
|
||||
|
@ -471,7 +453,7 @@ TEST_P(IOSurfaceUsageTests, UninitializedTextureIsCleared) {
|
|||
textureDescriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
|
||||
|
||||
// wrap ioSurface and ensure color is not visible when isInitialized set to false
|
||||
wgpu::Texture ioSurfaceTexture = WrapIOSurface(&textureDescriptor, ioSurface.get(), 0, false);
|
||||
wgpu::Texture ioSurfaceTexture = WrapIOSurface(&textureDescriptor, ioSurface.get(), false);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), ioSurfaceTexture, 0, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,58 @@ std::vector<uint8_t> VideoViewsTests::GetTestTextureData(wgpu::TextureFormat for
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t VideoViewsTests::NumPlanes(wgpu::TextureFormat format) {
|
||||
switch (format) {
|
||||
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
|
||||
return 2;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
std::vector<uint8_t> VideoViewsTests::GetTestTextureDataWithPlaneIndex(size_t planeIndex,
|
||||
size_t bytesPerRow,
|
||||
size_t height,
|
||||
bool isCheckerboard) {
|
||||
std::vector<uint8_t> texelData = VideoViewsTests::GetTestTextureData(
|
||||
wgpu::TextureFormat::R8BG8Biplanar420Unorm, isCheckerboard);
|
||||
const uint32_t texelDataRowBytes = kYUVImageDataWidthInTexels;
|
||||
const uint32_t texelDataHeight =
|
||||
planeIndex == 0 ? kYUVImageDataHeightInTexels : kYUVImageDataHeightInTexels / 2;
|
||||
|
||||
std::vector<uint8_t> texels(bytesPerRow * height, 0);
|
||||
uint32_t plane_first_texel_offset = 0;
|
||||
// The size of the test video frame is 4 x 4
|
||||
switch (planeIndex) {
|
||||
case VideoViewsTests::kYUVLumaPlaneIndex:
|
||||
for (uint32_t i = 0; i < texelDataHeight; ++i) {
|
||||
if (i < texelDataHeight) {
|
||||
for (uint32_t j = 0; j < texelDataRowBytes; ++j) {
|
||||
texels[bytesPerRow * i + j] =
|
||||
texelData[texelDataRowBytes * i + j + plane_first_texel_offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
return texels;
|
||||
case VideoViewsTests::kYUVChromaPlaneIndex:
|
||||
// TexelData is 4 * 6 size, first 4 * 4 is Y plane, UV plane started
|
||||
// at index 16.
|
||||
plane_first_texel_offset = 16;
|
||||
for (uint32_t i = 0; i < texelDataHeight; ++i) {
|
||||
if (i < texelDataHeight) {
|
||||
for (uint32_t j = 0; j < texelDataRowBytes; ++j) {
|
||||
texels[bytesPerRow * i + j] =
|
||||
texelData[texelDataRowBytes * i + j + plane_first_texel_offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
return texels;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Vertex shader used to render a sampled texture into a quad.
|
||||
wgpu::ShaderModule VideoViewsTests::GetTestVertexShaderModule() const {
|
||||
return utils::CreateShaderModule(device, R"(
|
||||
|
|
|
@ -28,7 +28,8 @@ class VideoViewsTestBackend {
|
|||
virtual ~VideoViewsTestBackend();
|
||||
|
||||
virtual void OnSetUp(WGPUDevice device) = 0;
|
||||
virtual void OnTearDown() = 0;
|
||||
virtual void OnTearDown() {
|
||||
}
|
||||
|
||||
class PlatformTexture {
|
||||
public:
|
||||
|
@ -74,6 +75,11 @@ class VideoViewsTests : public DawnTest {
|
|||
RGBA8{90, 240, 0, 0xFF}}; // UV
|
||||
|
||||
static std::vector<uint8_t> GetTestTextureData(wgpu::TextureFormat format, bool isCheckerboard);
|
||||
static uint32_t NumPlanes(wgpu::TextureFormat format);
|
||||
static std::vector<uint8_t> GetTestTextureDataWithPlaneIndex(size_t planeIndex,
|
||||
size_t bytesPerRow,
|
||||
size_t height,
|
||||
bool isCheckerboard);
|
||||
|
||||
protected:
|
||||
void SetUp() override;
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2022 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 "VideoViewsTests.h"
|
||||
|
||||
#include "dawn/common/Assert.h"
|
||||
#include "dawn/common/CoreFoundationRef.h"
|
||||
#include "dawn/native/MetalBackend.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreVideo/CVPixelBuffer.h>
|
||||
#include <IOSurface/IOSurfaceRef.h>
|
||||
|
||||
namespace {
|
||||
void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, int32_t value) {
|
||||
CFNumberRef number(CFNumberCreate(nullptr, kCFNumberSInt32Type, &value));
|
||||
CFDictionaryAddValue(dictionary, key, number);
|
||||
CFRelease(number);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class PlatformTextureIOSurface : public VideoViewsTestBackend::PlatformTexture {
|
||||
public:
|
||||
PlatformTextureIOSurface(wgpu::Texture&& texture, IOSurfaceRef iosurface)
|
||||
: PlatformTexture(std::move(texture)) {
|
||||
mIOSurface = AcquireCFRef<IOSurfaceRef>(iosurface);
|
||||
}
|
||||
~PlatformTextureIOSurface() override {
|
||||
mIOSurface = nullptr;
|
||||
}
|
||||
|
||||
bool CanWrapAsWGPUTexture() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
CFRef<IOSurfaceRef> mIOSurface = nullptr;
|
||||
};
|
||||
|
||||
class VideoViewsTestBackendIOSurface : public VideoViewsTestBackend {
|
||||
public:
|
||||
void OnSetUp(WGPUDevice device) override {
|
||||
mWGPUDevice = device;
|
||||
}
|
||||
|
||||
private:
|
||||
OSType ToCVFormat(wgpu::TextureFormat format) {
|
||||
switch (format) {
|
||||
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
|
||||
return kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetSubSamplingFactorPerPlane(wgpu::TextureFormat format, size_t plane) {
|
||||
switch (format) {
|
||||
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
|
||||
return plane == VideoViewsTests::kYUVLumaPlaneIndex ? 1 : 2;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BytesPerElement(wgpu::TextureFormat format, size_t plane) {
|
||||
switch (format) {
|
||||
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
|
||||
return plane == VideoViewsTests::kYUVLumaPlaneIndex ? 1 : 2;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoViewsTestBackend::PlatformTexture> CreateVideoTextureForTest(
|
||||
wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage usage,
|
||||
bool isCheckerboard) override {
|
||||
CFMutableDictionaryRef dict(CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
AddIntegerValue(dict, kIOSurfaceWidth, VideoViewsTests::kYUVImageDataWidthInTexels);
|
||||
AddIntegerValue(dict, kIOSurfaceHeight, VideoViewsTests::kYUVImageDataHeightInTexels);
|
||||
AddIntegerValue(dict, kIOSurfacePixelFormat, ToCVFormat(format));
|
||||
|
||||
size_t num_planes = VideoViewsTests::NumPlanes(format);
|
||||
|
||||
CFMutableArrayRef planes(
|
||||
CFArrayCreateMutable(kCFAllocatorDefault, num_planes, &kCFTypeArrayCallBacks));
|
||||
size_t total_bytes_alloc = 0;
|
||||
for (size_t plane = 0; plane < num_planes; ++plane) {
|
||||
const size_t factor = GetSubSamplingFactorPerPlane(format, plane);
|
||||
const size_t plane_width = VideoViewsTests::kYUVImageDataWidthInTexels / factor;
|
||||
const size_t plane_height = VideoViewsTests::kYUVImageDataHeightInTexels / factor;
|
||||
const size_t plane_bytes_per_element = BytesPerElement(format, plane);
|
||||
const size_t plane_bytes_per_row = IOSurfaceAlignProperty(
|
||||
kIOSurfacePlaneBytesPerRow, plane_width * plane_bytes_per_element);
|
||||
const size_t plane_bytes_alloc =
|
||||
IOSurfaceAlignProperty(kIOSurfacePlaneSize, plane_height * plane_bytes_per_row);
|
||||
const size_t plane_offset =
|
||||
IOSurfaceAlignProperty(kIOSurfacePlaneOffset, total_bytes_alloc);
|
||||
|
||||
CFMutableDictionaryRef plane_info(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
|
||||
AddIntegerValue(plane_info, kIOSurfacePlaneWidth, plane_width);
|
||||
AddIntegerValue(plane_info, kIOSurfacePlaneHeight, plane_height);
|
||||
AddIntegerValue(plane_info, kIOSurfacePlaneBytesPerElement, plane_bytes_per_element);
|
||||
AddIntegerValue(plane_info, kIOSurfacePlaneBytesPerRow, plane_bytes_per_row);
|
||||
AddIntegerValue(plane_info, kIOSurfacePlaneSize, plane_bytes_alloc);
|
||||
AddIntegerValue(plane_info, kIOSurfacePlaneOffset, plane_offset);
|
||||
CFArrayAppendValue(planes, plane_info);
|
||||
CFRelease(plane_info);
|
||||
total_bytes_alloc = plane_offset + plane_bytes_alloc;
|
||||
}
|
||||
CFDictionaryAddValue(dict, kIOSurfacePlaneInfo, planes);
|
||||
CFRelease(planes);
|
||||
|
||||
total_bytes_alloc = IOSurfaceAlignProperty(kIOSurfaceAllocSize, total_bytes_alloc);
|
||||
AddIntegerValue(dict, kIOSurfaceAllocSize, total_bytes_alloc);
|
||||
|
||||
IOSurfaceRef surface = IOSurfaceCreate(dict);
|
||||
CFRelease(dict);
|
||||
|
||||
IOSurfaceLock(surface, 0, nullptr);
|
||||
for (size_t plane = 0; plane < num_planes; ++plane) {
|
||||
std::vector<uint8_t> data = VideoViewsTests::GetTestTextureDataWithPlaneIndex(
|
||||
plane, IOSurfaceGetBytesPerRowOfPlane(surface, plane),
|
||||
IOSurfaceGetHeightOfPlane(surface, plane), isCheckerboard);
|
||||
void* pointer = IOSurfaceGetBaseAddressOfPlane(surface, plane);
|
||||
memcpy(pointer, data.data(), data.size());
|
||||
}
|
||||
IOSurfaceUnlock(surface, 0, nullptr);
|
||||
|
||||
wgpu::TextureDescriptor textureDesc;
|
||||
textureDesc.format = format;
|
||||
textureDesc.dimension = wgpu::TextureDimension::e2D;
|
||||
textureDesc.usage = usage;
|
||||
textureDesc.size = {VideoViewsTests::kYUVImageDataWidthInTexels,
|
||||
VideoViewsTests::kYUVImageDataHeightInTexels, 1};
|
||||
|
||||
wgpu::DawnTextureInternalUsageDescriptor internalDesc;
|
||||
internalDesc.internalUsage = wgpu::TextureUsage::CopySrc;
|
||||
textureDesc.nextInChain = &internalDesc;
|
||||
|
||||
dawn::native::metal::ExternalImageDescriptorIOSurface descriptor = {};
|
||||
descriptor.cTextureDescriptor =
|
||||
reinterpret_cast<const WGPUTextureDescriptor*>(&textureDesc);
|
||||
descriptor.isInitialized = true;
|
||||
descriptor.ioSurface = surface;
|
||||
|
||||
return std::make_unique<PlatformTextureIOSurface>(
|
||||
wgpu::Texture::Acquire(dawn::native::metal::WrapIOSurface(mWGPUDevice, &descriptor)),
|
||||
surface);
|
||||
}
|
||||
|
||||
void DestroyVideoTextureForTest(
|
||||
std::unique_ptr<VideoViewsTestBackend::PlatformTexture>&& platformTexture) override {
|
||||
}
|
||||
|
||||
WGPUDevice mWGPUDevice = nullptr;
|
||||
};
|
||||
|
||||
// static
|
||||
BackendTestConfig VideoViewsTestBackend::Backend() {
|
||||
return MetalBackend();
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<VideoViewsTestBackend> VideoViewsTestBackend::Create() {
|
||||
return std::make_unique<VideoViewsTestBackendIOSurface>();
|
||||
}
|
|
@ -77,9 +77,6 @@ class VideoViewsTestBackendWin : public VideoViewsTestBackend {
|
|||
mD3d11Device = std::move(d3d11Device);
|
||||
}
|
||||
|
||||
void OnTearDown() override {
|
||||
}
|
||||
|
||||
protected:
|
||||
static DXGI_FORMAT GetDXGITextureFormat(wgpu::TextureFormat format) {
|
||||
switch (format) {
|
||||
|
|
Loading…
Reference in New Issue