Some external images must be sampled from by providing normalized UV coordinates to webrender, but currently webrender only supports unnormalized UVs. This patch adds a flag to webrender's external image API that specifies whether the UV coordinates supplied when the texture is locked are normalized or unnormalized. This flag is plumbed through webrender to the required locations. We then add support for taking normalized UVs as inputs to the brush_image and cs_scale shaders. The only other shader that can be used with external textures is the composite shader, which already supports normalized UVs. This does not change any behaviour, that will happen in the next patch in this series. Differential Revision: https://phabricator.services.mozilla.com/D220581
195 lines
7.2 KiB
C++
195 lines
7.2 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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 "DMABUFTextureHostOGL.h"
|
|
#include "mozilla/widget/DMABufSurface.h"
|
|
#include "mozilla/webrender/RenderDMABUFTextureHost.h"
|
|
#include "mozilla/webrender/RenderThread.h"
|
|
#include "mozilla/webrender/WebRenderAPI.h"
|
|
#include "GLContextEGL.h"
|
|
|
|
namespace mozilla::layers {
|
|
|
|
DMABUFTextureHostOGL::DMABUFTextureHostOGL(TextureFlags aFlags,
|
|
const SurfaceDescriptor& aDesc)
|
|
: TextureHost(TextureHostType::DMABUF, aFlags) {
|
|
MOZ_COUNT_CTOR(DMABUFTextureHostOGL);
|
|
|
|
// DMABufSurface::CreateDMABufSurface() can fail, for instance when we're run
|
|
// out of file descriptors.
|
|
mSurface =
|
|
DMABufSurface::CreateDMABufSurface(aDesc.get_SurfaceDescriptorDMABuf());
|
|
}
|
|
|
|
DMABUFTextureHostOGL::~DMABUFTextureHostOGL() {
|
|
MOZ_COUNT_DTOR(DMABUFTextureHostOGL);
|
|
}
|
|
|
|
gfx::SurfaceFormat DMABUFTextureHostOGL::GetFormat() const {
|
|
if (!mSurface) {
|
|
return gfx::SurfaceFormat::UNKNOWN;
|
|
}
|
|
return mSurface->GetFormat();
|
|
}
|
|
|
|
gfx::YUVColorSpace DMABUFTextureHostOGL::GetYUVColorSpace() const {
|
|
if (!mSurface) {
|
|
return gfx::YUVColorSpace::Identity;
|
|
}
|
|
return mSurface->GetYUVColorSpace();
|
|
}
|
|
|
|
gfx::ColorRange DMABUFTextureHostOGL::GetColorRange() const {
|
|
if (!mSurface) {
|
|
return gfx::ColorRange::LIMITED;
|
|
}
|
|
return mSurface->IsFullRange() ? gfx::ColorRange::FULL
|
|
: gfx::ColorRange::LIMITED;
|
|
}
|
|
|
|
uint32_t DMABUFTextureHostOGL::NumSubTextures() {
|
|
return mSurface ? mSurface->GetTextureCount() : 0;
|
|
}
|
|
|
|
gfx::IntSize DMABUFTextureHostOGL::GetSize() const {
|
|
if (!mSurface) {
|
|
return gfx::IntSize();
|
|
}
|
|
return gfx::IntSize(mSurface->GetWidth(), mSurface->GetHeight());
|
|
}
|
|
|
|
gl::GLContext* DMABUFTextureHostOGL::gl() const { return nullptr; }
|
|
|
|
void DMABUFTextureHostOGL::CreateRenderTexture(
|
|
const wr::ExternalImageId& aExternalImageId) {
|
|
MOZ_ASSERT(mExternalImageId.isSome());
|
|
|
|
if (!mSurface) {
|
|
return;
|
|
}
|
|
RefPtr<wr::RenderTextureHost> texture =
|
|
new wr::RenderDMABUFTextureHost(mSurface);
|
|
wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
|
|
texture.forget());
|
|
}
|
|
|
|
void DMABUFTextureHostOGL::PushResourceUpdates(
|
|
wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
|
|
const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
|
|
if (!mSurface) {
|
|
return;
|
|
}
|
|
|
|
auto method = aOp == TextureHost::ADD_IMAGE
|
|
? &wr::TransactionBuilder::AddExternalImage
|
|
: &wr::TransactionBuilder::UpdateExternalImage;
|
|
auto imageType =
|
|
wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D);
|
|
|
|
switch (mSurface->GetFormat()) {
|
|
case gfx::SurfaceFormat::R8G8B8X8:
|
|
case gfx::SurfaceFormat::R8G8B8A8:
|
|
case gfx::SurfaceFormat::B8G8R8X8:
|
|
case gfx::SurfaceFormat::B8G8R8A8: {
|
|
MOZ_ASSERT(aImageKeys.length() == 1);
|
|
// XXX Add RGBA handling. Temporary hack to avoid crash
|
|
// With BGRA format setting, rendering works without problem.
|
|
wr::ImageDescriptor descriptor(GetSize(), mSurface->GetFormat());
|
|
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
|
|
/* aNormalizedUvs */ false);
|
|
break;
|
|
}
|
|
case gfx::SurfaceFormat::NV12: {
|
|
MOZ_ASSERT(aImageKeys.length() == 2);
|
|
MOZ_ASSERT(mSurface->GetTextureCount() == 2);
|
|
wr::ImageDescriptor descriptor0(
|
|
gfx::IntSize(mSurface->GetWidth(0), mSurface->GetHeight(0)),
|
|
gfx::SurfaceFormat::A8);
|
|
wr::ImageDescriptor descriptor1(
|
|
gfx::IntSize(mSurface->GetWidth(1), mSurface->GetHeight(1)),
|
|
gfx::SurfaceFormat::R8G8);
|
|
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
|
|
/* aNormalizedUvs */ false);
|
|
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
|
|
/* aNormalizedUvs */ false);
|
|
break;
|
|
}
|
|
case gfx::SurfaceFormat::YUV420: {
|
|
MOZ_ASSERT(aImageKeys.length() == 3);
|
|
MOZ_ASSERT(mSurface->GetTextureCount() == 3);
|
|
wr::ImageDescriptor descriptor0(
|
|
gfx::IntSize(mSurface->GetWidth(0), mSurface->GetHeight(0)),
|
|
gfx::SurfaceFormat::A8);
|
|
wr::ImageDescriptor descriptor1(
|
|
gfx::IntSize(mSurface->GetWidth(1), mSurface->GetHeight(1)),
|
|
gfx::SurfaceFormat::A8);
|
|
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
|
|
/* aNormalizedUvs */ false);
|
|
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
|
|
/* aNormalizedUvs */ false);
|
|
(aResources.*method)(aImageKeys[2], descriptor1, aExtID, imageType, 2,
|
|
/* aNormalizedUvs */ false);
|
|
break;
|
|
}
|
|
default: {
|
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
|
}
|
|
}
|
|
}
|
|
|
|
void DMABUFTextureHostOGL::PushDisplayItems(
|
|
wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
|
|
const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
|
|
const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
|
|
if (!mSurface) {
|
|
return;
|
|
}
|
|
bool preferCompositorSurface =
|
|
aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE);
|
|
switch (mSurface->GetFormat()) {
|
|
case gfx::SurfaceFormat::R8G8B8X8:
|
|
case gfx::SurfaceFormat::R8G8B8A8:
|
|
case gfx::SurfaceFormat::B8G8R8A8:
|
|
case gfx::SurfaceFormat::B8G8R8X8: {
|
|
MOZ_ASSERT(aImageKeys.length() == 1);
|
|
aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0],
|
|
!(mFlags & TextureFlags::NON_PREMULTIPLIED),
|
|
wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
|
|
preferCompositorSurface);
|
|
break;
|
|
}
|
|
case gfx::SurfaceFormat::NV12: {
|
|
MOZ_ASSERT(aImageKeys.length() == 2);
|
|
MOZ_ASSERT(mSurface->GetTextureCount() == 2);
|
|
// Those images can only be generated at present by the VAAPI H264 decoder
|
|
// which only supports 8 bits color depth.
|
|
aBuilder.PushNV12Image(aBounds, aClip, true, aImageKeys[0], aImageKeys[1],
|
|
wr::ColorDepth::Color8,
|
|
wr::ToWrYuvColorSpace(GetYUVColorSpace()),
|
|
wr::ToWrColorRange(GetColorRange()), aFilter,
|
|
preferCompositorSurface);
|
|
break;
|
|
}
|
|
case gfx::SurfaceFormat::YUV420: {
|
|
MOZ_ASSERT(aImageKeys.length() == 3);
|
|
MOZ_ASSERT(mSurface->GetTextureCount() == 3);
|
|
// Those images can only be generated at present by the VAAPI vp8 decoder
|
|
// which only supports 8 bits color depth.
|
|
aBuilder.PushYCbCrPlanarImage(
|
|
aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2],
|
|
wr::ColorDepth::Color8, wr::ToWrYuvColorSpace(GetYUVColorSpace()),
|
|
wr::ToWrColorRange(GetColorRange()), aFilter,
|
|
preferCompositorSurface);
|
|
break;
|
|
}
|
|
default: {
|
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace mozilla::layers
|