Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for radial gradients #734

Merged
merged 2 commits into from Jan 19, 2017
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -31,6 +31,7 @@
#define UV_PIXEL uint(1)

#define MAX_STOPS_PER_ANGLE_GRADIENT 8
#define MAX_STOPS_PER_RADIAL_GRADIENT 8

uniform sampler2DArray sCache;

@@ -215,6 +216,22 @@ GradientStop fetch_gradient_stop(int index) {
return stop;
}

struct RadialGradient {
vec4 start_end_center;
vec4 start_end_radius;
};

RadialGradient fetch_radial_gradient(int index) {
RadialGradient gradient;

ivec2 uv = get_fetch_uv_2(index);

gradient.start_end_center = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
gradient.start_end_radius = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));

return gradient;
}

struct Glyph {
vec4 offset;
};
@@ -0,0 +1,67 @@
/* 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/. */

float offset(int index) {
return vOffsets[index / 4][index % 4];
}

float linearStep(float lo, float hi, float x) {
float d = hi - lo;
float v = x - lo;
if (d != 0.0) {
v /= d;
}
return clamp(v, 0.0, 1.0);
}

void main(void) {
vec2 cd = vEndCenter - vStartCenter;
vec2 pd = vPos - vStartCenter;
float rd = vEndRadius - vStartRadius;

// Solve for t in length(t * cd - pd) = vStartRadius + t * rd
// using a quadratic equation in form of At^2 - 2Bt + C = 0
float A = dot(cd, cd) - rd * rd;
float B = dot(pd, cd) + vStartRadius * rd;
float C = dot(pd, pd) - vStartRadius * vStartRadius;

float x;
if (A == 0.0) {
// Since A is 0, just solve for -2Bt + C = 0
if (B == 0.0) {
discard;
}
float t = 0.5 * C / B;
if (vStartRadius + rd * t >= 0.0) {
x = t;
} else {
discard;
}
} else {
float discr = B * B - A * C;
if (discr < 0.0) {
discard;
}
discr = sqrt(discr);
float t0 = (B + discr) / A;
float t1 = (B - discr) / A;
if (vStartRadius + rd * t0 >= 0.0) {
x = t0;
} else if (vStartRadius + rd * t1 >= 0.0) {
x = t1;
} else {
discard;
}
}

oFragColor = mix(vColors[0],

This comment has been minimized.

@kvark

kvark Jan 20, 2017

Member

Can the radial gradient be masked? I think we are missing a mask fetch here.

vColors[1],
linearStep(offset(0), offset(1), x));

for (int i=1 ; i < vStopCount-1 ; ++i) {
oFragColor = mix(oFragColor,
vColors[i+1],
linearStep(offset(i), offset(i+1), x));
}
}
@@ -0,0 +1,12 @@
/* 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/. */

flat varying int vStopCount;
flat varying vec2 vStartCenter;
flat varying vec2 vEndCenter;
flat varying float vStartRadius;
flat varying float vEndRadius;
varying vec2 vPos;
flat varying vec4 vColors[MAX_STOPS_PER_RADIAL_GRADIENT];
flat varying vec4 vOffsets[MAX_STOPS_PER_RADIAL_GRADIENT/4];
@@ -0,0 +1,35 @@
#line 1
/* 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/. */

void main(void) {
Primitive prim = load_primitive();
RadialGradient gradient = fetch_radial_gradient(prim.prim_index);

VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
prim.tile);

vStopCount = int(prim.user_data.x);
vPos = vi.local_clamped_pos;

// Snap the start/end points to device pixel units.
// I'm not sure this is entirely correct, but the
// old render path does this, and it is needed to
// make the angle gradient ref tests pass. It might
// be better to fix this higher up in DL construction
// and not snap here?
vStartCenter = floor(0.5 + gradient.start_end_center.xy * uDevicePixelRatio) / uDevicePixelRatio;
vEndCenter = floor(0.5 + gradient.start_end_center.zw * uDevicePixelRatio) / uDevicePixelRatio;
vStartRadius = gradient.start_end_radius.x;
vEndRadius = gradient.start_end_radius.y;

