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
This commit is contained in:
Jamie Nicol
2024-09-09 14:06:26 +00:00
parent c8702855e1
commit 61607f450a
27 changed files with 240 additions and 115 deletions

View File

@@ -125,7 +125,7 @@ void DcompSurfaceHandleHost::PushResourceUpdates(
this, wr::AsUint64(aExternalImageId),
policy == TextureHost::NativeTexturePolicy::REQUIRE ? "rect" : "ext");
(aResources.*method)(aImageKeys[0], descriptor, aExternalImageId, imageType,
0);
0, /* aNormalizedUvs */ false);
}
void DcompSurfaceHandleHost::PushDisplayItems(

View File

@@ -543,7 +543,8 @@ void BufferTextureHost::PushResourceUpdates(
GetSize(),
ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
GetFormat());
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
} else {
MOZ_ASSERT(aImageKeys.length() == 3);
@@ -555,9 +556,12 @@ void BufferTextureHost::PushResourceUpdates(
wr::ImageDescriptor cbcrDescriptor(
cbcrSize, desc.cbCrStride(),
SurfaceFormatForColorDepth(desc.colorDepth()));
(aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1);
(aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, imageType, 2);
(aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
(aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1,
/* aNormalizedUvs */ false);
(aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, imageType, 2,
/* aNormalizedUvs */ false);
}
}

View File

@@ -1242,7 +1242,8 @@ void DXGITextureHostD3D11::PushResourceUpdates(
wr::ImageBufferKind::TextureRect)
: wr::ExternalImageType::TextureHandle(
wr::ImageBufferKind::TextureExternal);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
break;
}
case gfx::SurfaceFormat::P010:
@@ -1268,8 +1269,10 @@ void DXGITextureHostD3D11::PushResourceUpdates(
wr::ImageBufferKind::TextureRect)
: wr::ExternalImageType::TextureHandle(
wr::ImageBufferKind::TextureExternal);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
/* aNormalizedUvs */ false);
break;
}
default: {
@@ -1418,9 +1421,12 @@ void DXGIYCbCrTextureHostD3D11::PushResourceUpdates(
wr::ImageDescriptor descriptor0(mSizeY, gfx::SurfaceFormat::A8);
// cb and cr
wr::ImageDescriptor descriptor1(mSizeCbCr, gfx::SurfaceFormat::A8);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
(aResources.*method)(aImageKeys[2], descriptor1, aExtID, imageType, 2);
(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);
}
void DXGIYCbCrTextureHostD3D11::PushDisplayItems(

View File

@@ -98,7 +98,8 @@ void DMABUFTextureHostOGL::PushResourceUpdates(
// 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);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
break;
}
case gfx::SurfaceFormat::NV12: {
@@ -110,8 +111,10 @@ void DMABUFTextureHostOGL::PushResourceUpdates(
wr::ImageDescriptor descriptor1(
gfx::IntSize(mSurface->GetWidth(1), mSurface->GetHeight(1)),
gfx::SurfaceFormat::R8G8);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
(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: {
@@ -123,9 +126,12 @@ void DMABUFTextureHostOGL::PushResourceUpdates(
wr::ImageDescriptor descriptor1(
gfx::IntSize(mSurface->GetWidth(1), mSurface->GetHeight(1)),
gfx::SurfaceFormat::A8);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
(aResources.*method)(aImageKeys[2], descriptor1, aExtID, imageType, 2);
(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: {

View File

@@ -130,7 +130,8 @@ void MacIOSurfaceTextureHostOGL::PushResourceUpdates(
? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
wr::ImageDescriptor descriptor(GetSize(), format);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
break;
}
case gfx::SurfaceFormat::YUY2: {
@@ -141,7 +142,8 @@ void MacIOSurfaceTextureHostOGL::PushResourceUpdates(
MOZ_ASSERT(aImageKeys.length() == 1);
MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
wr::ImageDescriptor descriptor(GetSize(), gfx::SurfaceFormat::B8G8R8X8);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
break;
}
case gfx::SurfaceFormat::NV12: {
@@ -155,8 +157,10 @@ void MacIOSurfaceTextureHostOGL::PushResourceUpdates(
gfx::IntSize(mSurface->GetDevicePixelWidth(1),
mSurface->GetDevicePixelHeight(1)),
gfx::SurfaceFormat::R8G8);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
/* aNormalizedUvs */ false);
break;
}
case gfx::SurfaceFormat::P010: {
@@ -170,8 +174,10 @@ void MacIOSurfaceTextureHostOGL::PushResourceUpdates(
gfx::IntSize(mSurface->GetDevicePixelWidth(1),
mSurface->GetDevicePixelHeight(1)),
gfx::SurfaceFormat::R16G16);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
/* aNormalizedUvs */ false);
break;
}
case gfx::SurfaceFormat::NV16: {
@@ -185,8 +191,10 @@ void MacIOSurfaceTextureHostOGL::PushResourceUpdates(
gfx::IntSize(mSurface->GetDevicePixelWidth(1),
mSurface->GetDevicePixelHeight(1)),
gfx::SurfaceFormat::R16G16);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1);
(aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
(aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1,
/* aNormalizedUvs */ false);
break;
}
default: {

View File

@@ -582,7 +582,8 @@ void SurfaceTextureHost::PushResourceUpdates(
? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
wr::ImageDescriptor descriptor(GetSize(), format);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
break;
}
default: {
@@ -875,7 +876,8 @@ void AndroidHardwareBufferTextureHost::PushResourceUpdates(
? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
wr::ImageDescriptor descriptor(GetSize(), format);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
break;
}
default: {
@@ -1031,7 +1033,8 @@ void EGLImageTextureHost::PushResourceUpdates(
? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
wr::ImageDescriptor descriptor(GetSize(), formatTmp);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
/* aNormalizedUvs */ false);
}
void EGLImageTextureHost::PushDisplayItems(

View File

@@ -843,7 +843,8 @@ bool WebRenderBridgeParent::UpdateSharedExternalImage(
wr::ImageDescriptor descriptor(surfaceSize, dSurf->Stride(),
dSurf->GetFormat());
aResources.UpdateExternalImageWithDirtyRect(
aKey, descriptor, aExtId, imageType, wr::ToDeviceIntRect(aDirtyRect), 0);
aKey, descriptor, aExtId, imageType, wr::ToDeviceIntRect(aDirtyRect), 0,
/* aNormalizedUvs */ false);
return true;
}

View File

@@ -982,9 +982,11 @@ void TransactionBuilder::AddExternalImage(ImageKey key,
const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::ExternalImageType aImageType,
uint8_t aChannelIndex) {
uint8_t aChannelIndex,
bool aNormalizedUvs) {
wr_resource_updates_add_external_image(mTxn, key, &aDescriptor, aExtID,
&aImageType, aChannelIndex);
&aImageType, aChannelIndex,
aNormalizedUvs);
}
void TransactionBuilder::AddExternalImageBuffer(
@@ -1014,17 +1016,20 @@ void TransactionBuilder::UpdateExternalImage(ImageKey aKey,
const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::ExternalImageType aImageType,
uint8_t aChannelIndex) {
uint8_t aChannelIndex,
bool aNormalizedUvs) {
wr_resource_updates_update_external_image(mTxn, aKey, &aDescriptor, aExtID,
&aImageType, aChannelIndex);
&aImageType, aChannelIndex,
aNormalizedUvs);
}
void TransactionBuilder::UpdateExternalImageWithDirtyRect(
ImageKey aKey, const ImageDescriptor& aDescriptor, ExternalImageId aExtID,
wr::ExternalImageType aImageType, const wr::DeviceIntRect& aDirtyRect,
uint8_t aChannelIndex) {
uint8_t aChannelIndex, bool aNormalizedUvs) {
wr_resource_updates_update_external_image_with_dirty_rect(
mTxn, aKey, &aDescriptor, aExtID, &aImageType, aChannelIndex, aDirtyRect);
mTxn, aKey, &aDescriptor, aExtID, &aImageType, aChannelIndex,
aNormalizedUvs, aDirtyRect);
}
void TransactionBuilder::SetBlobImageVisibleArea(

View File

@@ -157,7 +157,7 @@ class TransactionBuilder final {
void AddExternalImage(ImageKey key, const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::ExternalImageType aImageType,
uint8_t aChannelIndex = 0);
uint8_t aChannelIndex = 0, bool aNormalizedUvs = false);
void UpdateImageBuffer(wr::ImageKey aKey, const ImageDescriptor& aDescriptor,
wr::Vec<uint8_t>& aBytes);
@@ -171,14 +171,13 @@ class TransactionBuilder final {
void UpdateExternalImage(ImageKey aKey, const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::ExternalImageType aImageType,
uint8_t aChannelIndex = 0);
uint8_t aChannelIndex = 0,
bool aNormalizedUvs = false);
void UpdateExternalImageWithDirtyRect(ImageKey aKey,
const ImageDescriptor& aDescriptor,
ExternalImageId aExtID,
wr::ExternalImageType aImageType,
const wr::DeviceIntRect& aDirtyRect,
uint8_t aChannelIndex = 0);
void UpdateExternalImageWithDirtyRect(
ImageKey aKey, const ImageDescriptor& aDescriptor, ExternalImageId aExtID,
wr::ExternalImageType aImageType, const wr::DeviceIntRect& aDirtyRect,
uint8_t aChannelIndex = 0, bool aNormalizedUvs = false);
void SetBlobImageVisibleArea(BlobImageKey aKey,
const wr::DeviceIntRect& aArea);

View File

@@ -2177,6 +2177,7 @@ pub extern "C" fn wr_resource_updates_add_external_image(
external_image_id: ExternalImageId,
image_type: &ExternalImageType,
channel_index: u8,
normalized_uvs: bool,
) {
txn.add_image(
image_key,
@@ -2185,6 +2186,7 @@ pub extern "C" fn wr_resource_updates_add_external_image(
id: external_image_id,
channel_index,
image_type: *image_type,
normalized_uvs,
}),
None,
);
@@ -2222,6 +2224,7 @@ pub extern "C" fn wr_resource_updates_update_external_image(
external_image_id: ExternalImageId,
image_type: &ExternalImageType,
channel_index: u8,
normalized_uvs: bool,
) {
txn.update_image(
key,
@@ -2230,6 +2233,7 @@ pub extern "C" fn wr_resource_updates_update_external_image(
id: external_image_id,
channel_index,
image_type: *image_type,
normalized_uvs,
}),
&DirtyRect::All,
);
@@ -2243,6 +2247,7 @@ pub extern "C" fn wr_resource_updates_update_external_image_with_dirty_rect(
external_image_id: ExternalImageId,
image_type: &ExternalImageType,
channel_index: u8,
normalized_uvs: bool,
dirty_rect: DeviceIntRect,
) {
txn.update_image(
@@ -2252,6 +2257,7 @@ pub extern "C" fn wr_resource_updates_update_external_image_with_dirty_rect(
id: external_image_id,
channel_index,
image_type: *image_type,
normalized_uvs,
}),
&DirtyRect::Partial(dirty_rect),
);

View File

@@ -261,6 +261,7 @@ impl Example for App {
id: ExternalImageId(0),
channel_index: size as u8,
image_type: ExternalImageType::Buffer,
normalized_uvs: false,
};
txn.add_image(

View File

@@ -115,6 +115,7 @@ impl Example for App {
image_type: ExternalImageType::TextureHandle(
ImageBufferKind::Texture2D,
),
normalized_uvs: false,
}),
None,
);
@@ -127,6 +128,7 @@ impl Example for App {
image_type: ExternalImageType::TextureHandle(
ImageBufferKind::Texture2D,
),
normalized_uvs: false,
}),
None,
);
@@ -139,6 +141,7 @@ impl Example for App {
image_type: ExternalImageType::TextureHandle(
ImageBufferKind::Texture2D,
),
normalized_uvs: false,
}),
None,
);
@@ -151,6 +154,7 @@ impl Example for App {
image_type: ExternalImageType::TextureHandle(
ImageBufferKind::Texture2D,
),
normalized_uvs: false,
}),
None,
);

View File

@@ -88,6 +88,7 @@ void text_shader_main(
#define BRUSH_FLAG_SEGMENT_NINEPATCH_MIDDLE 256
#define BRUSH_FLAG_TEXEL_RECT 512
#define BRUSH_FLAG_FORCE_AA 1024
#define BRUSH_FLAG_NORMALIZED_UVS 2048
#define INVALID_SEGMENT_INDEX 0xffff

View File

@@ -170,6 +170,11 @@ void brush_vs(
float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0;
v_perspective.x = perspective_interpolate;
if ((brush_flags & BRUSH_FLAG_NORMALIZED_UVS) != 0) {
uv0 *= texture_size;
uv1 *= texture_size;
}
// Handle case where the UV coords are inverted (e.g. from an
// external image).
vec2 min_uv = min(uv0, uv1);

View File

@@ -130,9 +130,7 @@ void main(void) {
uv = mix(aUvRect0.xy, aUvRect0.zw, uv);
// The uvs may be inverted, so use the min and max for the bounds
vec4 uvBounds = vec4(min(aUvRect0.xy, aUvRect0.zw), max(aUvRect0.xy, aUvRect0.zw));
int rescale_uv = int(aParams.y);
if (rescale_uv == 1)
{
if (int(aParams.y) == UV_TYPE_UNNORMALIZED) {
// using an atlas, so UVs are in pixels, and need to be
// normalized and clamped.
#if defined(WR_FEATURE_TEXTURE_RECT)

View File

@@ -19,28 +19,34 @@ uniform vec2 uTextureSize;
PER_INSTANCE attribute vec4 aScaleTargetRect;
PER_INSTANCE attribute vec4 aScaleSourceRect;
PER_INSTANCE attribute float aSourceRectType;
void main(void) {
vec2 src_offset = aScaleSourceRect.xy;
vec2 src_size = aScaleSourceRect.zw - aScaleSourceRect.xy;
// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
// non-normalized texture coordinates.
// The uvs may be inverted, so use the min and max for the bounds
vUvRect = vec4(min(aScaleSourceRect.xy, aScaleSourceRect.zw),
max(aScaleSourceRect.xy, aScaleSourceRect.zw));
vUv = (src_offset + src_size * aPosition.xy);
if (int(aSourceRectType) == UV_TYPE_UNNORMALIZED) {
vUvRect = vec4(vUvRect.xy + vec2(0.5), vUvRect.zw - vec2(0.5));
#ifdef WR_FEATURE_TEXTURE_RECT
// In WR_FEATURE_TEXTURE_RECT mode the UV coordinates used to sample
// from the texture should be unnormalized, so we leave them as is.
vec2 texture_size = vec2(1, 1);
#elif defined(WR_FEATURE_TEXTURE_EXTERNAL_ESSL1)
vec2 texture_size = uTextureSize;
#else
vec2 texture_size = vec2(TEX_SIZE(sColor0));
#endif
// The uvs may be inverted, so use the min and max for the bounds
vUvRect = vec4(min(aScaleSourceRect.xy, aScaleSourceRect.zw) + vec2(0.5),
max(aScaleSourceRect.xy, aScaleSourceRect.zw) - vec2(0.5)) / texture_size.xyxy;
vUvRect /= texture_size.xyxy;
vUv /= texture_size;
}
vec2 pos = mix(aScaleTargetRect.xy, aScaleTargetRect.zw, aPosition.xy);
vUv = (src_offset + src_size * aPosition.xy) / texture_size;
gl_Position = uTransform * vec4(pos, 0.0, 1.0);
}

View File

@@ -53,6 +53,12 @@ uniform bool u_mali_workaround_dummy;
#define TEX_SIZE(sampler) textureSize(sampler, 0)
#endif
// Keep these in sync with the corresponding constants in gpu_types.rs
// Specifies that the UV coordinates supplied to certain shaders are normalized.
#define UV_TYPE_NORMALIZED 0
// Specifies that the UV coordinates supplied to certain shaders are not normalized.
#define UV_TYPE_UNNORMALIZED 1
//======================================================================================
// Vertex shader attributes and uniforms
//======================================================================================

View File

@@ -2576,6 +2576,11 @@ impl BatchBuilder {
batch_params.prim_user_data,
);
let brush_flags = match image_instance.normalized_uvs {
true => brush_flags | BrushFlags::NORMALIZED_UVS,
false => brush_flags,
};
self.add_segmented_prim_to_batch(
segments,
common_data.opacity,

View File

@@ -123,6 +123,21 @@ pub struct BlurInstance {
pub struct ScalingInstance {
pub target_rect: DeviceRect,
pub source_rect: DeviceRect,
source_rect_type: f32,
}
impl ScalingInstance {
pub fn new(target_rect: DeviceRect, source_rect: DeviceRect, source_rect_normalized: bool) -> Self {
let source_rect_type = match source_rect_normalized {
true => UV_TYPE_NORMALIZED,
false => UV_TYPE_UNNORMALIZED,
};
Self {
target_rect,
source_rect,
source_rect_type: pack_as_float(source_rect_type),
}
}
}
#[derive(Clone, Debug)]
@@ -239,9 +254,10 @@ pub struct PrimitiveInstanceData {
data: [i32; 4],
}
/// Specifies that an RGB CompositeInstance's UV coordinates are normalized.
// Keep these in sync with the correspondong #defines in shared.glsl
/// Specifies that an RGB CompositeInstance or ScalingInstance's UV coordinates are normalized.
const UV_TYPE_NORMALIZED: u32 = 0;
/// Specifies that an RGB CompositeInstance's UV coordinates are not normalized.
/// Specifies that an RGB CompositeInstance or ScalingInstance's UV coordinates are not normalized.
const UV_TYPE_UNNORMALIZED: u32 = 1;
/// A GPU-friendly representation of the `ScaleOffset` type
@@ -318,14 +334,19 @@ impl CompositeInstance {
clip_rect: DeviceRect,
color: PremultipliedColorF,
uv_rect: TexelRect,
normalized_uvs: bool,
flip: (bool, bool),
) -> Self {
let uv_type = match normalized_uvs {
true => UV_TYPE_NORMALIZED,
false => UV_TYPE_UNNORMALIZED,
};
CompositeInstance {
rect,
clip_rect,
color,
_padding: 0.0,
color_space_or_uv_type: pack_as_float(UV_TYPE_UNNORMALIZED),
color_space_or_uv_type: pack_as_float(uv_type),
yuv_format: 0.0,
yuv_channel_bit_depth: 0.0,
uv_rects: [uv_rect, uv_rect, uv_rect],
@@ -640,6 +661,8 @@ bitflags! {
/// Whether to force the anti-aliasing when the primitive
/// is axis-aligned.
const FORCE_AA = 1024;
/// Specifies UV coordinates are normalized
const NORMALIZED_UVS = 2048;
}
}

View File

@@ -16,7 +16,7 @@ use crate::prim_store::DeferredResolve;
use crate::renderer::BLOCKS_PER_UV_RECT;
use crate::render_task_cache::RenderTaskCacheEntryHandle;
use crate::resource_cache::{ResourceCache, ImageRequest, CacheItem};
use crate::internal_types::{TextureSource, DeferredResolveIndex};
use crate::internal_types::{TextureSource, TextureSourceExternal, DeferredResolveIndex};
/// Resolve a resource cache's imagre request into a texture cache item.
pub fn resolve_image(
@@ -50,7 +50,11 @@ pub fn resolve_image(
};
let cache_item = CacheItem {
texture_id: TextureSource::External(deferred_resolve_index, image_buffer_kind),
texture_id: TextureSource::External(TextureSourceExternal {
index: deferred_resolve_index,
kind: image_buffer_kind,
normalized_uvs: external_image.normalized_uvs,
}),
uv_rect_handle: cache_handle,
uv_rect: DeviceIntRect::from_size(
image_properties.descriptor.size,

View File

@@ -1015,6 +1015,15 @@ impl CacheTextureId {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct DeferredResolveIndex(pub u32);
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct TextureSourceExternal {
pub index: DeferredResolveIndex,
pub kind: ImageBufferKind,
pub normalized_uvs: bool,
}
/// Identifies the source of an input texture to a shader.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "capture", derive(Serialize))]
@@ -1025,7 +1034,7 @@ pub enum TextureSource {
/// An entry in the texture cache.
TextureCache(CacheTextureId, Swizzle),
/// An external image texture, mananged by the embedding.
External(DeferredResolveIndex, ImageBufferKind),
External(TextureSourceExternal),
/// Select a dummy 1x1 white texture. This can be used by image
/// shaders that want to draw a solid color.
Dummy,
@@ -1036,7 +1045,7 @@ impl TextureSource {
match *self {
TextureSource::TextureCache(..) => ImageBufferKind::Texture2D,
TextureSource::External(_, image_buffer_kind) => image_buffer_kind,
TextureSource::External(TextureSourceExternal { kind, .. }) => kind,
// Render tasks use texture arrays for now.
TextureSource::Dummy => ImageBufferKind::Texture2D,
@@ -1045,6 +1054,13 @@ impl TextureSource {
}
}
pub fn uses_normalized_uvs(&self) -> bool {
match *self {
TextureSource::External(TextureSourceExternal { normalized_uvs, .. }) => normalized_uvs,
_ => false,
}
}
#[inline]
pub fn is_compatible(
&self,

View File

@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{
AlphaType, ColorDepth, ColorF, ColorU, ExternalImageData, ExternalImageType,
AlphaType, ColorDepth, ColorF, ColorU, ExternalImageType,
ImageKey as ApiImageKey, ImageBufferKind, ImageRendering, PremultipliedColorF,
RasterSpace, Shadow, YuvColorSpace, ColorRange, YuvFormat,
};
@@ -71,6 +71,7 @@ pub struct ImageInstance {
pub tight_local_clip_rect: LayoutRect,
pub visible_tiles: Vec<VisibleImageTile>,
pub src_color: Option<RenderTaskId>,
pub normalized_uvs: bool,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
@@ -176,31 +177,26 @@ impl ImageData {
frame_state.gpu_cache,
);
let orig_task_id = frame_state.rg_builder.add().init(
let mut task_id = frame_state.rg_builder.add().init(
RenderTask::new_image(size, request)
);
if let Some(external_image) = external_image {
// On some devices we cannot render from an ImageBufferKind::TextureExternal
// source using most shaders, so must peform a copy to a regular texture first.
let task_id = if frame_context.fb_config.external_images_require_copy
&& matches!(
external_image,
Some(ExternalImageData {
image_type: ExternalImageType::TextureHandle(
ImageBufferKind::TextureExternal
),
..
})
)
{
let requires_copy = frame_context.fb_config.external_images_require_copy &&
external_image.image_type ==
ExternalImageType::TextureHandle(ImageBufferKind::TextureExternal);
if requires_copy {
let target_kind = if descriptor.format.bytes_per_pixel() == 1 {
RenderTargetKind::Alpha
} else {
RenderTargetKind::Color
};
let task_id = RenderTask::new_scaling(
orig_task_id,
task_id = RenderTask::new_scaling(
task_id,
frame_state.rg_builder,
target_kind,
size
@@ -210,11 +206,15 @@ impl ImageData {
task_id,
frame_state.rg_builder,
);
}
task_id
} else {
orig_task_id
};
// Ensure the instance is rendered using normalized_uvs if the external image
// requires so. If we inserted a scale above this is not required as the
// instance is rendered from a render task rather than the external image.
if !requires_copy {
image_instance.normalized_uvs = external_image.normalized_uvs;
}
}
// Every frame, for cached items, we need to request the render
// task cache item. The closure will be invoked on the first
@@ -449,6 +449,7 @@ impl InternablePrimitive for Image {
tight_local_clip_rect: LayoutRect::zero(),
visible_tiles: Vec::new(),
src_color: None,
normalized_uvs: false,
});
PrimitiveInstanceKind::Image {

View File

@@ -874,10 +874,11 @@ fn add_scaling_instances(
instances
.entry(source)
.or_insert(Vec::new())
.push(ScalingInstance {
.push(ScalingInstance::new(
target_rect,
source_rect,
});
source.uses_normalized_uvs(),
));
}
fn add_svg_filter_instances(

View File

@@ -71,7 +71,7 @@ use crate::gpu_cache::{GpuCacheUpdate, GpuCacheUpdateList};
use crate::gpu_cache::{GpuCacheDebugChunk, GpuCacheDebugCmd};
use crate::gpu_types::{ScalingInstance, SvgFilterInstance, SVGFEFilterInstance, CopyInstance, PrimitiveInstanceData};
use crate::gpu_types::{BlurInstance, ClearInstance, CompositeInstance};
use crate::internal_types::{TextureSource, TextureCacheCategory, FrameId};
use crate::internal_types::{TextureSource, TextureSourceExternal, TextureCacheCategory, FrameId};
#[cfg(any(feature = "capture", feature = "replay"))]
use crate::internal_types::DebugOutput;
use crate::internal_types::{CacheTextureId, FastHashMap, FastHashSet, RenderedDocument, ResultMsg};
@@ -533,7 +533,7 @@ impl TextureResolver {
device.bind_texture(sampler, &self.dummy_cache_texture, swizzle);
swizzle
}
TextureSource::External(ref index, _) => {
TextureSource::External(TextureSourceExternal { ref index, .. }) => {
let texture = self.external_images
.get(index)
.expect("BUG: External image should be resolved by now");
@@ -574,7 +574,7 @@ impl TextureResolver {
default_value: TexelRect,
) -> TexelRect {
match source {
TextureSource::External(ref index, _) => {
TextureSource::External(TextureSourceExternal { ref index, .. }) => {
let texture = self.external_images
.get(index)
.expect("BUG: External image should be resolved by now");
@@ -593,7 +593,11 @@ impl TextureResolver {
TextureSource::TextureCache(id, _) => {
self.texture_cache_map[&id].texture.get_dimensions()
},
TextureSource::External(index, _) => {
TextureSource::External(TextureSourceExternal { index, .. }) => {
// If UV coords are normalized then this value will be incorrect. However, the
// texture size is currently only used to set the uTextureSize uniform, so that
// shaders without access to textureSize() can normalize unnormalized UVs. Which
// means this is not a problem.
let uv_rect = self.external_images[&index].get_uv_rect();
(uv_rect.uv1 - uv_rect.uv0).abs().to_size().to_i32()
},
@@ -623,6 +627,8 @@ impl TextureResolver {
let mut external_image_bytes = 0;
for img in self.external_images.values() {
let uv_rect = img.get_uv_rect();
// If UV coords are normalized then this value will be incorrect. This is unfortunate
// but doesn't impact end users at all.
let size = (uv_rect.uv1 - uv_rect.uv0).abs().to_size().to_i32();
// Assume 4 bytes per pixels which is true most of the time but
@@ -2475,14 +2481,13 @@ impl Renderer {
let instances = match source {
TextureSource::External(..) => {
uv_override_instances = instances.iter().map(|instance| {
let mut new_instance = instance.clone();
let texel_rect: TexelRect = self.texture_resolver.get_uv_rect(
&source,
instance.source_rect.cast().into()
).into();
ScalingInstance {
target_rect: instance.target_rect,
source_rect: DeviceRect::new(texel_rect.uv0, texel_rect.uv1),
}
new_instance.source_rect = DeviceRect::new(texel_rect.uv0, texel_rect.uv1);
new_instance
}).collect::<Vec<_>>();
&uv_override_instances
}
@@ -3083,6 +3088,7 @@ impl Renderer {
surface_rect.to_f32(),
PremultipliedColorF::WHITE,
uv_rect,
plane.texture.uses_normalized_uvs(),
(false, false),
);
@@ -3231,6 +3237,7 @@ impl Renderer {
clip_rect,
PremultipliedColorF::WHITE,
uv_rect,
plane.texture.uses_normalized_uvs(),
flip,
);
let features = instance.get_rgb_features();
@@ -5729,7 +5736,7 @@ impl Renderer {
.expect("Unable to lock the external image handler!");
for def in &deferred_images {
info!("\t{}", def.short_path);
let ExternalImageData { id, channel_index, image_type } = def.external;
let ExternalImageData { id, channel_index, image_type, .. } = def.external;
// The image rendering parameter is irrelevant because no filtering happens during capturing.
let ext_image = handler.lock(id, channel_index);
let (data, short_path) = match ext_image.source {

View File

@@ -346,6 +346,11 @@ pub mod desc {
count: 4,
kind: VertexAttributeKind::F32,
},
VertexAttribute {
name: "aSourceRectType",
count: 1,
kind: VertexAttributeKind::F32,
},
],
};

View File

@@ -74,8 +74,9 @@ pub enum ExternalImageSource<'a> {
/// The data that an external client should provide about
/// an external image. For instance, if providing video frames,
/// the application could call wr.render() whenever a new
/// video frame is ready. Note that the UV coords are supplied
/// in texel-space!
/// video frame is ready. Note that the UV coords are either normalized or
/// unnormalized depending on the value of normalized_uvs in the corresponding
/// ExternalImageData.
pub struct ExternalImage<'a> {
/// UV coordinates for the image.
pub uv: TexelRect,
@@ -144,6 +145,8 @@ pub struct ExternalImageData {
pub channel_index: u8,
/// Storage format identifier.
pub image_type: ExternalImageType,
/// Whether UV coordinates used with this image are normalized.
pub normalized_uvs: bool,
}
/// Specifies the format of a series of pixels, in driver terms.

View File

@@ -142,7 +142,8 @@ impl LocalExternalImageHandler {
ExternalImageData {
id: image_id,
channel_index: channel_idx,
image_type: ExternalImageType::TextureHandle(target)
image_type: ExternalImageType::TextureHandle(target),
normalized_uvs: false,
}
)
}