diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h index 26e377e3bd1a8..5f48364838470 100644 --- a/Source/WTF/wtf/PlatformHave.h +++ b/Source/WTF/wtf/PlatformHave.h @@ -1144,6 +1144,7 @@ #if HAVE(WEBGPU_IMPLEMENTATION) && ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 160000)) #define HAVE_METAL_BUFFER_BINDING_REFLECTION 1 +#define HAVE_COREVIDEO_METAL_SUPPORT COREVIDEO_SUPPORTS_METAL #endif #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000) diff --git a/Source/WebCore/Modules/WebGPU/GPUExternalTextureDescriptor.h b/Source/WebCore/Modules/WebGPU/GPUExternalTextureDescriptor.h index 7be778838546e..ba854e0e3c583 100644 --- a/Source/WebCore/Modules/WebGPU/GPUExternalTextureDescriptor.h +++ b/Source/WebCore/Modules/WebGPU/GPUExternalTextureDescriptor.h @@ -38,9 +38,10 @@ class HTMLVideoElement; struct GPUExternalTextureDescriptor : public GPUObjectDescriptorBase { PAL::WebGPU::ExternalTextureDescriptor convertToBacking() const { + auto playerIdentifier = source->playerIdentifier(); return { { label }, - // FIXME: Handle the video element. + playerIdentifier.has_value() ? playerIdentifier->toUInt64() : 0, WebCore::convertToBacking(colorSpace), }; } diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUConvertToBackingContext.h b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUConvertToBackingContext.h index f431472034a30..8d62d65b92972 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUConvertToBackingContext.h +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUConvertToBackingContext.h @@ -37,6 +37,7 @@ #include "WebGPUShaderStage.h" #include "WebGPUTextureUsage.h" #include +#include #include #include @@ -62,6 +63,7 @@ class ComputePipeline; enum class CullMode : uint8_t; class Device; enum class ErrorFilter : uint8_t; +class ExternalTexture; enum class FeatureName : uint8_t; enum class FilterMode : uint8_t; enum class FrontFace : uint8_t; @@ -154,6 +156,7 @@ class ConvertToBackingContext : public RefCounted { virtual WGPUComputePassEncoder convertToBacking(const ComputePassEncoder&) = 0; virtual WGPUComputePipeline convertToBacking(const ComputePipeline&) = 0; virtual WGPUDevice convertToBacking(const Device&) = 0; + virtual WGPUExternalTexture convertToBacking(const ExternalTexture&) = 0; virtual WGPUInstance convertToBacking(const GPU&) = 0; virtual WGPUPipelineLayout convertToBacking(const PipelineLayout&) = 0; virtual WGPUQuerySet convertToBacking(const QuerySet&) = 0; diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDeviceImpl.cpp b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDeviceImpl.cpp index 4114eee2bab92..83f82b6d1edbe 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDeviceImpl.cpp +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDeviceImpl.cpp @@ -40,6 +40,7 @@ #include "WebGPUComputePipelineImpl.h" #include "WebGPUConvertToBackingContext.h" #include "WebGPUExtent3D.h" +#include "WebGPUExternalTextureDescriptor.h" #include "WebGPUExternalTextureImpl.h" #include "WebGPUOutOfMemoryError.h" #include "WebGPUPipelineLayoutDescriptor.h" @@ -59,6 +60,7 @@ #include "WebGPUTextureImpl.h" #include "WebGPUTextureViewImpl.h" #include "WebGPUValidationError.h" +#include #include #include @@ -146,9 +148,27 @@ Ref DeviceImpl::createSampler(const SamplerDescriptor& descriptor) return SamplerImpl::create(wgpuDeviceCreateSampler(m_backing, &backingDescriptor), m_convertToBackingContext); } -Ref DeviceImpl::importExternalTexture(const ExternalTextureDescriptor&) +static WGPUColorSpace convertToWGPUColorSpace(const PredefinedColorSpace& colorSpace) { - return ExternalTextureImpl::create(m_convertToBackingContext); + switch (colorSpace) { + case PredefinedColorSpace::SRGB: + return WGPUColorSpace::SRGB; + case PredefinedColorSpace::DisplayP3: + return WGPUColorSpace::DisplayP3; + } +} + +Ref DeviceImpl::importExternalTexture(const ExternalTextureDescriptor& descriptor) +{ + auto label = descriptor.label.utf8(); + + WGPUExternalTextureDescriptor backingDescriptor { + .nextInChain = nullptr, + label.data(), + .pixelBuffer = descriptor.pixelBuffer, + .colorSpace = convertToWGPUColorSpace(descriptor.colorSpace), + }; + return ExternalTextureImpl::create(wgpuDeviceImportExternalTexture(backing(), &backingDescriptor), descriptor, m_convertToBackingContext); } Ref DeviceImpl::createBindGroupLayout(const BindGroupLayoutDescriptor& descriptor) @@ -169,8 +189,8 @@ Ref DeviceImpl::createBindGroupLayout(const BindGroupLayoutDesc entry.sampler ? m_convertToBackingContext->convertToBacking(entry.sampler->type) : WGPUSamplerBindingType_Undefined, }, { nullptr, - entry.texture ? m_convertToBackingContext->convertToBacking(entry.texture->sampleType) : WGPUTextureSampleType_Undefined, - entry.texture ? m_convertToBackingContext->convertToBacking(entry.texture->viewDimension) : WGPUTextureViewDimension_Undefined, + entry.texture ? m_convertToBackingContext->convertToBacking(entry.texture->sampleType) : (entry.externalTexture ? WGPUTextureSampleType_Float : WGPUTextureSampleType_Undefined), + entry.texture ? m_convertToBackingContext->convertToBacking(entry.texture->viewDimension) : (entry.externalTexture ? WGPUTextureViewDimension_2D : WGPUTextureViewDimension_Undefined), entry.texture ? entry.texture->multisampled : false, }, { nullptr, @@ -213,9 +233,18 @@ Ref DeviceImpl::createBindGroup(const BindGroupDescriptor& descriptor { auto label = descriptor.label.utf8(); - auto backingEntries = descriptor.entries.map([this] (const auto& bindGroupEntry) { + Vector chainedEntries; + auto backingEntries = descriptor.entries.map([this, &chainedEntries] (const auto& bindGroupEntry) { + auto externalTexture = std::holds_alternative>(bindGroupEntry.resource) ? m_convertToBackingContext->convertToBacking(std::get>(bindGroupEntry.resource).get()) : nullptr; + chainedEntries.append(WGPUBindGroupExternalTextureEntry { + { + .next = nullptr, + .sType = static_cast(WGPUSTypeExtended_BindGroupEntryExternalTexture) + }, + .externalTexture = externalTexture, + }); return WGPUBindGroupEntry { - nullptr, + externalTexture ? reinterpret_cast(&chainedEntries.last()) : nullptr, bindGroupEntry.binding, std::holds_alternative(bindGroupEntry.resource) ? m_convertToBackingContext->convertToBacking(std::get(bindGroupEntry.resource).buffer) : nullptr, std::holds_alternative(bindGroupEntry.resource) ? std::get(bindGroupEntry.resource).offset : 0, diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.cpp b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.cpp index ecf0a9d9854e0..32d83106324f2 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.cpp +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.cpp @@ -100,6 +100,11 @@ WGPUDevice DowncastConvertToBackingContext::convertToBacking(const Device& devic return static_cast(device).backing(); } +WGPUExternalTexture DowncastConvertToBackingContext::convertToBacking(const ExternalTexture& externalTexture) +{ + return static_cast(externalTexture).backing(); +} + WGPUInstance DowncastConvertToBackingContext::convertToBacking(const GPU& gpu) { return static_cast(gpu).backing(); diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.h b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.h index de8d5a1379365..b3bcba647395c 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.h +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUDowncastConvertToBackingContext.h @@ -50,6 +50,7 @@ class DowncastConvertToBackingContext final : public ConvertToBackingContext { WGPUComputePassEncoder convertToBacking(const ComputePassEncoder&) final; WGPUComputePipeline convertToBacking(const ComputePipeline&) final; WGPUDevice convertToBacking(const Device&) final; + WGPUExternalTexture convertToBacking(const ExternalTexture&) final; WGPUInstance convertToBacking(const GPU&) final; WGPUPipelineLayout convertToBacking(const PipelineLayout&) final; WGPUSurface convertToBacking(const PresentationContext&) final; diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.cpp b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.cpp index 365dc029422b2..2a9a935305c24 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.cpp +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.cpp @@ -29,12 +29,15 @@ #if HAVE(WEBGPU_IMPLEMENTATION) #include "WebGPUConvertToBackingContext.h" +#include "WebGPUExternalTextureDescriptor.h" #include namespace PAL::WebGPU { -ExternalTextureImpl::ExternalTextureImpl(ConvertToBackingContext& convertToBackingContext) +ExternalTextureImpl::ExternalTextureImpl(WGPUExternalTexture externalTexture, const ExternalTextureDescriptor& descriptor, ConvertToBackingContext& convertToBackingContext) : m_convertToBackingContext(convertToBackingContext) + , m_backing(externalTexture) + , m_colorSpace(descriptor.colorSpace) { } diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.h b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.h index d0ad162e6c958..f5f281a539f17 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.h +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUExternalTextureImpl.h @@ -28,26 +28,32 @@ #if HAVE(WEBGPU_IMPLEMENTATION) #include "WebGPUExternalTexture.h" +#include "WebGPUExternalTextureDescriptor.h" +#include "WebGPUPredefinedColorSpace.h" #include +#include namespace PAL::WebGPU { class ConvertToBackingContext; +struct ExternalTextureDescriptor; class ExternalTextureImpl final : public ExternalTexture { WTF_MAKE_FAST_ALLOCATED; public: - static Ref create(ConvertToBackingContext& convertToBackingContext) + static Ref create(WGPUExternalTexture externalTexture, const ExternalTextureDescriptor& descriptor, ConvertToBackingContext& convertToBackingContext) { - return adoptRef(*new ExternalTextureImpl(convertToBackingContext)); + return adoptRef(*new ExternalTextureImpl(externalTexture, descriptor, convertToBackingContext)); } virtual ~ExternalTextureImpl(); + WGPUExternalTexture backing() const { return m_backing; }; + private: friend class DowncastConvertToBackingContext; - ExternalTextureImpl(ConvertToBackingContext&); + ExternalTextureImpl(WGPUExternalTexture, const ExternalTextureDescriptor&, ConvertToBackingContext&); ExternalTextureImpl(const ExternalTextureImpl&) = delete; ExternalTextureImpl(ExternalTextureImpl&&) = delete; @@ -57,6 +63,9 @@ class ExternalTextureImpl final : public ExternalTexture { void setLabelInternal(const String&) final; Ref m_convertToBackingContext; + + WGPUExternalTexture m_backing; + PredefinedColorSpace m_colorSpace; }; } // namespace PAL::WebGPU diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUExternalTextureDescriptor.h b/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUExternalTextureDescriptor.h index 2acc9ba2451d8..83269112e4337 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUExternalTextureDescriptor.h +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUExternalTextureDescriptor.h @@ -28,10 +28,14 @@ #include "WebGPUObjectDescriptorBase.h" #include "WebGPUPredefinedColorSpace.h" +typedef struct __CVBuffer* CVPixelBufferRef; + namespace PAL::WebGPU { struct ExternalTextureDescriptor : public ObjectDescriptorBase { + uint64_t mediaIdentifier { 0 }; PredefinedColorSpace colorSpace { PredefinedColorSpace::SRGB }; + CVPixelBufferRef pixelBuffer { nullptr }; }; } // namespace PAL::WebGPU diff --git a/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUPredefinedColorSpace.h b/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUPredefinedColorSpace.h index e2af15456c399..139f32844cd71 100644 --- a/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUPredefinedColorSpace.h +++ b/Source/WebCore/PAL/pal/graphics/WebGPU/WebGPUPredefinedColorSpace.h @@ -32,6 +32,7 @@ namespace PAL::WebGPU { enum class PredefinedColorSpace : uint8_t { SRGB, + DisplayP3, }; } // namespace PAL::WebGPU diff --git a/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj b/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj index 1c8c25afc90d3..158431bc2d364 100644 --- a/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj +++ b/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 0D30F93729F1F94A0055D9F1 /* ExternalTexture.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0D30F93629F1F94A0055D9F1 /* ExternalTexture.mm */; }; + 0D30F93929F1FAC50055D9F1 /* ExternalTexture.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D30F93829F1FAC50055D9F1 /* ExternalTexture.h */; }; + 0D30F93B29F1FBE40055D9F1 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D30F93A29F1FBE40055D9F1 /* CoreVideo.framework */; }; 1C0F41EE280940650005886D /* HardwareCapabilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C0F41EC280940650005886D /* HardwareCapabilities.mm */; }; 1C2CEDEE271E8A7300EDC16F /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C2CEDED271E8A7300EDC16F /* Metal.framework */; }; 1C582FF927E04131009B40F0 /* CommandsMixin.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C582FF727E04131009B40F0 /* CommandsMixin.mm */; }; @@ -205,6 +208,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0D30F93629F1F94A0055D9F1 /* ExternalTexture.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ExternalTexture.mm; sourceTree = ""; }; + 0D30F93829F1FAC50055D9F1 /* ExternalTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExternalTexture.h; sourceTree = ""; }; + 0D30F93A29F1FBE40055D9F1 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; 0D4D2E80294A89CF0000A1AB /* BindableResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BindableResource.h; sourceTree = ""; }; 1C0F41EC280940650005886D /* HardwareCapabilities.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = HardwareCapabilities.mm; sourceTree = ""; }; 1C0F41ED280940650005886D /* HardwareCapabilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HardwareCapabilities.h; sourceTree = ""; }; @@ -400,6 +406,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0D30F93B29F1FBE40055D9F1 /* CoreVideo.framework in Frameworks */, 664C92FD286A66090008D143 /* IOSurface.framework in Frameworks */, 1CBAB0922718CCA0006080BB /* JavaScriptCore.framework in Frameworks */, 1CEBD8262716CACC00A5254D /* libwgsl.a in Frameworks */, @@ -475,6 +482,8 @@ 1C5ACA9B273A426D0095F8D5 /* Device.h */, 1C5ACAA3273A426D0095F8D5 /* Device.mm */, 1CEBD80B2716C37900A5254D /* ExportMacros.h */, + 0D30F93829F1FAC50055D9F1 /* ExternalTexture.h */, + 0D30F93629F1F94A0055D9F1 /* ExternalTexture.mm */, 1C0F41ED280940650005886D /* HardwareCapabilities.h */, 1C0F41EC280940650005886D /* HardwareCapabilities.mm */, 1C5ACAA0273A426D0095F8D5 /* Instance.h */, @@ -581,6 +590,7 @@ isa = PBXGroup; children = ( 1CEBD82B2716CAFB00A5254D /* CoreFoundation.framework */, + 0D30F93A29F1FBE40055D9F1 /* CoreVideo.framework */, 1CEBD82D2716CB1600A5254D /* Foundation.framework */, 664C92FC286A66090008D143 /* IOSurface.framework */, 1CBAB0912718CCA0006080BB /* JavaScriptCore.framework */, @@ -692,6 +702,7 @@ buildActionMask = 2147483647; files = ( 1CEBD7E72716AFBA00A5254D /* WebGPU.h in Headers */, + 0D30F93929F1FAC50055D9F1 /* ExternalTexture.h in Headers */, 973F784729C8A78200166C66 /* Pipeline.h in Headers */, 1C5ACAD3273A4C860095F8D5 /* WebGPUExt.h in Headers */, ); @@ -933,6 +944,7 @@ 1C5ACAC6273A426D0095F8D5 /* ComputePassEncoder.mm in Sources */, 1C5ACAC0273A426D0095F8D5 /* ComputePipeline.mm in Sources */, 1C5ACAC1273A426D0095F8D5 /* Device.mm in Sources */, + 0D30F93729F1F94A0055D9F1 /* ExternalTexture.mm in Sources */, 1C0F41EE280940650005886D /* HardwareCapabilities.mm in Sources */, 1C5ACA94273A41C20095F8D5 /* Instance.mm in Sources */, 973F784829C8A78200166C66 /* Pipeline.mm in Sources */, diff --git a/Source/WebGPU/WebGPU/APIConversions.h b/Source/WebGPU/WebGPU/APIConversions.h index 760ca64b2dd9c..55b00d13e4cc2 100644 --- a/Source/WebGPU/WebGPU/APIConversions.h +++ b/Source/WebGPU/WebGPU/APIConversions.h @@ -34,6 +34,7 @@ #import "ComputePassEncoder.h" #import "ComputePipeline.h" #import "Device.h" +#import "ExternalTexture.h" #import "Instance.h" #import "PipelineLayout.h" #import "PresentationContext.h" @@ -99,6 +100,11 @@ inline Device& fromAPI(WGPUDevice device) return static_cast(*device); } +inline ExternalTexture& fromAPI(WGPUExternalTexture texture) +{ + return static_cast(*texture); +} + inline Instance& fromAPI(WGPUInstance instance) { return static_cast(*instance); diff --git a/Source/WebGPU/WebGPU/BindGroup.mm b/Source/WebGPU/WebGPU/BindGroup.mm index dd2d1cd4e717f..5b003a6939b76 100644 --- a/Source/WebGPU/WebGPU/BindGroup.mm +++ b/Source/WebGPU/WebGPU/BindGroup.mm @@ -66,6 +66,69 @@ static MTLRenderStages metalRenderStage(ShaderStage shaderStage) template using ShaderStageArray = EnumeratedArray; +#if HAVE(COREVIDEO_METAL_SUPPORT) +static simd::float4x3 colorSpaceConversionMatrixForPixelBuffer(CVPixelBufferRef pixelBuffer) +{ + auto format = CVPixelBufferGetPixelFormatType(pixelBuffer); + UNUSED_PARAM(format); + + // FIXME: Implement other formats after https://bugs.webkit.org/show_bug.cgi?id=256724 is implemented + return simd::float4x3(simd::make_float3(+1.16895f, +1.16895f, +1.16895f), + simd::make_float3(-0.00012f, -0.21399f, +2.12073f), + simd::make_float3(+1.79968f, -0.53503f, +0.00012f), + simd::make_float3(-0.97284f, 0.30145f, -1.13348f)); +} +#endif + +Device::ExternalTextureData Device::createExternalTextureFromPixelBuffer(CVPixelBufferRef pixelBuffer, WGPUColorSpace colorSpace) const +{ +#if HAVE(COREVIDEO_METAL_SUPPORT) + UNUSED_PARAM(colorSpace); + + id mtlTexture0 = nil; + id mtlTexture1 = nil; + + CVMetalTextureRef plane0 = nullptr; + CVMetalTextureRef plane1 = nullptr; + + CVReturn status1 = CVMetalTextureCacheCreateTextureFromImage(nullptr, m_coreVideoTextureCache.get(), pixelBuffer, nullptr, MTLPixelFormatR8Unorm, CVPixelBufferGetWidthOfPlane(pixelBuffer, 0), CVPixelBufferGetHeightOfPlane(pixelBuffer, 0), 0, &plane0); + CVReturn status2 = CVMetalTextureCacheCreateTextureFromImage(nullptr, m_coreVideoTextureCache.get(), pixelBuffer, nullptr, MTLPixelFormatRG8Unorm, CVPixelBufferGetWidthOfPlane(pixelBuffer, 1), CVPixelBufferGetHeightOfPlane(pixelBuffer, 1), 1, &plane1); + + Boolean isFlipped = false; + + if (status1 == kCVReturnSuccess) { + mtlTexture0 = CVMetalTextureGetTexture(plane0); + isFlipped = CVMetalTextureIsFlipped(plane0); + } + + if (status2 == kCVReturnSuccess) { + mtlTexture1 = CVMetalTextureGetTexture(plane1); + ASSERT(isFlipped == CVMetalTextureIsFlipped(plane1)); + } + + m_defaultQueue->onSubmittedWorkDone([plane0, plane1](WGPUQueueWorkDoneStatus) { + if (plane0) + CFRelease(plane0); + + if (plane1) + CFRelease(plane1); + }); + + simd::float3x2 uvRemappingMatrix; + if (isFlipped) + uvRemappingMatrix = simd::float3x2(simd::make_float2(1.f, 0.f), simd::make_float2(0.f, -1.f), simd::make_float2(0.f, 1.f)); + else + uvRemappingMatrix = simd::make_float2(1.f, 1.f); + simd::float4x3 colorSpaceConversionMatrix = colorSpaceConversionMatrixForPixelBuffer(pixelBuffer); + + return { mtlTexture0, mtlTexture1, uvRemappingMatrix, colorSpaceConversionMatrix }; +#else + UNUSED_PARAM(pixelBuffer); + UNUSED_PARAM(colorSpace); + return { }; +#endif +} + Ref Device::createBindGroup(const WGPUBindGroupDescriptor& descriptor) { if (descriptor.nextInChain) @@ -92,13 +155,19 @@ static MTLRenderStages metalRenderStage(ShaderStage shaderStage) for (uint32_t i = 0, entryCount = descriptor.entryCount; i < entryCount; ++i) { const WGPUBindGroupEntry& entry = descriptor.entries[i]; - if (entry.nextInChain) - return BindGroup::createInvalid(*this); + WGPUExternalTexture wgpuExternalTexture = nullptr; + if (entry.nextInChain) { + if (entry.nextInChain->sType != static_cast(WGPUSTypeExtended_BindGroupEntryExternalTexture)) + return BindGroup::createInvalid(*this); + + wgpuExternalTexture = reinterpret_cast(const_cast(entry.nextInChain))->externalTexture; + } bool bufferIsPresent = WebGPU::bufferIsPresent(entry); bool samplerIsPresent = WebGPU::samplerIsPresent(entry); bool textureViewIsPresent = WebGPU::textureViewIsPresent(entry); - if (bufferIsPresent + samplerIsPresent + textureViewIsPresent != 1) + bool externalTextureIsPresent = !!wgpuExternalTexture; + if (bufferIsPresent + samplerIsPresent + textureViewIsPresent + externalTextureIsPresent != 1) return BindGroup::createInvalid(*this); for (ShaderStage stage : stages) { @@ -120,6 +189,25 @@ static MTLRenderStages metalRenderStage(ShaderStage shaderStage) id texture = WebGPU::fromAPI(entry.textureView).texture(); [argumentEncoder[stage] setTexture:texture atIndex:index++]; resources.append({ texture, MTLResourceUsageRead, metalRenderStage(stage) }); + } else if (externalTextureIsPresent) { + auto& externalTexture = WebGPU::fromAPI(wgpuExternalTexture); + auto textureData = createExternalTextureFromPixelBuffer(externalTexture.pixelBuffer(), externalTexture.colorSpace()); + [argumentEncoder[stage] setTexture:textureData.texture0 atIndex:index++]; + [argumentEncoder[stage] setTexture:textureData.texture1 atIndex:index++]; + ASSERT(textureData.texture0); + ASSERT(textureData.texture1); + if (textureData.texture0) + resources.append({ textureData.texture0, MTLResourceUsageRead, metalRenderStage(stage) }); + if (textureData.texture1) + resources.append({ textureData.texture1, MTLResourceUsageRead, metalRenderStage(stage) }); + // FIXME: encode CSC and UV remapping after https://bugs.webkit.org/show_bug.cgi?id=256721 is implemented + // simd::float3x2* uvRemapAddress = (simd::float3x2*)[argumentEncoder[stage] constantDataAtIndex:index++]; + // *uvRemapAddress = textureData.uvRemappingMatrix; + index++; + + // simd::float4x3* cscMatrixAddress = (simd::float4x3*)[argumentEncoder[stage] constantDataAtIndex:index++]; + // *cscMatrixAddress = textureData.colorSpaceConversionMatrix; + index++; } } } diff --git a/Source/WebGPU/WebGPU/BindGroupLayout.mm b/Source/WebGPU/WebGPU/BindGroupLayout.mm index 48534a986e195..6506c7b9b01b5 100644 --- a/Source/WebGPU/WebGPU/BindGroupLayout.mm +++ b/Source/WebGPU/WebGPU/BindGroupLayout.mm @@ -42,10 +42,19 @@ return nil; auto descriptor = [MTLArgumentDescriptor new]; - descriptor.dataType = MTLDataTypePointer; + auto bufferType = buffer.type; + if (bufferType == static_cast(WGPUBufferBindingType_Float3x2)) { + descriptor.dataType = MTLDataTypeFloat3x2; + bufferType = WGPUBufferBindingType_Uniform; + } else if (bufferType == static_cast(WGPUBufferBindingType_Float4x3)) { + descriptor.dataType = MTLDataTypeFloat4x3; + bufferType = WGPUBufferBindingType_Uniform; + } else + descriptor.dataType = MTLDataTypePointer; + // FIXME: Handle hasDynamicOffset. // FIXME: Handle minBindingSize. - switch (buffer.type) { + switch (bufferType) { case WGPUBufferBindingType_Uniform: case WGPUBufferBindingType_ReadOnlyStorage: #if USE(METAL_ARGUMENT_ACCESS_ENUMS) @@ -264,6 +273,12 @@ static bool containsStage(WGPUShaderStageFlags stageBitfield, auto stage) case MTLDataTypePointer: entry.buffer.type = WGPUBufferBindingType_Uniform; break; + case MTLDataTypeFloat3x3: + entry.buffer.type = static_cast(WGPUBufferBindingType_Float3x2); + break; + case MTLDataTypeFloat4x3: + entry.buffer.type = static_cast(WGPUBufferBindingType_Float4x3); + break; default: ASSERT_NOT_REACHED(); break; diff --git a/Source/WebGPU/WebGPU/Device.h b/Source/WebGPU/WebGPU/Device.h index 21c636ff1dc11..50de904ff871b 100644 --- a/Source/WebGPU/WebGPU/Device.h +++ b/Source/WebGPU/WebGPU/Device.h @@ -29,6 +29,9 @@ #import "HardwareCapabilities.h" #import #import "Queue.h" +#import +#import +#import #import #import #import @@ -48,6 +51,7 @@ class BindGroupLayout; class Buffer; class CommandEncoder; class ComputePipeline; +class ExternalTexture; class Instance; class PipelineLayout; class PresentationContext; @@ -76,6 +80,7 @@ class Device : public WGPUDeviceImpl, public ThreadSafeRefCountedAndCanMakeThrea Ref createCommandEncoder(const WGPUCommandEncoderDescriptor&); Ref createComputePipeline(const WGPUComputePipelineDescriptor&); void createComputePipelineAsync(const WGPUComputePipelineDescriptor&, CompletionHandler&&, String&& message)>&& callback); + Ref createExternalTexture(const WGPUExternalTextureDescriptor&); Ref createPipelineLayout(const WGPUPipelineLayoutDescriptor&); Ref createQuerySet(const WGPUQuerySetDescriptor&); Ref createRenderBundleEncoder(const WGPURenderBundleEncoderDescriptor&); @@ -130,6 +135,13 @@ class Device : public WGPUDeviceImpl, public ThreadSafeRefCountedAndCanMakeThrea void loseTheDevice(WGPUDeviceLostReason); void captureFrameIfNeeded() const; + struct ExternalTextureData { + id texture0 { nil }; + id texture1 { nil }; + simd::float3x2 uvRemappingMatrix; + simd::float4x3 colorSpaceConversionMatrix; + }; + ExternalTextureData createExternalTextureFromPixelBuffer(CVPixelBufferRef, WGPUColorSpace) const; struct Error { WGPUErrorType type; @@ -153,6 +165,9 @@ class Device : public WGPUDeviceImpl, public ThreadSafeRefCountedAndCanMakeThrea HardwareCapabilities m_capabilities { }; const Ref m_adapter; +#if HAVE(COREVIDEO_METAL_SUPPORT) + RetainPtr m_coreVideoTextureCache; +#endif }; } // namespace WebGPU diff --git a/Source/WebGPU/WebGPU/Device.mm b/Source/WebGPU/WebGPU/Device.mm index 959525bc5b369..02742ef836214 100644 --- a/Source/WebGPU/WebGPU/Device.mm +++ b/Source/WebGPU/WebGPU/Device.mm @@ -42,6 +42,7 @@ #import "Sampler.h" #import "ShaderModule.h" #import "Texture.h" +#import #import #import #import @@ -151,6 +152,12 @@ static void captureFrame(id captureObject) #endif #endif +#if HAVE(COREVIDEO_METAL_SUPPORT) + CVMetalTextureCacheRef coreVideoTextureCache; + CVReturn result = CVMetalTextureCacheCreate(nullptr, nullptr, device, nullptr, &coreVideoTextureCache); + ASSERT_UNUSED(result, result == kCVReturnSuccess); + m_coreVideoTextureCache = coreVideoTextureCache; +#endif GPUFrameCapture::registerForFrameCapture(m_device); } @@ -447,6 +454,11 @@ WGPUSampler wgpuDeviceCreateSampler(WGPUDevice device, const WGPUSamplerDescript return WebGPU::releaseToAPI(WebGPU::fromAPI(device).createSampler(*descriptor)); } +WGPUExternalTexture wgpuDeviceImportExternalTexture(WGPUDevice device, const WGPUExternalTextureDescriptor* descriptor) +{ + return WebGPU::releaseToAPI(WebGPU::fromAPI(device).createExternalTexture(*descriptor)); +} + WGPUShaderModule wgpuDeviceCreateShaderModule(WGPUDevice device, const WGPUShaderModuleDescriptor* descriptor) { return WebGPU::releaseToAPI(WebGPU::fromAPI(device).createShaderModule(*descriptor)); diff --git a/Source/WebGPU/WebGPU/ExternalTexture.h b/Source/WebGPU/WebGPU/ExternalTexture.h new file mode 100644 index 0000000000000..2ba36e222f35e --- /dev/null +++ b/Source/WebGPU/WebGPU/ExternalTexture.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Apple Inc. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + */ + +#pragma once + +#import "Device.h" +#import +#import + +struct WGPUExternalTextureImpl { +}; + +namespace WebGPU { + +class ExternalTexture : public WGPUExternalTextureImpl, public RefCounted { + WTF_MAKE_FAST_ALLOCATED; +public: + static Ref create(CVPixelBufferRef pixelBuffer, WGPUColorSpace colorSpace, Device& device) + { + return adoptRef(*new ExternalTexture(pixelBuffer, colorSpace, device)); + } + static Ref createInvalid(Device& device) + { + return adoptRef(*new ExternalTexture(device)); + } + + ~ExternalTexture(); + + CVPixelBufferRef pixelBuffer() const { return m_pixelBuffer; } + WGPUColorSpace colorSpace() const { return m_colorSpace; } + +private: + ExternalTexture(CVPixelBufferRef, WGPUColorSpace, Device&); + ExternalTexture(Device&); + + CVPixelBufferRef m_pixelBuffer; + WGPUColorSpace m_colorSpace; + const Ref m_device; +}; + +} // namespace WebGPU + diff --git a/Source/WebGPU/WebGPU/ExternalTexture.mm b/Source/WebGPU/WebGPU/ExternalTexture.mm new file mode 100644 index 0000000000000..9420bdcc0705d --- /dev/null +++ b/Source/WebGPU/WebGPU/ExternalTexture.mm @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Apple Inc. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + */ + +#import "config.h" +#import "ExternalTexture.h" + +#import "APIConversions.h" +#import "Device.h" +#import "TextureView.h" +#import +#import + +namespace WebGPU { + +Ref Device::createExternalTexture(const WGPUExternalTextureDescriptor& descriptor) +{ + return ExternalTexture::create(descriptor.pixelBuffer, descriptor.colorSpace, *this); +} + +ExternalTexture::ExternalTexture(CVPixelBufferRef pixelBuffer, WGPUColorSpace colorSpace, Device& device) + : m_pixelBuffer(pixelBuffer) + , m_colorSpace(colorSpace) + , m_device(device) +{ +} + +ExternalTexture::ExternalTexture(Device& device) + : m_device(device) +{ +} + +ExternalTexture::~ExternalTexture() = default; + +} // namespace WebGPU + diff --git a/Source/WebGPU/WebGPU/WebGPUExt.h b/Source/WebGPU/WebGPU/WebGPUExt.h index 223456dbb72b4..778d5e48983df 100644 --- a/Source/WebGPU/WebGPU/WebGPUExt.h +++ b/Source/WebGPU/WebGPU/WebGPUExt.h @@ -26,12 +26,15 @@ #ifndef WEBGPUEXT_H_ #define WEBGPUEXT_H_ +#include #include #ifdef __cplusplus extern "C" { #endif +typedef struct WGPUExternalTextureImpl* WGPUExternalTexture; + typedef void (^WGPUBufferMapBlockCallback)(WGPUBufferMapAsyncStatus status); typedef void (^WGPUCompilationInfoBlockCallback)(WGPUCompilationInfoRequestStatus status, WGPUCompilationInfo const * compilationInfo); typedef void (^WGPUCreateComputePipelineAsyncBlockCallback)(WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline, char const * message); @@ -45,9 +48,20 @@ typedef void (^WGPURequestInvalidDeviceBlockCallback)(WGPUDevice device); typedef void (^WGPUWorkItem)(void); typedef void (^WGPUScheduleWorkBlock)(WGPUWorkItem workItem); +typedef enum WGPUBufferBindingTypeExtended { + WGPUBufferBindingType_Float3x2 = WGPUBufferBindingType_Force32 - 1, + WGPUBufferBindingType_Float4x3 = WGPUBufferBindingType_Force32 - 2, +} WGPUBufferBindingTypeExtended; + +typedef enum WGPUColorSpace { + SRGB, + DisplayP3, +} WGPUColorSpace; + typedef enum WGPUSTypeExtended { WGPUSTypeExtended_InstanceCocoaDescriptor = 0x151BBC00, // Random WGPUSTypeExtended_SurfaceDescriptorCocoaSurfaceBacking = 0x017E9710, // Random + WGPUSTypeExtended_BindGroupEntryExternalTexture = 0xF7A6EBF9, // Random WGPUSTypeExtended_Force32 = 0x7FFFFFFF } WGPUSTypeExtended; @@ -71,6 +85,18 @@ typedef struct WGPUSurfaceDescriptorCocoaCustomSurface { WGPUCompositorIntegrationRegisterBlockCallback compositorIntegrationRegister; } WGPUSurfaceDescriptorCocoaCustomSurface; +typedef struct WGPUBindGroupExternalTextureEntry { + WGPUChainedStruct chain; + WGPUExternalTexture externalTexture; +} WGPUBindGroupExternalTextureEntry; + +typedef struct WGPUExternalTextureDescriptor { + WGPUChainedStruct const * nextInChain; + char const * label; // nullable + CVPixelBufferRef pixelBuffer; + WGPUColorSpace colorSpace; +} WGPUExternalTextureDescriptor; + #if !defined(WGPU_SKIP_PROCS) typedef void (*WGPUProcAdapterRelease)(WGPUAdapter adapter); @@ -177,6 +203,7 @@ WGPU_EXPORT void wgpuAdapterRequestDeviceWithBlock(WGPUAdapter adapter, WGPUDevi WGPU_EXPORT void wgpuBufferMapAsyncWithBlock(WGPUBuffer buffer, WGPUMapModeFlags mode, size_t offset, size_t size, WGPUBufferMapBlockCallback callback); WGPU_EXPORT void wgpuDeviceCreateComputePipelineAsyncWithBlock(WGPUDevice device, WGPUComputePipelineDescriptor const * descriptor, WGPUCreateComputePipelineAsyncBlockCallback callback); WGPU_EXPORT void wgpuDeviceCreateRenderPipelineAsyncWithBlock(WGPUDevice device, WGPURenderPipelineDescriptor const * descriptor, WGPUCreateRenderPipelineAsyncBlockCallback callback); +WGPU_EXPORT WGPUExternalTexture wgpuDeviceImportExternalTexture(WGPUDevice device, const WGPUExternalTextureDescriptor* descriptor); WGPU_EXPORT bool wgpuDevicePopErrorScopeWithBlock(WGPUDevice device, WGPUErrorBlockCallback callback); WGPU_EXPORT void wgpuDeviceSetDeviceLostCallbackWithBlock(WGPUDevice device, WGPUDeviceLostBlockCallback callback); WGPU_EXPORT void wgpuDeviceSetUncapturedErrorCallbackWithBlock(WGPUDevice device, WGPUErrorBlockCallback callback); diff --git a/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp b/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp index 647619387366c..9f99a07cb93df 100644 --- a/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp +++ b/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp @@ -628,7 +628,9 @@ void RemoteRenderingBackend::lowMemoryHandler(Critical, Synchronous) void RemoteRenderingBackend::createRemoteGPU(WebGPUIdentifier identifier, IPC::StreamServerConnection::Handle&& connectionHandle) { auto addResult = m_remoteGPUMap.ensure(identifier, [&] { - return IPC::ScopedActiveMessageReceiveQueue { RemoteGPU::create(identifier, WTFMove(connectionHandle)) }; + return IPC::ScopedActiveMessageReceiveQueue { RemoteGPU::create([this] (MediaPlayerIdentifier identifier, Function&& callback) mutable { + this->performWithMediaPlayerOnMainThread(identifier, WTFMove(callback)); + }, identifier, WTFMove(connectionHandle)) }; }); ASSERT_UNUSED(addResult, addResult.isNewEntry); } diff --git a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.cpp b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.cpp index e542025eab3b7..17124d3b83a2c 100644 --- a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.cpp +++ b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.cpp @@ -41,10 +41,11 @@ namespace WebKit { -RemoteAdapter::RemoteAdapter(PAL::WebGPU::Adapter& adapter, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier) +RemoteAdapter::RemoteAdapter(Function&&)>& performWithMediaPlayerOnMainThread, PAL::WebGPU::Adapter& adapter, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier) : m_backing(adapter) , m_objectHeap(objectHeap) , m_streamConnection(WTFMove(streamConnection)) + , m_performWithMediaPlayerOnMainThread(performWithMediaPlayerOnMainThread) , m_identifier(identifier) { m_streamConnection->startReceivingMessages(*this, Messages::RemoteAdapter::messageReceiverName(), m_identifier.toUInt64()); @@ -71,14 +72,14 @@ void RemoteAdapter::requestDevice(const WebGPU::DeviceDescriptor& descriptor, We return; } - m_backing->requestDevice(*convertedDescriptor, [callback = WTFMove(callback), objectHeap = Ref { m_objectHeap }, streamConnection = m_streamConnection.copyRef(), identifier, queueIdentifier] (RefPtr&& devicePtr) mutable { + m_backing->requestDevice(*convertedDescriptor, [callback = WTFMove(callback), objectHeap = Ref { m_objectHeap }, streamConnection = m_streamConnection.copyRef(), identifier, queueIdentifier, &performWithMediaPlayerOnMainThread = m_performWithMediaPlayerOnMainThread] (RefPtr&& devicePtr) mutable { if (!devicePtr.get()) { callback({ }, { }); return; } auto device = devicePtr.releaseNonNull(); - auto remoteDevice = RemoteDevice::create(device, objectHeap, WTFMove(streamConnection), identifier, queueIdentifier); + auto remoteDevice = RemoteDevice::create(performWithMediaPlayerOnMainThread, device, objectHeap, WTFMove(streamConnection), identifier, queueIdentifier); objectHeap->addObject(identifier, remoteDevice); objectHeap->addObject(queueIdentifier, remoteDevice->queue()); const auto& features = device->features(); diff --git a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.h b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.h index 84b09e836d2c1..828c5a1202764 100644 --- a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.h +++ b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteAdapter.h @@ -27,6 +27,7 @@ #if ENABLE(GPU_PROCESS) +#include "RemoteGPU.h" #include "StreamMessageReceiver.h" #include "WebGPUIdentifier.h" #include @@ -52,9 +53,9 @@ struct SupportedLimits; class RemoteAdapter final : public IPC::StreamMessageReceiver { WTF_MAKE_FAST_ALLOCATED; public: - static Ref create(PAL::WebGPU::Adapter& adapter, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier) + static Ref create(Function&&)>& performWithMediaPlayerOnMainThread, PAL::WebGPU::Adapter& adapter, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier) { - return adoptRef(*new RemoteAdapter(adapter, objectHeap, WTFMove(streamConnection), identifier)); + return adoptRef(*new RemoteAdapter(performWithMediaPlayerOnMainThread, adapter, objectHeap, WTFMove(streamConnection), identifier)); } virtual ~RemoteAdapter(); @@ -64,7 +65,7 @@ class RemoteAdapter final : public IPC::StreamMessageReceiver { private: friend class WebGPU::ObjectHeap; - RemoteAdapter(PAL::WebGPU::Adapter&, WebGPU::ObjectHeap&, Ref&&, WebGPUIdentifier); + RemoteAdapter(Function&&)>&, PAL::WebGPU::Adapter&, WebGPU::ObjectHeap&, Ref&&, WebGPUIdentifier); RemoteAdapter(const RemoteAdapter&) = delete; RemoteAdapter(RemoteAdapter&&) = delete; @@ -81,6 +82,7 @@ class RemoteAdapter final : public IPC::StreamMessageReceiver { Ref m_backing; WebGPU::ObjectHeap& m_objectHeap; Ref m_streamConnection; + Function&&)>& m_performWithMediaPlayerOnMainThread; WebGPUIdentifier m_identifier; }; diff --git a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.cpp b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.cpp index fa6ac89b43baa..4a000423b5f9c 100644 --- a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.cpp +++ b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.cpp @@ -35,11 +35,14 @@ #include "RemoteComputePipeline.h" #include "RemoteDeviceMessages.h" #include "RemoteExternalTexture.h" +#include "RemoteGPU.h" +#include "RemoteMediaPlayerManagerProxy.h" #include "RemotePipelineLayout.h" #include "RemoteQuerySet.h" #include "RemoteQueue.h" #include "RemoteRenderBundleEncoder.h" #include "RemoteRenderPipeline.h" +#include "RemoteRenderingBackend.h" #include "RemoteSampler.h" #include "RemoteShaderModule.h" #include "RemoteTexture.h" @@ -48,6 +51,7 @@ #include "WebGPUObjectHeap.h" #include "WebGPUOutOfMemoryError.h" #include "WebGPUValidationError.h" +#include #include #include #include @@ -79,12 +83,13 @@ namespace WebKit { -RemoteDevice::RemoteDevice(PAL::WebGPU::Device& device, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier, WebGPUIdentifier queueIdentifier) +RemoteDevice::RemoteDevice(Function&&)>& performWithMediaPlayerOnMainThread, PAL::WebGPU::Device& device, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier, WebGPUIdentifier queueIdentifier) : m_backing(device) , m_objectHeap(objectHeap) , m_streamConnection(streamConnection.copyRef()) , m_identifier(identifier) , m_queue(RemoteQueue::create(device.queue(), objectHeap, WTFMove(streamConnection), queueIdentifier)) + , m_performWithMediaPlayerOnMainThread(performWithMediaPlayerOnMainThread) { m_streamConnection->startReceivingMessages(*this, Messages::RemoteDevice::messageReceiverName(), m_identifier.toUInt64()); } @@ -151,9 +156,21 @@ void RemoteDevice::importExternalTexture(const WebGPU::ExternalTextureDescriptor { auto convertedDescriptor = m_objectHeap.convertFromBacking(descriptor); ASSERT(convertedDescriptor); - if (!convertedDescriptor) + if (!convertedDescriptor || !convertedDescriptor->mediaIdentifier) return; + m_performWithMediaPlayerOnMainThread(WebCore::MediaPlayerIdentifier(convertedDescriptor->mediaIdentifier), [&convertedDescriptor](auto& player) mutable { + auto videoFrame = player.videoFrameForCurrentTime(); + if (!videoFrame) + return; + +#if PLATFORM(COCOA) + CVPixelBufferRef pixelBuffer = videoFrame->pixelBuffer(); + ASSERT(pixelBuffer); + convertedDescriptor->pixelBuffer = pixelBuffer; +#endif + }); + auto externalTexture = m_backing->importExternalTexture(*convertedDescriptor); auto remoteExternalTexture = RemoteExternalTexture::create(externalTexture, m_objectHeap, m_streamConnection.copyRef(), identifier); m_objectHeap.addObject(identifier, remoteExternalTexture); diff --git a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.h b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.h index afdbb31eefcaf..74c8329d43d12 100644 --- a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.h +++ b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteDevice.h @@ -31,6 +31,7 @@ #include "StreamMessageReceiver.h" #include "WebGPUError.h" #include "WebGPUIdentifier.h" +#include #include #include #include @@ -45,8 +46,14 @@ namespace IPC { class StreamServerConnection; } +namespace WebCore { +class MediaPlayer; +} + namespace WebKit { +class RemoteGPU; + namespace WebGPU { struct BindGroupDescriptor; struct BindGroupLayoutDescriptor; @@ -67,9 +74,9 @@ struct TextureDescriptor; class RemoteDevice final : public IPC::StreamMessageReceiver { WTF_MAKE_FAST_ALLOCATED; public: - static Ref create(PAL::WebGPU::Device& device, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier, WebGPUIdentifier queueIdentifier) + static Ref create(Function&&)>& performWithMediaPlayerOnMainThread, PAL::WebGPU::Device& device, WebGPU::ObjectHeap& objectHeap, Ref&& streamConnection, WebGPUIdentifier identifier, WebGPUIdentifier queueIdentifier) { - return adoptRef(*new RemoteDevice(device, objectHeap, WTFMove(streamConnection), identifier, queueIdentifier)); + return adoptRef(*new RemoteDevice(performWithMediaPlayerOnMainThread, device, objectHeap, WTFMove(streamConnection), identifier, queueIdentifier)); } ~RemoteDevice(); @@ -81,7 +88,7 @@ class RemoteDevice final : public IPC::StreamMessageReceiver { private: friend class WebGPU::ObjectHeap; - RemoteDevice(PAL::WebGPU::Device&, WebGPU::ObjectHeap&, Ref&&, WebGPUIdentifier, WebGPUIdentifier queueIdentifier); + RemoteDevice(Function&&)>&, PAL::WebGPU::Device&, WebGPU::ObjectHeap&, Ref&&, WebGPUIdentifier, WebGPUIdentifier queueIdentifier); RemoteDevice(const RemoteDevice&) = delete; RemoteDevice(RemoteDevice&&) = delete; @@ -126,6 +133,7 @@ class RemoteDevice final : public IPC::StreamMessageReceiver { Ref m_streamConnection; WebGPUIdentifier m_identifier; Ref m_queue; + Function&&)>& m_performWithMediaPlayerOnMainThread; }; } // namespace WebKit diff --git a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.cpp b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.cpp index 78ea18bf1eb10..17ab80e9aa732 100644 --- a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.cpp +++ b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.cpp @@ -33,6 +33,7 @@ #include "RemoteGPUMessages.h" #include "RemoteGPUProxyMessages.h" #include "RemotePresentationContext.h" +#include "RemoteRenderingBackend.h" #include "StreamServerConnection.h" #include "WebGPUObjectHeap.h" #include @@ -46,10 +47,11 @@ namespace WebKit { -RemoteGPU::RemoteGPU(WebGPUIdentifier identifier, IPC::StreamServerConnection::Handle&& connectionHandle) +RemoteGPU::RemoteGPU(Function&&)>&& performWithMediaPlayerOnMainThread, WebGPUIdentifier identifier, IPC::StreamServerConnection::Handle&& connectionHandle) : m_workQueue(IPC::StreamConnectionWorkQueue::create("WebGPU work queue")) , m_streamConnection(IPC::StreamServerConnection::create(WTFMove(connectionHandle), workQueue())) , m_objectHeap(WebGPU::ObjectHeap::create()) + , m_performWithMediaPlayerOnMainThread(WTFMove(performWithMediaPlayerOnMainThread)) , m_identifier(identifier) { } @@ -118,13 +120,13 @@ void RemoteGPU::requestAdapter(const WebGPU::RequestAdapterOptions& options, Web return; } - m_backing->requestAdapter(*convertedOptions, [callback = WTFMove(callback), objectHeap = m_objectHeap.copyRef(), streamConnection = Ref { *m_streamConnection }, identifier] (RefPtr&& adapter) mutable { + m_backing->requestAdapter(*convertedOptions, [callback = WTFMove(callback), objectHeap = m_objectHeap.copyRef(), streamConnection = Ref { *m_streamConnection }, identifier, &performWithMediaPlayerOnMainThread = m_performWithMediaPlayerOnMainThread] (RefPtr&& adapter) mutable { if (!adapter) { callback(std::nullopt); return; } - auto remoteAdapter = RemoteAdapter::create(*adapter, objectHeap, WTFMove(streamConnection), identifier); + auto remoteAdapter = RemoteAdapter::create(performWithMediaPlayerOnMainThread, *adapter, objectHeap, WTFMove(streamConnection), identifier); objectHeap->addObject(identifier, remoteAdapter); auto name = adapter->name(); diff --git a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.h b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.h index 645597b878369..471c504471749 100644 --- a/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.h +++ b/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteGPU.h @@ -35,6 +35,7 @@ #include "WebGPUObjectHeap.h" #include "WebGPUSupportedFeatures.h" #include "WebGPUSupportedLimits.h" +#include #include #include #include @@ -49,8 +50,14 @@ namespace IPC { class StreamServerConnection; } +namespace WebCore { +class MediaPlayer; +} + namespace WebKit { +class RemoteRenderingBackend; + namespace WebGPU { class ObjectHeap; struct RequestAdapterOptions; @@ -59,9 +66,9 @@ struct RequestAdapterOptions; class RemoteGPU final : public IPC::StreamMessageReceiver { WTF_MAKE_FAST_ALLOCATED; public: - static Ref create(WebGPUIdentifier identifier, IPC::StreamServerConnection::Handle&& serverConnection) + static Ref create(Function&&)>&& performWithMediaPlayerOnMainThread, WebGPUIdentifier identifier, IPC::StreamServerConnection::Handle&& serverConnection) { - auto result = adoptRef(*new RemoteGPU(identifier, WTFMove(serverConnection))); + auto result = adoptRef(*new RemoteGPU(WTFMove(performWithMediaPlayerOnMainThread), identifier, WTFMove(serverConnection))); result->initialize(); return result; } @@ -73,7 +80,7 @@ class RemoteGPU final : public IPC::StreamMessageReceiver { private: friend class WebGPU::ObjectHeap; - RemoteGPU(WebGPUIdentifier, IPC::StreamServerConnection::Handle&&); + RemoteGPU(Function&&)>&&, WebGPUIdentifier, IPC::StreamServerConnection::Handle&&); RemoteGPU(const RemoteGPU&) = delete; RemoteGPU(RemoteGPU&&) = delete; @@ -103,6 +110,7 @@ class RemoteGPU final : public IPC::StreamMessageReceiver { RefPtr m_streamConnection; RefPtr m_backing WTF_GUARDED_BY_CAPABILITY(workQueue()); Ref m_objectHeap WTF_GUARDED_BY_CAPABILITY(workQueue()); + Function&&)> m_performWithMediaPlayerOnMainThread; const WebGPUIdentifier m_identifier; }; diff --git a/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.cpp b/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.cpp index 476cbeb78a343..a89bd326870d8 100644 --- a/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.cpp +++ b/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.cpp @@ -40,7 +40,7 @@ std::optional ConvertToBackingContext::convertToBacki if (!base) return std::nullopt; - return { { WTFMove(*base), externalTextureDescriptor.colorSpace } }; + return { { WTFMove(*base), WebCore::MediaPlayerIdentifier(externalTextureDescriptor.mediaIdentifier), externalTextureDescriptor.colorSpace } }; } std::optional ConvertFromBackingContext::convertFromBacking(const ExternalTextureDescriptor& externalTextureDescriptor) @@ -49,7 +49,7 @@ std::optional ConvertFromBackingContext: if (!base) return std::nullopt; - return { { WTFMove(*base), externalTextureDescriptor.colorSpace } }; + return { { WTFMove(*base), externalTextureDescriptor.mediaIdentifier.toUInt64(), externalTextureDescriptor.colorSpace } }; } } // namespace WebKit diff --git a/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.h b/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.h index e1f2809f04227..f8e9cef318c93 100644 --- a/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.h +++ b/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.h @@ -28,12 +28,14 @@ #if ENABLE(GPU_PROCESS) #include "WebGPUObjectDescriptorBase.h" +#include #include #include namespace WebKit::WebGPU { struct ExternalTextureDescriptor : public ObjectDescriptorBase { + WebCore::MediaPlayerIdentifier mediaIdentifier { 0 }; PAL::WebGPU::PredefinedColorSpace colorSpace { PAL::WebGPU::PredefinedColorSpace::SRGB }; }; diff --git a/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.serialization.in b/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.serialization.in index 8558bcc901e5b..8bb00324680f6 100644 --- a/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.serialization.in +++ b/Source/WebKit/Shared/WebGPU/WebGPUExternalTextureDescriptor.serialization.in @@ -22,6 +22,7 @@ #if ENABLE(GPU_PROCESS) [AdditionalEncoder=StreamConnectionEncoder] struct WebKit::WebGPU::ExternalTextureDescriptor : WebKit::WebGPU::ObjectDescriptorBase { + WebCore::MediaPlayerIdentifier mediaIdentifier; PAL::WebGPU::PredefinedColorSpace colorSpace; }; #endif diff --git a/Websites/webkit.org/demos/webgpu/external-textured-cube.html b/Websites/webkit.org/demos/webgpu/external-textured-cube.html new file mode 100644 index 0000000000000..ddaa9edec841d --- /dev/null +++ b/Websites/webkit.org/demos/webgpu/external-textured-cube.html @@ -0,0 +1,43 @@ + + + + + +WebGPU Instanced Textured Cubes with Depth Buffer + + + + +
+

