use crate::{
backend::renderer::{
element::{texture::TextureRenderElement, Element, Id, Kind, RenderElement, UnderlyingStorage},
utils::{CommitCounter, DamageSet, OpaqueRegions},
},
utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Transform},
};
use super::{GlesError, GlesFrame, GlesPixelProgram, GlesRenderer, GlesTexProgram, GlesTexture, Uniform};
#[derive(Debug, Clone)]
pub struct PixelShaderElement {
shader: GlesPixelProgram,
id: Id,
commit_counter: CommitCounter,
area: Rectangle<i32, Logical>,
opaque_regions: Vec<Rectangle<i32, Logical>>,
alpha: f32,
additional_uniforms: Vec<Uniform<'static>>,
kind: Kind,
}
impl PixelShaderElement {
pub fn new(
shader: GlesPixelProgram,
area: Rectangle<i32, Logical>,
opaque_regions: Option<Vec<Rectangle<i32, Logical>>>,
alpha: f32,
additional_uniforms: Vec<Uniform<'_>>,
kind: Kind,
) -> Self {
PixelShaderElement {
shader,
id: Id::new(),
commit_counter: CommitCounter::default(),
area,
opaque_regions: opaque_regions.unwrap_or_default(),
alpha,
additional_uniforms: additional_uniforms.into_iter().map(|u| u.into_owned()).collect(),
kind,
}
}
pub fn resize(
&mut self,
area: Rectangle<i32, Logical>,
opaque_regions: Option<Vec<Rectangle<i32, Logical>>>,
) {
let opaque_regions = opaque_regions.unwrap_or_default();
if self.area != area || self.opaque_regions != opaque_regions {
self.area = area;
self.opaque_regions = opaque_regions;
self.commit_counter.increment();
}
}
pub fn update_uniforms(&mut self, additional_uniforms: Vec<Uniform<'_>>) {
self.additional_uniforms = additional_uniforms.into_iter().map(|u| u.into_owned()).collect();
self.commit_counter.increment();
}
}
impl Element for PixelShaderElement {
fn id(&self) -> &Id {
&self.id
}
fn current_commit(&self) -> CommitCounter {
self.commit_counter
}
fn src(&self) -> Rectangle<f64, Buffer> {
Rectangle::from_size(self.area.size.to_f64().to_buffer(1.0, Transform::Normal))
}
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
self.area.to_physical_precise_round(scale)
}
fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> {
self.opaque_regions
.iter()
.map(|region| region.to_physical_precise_round(scale))
.collect()
}
fn alpha(&self) -> f32 {
self.alpha
}
fn kind(&self) -> Kind {
self.kind
}
}
impl RenderElement<GlesRenderer> for PixelShaderElement {
#[profiling::function]
fn draw(
&self,
frame: &mut GlesFrame<'_, '_>,
src: Rectangle<f64, Buffer>,
dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
_opaque_regions: &[Rectangle<i32, Physical>],
) -> Result<(), GlesError> {
frame.render_pixel_shader_to(
&self.shader,
src,
dst,
self.area.size.to_buffer(1, Transform::Normal),
Some(damage),
self.alpha,
&self.additional_uniforms,
)
}
#[inline]
fn underlying_storage(&self, _renderer: &mut GlesRenderer) -> Option<UnderlyingStorage<'_>> {
None
}
}
#[derive(Debug)]
pub struct TextureShaderElement {
inner: TextureRenderElement<GlesTexture>,
program: GlesTexProgram,
id: Id,
additional_uniforms: Vec<Uniform<'static>>,
}
impl TextureShaderElement {
pub fn new(
inner: TextureRenderElement<GlesTexture>,
program: GlesTexProgram,
additional_uniforms: Vec<Uniform<'_>>,
) -> Self {
Self {
inner,
program,
id: Id::new(),
additional_uniforms: additional_uniforms.into_iter().map(|u| u.into_owned()).collect(),
}
}
}
impl Element for TextureShaderElement {
fn id(&self) -> &Id {
&self.id
}
fn current_commit(&self) -> CommitCounter {
self.inner.current_commit()
}
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
self.inner.geometry(scale)
}
fn transform(&self) -> Transform {
self.inner.transform()
}
fn src(&self) -> Rectangle<f64, Buffer> {
self.inner.src()
}
fn damage_since(&self, scale: Scale<f64>, commit: Option<CommitCounter>) -> DamageSet<i32, Physical> {
self.inner.damage_since(scale, commit)
}
fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> {
self.inner.opaque_regions(scale)
}
fn alpha(&self) -> f32 {
self.inner.alpha()
}
fn kind(&self) -> Kind {
self.inner.kind()
}
fn location(&self, scale: Scale<f64>) -> Point<i32, Physical> {
self.inner.location(scale)
}
}
impl RenderElement<GlesRenderer> for TextureShaderElement {
#[profiling::function]
fn draw(
&self,
frame: &mut GlesFrame<'_, '_>,
src: Rectangle<f64, Buffer>,
dst: Rectangle<i32, Physical>,
damage: &[Rectangle<i32, Physical>],
opaque_regions: &[Rectangle<i32, Physical>],
) -> Result<(), GlesError> {
frame.render_texture_from_to(
&self.inner.texture,
src,
dst,
damage,
opaque_regions,
self.transform(),
self.alpha(),
Some(&self.program),
&self.additional_uniforms,
)
}
}