xref: /aosp_15_r20/external/skia/src/shaders/SkPerlinNoiseShaderImpl.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/shaders/SkPerlinNoiseShaderImpl.h"
9 
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkShader.h"
14 #include "include/effects/SkPerlinNoiseShader.h"
15 #include "src/base/SkArenaAlloc.h"
16 #include "src/core/SkEffectPriv.h"
17 #include "src/core/SkRasterPipeline.h"
18 #include "src/core/SkRasterPipelineOpContexts.h"
19 #include "src/core/SkRasterPipelineOpList.h"
20 #include "src/core/SkReadBuffer.h"
21 #include "src/core/SkWriteBuffer.h"
22 #include "src/shaders/SkPerlinNoiseShaderType.h"
23 
24 #include <optional>
25 
SkPerlinNoiseShader(SkPerlinNoiseShaderType type,SkScalar baseFrequencyX,SkScalar baseFrequencyY,int numOctaves,SkScalar seed,const SkISize * tileSize)26 SkPerlinNoiseShader::SkPerlinNoiseShader(SkPerlinNoiseShaderType type,
27                                          SkScalar baseFrequencyX,
28                                          SkScalar baseFrequencyY,
29                                          int numOctaves,
30                                          SkScalar seed,
31                                          const SkISize* tileSize)
32         : fType(type)
33         , fBaseFrequencyX(baseFrequencyX)
34         , fBaseFrequencyY(baseFrequencyY)
35         , fNumOctaves(numOctaves > kMaxOctaves ? kMaxOctaves
36                                                : numOctaves)  // [0,255] octaves allowed
37         , fSeed(seed)
38         , fTileSize(nullptr == tileSize ? SkISize::Make(0, 0) : *tileSize)
39         , fStitchTiles(!fTileSize.isEmpty()) {
40     SkASSERT(numOctaves >= 0 && numOctaves <= kMaxOctaves);
41     SkASSERT(fBaseFrequencyX >= 0);
42     SkASSERT(fBaseFrequencyY >= 0);
43 
44     // If kBlockSize changes then it must be changed in the SkSL noise_function
45     // implementation and the graphite backend
46     static_assert(SkPerlinNoiseShader::kBlockSize == 256);
47 }
48 
CreateProc(SkReadBuffer & buffer)49 sk_sp<SkFlattenable> SkPerlinNoiseShader::CreateProc(SkReadBuffer& buffer) {
50     SkPerlinNoiseShaderType type = buffer.read32LE(SkPerlinNoiseShaderType::kLast);
51 
52     SkScalar freqX = buffer.readScalar();
53     SkScalar freqY = buffer.readScalar();
54     int octaves = buffer.read32LE<int>(kMaxOctaves);
55 
56     SkScalar seed = buffer.readScalar();
57     SkISize tileSize;
58     tileSize.fWidth = buffer.readInt();
59     tileSize.fHeight = buffer.readInt();
60 
61     switch (type) {
62         case SkPerlinNoiseShaderType::kFractalNoise:
63             return SkShaders::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
64         case SkPerlinNoiseShaderType::kTurbulence:
65             return SkShaders::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
66         default:
67             // Really shouldn't get here b.c. of earlier check on type
68             buffer.validate(false);
69             return nullptr;
70     }
71 }
72 
flatten(SkWriteBuffer & buffer) const73 void SkPerlinNoiseShader::flatten(SkWriteBuffer& buffer) const {
74     buffer.writeInt((int)fType);
75     buffer.writeScalar(fBaseFrequencyX);
76     buffer.writeScalar(fBaseFrequencyY);
77     buffer.writeInt(fNumOctaves);
78     buffer.writeScalar(fSeed);
79     buffer.writeInt(fTileSize.fWidth);
80     buffer.writeInt(fTileSize.fHeight);
81 }
82 
appendStages(const SkStageRec & rec,const SkShaders::MatrixRec & mRec) const83 bool SkPerlinNoiseShader::appendStages(const SkStageRec& rec,
84                                        const SkShaders::MatrixRec& mRec) const {
85     std::optional<SkShaders::MatrixRec> newMRec = mRec.apply(rec);
86     if (!newMRec.has_value()) {
87         return false;
88     }
89 
90     fInitPaintingDataOnce([&] {
91         const_cast<SkPerlinNoiseShader*>(this)->fPaintingData = this->getPaintingData();
92     });
93 
94     auto* ctx = rec.fAlloc->make<SkRasterPipeline_PerlinNoiseCtx>();
95     ctx->noiseType = fType;
96     ctx->baseFrequencyX = fPaintingData->fBaseFrequency.fX;
97     ctx->baseFrequencyY = fPaintingData->fBaseFrequency.fY;
98     ctx->stitchDataInX = fPaintingData->fStitchDataInit.fWidth;
99     ctx->stitchDataInY = fPaintingData->fStitchDataInit.fHeight;
100     ctx->stitching = fStitchTiles;
101     ctx->numOctaves = fNumOctaves;
102     ctx->latticeSelector = fPaintingData->fLatticeSelector;
103     ctx->noiseData = &fPaintingData->fNoise[0][0][0];
104 
105     rec.fPipeline->append(SkRasterPipelineOp::perlin_noise, ctx);
106     return true;
107 }
108 
109 ///////////////////////////////////////////////////////////////////////////////////////////////////
110 
valid_input(SkScalar baseX,SkScalar baseY,int numOctaves,const SkISize * tileSize,SkScalar seed)111 static bool valid_input(
112         SkScalar baseX, SkScalar baseY, int numOctaves, const SkISize* tileSize, SkScalar seed) {
113     if (!(baseX >= 0 && baseY >= 0)) {
114         return false;
115     }
116     if (!(numOctaves >= 0 && numOctaves <= SkPerlinNoiseShader::kMaxOctaves)) {
117         return false;
118     }
119     if (tileSize && !(tileSize->width() >= 0 && tileSize->height() >= 0)) {
120         return false;
121     }
122     if (!SkIsFinite(seed)) {
123         return false;
124     }
125     return true;
126 }
127 
SkRegisterPerlinNoiseShaderFlattenable()128 void SkRegisterPerlinNoiseShaderFlattenable() {
129     SK_REGISTER_FLATTENABLE(SkPerlinNoiseShader);
130     // Previous name
131     SkFlattenable::Register("SkPerlinNoiseShaderImpl", SkPerlinNoiseShader::CreateProc);
132 }
133 
134 namespace SkShaders {
MakeFractalNoise(SkScalar baseFrequencyX,SkScalar baseFrequencyY,int numOctaves,SkScalar seed,const SkISize * tileSize)135 sk_sp<SkShader> MakeFractalNoise(SkScalar baseFrequencyX,
136                                  SkScalar baseFrequencyY,
137                                  int numOctaves,
138                                  SkScalar seed,
139                                  const SkISize* tileSize) {
140     if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
141         return nullptr;
142     }
143 
144     if (0 == numOctaves) {
145         // For kFractalNoise, w/o any octaves, the entire shader collapses to:
146         //    [0,0,0,0] * 0.5 + 0.5
147         constexpr SkColor4f kTransparentGray = {0.5f, 0.5f, 0.5f, 0.5f};
148 
149         return SkShaders::Color(kTransparentGray, /* colorSpace= */ nullptr);
150     }
151 
152     return sk_sp<SkShader>(new SkPerlinNoiseShader(SkPerlinNoiseShaderType::kFractalNoise,
153                                                    baseFrequencyX,
154                                                    baseFrequencyY,
155                                                    numOctaves,
156                                                    seed,
157                                                    tileSize));
158 }
159 
MakeTurbulence(SkScalar baseFrequencyX,SkScalar baseFrequencyY,int numOctaves,SkScalar seed,const SkISize * tileSize)160 sk_sp<SkShader> MakeTurbulence(SkScalar baseFrequencyX,
161                                SkScalar baseFrequencyY,
162                                int numOctaves,
163                                SkScalar seed,
164                                const SkISize* tileSize) {
165     if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, tileSize, seed)) {
166         return nullptr;
167     }
168 
169     if (0 == numOctaves) {
170         // For kTurbulence, w/o any octaves, the entire shader collapses to: [0,0,0,0]
171         return SkShaders::Color(SkColors::kTransparent, /* colorSpace= */ nullptr);
172     }
173 
174     return sk_sp<SkShader>(new SkPerlinNoiseShader(SkPerlinNoiseShaderType::kTurbulence,
175                                                    baseFrequencyX,
176                                                    baseFrequencyY,
177                                                    numOctaves,
178                                                    seed,
179                                                    tileSize));
180 }
181 
182 }  // namespace SkShaders
183