Instanced Textured Cubes with Depth Buffer

+ + +
+
+

WebGPU not available

+

+ Make sure you are on a system with WebGPU enabled. In + Safari, first make sure the Developer Menu is visible (Preferences > + Advanced), then Develop > Experimental Features > WebGPU. +

+

+ In addition, you must be using Safari Technology Preview 92 or above. + You can get the latest STP here. +

+
+ + + diff --git a/Websites/webkit.org/demos/webgpu/scripts/external-textured-cube.js b/Websites/webkit.org/demos/webgpu/scripts/external-textured-cube.js new file mode 100644 index 0000000000000..0dce7fdff60e4 --- /dev/null +++ b/Websites/webkit.org/demos/webgpu/scripts/external-textured-cube.js @@ -0,0 +1,323 @@ +async function helloCube() { + if (!navigator.gpu || GPUBufferUsage.COPY_SRC === undefined) { + document.body.className = 'error'; + return; + } + + const video = document.querySelector('video'); + await video.play(); + + const canvas = document.querySelector("canvas"); + canvas.width = 600; + canvas.height = 600; + + const adapter = await navigator.gpu.requestAdapter(); + const device = await adapter.requestDevice(); + + const preferredBackingFormat = navigator.gpu.getPreferredCanvasFormat(); + /*** Vertex Buffer Setup ***/ + + /* Vertex Data */ + const vertexStride = 10 * 4; + const vertexDataSize = vertexStride * 36; + + /* GPUBufferDfescriptor */ + const vertexDataBufferDescriptor = { + size: vertexDataSize, + usage: GPUBufferUsage.VERTEX, + mappedAtCreation: true + }; + + /* GPUBuffer */ + const vertexBuffer = device.createBuffer(vertexDataBufferDescriptor); + const vertexWriteArray = new Float32Array(vertexBuffer.getMappedRange()); + vertexWriteArray.set([ + // float4 position, float4 color, float2 uv + .5, -.5, .5, 1, 1, 0, 1, 1, 1, 1, + -.5, -.5, .5, 1, 0, 0, 1, 1, 0, 1, + -.5, -.5, -.5, 1, 0, 0, 0, 1, 0, 0, + .5, -.5, -.5, 1, 1, 0, 0, 1, 1, 0, + .5, -.5, .5, 1, 1, 0, 1, 1, 1, 1, + -.5, -.5, -.5, 1, 0, 0, 0, 1, 0, 0, + + .5, .5, .5, 1, 1, 1, 1, 1, 1, 1, + .5, -.5, .5, 1, 1, 0, 1, 1, 0, 1, + .5, -.5, -.5, 1, 1, 0, 0, 1, 0, 0, + .5, .5, -.5, 1, 1, 1, 0, 1, 1, 0, + .5, .5, .5, 1, 1, 1, 1, 1, 1, 1, + .5, -.5, -.5, 1, 1, 0, 0, 1, 0, 0, + + -.5, .5, .5, 1, 0, 1, 1, 1, 1, 1, + .5, .5, .5, 1, 1, 1, 1, 1, 0, 1, + .5, .5, -.5, 1, 1, 1, 0, 1, 0, 0, + -.5, .5, -.5, 1, 0, 1, 0, 1, 1, 0, + -.5, .5, .5, 1, 0, 1, 1, 1, 1, 1, + .5, .5, -.5, 1, 1, 1, 0, 1, 0, 0, + + -.5, -.5, .5, 1, 0, 0, 1, 1, 1, 1, + -.5, .5, .5, 1, 0, 1, 1, 1, 0, 1, + -.5, .5, -.5, 1, 0, 1, 0, 1, 0, 0, + -.5, -.5, -.5, 1, 0, 0, 0, 1, 1, 0, + -.5, -.5, .5, 1, 0, 0, 1, 1, 1, 1, + -.5, .5, -.5, 1, 0, 1, 0, 1, 0, 0, + + .5, .5, .5, 1, 1, 1, 1, 1, 1, 1, + -.5, .5, .5, 1, 0, 1, 1, 1, 0, 1, + -.5, -.5, .5, 1, 0, 0, 1, 1, 0, 0, + -.5, -.5, .5, 1, 0, 0, 1, 1, 0, 0, + .5, -.5, .5, 1, 1, 0, 1, 1, 1, 0, + .5, .5, .5, 1, 1, 1, 1, 1, 1, 1, + + .5, -.5, -.5, 1, 1, 0, 0, 1, 1, 1, + -.5, -.5, -.5, 1, 0, 0, 0, 1, 0, 1, + -.5, .5, -.5, 1, 0, 1, 0, 1, 0, 0, + .5, .5, -.5, 1, 1, 1, 0, 1, 1, 0, + .5, -.5, -.5, 1, 1, 0, 0, 1, 1, 1, + -.5, .5, -.5, 1, 0, 1, 0, 1, 0, 0, + ]); + vertexBuffer.unmap(); + + const uniformBufferSize = 12; + const uniformBuffer = device.createBuffer({ + size: uniformBufferSize, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, + }); + + /* GPUTexture */ + const image = new Image(); + const imageLoadPromise = new Promise(resolve => { + image.onload = () => resolve(); + image.src = "resources/webkit-logo.png" + }); + await Promise.resolve(imageLoadPromise); + + const textureSize = { + width: image.width, + height: image.height, + depth: 1 + }; + + const textureDescriptor = { + size: textureSize, + arrayLayerCount: 1, + mipLevelCount: 1, + sampleCount: 1, + dimension: "2d", + format: preferredBackingFormat, + usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT, + }; + const texture = device.createTexture(textureDescriptor); + + const imageBitmap = await createImageBitmap(image); + + device.queue.copyExternalImageToTexture( + { source: imageBitmap }, + { texture: texture }, + [image.width, image.height] + ); + + const sampler = device.createSampler({ + magFilter: "linear", + minFilter: "linear" + }); + + const shader = ` + struct VertexIn { + @location(0) position: vec4, + @location(1) color: vec4, + @location(2) uv: vec2, + }; + + struct VertexOut { + @builtin(position) position: vec4, + @location(0) color: vec4, + @location(1) uv: vec2, + }; + + @group(0) @binding(0) var time : vec3; + @group(0) @binding(1) var colorTexture: texture_2d ; + @group(0) @binding(2) var colorTexture1: texture_2d ; + @group(0) @binding(3) var uvRemap: mat3x3 ; + @group(0) @binding(4) var csc: mat4x3 ; + @group(0) @binding(5) var textureSampler : sampler; + + @vertex + fn vsmain(@builtin(vertex_index) VertexIndex: u32, vin: VertexIn) -> VertexOut + { + let alpha = time[0]; + let beta = time[1]; + let gamma = time[2]; + let cA = cos(alpha); + let sA = sin(alpha); + let cB = cos(beta); + let sB = sin(beta); + let cG = cos(gamma); + let sG = sin(gamma); + + let m = mat4x4(cA * cB, sA * cB, -sB, 0., + cA*sB*sG - sA*cG, sA*sB*sG + cA*cG, cB * sG, 0., + cA*sB*cG + sA*sG, sA*sB*cG - cA*sG, cB * cG, 0., + 0., 0., 0., 1.); + + var vout : VertexOut; + vout.position = vin.position * m; + vout.position.z = (vout.position.z + 0.5) * 0.5; + vout.color = vin.color; + vout.uv = vin.uv; + return vout; + } + + @fragment + fn fsmain(in: VertexOut) -> @location(0) vec4 + { + var coords = vec3(in.uv, 1.0) * uvRemap; + coords = vec3(in.uv, 1.0); + let uvRemap2 = mat3x2(1.0, 0.0, + 0.0, -1.0, + 0.0, 1.0); + let coords2 = uvRemap2 * vec3(in.uv, 1.0); + let textureColor0 = textureSample(colorTexture, textureSampler, coords2.rg); + let textureColor1 = textureSample(colorTexture1, textureSampler, coords2.rg); + let ycbcr = vec3(textureColor0.r, textureColor1.rg); + let localCsc = mat4x3(1.16895, 1.16895, 1.16895, + -0.00012, -0.21399, 2.12073, + 1.79968, -0.53503, 0.00012, + -0.97284, 0.30145, -1.13348); + var textureColor = csc * vec4(ycbcr, 1.0); + textureColor = localCsc * vec4(ycbcr, 1.0); + return 0.005 * in.color + 0.995 * vec4(textureColor, 1.0); + } + `; + + const shaderModule = device.createShaderModule({ code: shader }); + + /* GPUPipelineStageDescriptors */ + const vertexStageDescriptor = { + module: shaderModule, + entryPoint: "vsmain", + buffers: [{ + arrayStride: vertexStride, + stepMode: "vertex", + attributes: [{ + format: "float32x4", + offset: 0, + shaderLocation: 0, + }, { + format: "float32x4", + offset: 4 * 4, + shaderLocation: 1, + }, { + format: "float32x2", + offset: 8 * 4, + shaderLocation: 2, + }], + }] + }; + + const fragmentStageDescriptor = { module: shaderModule, entryPoint: "fsmain", targets: [ {format: preferredBackingFormat }, ], }; + + /* GPURenderPipelineDescriptor */ + + const renderPipelineDescriptor = { + layout: "auto", + vertex: vertexStageDescriptor, + fragment: fragmentStageDescriptor, + primitive: { + topology: "triangle-list", + cullMode: "back" + }, + }; + /* GPURenderPipeline */ + const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor); + + /*** Swap Chain Setup ***/ + function frameUpdate() { + /*** Shader Setup ***/ + const uniformBindGroup = device.createBindGroup({ + layout: renderPipeline.getBindGroupLayout(0), + entries: [ + { + binding: 0, + resource: { + buffer: uniformBuffer, + offset: 0 + }, + }, + { + binding: 1, + resource: device.importExternalTexture({ + source: video, + }), + }, + { + binding: 2, + resource: sampler, + }, + ], + }); + + const secondsBuffer = new Float32Array(3); + const d = new Date(); + const seconds = d.getMilliseconds() / 1000.0 + d.getSeconds(); + secondsBuffer.set([seconds*10 * (6.28318530718 / 60.0), + seconds*5 * (6.28318530718 / 60.0), + seconds*1 * (6.28318530718 / 60.0)]); + device.queue.writeBuffer(uniformBuffer, 0, secondsBuffer); + + const gpuContext = canvas.getContext("webgpu"); + + /* GPUCanvasConfiguration */ + const canvasConfiguration = { device: device, format: preferredBackingFormat }; + gpuContext.configure(canvasConfiguration); + /* GPUTexture */ + const currentTexture = gpuContext.getCurrentTexture(); + + /*** Render Pass Setup ***/ + + /* Acquire Texture To Render To */ + + /* GPUTextureView */ + const renderAttachment = currentTexture.createView(); + + /* GPUColor */ + const darkBlue = { r: 0.15, g: 0.15, b: 0.5, a: 1 }; + + /* GPURenderPassColorATtachmentDescriptor */ + const colorAttachmentDescriptor = { + view: renderAttachment, + loadOp: "clear", + storeOp: "store", + clearColor: darkBlue + }; + + /* GPURenderPassDescriptor */ + const renderPassDescriptor = { colorAttachments: [colorAttachmentDescriptor] }; + + /*** Rendering ***/ + + /* GPUCommandEncoder */ + const commandEncoder = device.createCommandEncoder(); + /* GPURenderPassEncoder */ + const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); + + renderPassEncoder.setPipeline(renderPipeline); + const vertexBufferSlot = 0; + renderPassEncoder.setVertexBuffer(vertexBufferSlot, vertexBuffer); + renderPassEncoder.setBindGroup(0, uniformBindGroup); + renderPassEncoder.draw(36); // 36 vertices + renderPassEncoder.end(); + + /* GPUComamndBuffer */ + const commandBuffer = commandEncoder.finish(); + + /* GPUQueue */ + const queue = device.queue; + queue.submit([commandBuffer]); + + requestAnimationFrame(frameUpdate); + } + + requestAnimationFrame(frameUpdate); +} + +window.addEventListener("DOMContentLoaded", helloCube);