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()) {
59 bool LinearGradientContents::CanApplyFastGradient()
const {
63 std::optional<Rect> maybe_rect =
GetGeometry()->GetCoverage(Matrix());
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_;
104 bool 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()) {
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{
159 vtx_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()),
160 .transform = entity.GetShaderTransform(pass),
164 pass.SetLabel(
"LinearGradient");
166 VS::FrameInfo frame_info;
169 [&renderer](ContentContextOptions options) {
170 return renderer.GetFastGradientPipeline(options);
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);
198 return RenderSSBO(renderer, entity, pass);
200 return RenderTexture(renderer, entity, pass);
203 bool LinearGradientContents::RenderTexture(
const ContentContext& renderer,
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(
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;
265 bool LinearGradientContents::RenderSSBO(
const ContentContext& renderer,
266 const Entity& entity,
267 RenderPass& pass)
const {
271 VS::FrameInfo frame_info;
275 [&renderer](ContentContextOptions options) {
276 return renderer.GetLinearGradientSSBOFillPipeline(options);
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_);