23 start_point_ = start_point;
24 end_point_ = end_point;
28 colors_ = std::move(
colors);
32 stops_ = std::move(stops);
44 tile_mode_ = tile_mode;
51 for (
auto color : colors_) {
52 if (!
color.IsOpaque()) {
59bool LinearGradientContents::CanApplyFastGradient()
const {
64 if (!maybe_rect.has_value()) {
71 Point start = (start_point_.
y < end_point_.
y) ? start_point_ : end_point_;
72 Point end = (start_point_.
y < end_point_.
y) ? end_point_ : start_point_;
84 Point start = (start_point_.
x < end_point_.
x) ? start_point_ : end_point_;
85 Point end = (start_point_.
x < end_point_.
x) ? end_point_ : start_point_;
104bool LinearGradientContents::FastLinearGradient(
const ContentContext&
renderer,
105 const Entity& entity,
106 RenderPass& pass)
const {
111 bool force_stencil = !geometry.IsAxisAlignedRect();
113 auto geom_callback = [&](
const ContentContext&
renderer,
const Entity& entity,
115 const Geometry& geometry) -> GeometryResult {
120 std::optional<Rect> maybe_rect = geometry.GetCoverage(
Matrix());
121 if (!maybe_rect.has_value()) {
125 bool horizontal_axis = start_point_.
y == end_point_.
y;
130 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
131 vtx_builder.Reserve(6 * (stops_.size() - 1));
133 for (
auto i = 1u;
i < stops_.size();
i++) {
135 Point current = (1.0 - t) * start_point_ + t * end_point_;
136 Rect section = horizontal_axis
138 current.x -
prev.x,
rect.GetHeight())
142 vtx_builder.AddVertices({
143 {section.GetLeftTop(), colors_[
i - 1]},
144 {section.GetRightTop(),
145 horizontal_axis ? colors_[
i] : colors_[
i - 1]},
146 {section.GetLeftBottom(),
147 horizontal_axis ? colors_[
i - 1] : colors_[
i]},
148 {section.GetRightTop(),
149 horizontal_axis ? colors_[
i] : colors_[
i - 1]},
150 {section.GetLeftBottom(),
151 horizontal_axis ? colors_[
i - 1] : colors_[
i]},
152 {section.GetRightBottom(), colors_[
i]},
156 return GeometryResult{
159 vtx_builder.CreateVertexBuffer(
renderer.GetTransientsBuffer()),
160 .transform = entity.GetShaderTransform(pass),
164 pass.SetLabel(
"LinearGradient");
166 VS::FrameInfo frame_info;
172 return ColorSourceContents::DrawGeometry<VS>(
173 renderer, entity, pass, pipeline_callback, frame_info,
174 [
this, &
renderer, &entity](RenderPass& pass) {
175 auto& host_buffer =
renderer.GetTransientsBuffer();
177 FS::FragInfo frag_info;
181 FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
185 force_stencil, geom_callback);
194 if (CanApplyFastGradient()) {
195 return FastLinearGradient(
renderer, entity, pass);
197 if (
renderer.GetDeviceCapabilities().SupportsSSBO()) {
198 return RenderSSBO(
renderer, entity, pass);
200 return RenderTexture(
renderer, entity, pass);
209 VS::FrameInfo frame_info;
216 return ColorSourceContents::DrawGeometry<VS>(
217 renderer, entity, pass, pipeline_callback, frame_info,
218 [
this, &
renderer, &entity](RenderPass& pass) {
220 auto gradient_texture =
222 if (gradient_texture ==
nullptr) {
226 FS::FragInfo frag_info;
227 frag_info.start_point = start_point_;
228 frag_info.end_point = end_point_;
229 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
230 frag_info.decal_border_color = decal_border_color_;
231 frag_info.texture_sampler_y_coord_scale =
232 gradient_texture->GetYCoordScale();
236 frag_info.half_texel =
237 Vector2(0.5 / gradient_texture->GetSize().width,
238 0.5 / gradient_texture->GetSize().height);
240 pass.SetCommandLabel(
"LinearGradientFill");
242 SamplerDescriptor sampler_desc;
246 FS::BindTextureSampler(
247 pass, std::move(gradient_texture),
248 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
251 pass,
renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
258 Point start_to_end = end_point - start_point;
260 (start_to_end.x * start_to_end.x + start_to_end.y * start_to_end.y);
261 return dot == 0.0f ? 0.0f : 1.0f /
dot;
265bool LinearGradientContents::RenderSSBO(
const ContentContext&
renderer,
266 const Entity& entity,
267 RenderPass& pass)
const {
271 VS::FrameInfo frame_info;
278 return ColorSourceContents::DrawGeometry<VS>(
279 renderer, entity, pass, pipeline_callback, frame_info,
280 [
this, &
renderer, &entity](RenderPass& pass) {
281 FS::FragInfo frag_info;
282 frag_info.start_point = start_point_;
283 frag_info.end_point = end_point_;
284 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
285 frag_info.decal_border_color = decal_border_color_;
288 frag_info.start_to_end = end_point_ - start_point_;
289 frag_info.inverse_dot_start_to_end =
290 CalculateInverseDotStartToEnd(start_point_, end_point_);
292 auto& host_buffer =
renderer.GetTransientsBuffer();
295 frag_info.colors_length =
colors.size();
297 host_buffer.Emplace(
colors.data(),
colors.size() *
sizeof(StopData),
300 pass.SetCommandLabel(
"LinearGradientSSBOFill");
303 pass,
renderer.GetTransientsBuffer().EmplaceUniform(frag_info));
304 FS::BindColorData(pass, color_buffer);
315 decal_border_color_ = color_filter_proc(decal_border_color_);
static float prev(float f)
Scalar GetOpacityFactor() const
Get the opacity factor for this color source.
std::function< std::shared_ptr< Pipeline< PipelineDescriptor > >(ContentContextOptions)> PipelineBuilderCallback
const Matrix & GetInverseEffectTransform() const
Set the inverted effect transform for this color source.
const std::shared_ptr< Geometry > & GetGeometry() const
Get the geometry that this contents will use to render.
std::function< Color(Color)> ColorFilterProc
~LinearGradientContents() override
bool IsOpaque() const override
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
const std::vector< Color > & GetColors() const
void SetTileMode(Entity::TileMode tile_mode)
const std::vector< Scalar > & GetStops() const
void SetColors(std::vector< Color > colors)
bool ApplyColorFilter(const ColorFilterProc &color_filter_proc) override
If possible, applies a color filter to this contents inputs on the CPU.
bool Render(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
void SetEndPoints(Point start_point, Point end_point)
void SetStops(std::vector< Scalar > stops)
Render passes encode render commands directed as one specific render target into an underlying comman...
VertexShader_ VertexShader
FragmentShader_ FragmentShader
sk_sp< SkBlender > blender SkRect rect
PODArray< SkColor > colors
std::vector< StopData > CreateGradientColors(const std::vector< Color > &colors, const std::vector< Scalar > &stops)
Populate a vector with the color and stop data for a gradient.
std::shared_ptr< Texture > CreateGradientTexture(const GradientData &gradient_data, const std::shared_ptr< impeller::Context > &context)
Create a host visible texture that contains the gradient defined by the provided gradient data.
GradientData CreateGradientBuffer(const std::vector< Color > &colors, const std::vector< Scalar > &stops)
Populate a vector with the interpolated color bytes for the linear gradient described by colors and s...
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
constexpr size_t DefaultUniformAlignment()
SK_API sk_sp< PrecompileColorFilter > Matrix()
SINT T dot(const Vec< N, T > &a, const Vec< N, T > &b)
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)