Files
tubestation/gfx/layers/opengl/DMABUFTextureHostOGL.cpp
Jamie Nicol 61607f450a Bug 1913568 - Add support for normalized UV coordinates to webrender. r=gfx-reviewers,nical
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
2024-09-09 14:06:26 +00:00

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