19 : geometry_(geometry) {}
28 start_point_ = start_point;
29 end_point_ = end_point;
33 colors_ = std::move(colors);
37 stops_ = std::move(stops);
49 tile_mode_ = tile_mode;
56 for (
auto color : colors_) {
57 if (!color.IsOpaque()) {
64bool LinearGradientContents::CanApplyFastGradient()
const {
69 if (!maybe_rect.has_value()) {
72 Rect rect = maybe_rect.value();
76 Point start = (start_point_.
y < end_point_.
y) ? start_point_ : end_point_;
77 Point end = (start_point_.
y < end_point_.
y) ? end_point_ : start_point_;
89 Point start = (start_point_.
x < end_point_.
x) ? start_point_ : end_point_;
90 Point end = (start_point_.
x < end_point_.
x) ? end_point_ : start_point_;
109bool LinearGradientContents::FastLinearGradient(
const ContentContext& renderer,
110 const Entity& entity,
111 RenderPass& pass)
const {
112 using VS = FastGradientPipeline::VertexShader;
113 using FS = FastGradientPipeline::FragmentShader;
116 bool force_stencil = !geometry->IsAxisAlignedRect();
118 auto geom_callback = [&](
const ContentContext& renderer,
const Entity& entity,
120 const Geometry* geometry) -> GeometryResult {
125 std::optional<Rect> maybe_rect = geometry->GetCoverage(Matrix());
126 if (!maybe_rect.has_value()) {
129 Rect rect = maybe_rect.value();
130 bool horizontal_axis = start_point_.
y == end_point_.
y;
135 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
136 vtx_builder.Reserve(6 * (stops_.size() - 1));
137 Point prev = start_point_;
138 for (
auto i = 1u;
i < stops_.size();
i++) {
140 Point current = (1.0 - t) * start_point_ + t * end_point_;
141 Rect section = horizontal_axis
143 current.x - prev.x, rect.GetHeight())
145 :
Rect::MakeXYWH(rect.GetX(), prev.
y, rect.GetWidth(),
147 vtx_builder.AddVertices({
148 {section.GetLeftTop(), colors_[
i - 1]},
149 {section.GetRightTop(),
150 horizontal_axis ? colors_[
i] : colors_[
i - 1]},
151 {section.GetLeftBottom(),
152 horizontal_axis ? colors_[
i - 1] : colors_[
i]},
153 {section.GetRightTop(),
154 horizontal_axis ? colors_[
i] : colors_[
i - 1]},
155 {section.GetLeftBottom(),
156 horizontal_axis ? colors_[
i - 1] : colors_[
i]},
157 {section.GetRightBottom(), colors_[
i]},
161 return GeometryResult{
163 .vertex_buffer = vtx_builder.CreateVertexBuffer(
164 renderer.GetTransientsDataBuffer(),
165 renderer.GetTransientsIndexesBuffer()),
166 .
transform = entity.GetShaderTransform(pass),
170 pass.SetLabel(
"LinearGradient");
172 VS::FrameInfo frame_info;
175 [&renderer](ContentContextOptions options) {
176 return renderer.GetFastGradientPipeline(options);
178 return ColorSourceContents::DrawGeometry<VS>(
179 renderer, entity, pass, pipeline_callback, frame_info,
180 [
this, &renderer, &entity](RenderPass& pass) {
181 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
183 FS::FragInfo frag_info;
188 FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
192 force_stencil, geom_callback);
195#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
196#define UNIFORM_COLORS_INFO(t) \
197 t##GradientUniformFillPipeline::FragmentShader::ColorsInfo
198#define UNIFORM_STOP_PAIRS_INFO(t) \
199 t##GradientUniformFillPipeline::FragmentShader::StopPairsInfo
200#define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_COLORS_INFO(Linear)::colors)
201#define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_STOP_PAIRS_INFO(Linear)::stop_pairs)
215 if (CanApplyFastGradient()) {
216 return FastLinearGradient(renderer, entity, pass);
219 return RenderSSBO(renderer, entity, pass);
223 return RenderUniform(renderer, entity, pass);
225 return RenderTexture(renderer, entity, pass);
228bool LinearGradientContents::RenderTexture(
const ContentContext& renderer,
231 using VS = LinearGradientFillPipeline::VertexShader;
232 using FS = LinearGradientFillPipeline::FragmentShader;
234 VS::FrameInfo frame_info;
241 return ColorSourceContents::DrawGeometry<VS>(
242 renderer, entity, pass, pipeline_callback, frame_info,
243 [
this, &renderer, &entity](RenderPass& pass) {
245 auto gradient_texture =
247 if (gradient_texture ==
nullptr) {
251 FS::FragInfo frag_info;
252 frag_info.start_point = start_point_;
253 frag_info.end_point = end_point_;
254 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
255 frag_info.decal_border_color = decal_border_color_;
260 frag_info.half_texel =
261 Vector2(0.5 / gradient_texture->GetSize().width,
262 0.5 / gradient_texture->GetSize().height);
264 pass.SetCommandLabel(
"LinearGradientFill");
266 SamplerDescriptor sampler_desc;
270 FS::BindTextureSampler(
271 pass, std::move(gradient_texture),
272 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
282 Point start_to_end = end_point - start_point;
284 (start_to_end.x * start_to_end.x + start_to_end.y * start_to_end.y);
285 return dot == 0.0f ? 0.0f : 1.0f / dot;
289bool LinearGradientContents::RenderSSBO(
const ContentContext& renderer,
290 const Entity& entity,
291 RenderPass& pass)
const {
292 using VS = LinearGradientSSBOFillPipeline::VertexShader;
293 using FS = LinearGradientSSBOFillPipeline::FragmentShader;
295 VS::FrameInfo frame_info;
299 [&renderer](ContentContextOptions options) {
300 return renderer.GetLinearGradientSSBOFillPipeline(options);
302 return ColorSourceContents::DrawGeometry<VS>(
303 renderer, entity, pass, pipeline_callback, frame_info,
304 [
this, &renderer, &entity](RenderPass& pass) {
305 FS::FragInfo frag_info;
306 frag_info.start_point = start_point_;
307 frag_info.end_point = end_point_;
308 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
309 frag_info.decal_border_color = decal_border_color_;
313 frag_info.start_to_end = end_point_ - start_point_;
314 frag_info.inverse_dot_start_to_end =
315 CalculateInverseDotStartToEnd(start_point_, end_point_);
317 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
320 frag_info.colors_length = colors.size();
321 auto color_buffer = data_host_buffer.Emplace(
322 colors.data(), colors.size() *
sizeof(StopData),
323 renderer.GetDeviceCapabilities()
324 .GetMinimumStorageBufferAlignment());
326 pass.SetCommandLabel(
"LinearGradientSSBOFill");
328 FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
329 FS::BindColorData(pass, color_buffer);
335bool LinearGradientContents::RenderUniform(
const ContentContext& renderer,
336 const Entity& entity,
337 RenderPass& pass)
const {
338 using VS = LinearGradientUniformFillPipeline::VertexShader;
339 using FS = LinearGradientUniformFillPipeline::FragmentShader;
341 VS::FrameInfo frame_info;
345 [&renderer](ContentContextOptions options) {
346 return renderer.GetLinearGradientUniformFillPipeline(options);
348 return ColorSourceContents::DrawGeometry<VS>(
349 renderer, entity, pass, pipeline_callback, frame_info,
350 [
this, &renderer, &entity](RenderPass& pass) {
351 FS::FragInfo frag_info;
352 FS::ColorsInfo colors_info;
353 FS::StopPairsInfo stop_pairs_info;
355 frag_info.start_point = start_point_;
356 frag_info.start_to_end = end_point_ - start_point_;
360 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
362 colors_, stops_, colors_info.colors, stop_pairs_info.stop_pairs);
363 frag_info.inverse_dot_start_to_end =
364 CalculateInverseDotStartToEnd(start_point_, end_point_);
365 frag_info.decal_border_color = decal_border_color_;
367 pass.SetCommandLabel(
"LinearGradientUniformFill");
369 auto& transients_buffer = renderer.GetTransientsDataBuffer();
370 FS::BindFragInfo(pass, transients_buffer.EmplaceUniform(frag_info));
371 FS::BindColorsInfo(pass, transients_buffer.EmplaceUniform(colors_info));
372 FS::BindStopPairsInfo(
373 pass, transients_buffer.EmplaceUniform(stop_pairs_info));
381 for (
Color& color : colors_) {
382 color = color_filter_proc(color);
384 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.
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
The coverage rectangle of this geometry, transformed by the transform argument.
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
LinearGradientContents(const Geometry *geometry)
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.
const Geometry * GetGeometry() const override
Get the geometry that this contents will use to render.
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_PAIRS_INFO(t)
#define UNIFORM_STOP_SIZE
#define UNIFORM_COLORS_INFO(t)
#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)