1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "experimental/graphite/src/ContextUtils.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include <string> 11cb93a386Sopenharmony_ci#include "experimental/graphite/src/DrawTypes.h" 12cb93a386Sopenharmony_ci#include "experimental/graphite/src/Uniform.h" 13cb93a386Sopenharmony_ci#include "experimental/graphite/src/UniformCache.h" 14cb93a386Sopenharmony_ci#include "experimental/graphite/src/UniformManager.h" 15cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_cinamespace skgpu { 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cinamespace { 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci// TODO: For the sprint we only support 4 stops in the gradients 22cb93a386Sopenharmony_cistatic constexpr int kMaxStops = 4; 23cb93a386Sopenharmony_ci// TODO: For the sprint we unify all the gradient uniforms into a standard set of 6: 24cb93a386Sopenharmony_ci// kMaxStops colors 25cb93a386Sopenharmony_ci// kMaxStops offsets 26cb93a386Sopenharmony_ci// 2 points 27cb93a386Sopenharmony_ci// 2 radii 28cb93a386Sopenharmony_cistatic constexpr int kNumGradientUniforms = 6; 29cb93a386Sopenharmony_cistatic constexpr Uniform kGradientUniforms[kNumGradientUniforms] { 30cb93a386Sopenharmony_ci {"colors", SLType::kHalf4 , kMaxStops }, 31cb93a386Sopenharmony_ci {"offsets", SLType::kFloat, kMaxStops }, 32cb93a386Sopenharmony_ci {"point0", SLType::kFloat2 }, 33cb93a386Sopenharmony_ci {"point1", SLType::kFloat2 }, 34cb93a386Sopenharmony_ci {"radius0", SLType::kFloat }, 35cb93a386Sopenharmony_ci {"radius1", SLType::kFloat }, 36cb93a386Sopenharmony_ci}; 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_cistatic constexpr int kNumSolidUniforms = 1; 39cb93a386Sopenharmony_cistatic constexpr Uniform kSolidUniforms[kNumSolidUniforms] { 40cb93a386Sopenharmony_ci {"color", SLType::kFloat4 } 41cb93a386Sopenharmony_ci}; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cisk_sp<UniformData> make_gradient_uniform_data_common(void* srcs[kNumGradientUniforms]) { 44cb93a386Sopenharmony_ci UniformManager mgr(Layout::kMetal); 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci // TODO: Given that, for the sprint, we always know the uniforms we could cache 'dataSize' 47cb93a386Sopenharmony_ci // for each layout and skip the first call. 48cb93a386Sopenharmony_ci size_t dataSize = mgr.writeUniforms(SkSpan<const Uniform>(kGradientUniforms, 49cb93a386Sopenharmony_ci kNumGradientUniforms), 50cb93a386Sopenharmony_ci nullptr, nullptr, nullptr); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci sk_sp<UniformData> result = UniformData::Make(kNumGradientUniforms, 53cb93a386Sopenharmony_ci kGradientUniforms, 54cb93a386Sopenharmony_ci dataSize); 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci mgr.writeUniforms(SkSpan<const Uniform>(kGradientUniforms, kNumGradientUniforms), 57cb93a386Sopenharmony_ci srcs, result->offsets(), result->data()); 58cb93a386Sopenharmony_ci return result; 59cb93a386Sopenharmony_ci} 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_cisk_sp<UniformData> make_linear_gradient_uniform_data(SkPoint startPoint, 62cb93a386Sopenharmony_ci SkPoint endPoint, 63cb93a386Sopenharmony_ci SkColor4f colors[kMaxStops], 64cb93a386Sopenharmony_ci float offsets[kMaxStops]) { 65cb93a386Sopenharmony_ci float unusedRadii[2] = { 0.0f, 0.0f }; 66cb93a386Sopenharmony_ci void* srcs[kNumGradientUniforms] = { 67cb93a386Sopenharmony_ci colors, 68cb93a386Sopenharmony_ci offsets, 69cb93a386Sopenharmony_ci &startPoint, 70cb93a386Sopenharmony_ci &endPoint, 71cb93a386Sopenharmony_ci &unusedRadii[0], 72cb93a386Sopenharmony_ci &unusedRadii[1], 73cb93a386Sopenharmony_ci }; 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci return make_gradient_uniform_data_common(srcs); 76cb93a386Sopenharmony_ci}; 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_cisk_sp<UniformData> make_radial_gradient_uniform_data(SkPoint point, 79cb93a386Sopenharmony_ci float radius, 80cb93a386Sopenharmony_ci SkColor4f colors[kMaxStops], 81cb93a386Sopenharmony_ci float offsets[kMaxStops]) { 82cb93a386Sopenharmony_ci SkPoint unusedPoint = {0.0f, 0.0f}; 83cb93a386Sopenharmony_ci float unusedRadius = 0.0f; 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci void* srcs[kNumGradientUniforms] = { 86cb93a386Sopenharmony_ci colors, 87cb93a386Sopenharmony_ci offsets, 88cb93a386Sopenharmony_ci &point, 89cb93a386Sopenharmony_ci &unusedPoint, 90cb93a386Sopenharmony_ci &radius, 91cb93a386Sopenharmony_ci &unusedRadius, 92cb93a386Sopenharmony_ci }; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci return make_gradient_uniform_data_common(srcs); 95cb93a386Sopenharmony_ci}; 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_cisk_sp<UniformData> make_sweep_gradient_uniform_data(SkPoint point, 98cb93a386Sopenharmony_ci SkColor4f colors[kMaxStops], 99cb93a386Sopenharmony_ci float offsets[kMaxStops]) { 100cb93a386Sopenharmony_ci SkPoint unusedPoint = {0.0f, 0.0f}; 101cb93a386Sopenharmony_ci float unusedRadii[2] = {0.0f, 0.0f}; 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci void* srcs[kNumGradientUniforms] = { 104cb93a386Sopenharmony_ci colors, 105cb93a386Sopenharmony_ci offsets, 106cb93a386Sopenharmony_ci &point, 107cb93a386Sopenharmony_ci &unusedPoint, 108cb93a386Sopenharmony_ci &unusedRadii[0], 109cb93a386Sopenharmony_ci &unusedRadii[1], 110cb93a386Sopenharmony_ci }; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci return make_gradient_uniform_data_common(srcs); 113cb93a386Sopenharmony_ci}; 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_cisk_sp<UniformData> make_conical_gradient_uniform_data(SkPoint point0, 116cb93a386Sopenharmony_ci SkPoint point1, 117cb93a386Sopenharmony_ci float radius0, 118cb93a386Sopenharmony_ci float radius1, 119cb93a386Sopenharmony_ci SkColor4f colors[kMaxStops], 120cb93a386Sopenharmony_ci float offsets[kMaxStops]) { 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci void* srcs[kNumGradientUniforms] = { 123cb93a386Sopenharmony_ci colors, 124cb93a386Sopenharmony_ci offsets, 125cb93a386Sopenharmony_ci &point0, 126cb93a386Sopenharmony_ci &point1, 127cb93a386Sopenharmony_ci &radius0, 128cb93a386Sopenharmony_ci &radius1, 129cb93a386Sopenharmony_ci }; 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci return make_gradient_uniform_data_common(srcs); 132cb93a386Sopenharmony_ci}; 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_civoid to_color4fs(int numColors, SkColor colors[kMaxStops], SkColor4f color4fs[kMaxStops]) { 135cb93a386Sopenharmony_ci SkASSERT(numColors >= 2 && numColors <= kMaxStops); 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci int i; 138cb93a386Sopenharmony_ci for (i = 0; i < numColors; ++i) { 139cb93a386Sopenharmony_ci color4fs[i] = SkColor4f::FromColor(colors[i]); 140cb93a386Sopenharmony_ci } 141cb93a386Sopenharmony_ci for ( ; i < kMaxStops; ++i) { 142cb93a386Sopenharmony_ci color4fs[i] = color4fs[numColors-1]; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci} 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_civoid expand_stops(int numStops, float offsets[kMaxStops]) { 147cb93a386Sopenharmony_ci SkASSERT(numStops >= 2 && numStops <= kMaxStops); 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci for (int i = numStops ; i < kMaxStops; ++i) { 150cb93a386Sopenharmony_ci offsets[i] = offsets[numStops-1]; 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci} 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_cisk_sp<UniformData> make_solid_uniform_data(SkColor4f color) { 155cb93a386Sopenharmony_ci UniformManager mgr(Layout::kMetal); 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci size_t dataSize = mgr.writeUniforms(SkSpan<const Uniform>(kSolidUniforms, kNumSolidUniforms), 158cb93a386Sopenharmony_ci nullptr, nullptr, nullptr); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci sk_sp<UniformData> result = UniformData::Make(kNumSolidUniforms, kSolidUniforms, dataSize); 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci void* srcs[kNumSolidUniforms] = { &color }; 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci mgr.writeUniforms(SkSpan<const Uniform>(kSolidUniforms, kNumSolidUniforms), 165cb93a386Sopenharmony_ci srcs, result->offsets(), result->data()); 166cb93a386Sopenharmony_ci return result; 167cb93a386Sopenharmony_ci} 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci} // anonymous namespace 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_cisk_sp<UniformData> UniformData::Make(int count, 172cb93a386Sopenharmony_ci const Uniform* uniforms, 173cb93a386Sopenharmony_ci size_t dataSize) { 174cb93a386Sopenharmony_ci // TODO: the offsets and data should just be allocated right after UniformData in an arena 175cb93a386Sopenharmony_ci uint32_t* offsets = new uint32_t[count]; 176cb93a386Sopenharmony_ci char* data = new char[dataSize]; 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci return sk_sp<UniformData>(new UniformData(count, uniforms, offsets, data, dataSize)); 179cb93a386Sopenharmony_ci} 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_cistd::tuple<Combination, sk_sp<UniformData>> ExtractCombo(UniformCache* cache, const SkPaint& p) { 182cb93a386Sopenharmony_ci Combination result; 183cb93a386Sopenharmony_ci sk_sp<UniformData> uniforms; 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci if (auto s = p.getShader()) { 186cb93a386Sopenharmony_ci SkColor colors[kMaxStops]; 187cb93a386Sopenharmony_ci SkColor4f color4fs[kMaxStops]; 188cb93a386Sopenharmony_ci float offsets[kMaxStops]; 189cb93a386Sopenharmony_ci SkShader::GradientInfo gradInfo; 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci gradInfo.fColorCount = kMaxStops; 192cb93a386Sopenharmony_ci gradInfo.fColors = colors; 193cb93a386Sopenharmony_ci gradInfo.fColorOffsets = offsets; 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_ci SkShader::GradientType type = s->asAGradient(&gradInfo); 196cb93a386Sopenharmony_ci if (gradInfo.fColorCount > kMaxStops) { 197cb93a386Sopenharmony_ci type = SkShader::GradientType::kNone_GradientType; 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci switch (type) { 201cb93a386Sopenharmony_ci case SkShader::kLinear_GradientType: { 202cb93a386Sopenharmony_ci to_color4fs(gradInfo.fColorCount, colors, color4fs); 203cb93a386Sopenharmony_ci expand_stops(gradInfo.fColorCount, offsets); 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci result.fShaderType = ShaderCombo::ShaderType::kLinearGradient; 206cb93a386Sopenharmony_ci result.fTileMode = gradInfo.fTileMode; 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci uniforms = make_linear_gradient_uniform_data(gradInfo.fPoint[0], 209cb93a386Sopenharmony_ci gradInfo.fPoint[1], 210cb93a386Sopenharmony_ci color4fs, 211cb93a386Sopenharmony_ci offsets); 212cb93a386Sopenharmony_ci } break; 213cb93a386Sopenharmony_ci case SkShader::kRadial_GradientType: { 214cb93a386Sopenharmony_ci to_color4fs(gradInfo.fColorCount, colors, color4fs); 215cb93a386Sopenharmony_ci expand_stops(gradInfo.fColorCount, offsets); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci result.fShaderType = ShaderCombo::ShaderType::kRadialGradient; 218cb93a386Sopenharmony_ci result.fTileMode = gradInfo.fTileMode; 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci uniforms = make_radial_gradient_uniform_data(gradInfo.fPoint[0], 221cb93a386Sopenharmony_ci gradInfo.fRadius[0], 222cb93a386Sopenharmony_ci color4fs, 223cb93a386Sopenharmony_ci offsets); 224cb93a386Sopenharmony_ci } break; 225cb93a386Sopenharmony_ci case SkShader::kSweep_GradientType: 226cb93a386Sopenharmony_ci to_color4fs(gradInfo.fColorCount, colors, color4fs); 227cb93a386Sopenharmony_ci expand_stops(gradInfo.fColorCount, offsets); 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci result.fShaderType = ShaderCombo::ShaderType::kSweepGradient; 230cb93a386Sopenharmony_ci result.fTileMode = gradInfo.fTileMode; 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci uniforms = make_sweep_gradient_uniform_data(gradInfo.fPoint[0], 233cb93a386Sopenharmony_ci color4fs, 234cb93a386Sopenharmony_ci offsets); 235cb93a386Sopenharmony_ci break; 236cb93a386Sopenharmony_ci case SkShader::GradientType::kConical_GradientType: 237cb93a386Sopenharmony_ci to_color4fs(gradInfo.fColorCount, colors, color4fs); 238cb93a386Sopenharmony_ci expand_stops(gradInfo.fColorCount, offsets); 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci result.fShaderType = ShaderCombo::ShaderType::kConicalGradient; 241cb93a386Sopenharmony_ci result.fTileMode = gradInfo.fTileMode; 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci uniforms = make_conical_gradient_uniform_data(gradInfo.fPoint[0], 244cb93a386Sopenharmony_ci gradInfo.fPoint[1], 245cb93a386Sopenharmony_ci gradInfo.fRadius[0], 246cb93a386Sopenharmony_ci gradInfo.fRadius[1], 247cb93a386Sopenharmony_ci color4fs, 248cb93a386Sopenharmony_ci offsets); 249cb93a386Sopenharmony_ci break; 250cb93a386Sopenharmony_ci case SkShader::GradientType::kColor_GradientType: 251cb93a386Sopenharmony_ci case SkShader::GradientType::kNone_GradientType: 252cb93a386Sopenharmony_ci default: 253cb93a386Sopenharmony_ci result.fShaderType = ShaderCombo::ShaderType::kNone; 254cb93a386Sopenharmony_ci result.fTileMode = SkTileMode::kRepeat; 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci uniforms = make_solid_uniform_data(p.getColor4f()); 257cb93a386Sopenharmony_ci break; 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci } else { 260cb93a386Sopenharmony_ci // Solid colored paint 261cb93a386Sopenharmony_ci result.fShaderType = ShaderCombo::ShaderType::kNone; 262cb93a386Sopenharmony_ci result.fTileMode = SkTileMode::kRepeat; 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci uniforms = make_solid_uniform_data(p.getColor4f()); 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci result.fBlendMode = p.getBlendMode_or(SkBlendMode::kSrcOver); 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_ci sk_sp<UniformData> trueUD = cache->findOrCreate(std::move(uniforms)); 270cb93a386Sopenharmony_ci return { result, std::move(trueUD) }; 271cb93a386Sopenharmony_ci} 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_cinamespace { 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci// TODO: use a SkSpan for the parameters 276cb93a386Sopenharmony_cistd::string emit_MSL_uniform_struct(const Uniform *uniforms, int numUniforms) { 277cb93a386Sopenharmony_ci std::string result; 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci result.append("struct FragmentUniforms {\n"); 280cb93a386Sopenharmony_ci for (int i = 0; i < numUniforms; ++i) { 281cb93a386Sopenharmony_ci // TODO: this is sufficient for the sprint but should be changed to use SkSL's 282cb93a386Sopenharmony_ci // machinery 283cb93a386Sopenharmony_ci switch (uniforms[i].type()) { 284cb93a386Sopenharmony_ci case SLType::kFloat4: 285cb93a386Sopenharmony_ci result.append("vector_float4"); 286cb93a386Sopenharmony_ci break; 287cb93a386Sopenharmony_ci case SLType::kFloat2: 288cb93a386Sopenharmony_ci result.append("vector_float2"); 289cb93a386Sopenharmony_ci break; 290cb93a386Sopenharmony_ci case SLType::kFloat: 291cb93a386Sopenharmony_ci result.append("float"); 292cb93a386Sopenharmony_ci break; 293cb93a386Sopenharmony_ci case SLType::kHalf4: 294cb93a386Sopenharmony_ci result.append("vector_half4"); 295cb93a386Sopenharmony_ci break; 296cb93a386Sopenharmony_ci default: 297cb93a386Sopenharmony_ci SkASSERT(0); 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci result.append(" "); 301cb93a386Sopenharmony_ci result.append(uniforms[i].name()); 302cb93a386Sopenharmony_ci if (uniforms[i].count()) { 303cb93a386Sopenharmony_ci result.append("["); 304cb93a386Sopenharmony_ci result.append(std::to_string(uniforms[i].count())); 305cb93a386Sopenharmony_ci result.append("]"); 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci result.append(";\n"); 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci result.append("};\n"); 310cb93a386Sopenharmony_ci return result; 311cb93a386Sopenharmony_ci} 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci} // anonymous namespace 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_cistd::string GetMSLUniformStruct(ShaderCombo::ShaderType shaderType) { 316cb93a386Sopenharmony_ci switch (shaderType) { 317cb93a386Sopenharmony_ci case ShaderCombo::ShaderType::kLinearGradient: 318cb93a386Sopenharmony_ci case ShaderCombo::ShaderType::kRadialGradient: 319cb93a386Sopenharmony_ci case ShaderCombo::ShaderType::kSweepGradient: 320cb93a386Sopenharmony_ci case ShaderCombo::ShaderType::kConicalGradient: 321cb93a386Sopenharmony_ci return emit_MSL_uniform_struct(kGradientUniforms, kNumGradientUniforms); 322cb93a386Sopenharmony_ci case ShaderCombo::ShaderType::kNone: 323cb93a386Sopenharmony_ci default: 324cb93a386Sopenharmony_ci return emit_MSL_uniform_struct(kSolidUniforms, kNumSolidUniforms); 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci} 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci} // namespace skgpu 329