for (int i=0 ; i < vStopCount ; ++i) {
GradientStop stop = fetch_gradient_stop(prim.sub_index + i);
vColors[i] = stop.color;
vOffsets[i/4][i%4] = stop.offset.x;
}
}
@@ -866,6 +866,15 @@ impl Frame {
info.end_point,
info.stops);
}
SpecificDisplayItem::RadialGradient(ref info) => {
context.builder.add_radial_gradient(item.rect,
&item.clip,
info.start_center,
info.start_radius,
info.end_center,
info.end_radius,
info.stops);
}
SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
context.builder.add_box_shadow(&box_shadow_info.box_bounds,
&item.clip,
@@ -76,6 +76,7 @@ pub enum PrimitiveKind {
YuvImage,
Border,
Gradient,
RadialGradient,
BoxShadow,
}

@@ -248,6 +249,22 @@ pub struct GradientPrimitiveCpu {
pub cache_dirty: bool,
}

#[derive(Debug, Clone)]
#[repr(C)]
pub struct RadialGradientPrimitiveGpu {
pub start_center: LayerPoint,
pub end_center: LayerPoint,
pub start_radius: f32,
pub end_radius: f32,
pub padding: [f32; 2],
}

#[derive(Debug)]
pub struct RadialGradientPrimitiveCpu {
pub stops_range: ItemRange,
pub cache_dirty: bool,
}

#[derive(Debug, Clone)]
#[repr(C)]
struct InstanceRect {
@@ -412,6 +429,7 @@ pub enum PrimitiveContainer {
YuvImage(YuvImagePrimitiveCpu, YuvImagePrimitiveGpu),
Border(BorderPrimitiveCpu, BorderPrimitiveGpu),
Gradient(GradientPrimitiveCpu, GradientPrimitiveGpu),
RadialGradient(RadialGradientPrimitiveCpu, RadialGradientPrimitiveGpu),
BoxShadow(BoxShadowPrimitiveGpu, Vec<LayerRect>),
}

@@ -422,6 +440,7 @@ pub struct PrimitiveStore {
pub cpu_images: Vec<ImagePrimitiveCpu>,
pub cpu_yuv_images: Vec<YuvImagePrimitiveCpu>,
pub cpu_gradients: Vec<GradientPrimitiveCpu>,
pub cpu_radial_gradients: Vec<RadialGradientPrimitiveCpu>,
pub cpu_metadata: Vec<PrimitiveMetadata>,
pub cpu_borders: Vec<BorderPrimitiveCpu>,

@@ -448,6 +467,7 @@ impl PrimitiveStore {
cpu_images: Vec::new(),
cpu_yuv_images: Vec::new(),
cpu_gradients: Vec::new(),
cpu_radial_gradients: Vec::new(),
cpu_borders: Vec::new(),
gpu_geometry: GpuStore::new(),
gpu_data16: GpuStore::new(),
@@ -596,6 +616,26 @@ impl PrimitiveStore {
self.cpu_gradients.push(gradient_cpu);
metadata
}
PrimitiveContainer::RadialGradient(radial_gradient_cpu, radial_gradient_gpu) => {
let gpu_address = self.gpu_data32.push(radial_gradient_gpu);
let gpu_stops_address = self.gpu_data32.alloc(radial_gradient_cpu.stops_range.length);

let metadata = PrimitiveMetadata {
is_opaque: false,
clip_source: clip_source,
clip_cache_info: clip_info,
prim_kind: PrimitiveKind::RadialGradient,
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_radial_gradients.len()),
gpu_prim_index: gpu_address,
gpu_data_address: gpu_stops_address,
gpu_data_count: radial_gradient_cpu.stops_range.length as i32,
render_task: None,
clip_task: None,
};

self.cpu_radial_gradients.push(radial_gradient_cpu);
metadata
}
PrimitiveContainer::BoxShadow(box_shadow_gpu, instance_rects) => {
let cache_key = PrimitiveCacheKey::BoxShadow(BoxShadowPrimitiveCacheKey {
blur_radius: Au::from_f32_px(box_shadow_gpu.blur_radius),
@@ -689,7 +729,8 @@ impl PrimitiveStore {
PrimitiveKind::Rectangle |
PrimitiveKind::Border |
PrimitiveKind::BoxShadow |
PrimitiveKind::Gradient => {}
PrimitiveKind::Gradient |
PrimitiveKind::RadialGradient=> {}
PrimitiveKind::TextRun => {
let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
let font_size_dp = text.logical_font_size.scale_by(device_pixel_ratio);
@@ -1018,6 +1059,26 @@ impl PrimitiveStore {
}
}

gradient.cache_dirty = false;
}
}
PrimitiveKind::RadialGradient => {
let gradient = &mut self.cpu_radial_gradients[metadata.cpu_prim_index.0];
if gradient.cache_dirty {
let src_stops = auxiliary_lists.gradient_stops(&gradient.stops_range);

debug_assert!(metadata.gpu_data_count == gradient.stops_range.length as i32);
let dest_stops = self.gpu_data32.get_slice_mut(metadata.gpu_data_address,
gradient.stops_range.length);

for (src, dest) in src_stops.iter().zip(dest_stops.iter_mut()) {
*dest = GpuBlock32::from(GradientStop {
offset: src.offset,
color: src.color,
padding: [0.0; 3],
});
}

gradient.cache_dirty = false;
}
}
@@ -1115,6 +1176,14 @@ impl From<GradientStop> for GpuBlock32 {
}
}

impl From<RadialGradientPrimitiveGpu> for GpuBlock32 {
fn from(data: RadialGradientPrimitiveGpu) -> GpuBlock32 {
unsafe {
mem::transmute::<RadialGradientPrimitiveGpu, GpuBlock32>(data)
}
}
}

impl From<YuvImagePrimitiveGpu> for GpuBlock64 {
fn from(data: YuvImagePrimitiveGpu) -> GpuBlock64 {
unsafe {
@@ -57,6 +57,7 @@ const GPU_TAG_PRIM_COMPOSITE: GpuProfileTag = GpuProfileTag { label: "Composite"
const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag { label: "TextRun", color: debug_colors::BLUE };
const GPU_TAG_PRIM_GRADIENT: GpuProfileTag = GpuProfileTag { label: "Gradient", color: debug_colors::YELLOW };
const GPU_TAG_PRIM_ANGLE_GRADIENT: GpuProfileTag = GpuProfileTag { label: "AngleGradient", color: debug_colors::POWDERBLUE };
const GPU_TAG_PRIM_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag { label: "RadialGradient", color: debug_colors::LIGHTPINK };
const GPU_TAG_PRIM_BOX_SHADOW: GpuProfileTag = GpuProfileTag { label: "BoxShadow", color: debug_colors::CYAN };
const GPU_TAG_PRIM_BORDER: GpuProfileTag = GpuProfileTag { label: "Border", color: debug_colors::ORANGE };
const GPU_TAG_PRIM_CACHE_IMAGE: GpuProfileTag = GpuProfileTag { label: "CacheImage", color: debug_colors::SILVER };
@@ -307,6 +308,7 @@ pub struct Renderer {
ps_border: PrimitiveShader,
ps_gradient: PrimitiveShader,
ps_angle_gradient: PrimitiveShader,
ps_radial_gradient: PrimitiveShader,
ps_box_shadow: PrimitiveShader,
ps_cache_image: PrimitiveShader,

@@ -473,6 +475,10 @@ impl Renderer {
&mut device,
&[],
options.precache_shaders);
let ps_radial_gradient = PrimitiveShader::new("ps_radial_gradient",
&mut device,
&[],
options.precache_shaders);
let ps_cache_image = PrimitiveShader::new("ps_cache_image",
&mut device,
&[],
@@ -625,6 +631,7 @@ impl Renderer {
ps_box_shadow: ps_box_shadow,
ps_gradient: ps_gradient,
ps_angle_gradient: ps_angle_gradient,
ps_radial_gradient: ps_radial_gradient,
ps_cache_image: ps_cache_image,
ps_blend: ps_blend,
ps_composite: ps_composite,
@@ -1010,6 +1017,10 @@ impl Renderer {
let shader = self.ps_angle_gradient.get(&mut self.device, transform_kind);
(data, GPU_TAG_PRIM_ANGLE_GRADIENT, shader)
}
&PrimitiveBatchData::RadialGradient(ref data) => {
let shader = self.ps_radial_gradient.get(&mut self.device, transform_kind);
(data, GPU_TAG_PRIM_RADIAL_GRADIENT, shader)
}
};

let _gm = self.gpu_profile.add_marker(marker);
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.