SkPictureShader.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * Copyright 2014 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. #include "src/shaders/SkPictureShader.h"
  8. #include "include/core/SkBitmap.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkImage.h"
  11. #include "src/core/SkArenaAlloc.h"
  12. #include "src/core/SkMatrixUtils.h"
  13. #include "src/core/SkPicturePriv.h"
  14. #include "src/core/SkReadBuffer.h"
  15. #include "src/core/SkResourceCache.h"
  16. #include "src/shaders/SkBitmapProcShader.h"
  17. #include "src/shaders/SkImageShader.h"
  18. #include <atomic>
  19. #if SK_SUPPORT_GPU
  20. #include "include/private/GrRecordingContext.h"
  21. #include "src/gpu/GrCaps.h"
  22. #include "src/gpu/GrColorSpaceInfo.h"
  23. #include "src/gpu/GrFragmentProcessor.h"
  24. #include "src/gpu/GrRecordingContextPriv.h"
  25. #include "src/gpu/SkGr.h"
  26. #endif
  27. sk_sp<SkShader> SkPicture::makeShader(SkTileMode tmx, SkTileMode tmy, const SkMatrix* localMatrix,
  28. const SkRect* tile) const {
  29. if (localMatrix && !localMatrix->invert(nullptr)) {
  30. return nullptr;
  31. }
  32. return SkPictureShader::Make(sk_ref_sp(this), tmx, tmy, localMatrix, tile);
  33. }
  34. sk_sp<SkShader> SkPicture::makeShader(SkTileMode tmx, SkTileMode tmy,
  35. const SkMatrix* localMatrix) const {
  36. return this->makeShader(tmx, tmy, localMatrix, nullptr);
  37. }
  38. namespace {
  39. static unsigned gBitmapShaderKeyNamespaceLabel;
  40. struct BitmapShaderKey : public SkResourceCache::Key {
  41. public:
  42. BitmapShaderKey(SkColorSpace* colorSpace,
  43. SkImage::BitDepth bitDepth,
  44. uint32_t shaderID,
  45. const SkSize& scale)
  46. : fColorSpaceXYZHash(colorSpace->toXYZD50Hash())
  47. , fColorSpaceTransferFnHash(colorSpace->transferFnHash())
  48. , fBitDepth(bitDepth)
  49. , fScale(scale) {
  50. static const size_t keySize = sizeof(fColorSpaceXYZHash) +
  51. sizeof(fColorSpaceTransferFnHash) +
  52. sizeof(fBitDepth) +
  53. sizeof(fScale);
  54. // This better be packed.
  55. SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - &fColorSpaceXYZHash) == keySize);
  56. this->init(&gBitmapShaderKeyNamespaceLabel, MakeSharedID(shaderID), keySize);
  57. }
  58. static uint64_t MakeSharedID(uint32_t shaderID) {
  59. uint64_t sharedID = SkSetFourByteTag('p', 's', 'd', 'r');
  60. return (sharedID << 32) | shaderID;
  61. }
  62. private:
  63. uint32_t fColorSpaceXYZHash;
  64. uint32_t fColorSpaceTransferFnHash;
  65. SkImage::BitDepth fBitDepth;
  66. SkSize fScale;
  67. SkDEBUGCODE(uint32_t fEndOfStruct;)
  68. };
  69. struct BitmapShaderRec : public SkResourceCache::Rec {
  70. BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader)
  71. : fKey(key)
  72. , fShader(SkRef(tileShader)) {}
  73. BitmapShaderKey fKey;
  74. sk_sp<SkShader> fShader;
  75. const Key& getKey() const override { return fKey; }
  76. size_t bytesUsed() const override {
  77. // Just the record overhead -- the actual pixels are accounted by SkImage_Lazy.
  78. return sizeof(fKey) + sizeof(SkImageShader);
  79. }
  80. const char* getCategory() const override { return "bitmap-shader"; }
  81. SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
  82. static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
  83. const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec);
  84. sk_sp<SkShader>* result = reinterpret_cast<sk_sp<SkShader>*>(contextShader);
  85. *result = rec.fShader;
  86. // The bitmap shader is backed by an image generator, thus it can always re-generate its
  87. // pixels if discarded.
  88. return true;
  89. }
  90. };
  91. uint32_t next_id() {
  92. static std::atomic<uint32_t> nextID{1};
  93. uint32_t id;
  94. do {
  95. id = nextID++;
  96. } while (id == SK_InvalidGenID);
  97. return id;
  98. }
  99. } // namespace
  100. SkPictureShader::SkPictureShader(sk_sp<SkPicture> picture, SkTileMode tmx, SkTileMode tmy,
  101. const SkMatrix* localMatrix, const SkRect* tile)
  102. : INHERITED(localMatrix)
  103. , fPicture(std::move(picture))
  104. , fTile(tile ? *tile : fPicture->cullRect())
  105. , fTmx(tmx)
  106. , fTmy(tmy)
  107. , fUniqueID(next_id())
  108. , fAddedToCache(false) {}
  109. SkPictureShader::~SkPictureShader() {
  110. if (fAddedToCache.load()) {
  111. SkResourceCache::PostPurgeSharedID(BitmapShaderKey::MakeSharedID(fUniqueID));
  112. }
  113. }
  114. sk_sp<SkShader> SkPictureShader::Make(sk_sp<SkPicture> picture, SkTileMode tmx, SkTileMode tmy,
  115. const SkMatrix* localMatrix, const SkRect* tile) {
  116. if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) {
  117. return SkShaders::Empty();
  118. }
  119. return sk_sp<SkShader>(new SkPictureShader(std::move(picture), tmx, tmy, localMatrix, tile));
  120. }
  121. SkPicture* SkPictureShader::isAPicture(SkMatrix* matrix,
  122. SkTileMode tileModes[2],
  123. SkRect* tile) const {
  124. if (matrix) {
  125. *matrix = this->getLocalMatrix();
  126. }
  127. if (tileModes) {
  128. tileModes[0] = fTmx;
  129. tileModes[1] = fTmy;
  130. }
  131. if (tile) {
  132. *tile = fTile;
  133. }
  134. return fPicture.get();
  135. }
  136. sk_sp<SkFlattenable> SkPictureShader::CreateProc(SkReadBuffer& buffer) {
  137. SkMatrix lm;
  138. buffer.readMatrix(&lm);
  139. auto tmx = buffer.read32LE(SkTileMode::kLastTileMode);
  140. auto tmy = buffer.read32LE(SkTileMode::kLastTileMode);
  141. SkRect tile;
  142. buffer.readRect(&tile);
  143. sk_sp<SkPicture> picture;
  144. bool didSerialize = buffer.readBool();
  145. if (didSerialize) {
  146. picture = SkPicturePriv::MakeFromBuffer(buffer);
  147. }
  148. return SkPictureShader::Make(picture, tmx, tmy, &lm, &tile);
  149. }
  150. void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
  151. buffer.writeMatrix(this->getLocalMatrix());
  152. buffer.write32((unsigned)fTmx);
  153. buffer.write32((unsigned)fTmy);
  154. buffer.writeRect(fTile);
  155. buffer.writeBool(true);
  156. SkPicturePriv::Flatten(fPicture, buffer);
  157. }
  158. // Returns a cached image shader, which wraps a single picture tile at the given
  159. // CTM/local matrix. Also adjusts the local matrix for tile scaling.
  160. sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix,
  161. SkTCopyOnFirstWrite<SkMatrix>* localMatrix,
  162. SkColorType dstColorType,
  163. SkColorSpace* dstColorSpace,
  164. const int maxTextureSize) const {
  165. SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
  166. const SkMatrix m = SkMatrix::Concat(viewMatrix, **localMatrix);
  167. // Use a rotation-invariant scale
  168. SkPoint scale;
  169. //
  170. // TODO: replace this with decomposeScale() -- but beware LayoutTest rebaselines!
  171. //
  172. if (!SkDecomposeUpper2x2(m, nullptr, &scale, nullptr)) {
  173. // Decomposition failed, use an approximation.
  174. scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
  175. SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
  176. }
  177. SkSize scaledSize = SkSize::Make(SkScalarAbs(scale.x() * fTile.width()),
  178. SkScalarAbs(scale.y() * fTile.height()));
  179. // Clamp the tile size to about 4M pixels
  180. static const SkScalar kMaxTileArea = 2048 * 2048;
  181. SkScalar tileArea = scaledSize.width() * scaledSize.height();
  182. if (tileArea > kMaxTileArea) {
  183. SkScalar clampScale = SkScalarSqrt(kMaxTileArea / tileArea);
  184. scaledSize.set(scaledSize.width() * clampScale,
  185. scaledSize.height() * clampScale);
  186. }
  187. #if SK_SUPPORT_GPU
  188. // Scale down the tile size if larger than maxTextureSize for GPU Path or it should fail on create texture
  189. if (maxTextureSize) {
  190. if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
  191. SkScalar downScale = maxTextureSize / SkMaxScalar(scaledSize.width(), scaledSize.height());
  192. scaledSize.set(SkScalarFloorToScalar(scaledSize.width() * downScale),
  193. SkScalarFloorToScalar(scaledSize.height() * downScale));
  194. }
  195. }
  196. #endif
  197. const SkISize tileSize = scaledSize.toCeil();
  198. if (tileSize.isEmpty()) {
  199. return SkShaders::Empty();
  200. }
  201. // The actual scale, compensating for rounding & clamping.
  202. const SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.width(),
  203. SkIntToScalar(tileSize.height()) / fTile.height());
  204. sk_sp<SkColorSpace> imgCS = dstColorSpace ? sk_ref_sp(dstColorSpace): SkColorSpace::MakeSRGB();
  205. SkImage::BitDepth bitDepth =
  206. dstColorType >= kRGBA_F16Norm_SkColorType
  207. ? SkImage::BitDepth::kF16 : SkImage::BitDepth::kU8;
  208. BitmapShaderKey key(imgCS.get(), bitDepth, fUniqueID, tileScale);
  209. sk_sp<SkShader> tileShader;
  210. if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) {
  211. SkMatrix tileMatrix;
  212. tileMatrix.setRectToRect(fTile, SkRect::MakeIWH(tileSize.width(), tileSize.height()),
  213. SkMatrix::kFill_ScaleToFit);
  214. sk_sp<SkImage> tileImage = SkImage::MakeFromPicture(fPicture, tileSize, &tileMatrix,
  215. nullptr, bitDepth, std::move(imgCS));
  216. if (!tileImage) {
  217. return nullptr;
  218. }
  219. tileShader = tileImage->makeShader(fTmx, fTmy);
  220. SkResourceCache::Add(new BitmapShaderRec(key, tileShader.get()));
  221. fAddedToCache.store(true);
  222. }
  223. if (tileScale.width() != 1 || tileScale.height() != 1) {
  224. localMatrix->writable()->preScale(1 / tileScale.width(), 1 / tileScale.height());
  225. }
  226. return tileShader;
  227. }
  228. bool SkPictureShader::onAppendStages(const SkStageRec& rec) const {
  229. auto lm = this->totalLocalMatrix(rec.fLocalM);
  230. // Keep bitmapShader alive by using alloc instead of stack memory
  231. auto& bitmapShader = *rec.fAlloc->make<sk_sp<SkShader>>();
  232. bitmapShader = this->refBitmapShader(rec.fCTM, &lm, rec.fDstColorType, rec.fDstCS);
  233. if (!bitmapShader) {
  234. return false;
  235. }
  236. SkStageRec localRec = rec;
  237. localRec.fLocalM = lm->isIdentity() ? nullptr : lm.get();
  238. return as_SB(bitmapShader)->appendStages(localRec);
  239. }
  240. /////////////////////////////////////////////////////////////////////////////////////////
  241. #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
  242. SkShaderBase::Context* SkPictureShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc)
  243. const {
  244. auto lm = this->totalLocalMatrix(rec.fLocalMatrix);
  245. sk_sp<SkShader> bitmapShader = this->refBitmapShader(*rec.fMatrix, &lm, rec.fDstColorType,
  246. rec.fDstColorSpace);
  247. if (!bitmapShader) {
  248. return nullptr;
  249. }
  250. ContextRec localRec = rec;
  251. localRec.fLocalMatrix = lm->isIdentity() ? nullptr : lm.get();
  252. PictureShaderContext* ctx =
  253. alloc->make<PictureShaderContext>(*this, localRec, std::move(bitmapShader), alloc);
  254. if (nullptr == ctx->fBitmapShaderContext) {
  255. ctx = nullptr;
  256. }
  257. return ctx;
  258. }
  259. #endif
  260. /////////////////////////////////////////////////////////////////////////////////////////
  261. SkPictureShader::PictureShaderContext::PictureShaderContext(
  262. const SkPictureShader& shader, const ContextRec& rec, sk_sp<SkShader> bitmapShader,
  263. SkArenaAlloc* alloc)
  264. : INHERITED(shader, rec)
  265. , fBitmapShader(std::move(bitmapShader))
  266. {
  267. fBitmapShaderContext = as_SB(fBitmapShader)->makeContext(rec, alloc);
  268. //if fBitmapShaderContext is null, we are invalid
  269. }
  270. uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
  271. SkASSERT(fBitmapShaderContext);
  272. return fBitmapShaderContext->getFlags();
  273. }
  274. void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
  275. SkASSERT(fBitmapShaderContext);
  276. fBitmapShaderContext->shadeSpan(x, y, dstC, count);
  277. }
  278. #if SK_SUPPORT_GPU
  279. #include "include/gpu/GrContext.h"
  280. #include "src/gpu/GrContextPriv.h"
  281. std::unique_ptr<GrFragmentProcessor> SkPictureShader::asFragmentProcessor(
  282. const GrFPArgs& args) const {
  283. int maxTextureSize = 0;
  284. if (args.fContext) {
  285. maxTextureSize = args.fContext->priv().caps()->maxTextureSize();
  286. }
  287. auto lm = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
  288. SkColorType dstColorType = GrColorTypeToSkColorType(args.fDstColorSpaceInfo->colorType());
  289. if (dstColorType == kUnknown_SkColorType) {
  290. dstColorType = kRGBA_8888_SkColorType;
  291. }
  292. sk_sp<SkShader> bitmapShader(this->refBitmapShader(*args.fViewMatrix, &lm, dstColorType,
  293. args.fDstColorSpaceInfo->colorSpace(),
  294. maxTextureSize));
  295. if (!bitmapShader) {
  296. return nullptr;
  297. }
  298. // We want to *reset* args.fPreLocalMatrix, not compose it.
  299. GrFPArgs newArgs(args.fContext, args.fViewMatrix, args.fFilterQuality, args.fDstColorSpaceInfo);
  300. newArgs.fPreLocalMatrix = lm.get();
  301. return as_SB(bitmapShader)->asFragmentProcessor(newArgs);
  302. }
  303. #endif