Skip to content

Commit 0bb8155

Browse files
committed
Bug 1979100 - Implement WebGPU Device.importExternalTexture(). r=webgpu-reviewers,webidl,smaug,teoxoy
First we create an ExternalTextureSource using the infrastructure added in the previous patch, and from that we create an ExternalTexture. In order to create the external texture the client side passes an `ExternalTextureDescriptor` to the host side, which encodes the source as a optional ID. On the host side additional information is queried from the ExternalTextureSourceHost, which is combined with the `ExternalTextureDescriptor` provided by the client in order to call wgpu's create_external_texture(). If there was an error importing the source on the client side the source ID will be `None`. If there was an error importing the source on the host side, it will return an empty slice of texture views as its planes. In either case this indicates we should propagate the error state to the external texture. Subsequent patches will allow for creating multiple external textures from the same source, and returning previously imported external textures rather than always creating a new one. Note that for now we have not requested Features::EXTERNAL_TEXTURE when creating the wgpu device, meaning that any attempts to actually create an external texture will result in an error. Differential Revision: https://phabricator.services.mozilla.com/D259820
1 parent 8c62114 commit 0bb8155

13 files changed

Lines changed: 478 additions & 18 deletions

File tree

dom/webgpu/Device.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "CompilationInfo.h"
1313
#include "ComputePipeline.h"
1414
#include "DeviceLostInfo.h"
15+
#include "ExternalTexture.h"
1516
#include "InternalError.h"
1617
#include "OutOfMemoryError.h"
1718
#include "PipelineLayout.h"
@@ -195,6 +196,14 @@ already_AddRefed<Texture> Device::CreateTexture(
195196
return texture.forget();
196197
}
197198

