/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DcompSurfaceImage.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/ipc/FileDescriptor.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/KnowsCompositor.h" #include "mozilla/layers/LayersSurfaces.h" #include "mozilla/layers/TextureForwarder.h" #include "mozilla/webrender/RenderDcompSurfaceTextureHost.h" #include "mozilla/webrender/WebRenderAPI.h" extern mozilla::LazyLogModule gDcompSurface; #define LOG(...) MOZ_LOG(gDcompSurface, LogLevel::Debug, (__VA_ARGS__)) namespace mozilla::layers { static constexpr int32_t kMaxDcompSurfaceDimension = 16384; static bool IsValidDcompSurfaceDescriptor( const SurfaceDescriptorDcompSurface& aDescriptor) { if (!aDescriptor.handle().IsValid()) { gfxCriticalNote << "DcompSurfaceHandleHost: invalid FileDescriptor"; return false; } const gfx::SurfaceFormat fmt = aDescriptor.format(); if (fmt != gfx::SurfaceFormat::B8G8R8A8 && fmt != gfx::SurfaceFormat::R8G8B8A8 && fmt != gfx::SurfaceFormat::R16G16B16A16F) { gfxCriticalNote << "DcompSurfaceHandleHost: unsupported format " << static_cast(fmt); return false; } const gfx::IntSize size = aDescriptor.size(); if (size.width <= 0 || size.height <= 0 || size.width > kMaxDcompSurfaceDimension || size.height > kMaxDcompSurfaceDimension) { gfxCriticalNote << "DcompSurfaceHandleHost: bad size " << size.width << "x" << size.height; return false; } return true; } already_AddRefed CreateTextureHostDcompSurface( const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator, LayersBackend aBackend, TextureFlags aFlags) { MOZ_ASSERT(aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorDcompSurface); if (!IsValidDcompSurfaceDescriptor( aDesc.get_SurfaceDescriptorDcompSurface())) { return nullptr; } RefPtr result = MakeRefPtr( aFlags, aDesc.get_SurfaceDescriptorDcompSurface()); return result.forget(); } /* static */ already_AddRefed DcompSurfaceTexture::CreateTextureClient( HANDLE aHandle, gfx::IntSize aSize, gfx::SurfaceFormat aFormat, KnowsCompositor* aKnowsCompositor) { RefPtr textureClient = MakeAndAddRef( new DcompSurfaceTexture(aHandle, aSize, aFormat), TextureFlags::NO_FLAGS, aKnowsCompositor->GetTextureForwarder().get()); return textureClient.forget(); } DcompSurfaceTexture::~DcompSurfaceTexture() { LOG("Destroy DcompSurfaceTexture %p, close handle=%p", this, mHandle); CloseHandle(mHandle); } bool DcompSurfaceTexture::Serialize(SurfaceDescriptor& aOutDescriptor) { aOutDescriptor = SurfaceDescriptorDcompSurface(ipc::FileDescriptor(mHandle), mSize, mFormat); return true; } void DcompSurfaceTexture::GetSubDescriptor( RemoteDecoderVideoSubDescriptor* aOutDesc) { *aOutDesc = SurfaceDescriptorDcompSurface(ipc::FileDescriptor(mHandle), mSize, mFormat); } DcompSurfaceImage::DcompSurfaceImage(HANDLE aHandle, gfx::IntSize aSize, gfx::SurfaceFormat aFormat, KnowsCompositor* aKnowsCompositor) : Image(nullptr, ImageFormat::DCOMP_SURFACE), mTextureClient(DcompSurfaceTexture::CreateTextureClient( aHandle, aSize, aFormat, aKnowsCompositor)) { // Dcomp surface supports DXGI_FORMAT_B8G8R8A8_UNORM, // DXGI_FORMAT_R8G8B8A8_UNORM and DXGI_FORMAT_R16G16B16A16_FLOAT MOZ_ASSERT(aFormat == gfx::SurfaceFormat::B8G8R8A8 || aFormat == gfx::SurfaceFormat::R8G8B8A8 || aFormat == gfx::SurfaceFormat::R16G16B16A16F); } TextureClient* DcompSurfaceImage::GetTextureClient( KnowsCompositor* aKnowsCompositor) { return mTextureClient; } DcompSurfaceHandleHost::DcompSurfaceHandleHost( TextureFlags aFlags, const SurfaceDescriptorDcompSurface& aDescriptor) : TextureHost(TextureHostType::DcompSurface, aFlags), mHandle(const_cast(aDescriptor.handle()) .TakePlatformHandle()), mSize(aDescriptor.size()), mFormat(aDescriptor.format()) { LOG("Create DcompSurfaceHandleHost %p", this); } DcompSurfaceHandleHost::~DcompSurfaceHandleHost() { LOG("Destroy DcompSurfaceHandleHost %p", this); } void DcompSurfaceHandleHost::CreateRenderTexture( const wr::ExternalImageId& aExternalImageId) { MOZ_ASSERT(mExternalImageId.isSome()); LOG("DcompSurfaceHandleHost %p CreateRenderTexture, ext-id=%" PRIu64, this, wr::AsUint64(aExternalImageId)); RefPtr texture = MakeRefPtr( mHandle.get(), mSize, mFormat); wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, texture.forget()); } void DcompSurfaceHandleHost::PushResourceUpdates( wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, const Range& aImageKeys, const wr::ExternalImageId& aExternalImageId) { if (!gfx::gfxVars::UseWebRenderANGLE()) { MOZ_ASSERT_UNREACHABLE("Unexpected to be called without ANGLE"); return; } MOZ_ASSERT(mHandle); if (aImageKeys.length() != 1) { MOZ_ASSERT_UNREACHABLE("unexpected key length"); return; } auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage : &wr::TransactionBuilder::UpdateExternalImage; auto format = wr::SurfaceFormatToImageFormat(GetFormat()); if (NS_WARN_IF(!format)) { return; } wr::ImageDescriptor descriptor(mSize, *format, wr::ToOpacityType(GetFormat())); // Prefer TextureExternal unless the backend requires TextureRect. TextureHost::NativeTexturePolicy policy = TextureHost::BackendNativeTexturePolicy( aResources.GetCapabilities().mBackendType, mSize); auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE ? wr::ExternalImageType::TextureHandle( wr::ImageBufferKind::TextureRect) : wr::ExternalImageType::TextureHandle( wr::ImageBufferKind::TextureExternal); LOG("DcompSurfaceHandleHost %p PushResourceUpdate, exi-id=%" PRIu64 ", type=%s", this, wr::AsUint64(aExternalImageId), policy == TextureHost::NativeTexturePolicy::REQUIRE ? "rect" : "ext"); (aResources.*method)(aImageKeys[0], descriptor, aExternalImageId, imageType, 0, /* aNormalizedUvs */ false); } void DcompSurfaceHandleHost::PushDisplayItems( wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, wr::ImageRendering aFilter, const Range& aImageKeys, PushDisplayItemFlagSet aFlags) { if (!gfx::gfxVars::UseWebRenderANGLE()) { MOZ_ASSERT_UNREACHABLE("Unexpected to be called without ANGLE"); return; } LOG("DcompSurfaceHandleHost %p PushDisplayItems", this); if (aImageKeys.length() != 1) { MOZ_ASSERT_UNREACHABLE("unexpected key length"); return; } aBuilder.PushImage( aBounds, aClip, true, false, aFilter, aImageKeys[0], !(mFlags & TextureFlags::NON_PREMULTIPLIED), wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE), SupportsExternalCompositing(aBuilder.GetBackendType())); } } // namespace mozilla::layers #undef LOG