use api::{AlphaType, PremultipliedColorF, YuvFormat, YuvRangedColorSpace};
use api::units::*;
use crate::composite::CompositeFeatures;
use crate::segment::EdgeAaSegmentMask;
use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
use crate::gpu_cache::{GpuCacheAddress, GpuDataRequest};
use crate::internal_types::FastHashMap;
use crate::prim_store::ClipData;
use crate::render_task::RenderTaskAddress;
use crate::render_task_graph::RenderTaskId;
use crate::renderer::{ShaderColorMode, GpuBufferAddress};
use std::i32;
use crate::util::{TransformedRectKind, MatrixHelpers};
use glyph_rasterizer::SubpixelDirection;
use crate::util::{ScaleOffset, pack_as_float};
pub const VECS_PER_TRANSFORM: usize = 8;
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ZBufferId(pub i32);
impl ZBufferId {
pub fn invalid() -> Self {
ZBufferId(i32::MAX)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ZBufferIdGenerator {
next: i32,
max_depth_ids: i32,
}
impl ZBufferIdGenerator {
pub fn new(max_depth_ids: i32) -> Self {
ZBufferIdGenerator {
next: 0,
max_depth_ids,
}
}
pub fn next(&mut self) -> ZBufferId {
debug_assert!(self.next < self.max_depth_ids);
let id = ZBufferId(self.next);
self.next += 1;
id
}
}
#[derive(Clone, Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CopyInstance {
pub src_rect: DeviceRect,
pub dst_rect: DeviceRect,
pub dst_texture_size: DeviceSize,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub enum RasterizationSpace {
Local = 0,
Screen = 1,
}
#[derive(Debug, Copy, Clone, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub enum BoxShadowStretchMode {
Stretch = 0,
Simple = 1,
}
#[repr(i32)]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BlurDirection {
Horizontal = 0,
Vertical,
}
impl BlurDirection {
pub fn as_int(self) -> i32 {
match self {
BlurDirection::Horizontal => 0,
BlurDirection::Vertical => 1,
}
}
}
#[derive(Clone, Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BlurInstance {
pub task_address: RenderTaskAddress,
pub src_task_address: RenderTaskAddress,
pub blur_direction: i32,
pub blur_std_deviation: f32,
pub blur_region: DeviceSize,
}
#[derive(Clone, Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ScalingInstance {
pub target_rect: DeviceRect,
pub source_rect: DeviceRect,
}
#[derive(Clone, Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct SvgFilterInstance {
pub task_address: RenderTaskAddress,
pub input_1_task_address: RenderTaskAddress,
pub input_2_task_address: RenderTaskAddress,
pub kind: u16,
pub input_count: u16,
pub generic_int: u16,
pub padding: u16,
pub extra_data_address: GpuCacheAddress,
}
#[derive(Clone, Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct SVGFEFilterInstance {
pub target_rect: DeviceRect,
pub input_1_content_scale_and_offset: [f32; 4],
pub input_2_content_scale_and_offset: [f32; 4],
pub input_1_task_address: RenderTaskAddress,
pub input_2_task_address: RenderTaskAddress,
pub kind: u16,
pub input_count: u16,
pub extra_data_address: GpuCacheAddress,
}
#[derive(Copy, Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BorderSegment {
TopLeft,
TopRight,
BottomRight,
BottomLeft,
Left,
Top,
Right,
Bottom,
}
#[derive(Debug, Clone)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BorderInstance {
pub task_origin: DevicePoint,
pub local_rect: DeviceRect,
pub color0: PremultipliedColorF,
pub color1: PremultipliedColorF,
pub flags: i32,
pub widths: DeviceSize,
pub radius: DeviceSize,
pub clip_params: [f32; 8],
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct ClipMaskInstanceCommon {
pub sub_rect: DeviceRect,
pub task_origin: DevicePoint,
pub screen_origin: DevicePoint,
pub device_pixel_scale: f32,
pub clip_transform_id: TransformPaletteId,
pub prim_transform_id: TransformPaletteId,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct ClipMaskInstanceRect {
pub common: ClipMaskInstanceCommon,
pub local_pos: LayoutPoint,
pub clip_data: ClipData,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct BoxShadowData {
pub src_rect_size: LayoutSize,
pub clip_mode: i32,
pub stretch_mode_x: i32,
pub stretch_mode_y: i32,
pub dest_rect: LayoutRect,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct ClipMaskInstanceBoxShadow {
pub common: ClipMaskInstanceCommon,
pub resource_address: GpuCacheAddress,
pub shadow_data: BoxShadowData,
}
#[repr(C)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveInstanceData {
data: [i32; 4],
}
const UV_TYPE_NORMALIZED: u32 = 0;
const UV_TYPE_UNNORMALIZED: u32 = 1;
#[derive(Clone, Debug)]
#[repr(C)]
pub struct CompositorTransform {
pub sx: f32,
pub sy: f32,
pub tx: f32,
pub ty: f32,
}
impl From<ScaleOffset> for CompositorTransform {
fn from(scale_offset: ScaleOffset) -> Self {
CompositorTransform {
sx: scale_offset.scale.x,
sy: scale_offset.scale.y,
tx: scale_offset.offset.x,
ty: scale_offset.offset.y,
}
}
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct CompositeInstance {
rect: DeviceRect,
clip_rect: DeviceRect,
color: PremultipliedColorF,
_padding: f32,
color_space_or_uv_type: f32, yuv_format: f32, yuv_channel_bit_depth: f32,
uv_rects: [TexelRect; 3],
flip: (f32, f32),
}
impl CompositeInstance {
pub fn new(
rect: DeviceRect,
clip_rect: DeviceRect,
color: PremultipliedColorF,
flip: (bool, bool),
) -> Self {
let uv = TexelRect::new(0.0, 0.0, 1.0, 1.0);
CompositeInstance {
rect,
clip_rect,
color,
_padding: 0.0,
color_space_or_uv_type: pack_as_float(UV_TYPE_NORMALIZED),
yuv_format: 0.0,
yuv_channel_bit_depth: 0.0,
uv_rects: [uv, uv, uv],
flip: (flip.0.into(), flip.1.into()),
}
}
pub fn new_rgb(
rect: DeviceRect,
clip_rect: DeviceRect,
color: PremultipliedColorF,
uv_rect: TexelRect,
flip: (bool, bool),
) -> Self {
CompositeInstance {
rect,
clip_rect,
color,
_padding: 0.0,
color_space_or_uv_type: pack_as_float(UV_TYPE_UNNORMALIZED),
yuv_format: 0.0,
yuv_channel_bit_depth: 0.0,
uv_rects: [uv_rect, uv_rect, uv_rect],
flip: (flip.0.into(), flip.1.into()),
}
}
pub fn new_yuv(
rect: DeviceRect,
clip_rect: DeviceRect,
yuv_color_space: YuvRangedColorSpace,
yuv_format: YuvFormat,
yuv_channel_bit_depth: u32,
uv_rects: [TexelRect; 3],
flip: (bool, bool),
) -> Self {
CompositeInstance {
rect,
clip_rect,
color: PremultipliedColorF::WHITE,
_padding: 0.0,
color_space_or_uv_type: pack_as_float(yuv_color_space as u32),
yuv_format: pack_as_float(yuv_format as u32),
yuv_channel_bit_depth: pack_as_float(yuv_channel_bit_depth),
uv_rects,
flip: (flip.0.into(), flip.1.into()),
}
}
pub fn get_rgb_features(&self) -> CompositeFeatures {
let mut features = CompositeFeatures::empty();
if self.color_space_or_uv_type == pack_as_float(UV_TYPE_NORMALIZED)
&& self.uv_rects[0] == TexelRect::new(0.0, 0.0, 1.0, 1.0)
{
features |= CompositeFeatures::NO_UV_CLAMP;
}
if self.color == PremultipliedColorF::WHITE {
features |= CompositeFeatures::NO_COLOR_MODULATION
}
features
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct ClearInstance {
pub rect: [f32; 4],
pub color: [f32; 4],
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaderIndex(pub i32);
#[derive(Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaders {
pub headers_int: Vec<PrimitiveHeaderI>,
pub headers_float: Vec<PrimitiveHeaderF>,
}
impl PrimitiveHeaders {
pub fn new() -> PrimitiveHeaders {
PrimitiveHeaders {
headers_int: Vec::new(),
headers_float: Vec::new(),
}
}
pub fn push(
&mut self,
prim_header: &PrimitiveHeader,
z: ZBufferId,
render_task_address: RenderTaskAddress,
user_data: [i32; 4],
) -> PrimitiveHeaderIndex {
debug_assert_eq!(self.headers_int.len(), self.headers_float.len());
let id = self.headers_float.len();
self.headers_float.push(PrimitiveHeaderF {
local_rect: prim_header.local_rect,
local_clip_rect: prim_header.local_clip_rect,
});
self.headers_int.push(PrimitiveHeaderI {
z,
render_task_address,
specific_prim_address: prim_header.specific_prim_address.as_int(),
transform_id: prim_header.transform_id,
user_data,
});
PrimitiveHeaderIndex(id as i32)
}
}
#[derive(Debug)]
pub struct PrimitiveHeader {
pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect,
pub specific_prim_address: GpuCacheAddress,
pub transform_id: TransformPaletteId,
}
#[derive(Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaderF {
pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect,
}
#[derive(Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaderI {
pub z: ZBufferId,
pub specific_prim_address: i32,
pub transform_id: TransformPaletteId,
pub render_task_address: RenderTaskAddress,
pub user_data: [i32; 4],
}
pub struct GlyphInstance {
pub prim_header_index: PrimitiveHeaderIndex,
}
impl GlyphInstance {
pub fn new(
prim_header_index: PrimitiveHeaderIndex,
) -> Self {
GlyphInstance {
prim_header_index,
}
}
pub fn build(&self,
clip_task: RenderTaskAddress,
subpx_dir: SubpixelDirection,
glyph_index_in_text_run: i32,
glyph_uv_rect: GpuCacheAddress,
color_mode: ShaderColorMode,
) -> PrimitiveInstanceData {
PrimitiveInstanceData {
data: [
self.prim_header_index.0 as i32,
clip_task.0 as i32,
(subpx_dir as u32 as i32) << 24
| (color_mode as u32 as i32) << 16
| glyph_index_in_text_run,
glyph_uv_rect.as_int(),
],
}
}
}
pub struct SplitCompositeInstance {
pub prim_header_index: PrimitiveHeaderIndex,
pub polygons_address: i32,
pub z: ZBufferId,
pub render_task_address: RenderTaskAddress,
}
impl From<SplitCompositeInstance> for PrimitiveInstanceData {
fn from(instance: SplitCompositeInstance) -> Self {
PrimitiveInstanceData {
data: [
instance.prim_header_index.0,
instance.polygons_address,
instance.z.0,
instance.render_task_address.0,
],
}
}
}
#[derive(Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct QuadInstance {
pub dst_task_address: RenderTaskAddress,
pub prim_address_i: GpuBufferAddress,
pub prim_address_f: GpuBufferAddress,
pub quad_flags: u8,
pub edge_flags: u8,
pub part_index: u8,
pub segment_index: u8,
}
impl From<QuadInstance> for PrimitiveInstanceData {
fn from(instance: QuadInstance) -> Self {
PrimitiveInstanceData {
data: [
instance.prim_address_i.as_int(),
instance.prim_address_f.as_int(),
((instance.quad_flags as i32) << 24) |
((instance.edge_flags as i32) << 16) |
((instance.part_index as i32) << 8) |
((instance.segment_index as i32) << 0),
instance.dst_task_address.0,
],
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
pub struct QuadSegment {
pub rect: LayoutRect,
pub task_id: RenderTaskId,
}
#[derive(Copy, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(u32)]
pub enum ClipSpace {
Raster = 0,
Primitive = 1,
}
impl ClipSpace {
pub fn as_int(self) -> u32 {
match self {
ClipSpace::Raster => 0,
ClipSpace::Primitive => 1,
}
}
}
#[repr(C)]
#[derive(Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct MaskInstance {
pub prim: PrimitiveInstanceData,
pub clip_transform_id: TransformPaletteId,
pub clip_address: i32,
pub clip_space: u32,
pub unused: i32,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, MallocSizeOf)]
pub struct BrushFlags(u16);
bitflags! {
impl BrushFlags: u16 {
const PERSPECTIVE_INTERPOLATION = 1;
const SEGMENT_RELATIVE = 2;
const SEGMENT_REPEAT_X = 4;
const SEGMENT_REPEAT_Y = 8;
const SEGMENT_REPEAT_X_ROUND = 16;
const SEGMENT_REPEAT_Y_ROUND = 32;
const SEGMENT_REPEAT_X_CENTERED = 64;
const SEGMENT_REPEAT_Y_CENTERED = 128;
const SEGMENT_NINEPATCH_MIDDLE = 256;
const SEGMENT_TEXEL_RECT = 512;
const FORCE_AA = 1024;
}
}
impl core::fmt::Debug for BrushFlags {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
if self.is_empty() {
write!(f, "{:#x}", Self::empty().bits())
} else {
bitflags::parser::to_writer(self, f)
}
}
}
pub struct BrushInstance {
pub prim_header_index: PrimitiveHeaderIndex,
pub clip_task_address: RenderTaskAddress,
pub segment_index: i32,
pub edge_flags: EdgeAaSegmentMask,
pub brush_flags: BrushFlags,
pub resource_address: i32,
}
impl From<BrushInstance> for PrimitiveInstanceData {
fn from(instance: BrushInstance) -> Self {
PrimitiveInstanceData {
data: [
instance.prim_header_index.0,
instance.clip_task_address.0,
instance.segment_index
| ((instance.brush_flags.bits() as i32) << 16)
| ((instance.edge_flags.bits() as i32) << 28),
instance.resource_address,
]
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct ImageBrushData {
pub color_mode: ShaderColorMode,
pub alpha_type: AlphaType,
pub raster_space: RasterizationSpace,
pub opacity: f32,
}
impl ImageBrushData {
#[inline]
pub fn encode(&self) -> [i32; 4] {
[
self.color_mode as i32 | ((self.alpha_type as i32) << 16),
self.raster_space as i32,
get_shader_opacity(self.opacity),
0,
]
}
}
#[derive(Copy, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct TransformPaletteId(pub u32);
impl TransformPaletteId {
pub const IDENTITY: Self = TransformPaletteId(0);
pub fn transform_kind(&self) -> TransformedRectKind {
if (self.0 >> 23) == 0 {
TransformedRectKind::AxisAligned
} else {
TransformedRectKind::Complex
}
}
pub fn override_transform_kind(&self, kind: TransformedRectKind) -> Self {
TransformPaletteId((self.0 & 0x7FFFFFu32) | ((kind as u32) << 23))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct TransformData {
transform: LayoutToPictureTransform,
inv_transform: PictureToLayoutTransform,
}
impl TransformData {
fn invalid() -> Self {
TransformData {
transform: LayoutToPictureTransform::identity(),
inv_transform: PictureToLayoutTransform::identity(),
}
}
}
#[derive(Clone)]
pub struct TransformMetadata {
transform_kind: TransformedRectKind,
}
impl TransformMetadata {
pub fn invalid() -> Self {
TransformMetadata {
transform_kind: TransformedRectKind::AxisAligned,
}
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
struct RelativeTransformKey {
from_index: SpatialNodeIndex,
to_index: SpatialNodeIndex,
}
pub struct TransformPalette {
transforms: Vec<TransformData>,
metadata: Vec<TransformMetadata>,
map: FastHashMap<RelativeTransformKey, usize>,
}
impl TransformPalette {
pub fn new(
count: usize,
) -> Self {
let _ = VECS_PER_TRANSFORM;
let mut transforms = Vec::with_capacity(count);
let mut metadata = Vec::with_capacity(count);
transforms.push(TransformData::invalid());
metadata.push(TransformMetadata::invalid());
TransformPalette {
transforms,
metadata,
map: FastHashMap::default(),
}
}
pub fn finish(self) -> Vec<TransformData> {
self.transforms
}
fn get_index(
&mut self,
child_index: SpatialNodeIndex,
parent_index: SpatialNodeIndex,
spatial_tree: &SpatialTree,
) -> usize {
if child_index == parent_index {
0
} else {
let key = RelativeTransformKey {
from_index: child_index,
to_index: parent_index,
};
let metadata = &mut self.metadata;
let transforms = &mut self.transforms;
*self.map
.entry(key)
.or_insert_with(|| {
let transform = spatial_tree.get_relative_transform(
child_index,
parent_index,
)
.into_transform()
.with_destination::<PicturePixel>();
register_transform(
metadata,
transforms,
transform,
)
})
}
}
pub fn get_id(
&mut self,
from_index: SpatialNodeIndex,
to_index: SpatialNodeIndex,
spatial_tree: &SpatialTree,
) -> TransformPaletteId {
let index = self.get_index(
from_index,
to_index,
spatial_tree,
);
let transform_kind = self.metadata[index].transform_kind as u32;
TransformPaletteId(
(index as u32) |
(transform_kind << 23)
)
}
pub fn get_custom(
&mut self,
transform: LayoutToPictureTransform,
) -> TransformPaletteId {
let index = register_transform(
&mut self.metadata,
&mut self.transforms,
transform,
);
let transform_kind = self.metadata[index].transform_kind as u32;
TransformPaletteId(
(index as u32) |
(transform_kind << 23)
)
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum UvRectKind {
Rect,
Quad {
top_left: DeviceHomogeneousVector,
top_right: DeviceHomogeneousVector,
bottom_left: DeviceHomogeneousVector,
bottom_right: DeviceHomogeneousVector,
},
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ImageSource {
pub p0: DevicePoint,
pub p1: DevicePoint,
pub user_data: [f32; 4],
pub uv_rect_kind: UvRectKind,
}
impl ImageSource {
pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
request.push([
self.p0.x,
self.p0.y,
self.p1.x,
self.p1.y,
]);
request.push(self.user_data);
if let UvRectKind::Quad { top_left, top_right, bottom_left, bottom_right } = self.uv_rect_kind {
request.push(top_left);
request.push(top_right);
request.push(bottom_left);
request.push(bottom_right);
}
}
}
fn register_transform(
metadatas: &mut Vec<TransformMetadata>,
transforms: &mut Vec<TransformData>,
transform: LayoutToPictureTransform,
) -> usize {
let inv_transform = transform
.inverse()
.unwrap_or_else(PictureToLayoutTransform::identity);
let metadata = TransformMetadata {
transform_kind: transform.transform_kind()
};
let data = TransformData {
transform,
inv_transform,
};
let index = transforms.len();
metadatas.push(metadata);
transforms.push(data);
index
}
pub fn get_shader_opacity(opacity: f32) -> i32 {
(opacity * 65535.0).round() as i32
}