199+
already_AddRefed<ExternalTexture> Device::ImportExternalTexture(
200+
const dom::GPUExternalTextureDescriptor& aDesc, ErrorResult& aRv) {
201+
RefPtr<ExternalTextureSourceClient> source =
202+
ExternalTextureSourceClient::Create(this, aDesc.mSource, aRv);
203+
204+
return ExternalTexture::Create(this, aDesc.mLabel, source, aDesc.mColorSpace);
205+
}
206+
198207
already_AddRefed<Sampler> Device::CreateSampler(
199208
const dom::GPUSamplerDescriptor& aDesc) {
200209
ffi::WGPUSamplerDescriptor desc = {};

dom/webgpu/Device.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct GPUExtent3DDict;
2525

2626
struct GPUBufferDescriptor;
2727
struct GPUTextureDescriptor;
28+
struct GPUExternalTextureDescriptor;
2829
struct GPUSamplerDescriptor;
2930
struct GPUBindGroupLayoutDescriptor;
3031
struct GPUPipelineLayoutDescriptor;
@@ -66,6 +67,7 @@ class BindGroupLayout;
6667
class Buffer;
6768
class CommandEncoder;
6869
class ComputePipeline;
70+
class ExternalTexture;
6971
class Fence;
7072
class InputState;
7173
class PipelineLayout;
@@ -155,6 +157,8 @@ class Device final : public DOMEventTargetHelper {
155157
already_AddRefed<Texture> CreateTexture(
156158
const dom::GPUTextureDescriptor& aDesc,
157159
Maybe<layers::RemoteTextureOwnerId> aOwnerId);
160+
already_AddRefed<ExternalTexture> ImportExternalTexture(
161+
const dom::GPUExternalTextureDescriptor& aDesc, ErrorResult& aRv);
158162
already_AddRefed<Sampler> CreateSampler(
159163
const dom::GPUSamplerDescriptor& aDesc);
160164

dom/webgpu/ExternalTexture.cpp

Lines changed: 243 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "ExternalTexture.h"
77

8+
#include "Colorspaces.h"
89
#include "ImageContainer.h"
910
#include "mozilla/Assertions.h"
1011
#include "mozilla/ErrorResult.h"
@@ -14,20 +15,64 @@
1415
#include "mozilla/gfx/Logging.h"
1516
#include "mozilla/layers/ImageDataSerializer.h"
1617
#include "mozilla/webgpu/Queue.h"
18+
#include "mozilla/webgpu/Utility.h"
1719
#include "mozilla/webgpu/WebGPUChild.h"
1820
#include "mozilla/webgpu/WebGPUParent.h"
1921
#include "nsLayoutUtils.h"
2022
#include "nsPrintfCString.h"
2123

2224
namespace mozilla::webgpu {
2325

24-
GPU_IMPL_CYCLE_COLLECTION(ExternalTexture, mGlobal)
26+
GPU_IMPL_CYCLE_COLLECTION(ExternalTexture, mParent)
27+
GPU_IMPL_JS_WRAP(ExternalTexture)
2528

26-
JSObject* ExternalTexture::WrapObject(JSContext* cx,
27-
JS ::Handle<JSObject*> givenProto) {
28-
return dom::GPUExternalTexture_Binding::Wrap(cx, this, givenProto);
29+
ExternalTexture::ExternalTexture(Device* const aParent, RawId aId,
30+
RefPtr<ExternalTextureSourceClient> aSource)
31+
: ChildOf(aParent), mId(aId), mSource(aSource) {
32+
MOZ_RELEASE_ASSERT(aId);
33+
}
34+
35+
/* static */ already_AddRefed<ExternalTexture> ExternalTexture::Create(
36+
Device* const aParent, const nsString& aLabel,
37+
const RefPtr<ExternalTextureSourceClient>& aSource,
38+
dom::PredefinedColorSpace aColorSpace) {
39+
const webgpu::StringHelper label(aLabel);
40+
const ffi::WGPUPredefinedColorSpace colorSpace =
41+
ConvertPredefinedColorSpace(aColorSpace);
42+
const ffi::WGPUExternalTextureDescriptor desc = {
43+
.label = label.Get(),
44+
.source = aSource ? aSource->mId : 0,
45+
.color_space = colorSpace,
46+
};
47+
48+
const RawId id = ffi::wgpu_client_create_external_texture(
49+
aParent->GetBridge()->GetClient(), aParent->mId, &desc);
50+
51+
RefPtr<ExternalTexture> externalTexture =
52+
new ExternalTexture(aParent, id, aSource);
53+
externalTexture->SetLabel(aLabel);
54+
55+
return externalTexture.forget();
56+
}
57+
58+
void ExternalTexture::Cleanup() {
59+
if (!mValid) {
60+
return;
61+
}
62+
mValid = false;
63+
64+
mSource = nullptr;
65+
66+
auto bridge = mParent->GetBridge();
67+
if (!bridge) {
68+
return;
69+
}
70+
71+
ffi::wgpu_client_drop_external_texture(bridge->GetClient(), mId);
2972
}
3073

74+
ExternalTexture::~ExternalTexture() { Cleanup(); }
75+
3176
ExternalTextureSourceClient::ExternalTextureSourceClient(
3277
WebGPUChild* aBridge, RawId aId, const std::array<RawId, 3>& aTextureIds,
3378
const std::array<RawId, 3>& aViewIds)
@@ -446,4 +491,198 @@ ExternalTextureSourceHost::CreateError() {
446491
gfx::YUVRangedColorSpace::GbrIdentity, {}, {});
447492
}
448493

494+
static color::ColorspaceTransform GetColorSpaceTransform(
495+
gfx::YUVRangedColorSpace aSrcColorSpace,
496+
ffi::WGPUPredefinedColorSpace aDestColorSpace) {
497+
const bool rec709GammaAsSrgb =
498+
StaticPrefs::gfx_color_management_rec709_gamma_as_srgb();
499+
const bool rec2020GammaAsRec709 =
500+
StaticPrefs::gfx_color_management_rec2020_gamma_as_rec709();
501+
502+
color::ColorspaceDesc srcColorSpace;
503+
switch (aSrcColorSpace) {
504+
case gfx::YUVRangedColorSpace::BT601_Narrow:
505+
srcColorSpace = {
506+
.chrom = color::Chromaticities::Rec601_525_Ntsc(),
507+
.tf = rec709GammaAsSrgb ? color::PiecewiseGammaDesc::Srgb()
508+
: color::PiecewiseGammaDesc::Rec709(),
509+
.yuv =
510+
color::YuvDesc{
511+
.yCoeffs = color::YuvLumaCoeffs::Rec601(),
512+
.ycbcr = color::YcbcrDesc::Narrow8(),
513+
},
514+
};
515+
break;
516+
case gfx::YUVRangedColorSpace::BT601_Full:
517+
srcColorSpace = {
518+
.chrom = color::Chromaticities::Rec601_525_Ntsc(),
519+
.tf = rec709GammaAsSrgb ? color::PiecewiseGammaDesc::Srgb()
520+
: color::PiecewiseGammaDesc::Rec709(),
521+
.yuv =
522+
color::YuvDesc{
523+
.yCoeffs = color::YuvLumaCoeffs::Rec601(),
524+
.ycbcr = color::YcbcrDesc::Full8(),
525+
},
526+
};
527+
break;
528+
case gfx::YUVRangedColorSpace::BT709_Narrow:
529+
srcColorSpace = {
530+
.chrom = color::Chromaticities::Rec709(),
531+
.tf = rec709GammaAsSrgb ? color::PiecewiseGammaDesc::Srgb()
532+
: color::PiecewiseGammaDesc::Rec709(),
533+
.yuv =
534+
color::YuvDesc{
535+
.yCoeffs = color::YuvLumaCoeffs::Rec709(),
536+
.ycbcr = color::YcbcrDesc::Narrow8(),
537+
},
538+
};
539+
break;
540+
case gfx::YUVRangedColorSpace::BT709_Full:
541+
srcColorSpace = {
542+
.chrom = color::Chromaticities::Rec709(),
543+
.tf = rec709GammaAsSrgb ? color::PiecewiseGammaDesc::Srgb()
544+
: color::PiecewiseGammaDesc::Rec709(),
545+
.yuv =
546+
color::YuvDesc{
547+
.yCoeffs = color::YuvLumaCoeffs::Rec709(),
548+
.ycbcr = color::YcbcrDesc::Full8(),
549+
},
550+
};
551+
break;
552+
case gfx::YUVRangedColorSpace::BT2020_Narrow:
553+
srcColorSpace = {
554+
.chrom = color::Chromaticities::Rec2020(),
555+
.tf = rec2020GammaAsRec709 && rec709GammaAsSrgb
556+
? color::PiecewiseGammaDesc::Srgb()
557+
: (rec2020GammaAsRec709
558+
? color::PiecewiseGammaDesc::Rec709()
559+
: color::PiecewiseGammaDesc::Rec2020_12bit()),
560+
.yuv =
561+
color::YuvDesc{
562+
.yCoeffs = color::YuvLumaCoeffs::Rec2020(),
563+
.ycbcr = color::YcbcrDesc::Narrow8(),
564+
},
565+
};
566+
break;
567+
case gfx::YUVRangedColorSpace::BT2020_Full:
568+
srcColorSpace = {
569+
.chrom = color::Chromaticities::Rec2020(),
570+
.tf = rec2020GammaAsRec709 && rec709GammaAsSrgb
571+
? color::PiecewiseGammaDesc::Srgb()
572+
: (rec2020GammaAsRec709
573+
? color::PiecewiseGammaDesc::Rec709()
574+
: color::PiecewiseGammaDesc::Rec2020_12bit()),
575+
.yuv =
576+
color::YuvDesc{
577+
.yCoeffs = color::YuvLumaCoeffs::Rec2020(),
578+
.ycbcr = color::YcbcrDesc::Full8(),
579+
},
580+
};
581+
break;
582+
case gfx::YUVRangedColorSpace::GbrIdentity:
583+
srcColorSpace = {
584+
.chrom = color::Chromaticities::Rec709(),
585+
.tf = color::PiecewiseGammaDesc::Rec709(),
586+
.yuv =
587+
color::YuvDesc{
588+
.yCoeffs = color::YuvLumaCoeffs::Gbr(),
589+
.ycbcr = color::YcbcrDesc::Full8(),
590+
},
591+
};
592+
break;
593+
}
594+
595+
color::ColorspaceDesc destColorSpace{};
596+
switch (aDestColorSpace) {
597+
case ffi::WGPUPredefinedColorSpace_Srgb:
598+
destColorSpace = {.chrom = color::Chromaticities::Srgb(),
599+
.tf = color::PiecewiseGammaDesc::Srgb()};
600+
break;
601+
case ffi::WGPUPredefinedColorSpace_DisplayP3:
602+
destColorSpace = {.chrom = color::Chromaticities::DisplayP3(),
603+
.tf = color::PiecewiseGammaDesc::DisplayP3()};
604+
break;
605+
case ffi::WGPUPredefinedColorSpace_Sentinel:
606+
MOZ_CRASH("Invalid WGPUPredefinedColorSpace");
607+
}
608+
609+
return color::ColorspaceTransform::Create(srcColorSpace, destColorSpace);
610+
}
611+
612+
static ffi::WGPUExternalTextureFormat MapFormat(gfx::SurfaceFormat aFormat) {
613+
switch (aFormat) {
614+
case gfx::SurfaceFormat::B8G8R8A8:
615+
case gfx::SurfaceFormat::B8G8R8X8:
616+
case gfx::SurfaceFormat::R8G8B8A8:
617+
case gfx::SurfaceFormat::R8G8B8X8:
618+
return ffi::WGPUExternalTextureFormat_Rgba;
619+
case gfx::SurfaceFormat::YUV420:
620+
return ffi::WGPUExternalTextureFormat_Yu12;
621+
case gfx::SurfaceFormat::NV12:
622+
return ffi::WGPUExternalTextureFormat_Nv12;
623+
default:
624+
MOZ_CRASH("Unexpected SurfaceFormat");
625+
}
626+
}
627+
628+
static ffi::WGPUExternalTextureTransferFunction MapTransferFunction(
629+
std::optional<color::PiecewiseGammaDesc> aTf) {
630+
if (aTf) {
631+
return ffi::WGPUExternalTextureTransferFunction{
632+
.a = aTf->a,
633+
.b = aTf->b,
634+
.g = aTf->g,
635+
.k = aTf->k,
636+
};
637+
} else {
638+
return ffi::WGPUExternalTextureTransferFunction{
639+
.a = 1.0,
640+
.b = 1.0,
641+
.g = 1.0,
642+
.k = 1.0,
643+
};
644+
}
645+
}
646+
647+
ffi::WGPUExternalTextureDescriptorFromSource
648+
ExternalTextureSourceHost::GetExternalTextureDescriptor(
649+
ffi::WGPUPredefinedColorSpace aDestColorSpace) const {
650+
ffi::WGPUExternalTextureDescriptorFromSource desc;
651+
652+
desc.planes = ffi::WGPUFfiSlice_TextureViewId{
653+
.data = mViewIds.Elements(),
654+
.length = mViewIds.Length(),
655+
};
656+
desc.width = static_cast<uint32_t>(mSize.width);
657+
desc.height = static_cast<uint32_t>(mSize.height);
658+
desc.format = MapFormat(mFormat);
659+
660+
auto colorSpaceTransform =
661+
GetColorSpaceTransform(mColorSpace, aDestColorSpace);
662+
// Makes a generator for a color::mat that yields its components in
663+
// column-major order
664+
auto make_column_major_generator = [](auto mat) {
665+
return [i = 0, mat]() mutable {
666+
auto val = mat.at(i / mat.y_rows, i % mat.y_rows);
667+
i++;
668+
return val;
669+
};
670+
};
671+
std::generate(
672+
std::begin(desc.yuv_conversion_matrix),
673+
std::end(desc.yuv_conversion_matrix),
674+
make_column_major_generator(colorSpaceTransform.srcRgbTfFromSrc));
675+
std::generate(
676+
std::begin(desc.gamut_conversion_matrix),
677+
std::end(desc.gamut_conversion_matrix),
678+
make_column_major_generator(colorSpaceTransform.dstRgbLinFromSrcRgbLin));
679+
desc.src_transfer_function = MapTransferFunction(colorSpaceTransform.srcTf);
680+
desc.dst_transfer_function = MapTransferFunction(colorSpaceTransform.dstTf);
681+
std::copy(mSampleTransform.begin(), mSampleTransform.end(),
682+
desc.sample_transform);
683+
std::copy(mLoadTransform.begin(), mLoadTransform.end(), desc.load_transform);
684+
685+
return desc;
686+
}
687+
449688
} // namespace mozilla::webgpu

0 commit comments

Comments
 (0)