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()) {
64 bool 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_;
109 bool LinearGradientContents::FastLinearGradient(
const ContentContext& renderer,
110 const Entity& entity,
111 RenderPass& pass)
const {
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_FRAG_INFO(t) \
197 t##GradientUniformFillPipeline::FragmentShader::FragInfo
198 #define UNIFORM_COLOR_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::colors)
199 #define UNIFORM_STOP_SIZE ARRAY_LEN(UNIFORM_FRAG_INFO(Linear)::stop_pairs)
209 if (CanApplyFastGradient()) {
210 return FastLinearGradient(renderer, entity, pass);
213 return RenderSSBO(renderer, entity, pass);
217 return RenderUniform(renderer, entity, pass);
219 return RenderTexture(renderer, entity, pass);
222 bool LinearGradientContents::RenderTexture(
const ContentContext& renderer,
228 VS::FrameInfo frame_info;
235 return ColorSourceContents::DrawGeometry<VS>(
236 renderer, entity, pass, pipeline_callback, frame_info,
237 [
this, &renderer, &entity](RenderPass& pass) {
239 auto gradient_texture =
241 if (gradient_texture ==
nullptr) {
245 FS::FragInfo frag_info;
246 frag_info.start_point = start_point_;
247 frag_info.end_point = end_point_;
248 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
249 frag_info.decal_border_color = decal_border_color_;
250 frag_info.texture_sampler_y_coord_scale =
251 gradient_texture->GetYCoordScale();
256 frag_info.half_texel =
257 Vector2(0.5 / gradient_texture->GetSize().width,
258 0.5 / gradient_texture->GetSize().height);
260 pass.SetCommandLabel(
"LinearGradientFill");
262 SamplerDescriptor sampler_desc;
266 FS::BindTextureSampler(
267 pass, std::move(gradient_texture),
268 renderer.
GetContext()->GetSamplerLibrary()->GetSampler(
278 Point start_to_end = end_point - start_point;
280 (start_to_end.x * start_to_end.x + start_to_end.y * start_to_end.y);
281 return dot == 0.0f ? 0.0f : 1.0f / dot;
285 bool LinearGradientContents::RenderSSBO(
const ContentContext& renderer,
286 const Entity& entity,
287 RenderPass& pass)
const {
291 VS::FrameInfo frame_info;
295 [&renderer](ContentContextOptions options) {
296 return renderer.GetLinearGradientSSBOFillPipeline(options);
298 return ColorSourceContents::DrawGeometry<VS>(
299 renderer, entity, pass, pipeline_callback, frame_info,
300 [
this, &renderer, &entity](RenderPass& pass) {
301 FS::FragInfo frag_info;
302 frag_info.start_point = start_point_;
303 frag_info.end_point = end_point_;
304 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
305 frag_info.decal_border_color = decal_border_color_;
309 frag_info.start_to_end = end_point_ - start_point_;
310 frag_info.inverse_dot_start_to_end =
311 CalculateInverseDotStartToEnd(start_point_, end_point_);
313 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
316 frag_info.colors_length = colors.size();
317 auto color_buffer = data_host_buffer.Emplace(
318 colors.data(), colors.size() *
sizeof(StopData),
319 renderer.GetDeviceCapabilities()
320 .GetMinimumStorageBufferAlignment());
322 pass.SetCommandLabel(
"LinearGradientSSBOFill");
324 FS::BindFragInfo(pass, data_host_buffer.EmplaceUniform(frag_info));
325 FS::BindColorData(pass, color_buffer);
331 bool LinearGradientContents::RenderUniform(
const ContentContext& renderer,
332 const Entity& entity,
333 RenderPass& pass)
const {
337 VS::FrameInfo frame_info;
341 [&renderer](ContentContextOptions options) {
342 return renderer.GetLinearGradientUniformFillPipeline(options);
344 return ColorSourceContents::DrawGeometry<VS>(
345 renderer, entity, pass, pipeline_callback, frame_info,
346 [
this, &renderer, &entity](RenderPass& pass) {
347 FS::FragInfo frag_info;
348 frag_info.start_point = start_point_;
349 frag_info.start_to_end = end_point_ - start_point_;
353 frag_info.tile_mode =
static_cast<Scalar>(tile_mode_);
355 colors_, stops_, frag_info.colors, frag_info.stop_pairs);
356 frag_info.inverse_dot_start_to_end =
357 CalculateInverseDotStartToEnd(start_point_, end_point_);
358 frag_info.decal_border_color = decal_border_color_;
360 pass.SetCommandLabel(
"LinearGradientUniformFill");
363 pass, renderer.GetTransientsDataBuffer().EmplaceUniform(frag_info));
371 for (
Color& color : colors_) {
372 color = color_filter_proc(color);
374 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
PipelineRef GetLinearGradientFillPipeline(ContentContextOptions opts) const
const Capabilities & GetDeviceCapabilities() const
HostBuffer & GetTransientsDataBuffer() const
Retrieve the current host buffer for transient storage of other non-index data.
std::shared_ptr< Context > GetContext() const
std::function< Color(Color)> ColorFilterProc
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
virtual Scalar ComputeAlphaCoverage(const Matrix &transform) const
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
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...
VertexShader_ VertexShader
FragmentShader_ FragmentShader
#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::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.
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)