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()) {
67 Rect rect = maybe_rect.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 {
107 using VS = FastGradientPipeline::VertexShader;
108 using FS = FastGradientPipeline::FragmentShader;
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()) {
124 Rect rect = maybe_rect.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));
132 Point prev = start_point_;
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())
140 :
Rect::MakeXYWH(rect.GetX(), prev.
y, rect.GetWidth(),
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{
158 .vertex_buffer = vtx_builder.CreateVertexBuffer(
159 renderer.GetTransientsDataBuffer(),
160 renderer.GetTransientsIndexesBuffer()),
161 .
transform = entity.GetShaderTransform(pass),
165 pass.SetLabel(
"LinearGradient");
167 VS::FrameInfo frame_info;
170 [&renderer](ContentContextOptions options) {
171 return renderer.GetFastGradientPipeline(options);
173 return ColorSourceContents::DrawGeometry<VS>(
174 renderer, entity, pass, pipeline_callback, frame_info,
175 [
this, &renderer, &entity](RenderPass& pass) {
176 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
178 FS::FragInfo frag_info;
183 FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
187 force_stencil, geom_callback);
190#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
191#define UNIFORM_FRAG_INFO(t) \
192 t##GradientUniformFillPipeline::FragmentShader::FragInfo
193#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::colors)
194#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::stop_pairs)
204 if (CanApplyFastGradient()) {
205 return FastLinearGradient(renderer, entity, pass);
208 return RenderSSBO(renderer, entity, pass);
212 return RenderUniform(renderer, entity, pass);
214 return RenderTexture(renderer, entity, pass);
217bool LinearGradientContents::RenderTexture(
const ContentContext& renderer,
220 using VS = LinearGradientFillPipeline::VertexShader;
221 using FS = LinearGradientFillPipeline::FragmentShader;
223 VS::FrameInfo frame_info;
230 return ColorSourceContents::DrawGeometry<VS>(
231 renderer, entity, pass, pipeline_callback, frame_info,
232 [
this, &renderer, &entity](RenderPass& pass) {
234 auto gradient_texture =
236 if (gradient_texture ==
nullptr) {
240 FS::FragInfo frag_info;
241 frag_info.start_point = start_point_;
242 frag_info.end_point = end_point_;
243 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
244 frag_info.decal_border_color = decal_border_color_;
245 frag_info.texture_sampler_y_coord_scale =
246 gradient_texture->GetYCoordScale();
251 frag_info.half_texel =
252 Vector2(0.5 / gradient_texture->GetSize().width,
253 0.5 / gradient_texture->GetSize().height);
255 pass.SetCommandLabel(
"LinearGradientFill");
257 SamplerDescriptor sampler_desc;
261 FS::BindTextureSampler(
262 pass, std::move(gradient_texture),
263 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
273 Point start_to_end = end_point - start_point;
275 (start_to_end.x * start_to_end.x + start_to_end.y * start_to_end.y);
276 return dot == 0.0f ? 0.0f : 1.0f / dot;
280bool LinearGradientContents::RenderSSBO(
const ContentContext& renderer,
281 const Entity& entity,
282 RenderPass& pass)
const {
283 using VS = LinearGradientSSBOFillPipeline::VertexShader;
284 using FS = LinearGradientSSBOFillPipeline::FragmentShader;
286 VS::FrameInfo frame_info;
290 [&renderer](ContentContextOptions options) {
291 return renderer.GetLinearGradientSSBOFillPipeline(options);
293 return ColorSourceContents::DrawGeometry<VS>(
294 renderer, entity, pass, pipeline_callback, frame_info,
295 [
this, &renderer, &entity](RenderPass& pass) {
296 FS::FragInfo frag_info;
297 frag_info.start_point = start_point_;
298 frag_info.end_point = end_point_;
299 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
300 frag_info.decal_border_color = decal_border_color_;
304 frag_info.start_to_end = end_point_ - start_point_;
305 frag_info.inverse_dot_start_to_end =
306 CalculateInverseDotStartToEnd(start_point_, end_point_);
308 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
311 frag_info.colors_length = colors.size();
312 auto color_buffer = data_host_buffer.Emplace(
313 colors.data(), colors.size() *
sizeof(StopData),
314 renderer.GetDeviceCapabilities()
315 .GetMinimumStorageBufferAlignment());
317 pass.SetCommandLabel(
"LinearGradientSSBOFill");
319 FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
320 FS::BindColorData(pass, color_buffer);
326bool LinearGradientContents::RenderUniform(
const ContentContext& renderer,
327 const Entity& entity,
328 RenderPass& pass)
const {
329 using VS = LinearGradientUniformFillPipeline::VertexShader;
330 using FS = LinearGradientUniformFillPipeline::FragmentShader;
332 VS::FrameInfo frame_info;
336 [&renderer](ContentContextOptions options) {
337 return renderer.GetLinearGradientUniformFillPipeline(options);
339 return ColorSourceContents::DrawGeometry<VS>(
340 renderer, entity, pass, pipeline_callback, frame_info,
341 [
this, &renderer, &entity](RenderPass& pass) {
342 FS::FragInfo frag_info;
343 frag_info.start_point = start_point_;
344 frag_info.start_to_end = end_point_ - start_point_;
348 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
350 colors_, stops_, frag_info.colors, frag_info.stop_pairs);
351 frag_info.inverse_dot_start_to_end =
352 CalculateInverseDotStartToEnd(start_point_, end_point_);
353 frag_info.decal_border_color = decal_border_color_;
355 pass.SetCommandLabel(
"LinearGradientUniformFill");
358 pass, renderer.GetTransientsDataBuffer().EmplaceUniform(frag_info));
366 for (
Color& color : colors_) {
367 color = color_filter_proc(color);
369 decal_border_color_ = color_filter_proc(decal_border_color_);
virtual bool SupportsSSBO() const =0
Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.
const Geometry * GetGeometry() const
Get the geometry that this contents will use to render.
Scalar GetOpacityFactor() const
Get the opacity factor for this color source.
bool AppliesAlphaForStrokeCoverage(const Matrix &transform) const
Whether the entity should be treated as non-opaque due to stroke geometry requiring alpha for coverag...
const Matrix & GetInverseEffectTransform() const
Set the inverted effect transform for this color source.
std::function< PipelineRef(ContentContextOptions)> PipelineBuilderCallback
HostBuffer & GetTransientsDataBuffer() const
Retrieve the current host buffer for transient storage of other non-index data.
PipelineRef GetLinearGradientFillPipeline(ContentContextOptions opts) const
const Capabilities & GetDeviceCapabilities() const
std::shared_ptr< Context > GetContext() const
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
virtual Scalar ComputeAlphaCoverage(const Matrix &transform) const
BufferView EmplaceUniform(const UniformType &uniform)
Emplace uniform data onto the host buffer. Ensure that backend specific uniform alignment requirement...
~LinearGradientContents() override
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)
bool IsOpaque(const Matrix &transform) const override
Whether this Contents only emits opaque source colors from the fragment stage. This value does not ac...
Render passes encode render commands directed as one specific render target into an underlying comman...
#define UNIFORM_STOP_SIZE
#define UNIFORM_COLOR_SIZE
LinePipeline::FragmentShader FS
int PopulateUniformGradientColors(const std::vector< Color > &colors, const std::vector< Scalar > &stops, Vector4 frag_info_colors[kMaxUniformGradientStops], Vector4 frag_info_stop_pairs[kMaxUniformGradientStops/2])
Populate 2 arrays with the colors and stop data for a gradient.
std::function< Color(Color)> ColorFilterProc
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.
LinePipeline::VertexShader VS
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)
static constexpr uint32_t kMaxUniformGradientStops
A 4x4 matrix using column-major storage.
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)