зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1521656 - WR switch image UV quad coordinates into homogeneous space r=gw
For screen-space rasterized images, we provide the shader with the UV corners of an image. The shaders then interpolate between the corners as an intermediate step of finding their UV to assign to a vertex. When the transformation is perspective, the corners stop being representative in real screen space, and the old code didn't handle the case of a corner being out of the positive hemisphere. This change doesn't do perspective division on Rust side and defers this to the shader, which can do division *after* interpolation between corners. This change makes us handle the near plane better and resolves clipping problems with perspective-interpolated images that occured due to precision issues of perspective divided corners. Differential Revision: https://phabricator.services.mozilla.com/D18123 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
359dd0e426
Коммит
5a351be647
|
@ -37,10 +37,7 @@ void brush_vs(
|
|||
// PictureTask src_task = fetch_picture_task(user_data.x);
|
||||
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
|
||||
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
|
||||
ImageResourceExtra extra_data = fetch_image_resource_extra(user_data.x);
|
||||
vec2 x = mix(extra_data.st_tl, extra_data.st_tr, f.x);
|
||||
vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x);
|
||||
f = mix(x, y, f.y);
|
||||
f = get_image_quad_uv(user_data.x, f);
|
||||
vec2 uv = mix(uv0, uv1, f);
|
||||
float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0;
|
||||
|
||||
|
|
|
@ -131,10 +131,7 @@ void brush_vs(
|
|||
// Since the screen space UVs specify an arbitrary quad, do
|
||||
// a bilinear interpolation to get the correct UV for this
|
||||
// local position.
|
||||
ImageResourceExtra extra_data = fetch_image_resource_extra(user_data.w);
|
||||
vec2 x = mix(extra_data.st_tl, extra_data.st_tr, f.x);
|
||||
vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x);
|
||||
f = mix(x, y, f.y);
|
||||
f = get_image_quad_uv(user_data.w, f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -117,20 +117,21 @@ ImageResource fetch_image_resource_direct(ivec2 address) {
|
|||
|
||||
// Fetch optional extra data for a texture cache resource. This can contain
|
||||
// a polygon defining a UV rect within the texture cache resource.
|
||||
// Note: the polygon coordinates are in homogeneous space.
|
||||
struct ImageResourceExtra {
|
||||
vec2 st_tl;
|
||||
vec2 st_tr;
|
||||
vec2 st_bl;
|
||||
vec2 st_br;
|
||||
vec4 st_tl;
|
||||
vec4 st_tr;
|
||||
vec4 st_bl;
|
||||
vec4 st_br;
|
||||
};
|
||||
|
||||
ImageResourceExtra fetch_image_resource_extra(int address) {
|
||||
vec4 data[2] = fetch_from_gpu_cache_2(address + VECS_PER_IMAGE_RESOURCE);
|
||||
vec4 data[4] = fetch_from_gpu_cache_4(address + VECS_PER_IMAGE_RESOURCE);
|
||||
return ImageResourceExtra(
|
||||
data[0].xy,
|
||||
data[0].zw,
|
||||
data[1].xy,
|
||||
data[1].zw
|
||||
data[0],
|
||||
data[1],
|
||||
data[2],
|
||||
data[3]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -222,6 +222,16 @@ void write_clip(vec4 world_pos, vec2 snap_offset, ClipArea area) {
|
|||
);
|
||||
vClipMaskUv = vec4(uv, area.common_data.texture_layer_index, world_pos.w);
|
||||
}
|
||||
|
||||
// Read the exta image data containing the homogeneous screen space coordinates
|
||||
// of the corners, interpolate between them, and return real screen space UV.
|
||||
vec2 get_image_quad_uv(int address, vec2 f) {
|
||||
ImageResourceExtra extra_data = fetch_image_resource_extra(address);
|
||||
vec4 x = mix(extra_data.st_tl, extra_data.st_tr, f.x);
|
||||
vec4 y = mix(extra_data.st_bl, extra_data.st_br, f.x);
|
||||
vec4 z = mix(x, y, f.y);
|
||||
return z.xy / z.w;
|
||||
}
|
||||
#endif //WR_VERTEX_SHADER
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
|
|
|
@ -61,7 +61,6 @@ void main(void) {
|
|||
PictureTask dest_task = fetch_picture_task(ph.render_task_index);
|
||||
Transform transform = fetch_transform(ph.transform_id);
|
||||
ImageResource res = fetch_image_resource(ph.user_data.x);
|
||||
ImageResourceExtra extra_data = fetch_image_resource_extra(ph.user_data.x);
|
||||
ClipArea clip_area = fetch_clip_area(ph.clip_task_index);
|
||||
|
||||
vec2 dest_origin = dest_task.common_data.task_rect.p0 -
|
||||
|
@ -99,12 +98,7 @@ void main(void) {
|
|||
) / texture_size.xyxy;
|
||||
|
||||
vec2 f = (local_pos - ph.local_rect.p0) / ph.local_rect.size;
|
||||
|
||||
f = bilerp(
|
||||
extra_data.st_tl, extra_data.st_tr,
|
||||
extra_data.st_bl, extra_data.st_br,
|
||||
f.y, f.x
|
||||
);
|
||||
f = get_image_quad_uv(ph.user_data.x, f);
|
||||
vec2 uv = mix(uv0, uv1, f);
|
||||
float perspective_interpolate = float(ph.user_data.y);
|
||||
|
||||
|
|
|
@ -1260,7 +1260,7 @@ impl Device {
|
|||
#[cfg(debug_assertions)]
|
||||
fn print_shader_errors(source: &str, log: &str) {
|
||||
// hacky way to extract the offending lines
|
||||
if !log.starts_with("0:") {
|
||||
if !log.starts_with("0:") && !log.starts_with("0(") {
|
||||
return;
|
||||
}
|
||||
let end_pos = match log[2..].chars().position(|c| !c.is_digit(10)) {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
//! for this frame.
|
||||
|
||||
use api::{DebugFlags, DocumentId, PremultipliedColorF, IdNamespace, TexelRect};
|
||||
use euclid::TypedRect;
|
||||
use euclid::{HomogeneousVector, TypedRect};
|
||||
use internal_types::{FastHashMap};
|
||||
use profiler::GpuCacheProfileCounters;
|
||||
use render_backend::{FrameStamp, FrameId};
|
||||
|
@ -112,6 +112,19 @@ impl<P> From<TypedRect<f32, P>> for GpuBlockData {
|
|||
}
|
||||
}
|
||||
|
||||
impl<P> From<HomogeneousVector<f32, P>> for GpuBlockData {
|
||||
fn from(v: HomogeneousVector<f32, P>) -> Self {
|
||||
GpuBlockData {
|
||||
data: [
|
||||
v.x,
|
||||
v.y,
|
||||
v.z,
|
||||
v.w,
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TexelRect> for GpuBlockData {
|
||||
fn from(tr: TexelRect) -> Self {
|
||||
GpuBlockData {
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{
|
||||
DevicePoint, DeviceSize, DeviceRect, LayoutRect, LayoutToWorldTransform, LayoutTransform,
|
||||
DeviceHomogeneousVector, DevicePoint, DeviceSize, DeviceRect,
|
||||
LayoutRect, LayoutToWorldTransform, LayoutTransform,
|
||||
PremultipliedColorF, LayoutToPictureTransform, PictureToLayoutTransform, PicturePixel,
|
||||
WorldPixel, WorldToLayoutTransform, LayoutPoint,
|
||||
};
|
||||
|
@ -565,10 +566,10 @@ pub enum UvRectKind {
|
|||
// use a bilerp() to correctly interpolate a
|
||||
// UV coord in the vertex shader.
|
||||
Quad {
|
||||
top_left: DevicePoint,
|
||||
top_right: DevicePoint,
|
||||
bottom_left: DevicePoint,
|
||||
bottom_right: DevicePoint,
|
||||
top_left: DeviceHomogeneousVector,
|
||||
top_right: DeviceHomogeneousVector,
|
||||
bottom_left: DeviceHomogeneousVector,
|
||||
bottom_right: DeviceHomogeneousVector,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -585,6 +586,8 @@ pub struct ImageSource {
|
|||
|
||||
impl ImageSource {
|
||||
pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
|
||||
// see fetch_image_resource in GLSL
|
||||
// has to be VECS_PER_IMAGE_RESOURCE vectors
|
||||
request.push([
|
||||
self.p0.x,
|
||||
self.p0.y,
|
||||
|
@ -600,19 +603,12 @@ impl ImageSource {
|
|||
|
||||
// If this is a polygon uv kind, then upload the four vertices.
|
||||
if let UvRectKind::Quad { top_left, top_right, bottom_left, bottom_right } = self.uv_rect_kind {
|
||||
request.push([
|
||||
top_left.x,
|
||||
top_left.y,
|
||||
top_right.x,
|
||||
top_right.y,
|
||||
]);
|
||||
|
||||
request.push([
|
||||
bottom_left.x,
|
||||
bottom_left.y,
|
||||
bottom_right.x,
|
||||
bottom_right.y,
|
||||
]);
|
||||
// see fetch_image_resource_extra in GLSL
|
||||
//Note: we really need only 3 components per point here: X, Y, and W
|
||||
request.push(top_left);
|
||||
request.push(top_right);
|
||||
request.push(bottom_left);
|
||||
request.push(bottom_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@ use api::{DeviceIntRect, DeviceIntSize, DevicePoint, DeviceRect};
|
|||
use api::{LayoutRect, PictureToRasterTransform, LayoutPixel, PropertyBinding, PropertyBindingId};
|
||||
use api::{DevicePixelScale, RasterRect, RasterSpace, ColorF, ImageKey, DirtyRect, WorldSize, ClipMode, LayoutSize};
|
||||
use api::{PicturePixel, RasterPixel, WorldPixel, WorldRect, ImageFormat, ImageDescriptor, WorldVector2D, LayoutPoint};
|
||||
use api::{DebugFlags, DeviceVector2D};
|
||||
use api::{DebugFlags, DeviceHomogeneousVector, DeviceVector2D};
|
||||
use box_shadow::{BLUR_SAMPLE_SCALE};
|
||||
use clip::{ClipChainId, ClipChainNode, ClipItem};
|
||||
use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex, CoordinateSystemId};
|
||||
use debug_colors;
|
||||
use device::TextureFilter;
|
||||
use euclid::{size2, TypedScale, vec3, TypedRect, TypedPoint2D, TypedSize2D};
|
||||
use euclid::{size2, vec3, TypedRect, TypedPoint2D, TypedSize2D};
|
||||
use euclid::approxeq::ApproxEq;
|
||||
use frame_builder::{FrameVisibilityContext, FrameVisibilityState};
|
||||
use intern::ItemUid;
|
||||
|
@ -2942,38 +2942,38 @@ impl PicturePrimitive {
|
|||
}
|
||||
}
|
||||
|
||||
// Calculate a single screen-space UV for a picture.
|
||||
// Calculate a single homogeneous screen-space UV for a picture.
|
||||
fn calculate_screen_uv(
|
||||
local_pos: &PicturePoint,
|
||||
transform: &PictureToRasterTransform,
|
||||
rendered_rect: &DeviceRect,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
supports_snapping: bool,
|
||||
) -> DevicePoint {
|
||||
let raster_pos = match transform.transform_point2d(local_pos) {
|
||||
Some(pos) => pos,
|
||||
None => {
|
||||
//Warning: this is incorrect and needs to be fixed properly.
|
||||
// The transformation has put a local vertex behind the near clipping plane...
|
||||
// Proper solution would be to keep the near-clipping-plane results around
|
||||
// (currently produced by calculate_screen_bounding_rect) and use them here.
|
||||
return DevicePoint::new(0.5, 0.5);
|
||||
}
|
||||
};
|
||||
) -> DeviceHomogeneousVector {
|
||||
let raster_pos = transform.transform_point2d_homogeneous(local_pos);
|
||||
|
||||
let raster_to_device_space = TypedScale::new(1.0) * device_pixel_scale;
|
||||
|
||||
let mut device_pos = raster_pos * raster_to_device_space;
|
||||
let mut device_vec = DeviceHomogeneousVector::new(
|
||||
raster_pos.x * device_pixel_scale.0,
|
||||
raster_pos.y * device_pixel_scale.0,
|
||||
0.0,
|
||||
raster_pos.w,
|
||||
);
|
||||
|
||||
// Apply snapping for axis-aligned scroll nodes, as per prim_shared.glsl.
|
||||
if transform.transform_kind() == TransformedRectKind::AxisAligned && supports_snapping {
|
||||
device_pos.x = (device_pos.x + 0.5).floor();
|
||||
device_pos.y = (device_pos.y + 0.5).floor();
|
||||
device_vec = DeviceHomogeneousVector::new(
|
||||
(device_vec.x / device_vec.w + 0.5).floor(),
|
||||
(device_vec.y / device_vec.w + 0.5).floor(),
|
||||
0.0,
|
||||
1.0,
|
||||
);
|
||||
}
|
||||
|
||||
DevicePoint::new(
|
||||
(device_pos.x - rendered_rect.origin.x) / rendered_rect.size.width,
|
||||
(device_pos.y - rendered_rect.origin.y) / rendered_rect.size.height,
|
||||
DeviceHomogeneousVector::new(
|
||||
(device_vec.x - rendered_rect.origin.x * device_vec.w) / rendered_rect.size.width,
|
||||
(device_vec.y - rendered_rect.origin.y * device_vec.w) / rendered_rect.size.height,
|
||||
0.0,
|
||||
device_vec.w,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
use app_units::Au;
|
||||
use euclid::{Length, TypedRect, TypedScale, TypedSize2D, TypedTransform3D, TypedTranslation2D};
|
||||
use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D, TypedSideOffsets2D};
|
||||
use euclid::HomogeneousVector;
|
||||
use DirtyRect;
|
||||
|
||||
/// Geometry in the coordinate system of the render target (screen or intermediate
|
||||
|
@ -32,6 +33,7 @@ pub type DeviceRect = TypedRect<f32, DevicePixel>;
|
|||
pub type DevicePoint = TypedPoint2D<f32, DevicePixel>;
|
||||
pub type DeviceVector2D = TypedVector2D<f32, DevicePixel>;
|
||||
pub type DeviceSize = TypedSize2D<f32, DevicePixel>;
|
||||
pub type DeviceHomogeneousVector = HomogeneousVector<f32, DevicePixel>;
|
||||
|
||||
/// Geometry in the coordinate system of a Picture (intermediate
|
||||
/// surface) in physical pixels.
|
||||
|
|
Загрузка…
Ссылка в новой задаче