Skip to content

Commit 39d1c1e

Browse files
Revert "Never share pixels when we make a subset image"
This reverts commit 3eff245. Reason for revert: did I break abandongpu bot? Original change's description: > Never share pixels when we make a subset image > > - mostly just affects Lazy images (raster was already always copying) > - issue with other factories that offer subsetting > - (e.g. MakeFromGenerator) > - can we remove those options, and require makeSubset() afterwards? > - greatly simplifies dealing with mipmaps > > Landing this would obsolete > https://skia-review.googlesource.com/c/skia/+/305960 > > Related: https://skia-review.googlesource.com/c/skia/+/306136 > > Related: https://bugs.chromium.org/p/skia/issues/detail?id=10544 > > Change-Id: I074420543bd2fcd46ed1620bbf0eed00371ab018 > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/305970 > Commit-Queue: Mike Reed <reed@google.com> > Reviewed-by: Leon Scroggins <scroggo@google.com> TBR=mtklein@google.com,bsalomon@google.com,robertphillips@google.com,scroggo@google.com,brianosman@google.com,reed@google.com Change-Id: Iab2f92855fe61e48f0e432b7257eb7ddef78fcfa No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://skia-review.googlesource.com/c/skia/+/306377 Reviewed-by: Mike Reed <reed@google.com>
1 parent 3eff245 commit 39d1c1e

File tree

8 files changed

+147
-35
lines changed

8 files changed

+147
-35
lines changed

gm/image_pict.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,7 @@ class ImageCacheratorGM : public skiagm::GM {
264264
if (!gen) {
265265
return false;
266266
}
267-
fImageSubset = SkImage::MakeFromGenerator(std::move(gen))->makeSubset(subset,
268-
dContext);
267+
fImageSubset = SkImage::MakeFromGenerator(std::move(gen))->makeSubset(subset);
269268

270269
SkASSERT(fImage->dimensions() == SkISize::Make(100, 100));
271270
SkASSERT(fImageSubset->dimensions() == SkISize::Make(50, 50));

include/core/SkImage.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,20 +1188,20 @@ class SK_API SkImage : public SkRefCnt {
11881188
*/
11891189
sk_sp<SkData> refEncodedData() const;
11901190

1191-
/** Returns subset of this image.
1191+
/** Returns subset of SkImage. subset must be fully contained by SkImage dimensions().
1192+
The implementation may share pixels, or may copy them.
11921193
11931194
Returns nullptr if any of the following are true:
11941195
- Subset is empty
1195-
- Subset is not contained inside the image's bounds
1196-
- Pixels in the image could not be read or copied
1196+
- Subset is not contained by bounds
1197+
- Pixels in SkImage could not be read or copied
11971198
11981199
If this image is texture-backed, the context parameter is required and must match the
1199-
context of the source image. If the context parameter is provided, and the image is
1200-
raster-backed, the subset will be converted to texture-backed.
1200+
context of the source image.
12011201
12021202
@param subset bounds of returned SkImage
12031203
@param context the GrDirectContext in play, if it exists
1204-
@return the subsetted image, or nullptr
1204+
@return partial or full SkImage, or nullptr
12051205
12061206
example: https://fiddle.skia.org/c/@Image_makeSubset
12071207
*/

src/core/SkImagePriv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,10 @@ bool SkImage_pinAsTexture(const SkImage*, GrRecordingContext*);
8585
*/
8686
void SkImage_unpinAsTexture(const SkImage*, GrRecordingContext*);
8787

88+
/**
89+
* Returns the bounds of the image relative to its encoded buffer. For all non-lazy images,
90+
* this returns (0,0,width,height). For a lazy-image, it may return a subset of that rect.
91+
*/
92+
SkIRect SkImage_getSubset(const SkImage*);
93+
8894
#endif

src/core/SkWriteBuffer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ bool SkBinaryWriteBuffer::writeToStream(SkWStream* stream) const {
151151
*/
152152
void SkBinaryWriteBuffer::writeImage(const SkImage* image) {
153153
uint32_t flags = 0;
154+
const SkIRect r = SkImage_getSubset(image);
155+
if (r.x() != 0 || r.y() != 0 || r.width() != image->width() || r.height() != image->height()) {
156+
flags |= SkWriteBufferImageFlags::kHasSubsetRect;
157+
}
154158
const SkMipmap* mips = as_IB(image)->onPeekMips();
155159
if (mips) {
156160
flags |= SkWriteBufferImageFlags::kHasMipmap;
@@ -167,8 +171,12 @@ void SkBinaryWriteBuffer::writeImage(const SkImage* image) {
167171
}
168172
this->writeDataAsByteArray(data.get());
169173

174+
if (flags & SkWriteBufferImageFlags::kHasSubsetRect) {
175+
this->writeIRect(r);
176+
}
170177
if (flags & SkWriteBufferImageFlags::kHasMipmap) {
171178
this->writeDataAsByteArray(mips->serialize().get());
179+
172180
}
173181
}
174182

src/image/SkImage.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,11 @@ void SkImage_unpinAsTexture(const SkImage* image, GrRecordingContext* rContext)
654654
as_IB(image)->onUnpinAsTexture(rContext);
655655
}
656656

657+
SkIRect SkImage_getSubset(const SkImage* image) {
658+
SkASSERT(image);
659+
return as_IB(image)->onGetSubset();
660+
}
661+
657662
///////////////////////////////////////////////////////////////////////////////////////////////////
658663

659664
SkMipmapBuilder::SkMipmapBuilder(const SkImageInfo& info) {

src/image/SkImage_Base.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ class SkImage_Base : public SkImage {
3636
public:
3737
~SkImage_Base() override;
3838

39+
virtual SkIRect onGetSubset() const {
40+
return { 0, 0, this->width(), this->height() };
41+
}
42+
3943
virtual bool onPeekPixels(SkPixmap*) const { return false; }
4044

4145
virtual const SkBitmap* onPeekBitmap() const { return nullptr; }

src/image/SkImage_Lazy.cpp

Lines changed: 109 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,38 @@ class SharedGenerator final : public SkNVRefCnt<SharedGenerator> {
6161

6262
///////////////////////////////////////////////////////////////////////////////
6363

64-
SkImage_Lazy::Validator::Validator(sk_sp<SharedGenerator> gen, const SkColorType* colorType,
65-
sk_sp<SkColorSpace> colorSpace)
64+
SkImage_Lazy::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRect* subset,
65+
const SkColorType* colorType, sk_sp<SkColorSpace> colorSpace)
6666
: fSharedGenerator(std::move(gen)) {
6767
if (!fSharedGenerator) {
6868
return;
6969
}
7070

7171
// The following generator accessors are safe without acquiring the mutex (const getters).
7272
// TODO: refactor to use a ScopedGenerator instead, for clarity.
73-
fInfo = fSharedGenerator->fGenerator->getInfo();
74-
if (fInfo.isEmpty()) {
73+
const SkImageInfo& info = fSharedGenerator->fGenerator->getInfo();
74+
if (info.isEmpty()) {
7575
fSharedGenerator.reset();
7676
return;
7777
}
7878

7979
fUniqueID = fSharedGenerator->fGenerator->uniqueID();
80-
81-
if (colorType && (*colorType == fInfo.colorType())) {
82-
colorType = nullptr;
80+
const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height());
81+
if (subset) {
82+
if (!bounds.contains(*subset)) {
83+
fSharedGenerator.reset();
84+
return;
85+
}
86+
if (*subset != bounds) {
87+
// we need a different uniqueID since we really are a subset of the raw generator
88+
fUniqueID = SkNextID::ImageID();
89+
}
90+
} else {
91+
subset = &bounds;
8392
}
8493

94+
fInfo = info.makeDimensions(subset->size());
95+
fOrigin = SkIPoint::Make(subset->x(), subset->y());
8596
if (colorType || colorSpace) {
8697
if (colorType) {
8798
fInfo = fInfo.makeColorType(*colorType);
@@ -120,15 +131,51 @@ class SkImage_Lazy::ScopedGenerator {
120131
///////////////////////////////////////////////////////////////////////////////
121132

122133
SkImage_Lazy::SkImage_Lazy(Validator* validator)
123-
: INHERITED(validator->fInfo, validator->fUniqueID)
124-
, fSharedGenerator(std::move(validator->fSharedGenerator))
125-
{
134+
: INHERITED(validator->fInfo, validator->fUniqueID)
135+
, fSharedGenerator(std::move(validator->fSharedGenerator))
136+
, fOrigin(validator->fOrigin) {
126137
SkASSERT(fSharedGenerator);
127138
}
128139

129140

130141
//////////////////////////////////////////////////////////////////////////////////////////////////
131142

143+
static bool generate_pixels(SkImageGenerator* gen, const SkPixmap& pmap, int originX, int originY) {
144+
const int genW = gen->getInfo().width();
145+
const int genH = gen->getInfo().height();
146+
const SkIRect srcR = SkIRect::MakeWH(genW, genH);
147+
const SkIRect dstR = SkIRect::MakeXYWH(originX, originY, pmap.width(), pmap.height());
148+
if (!srcR.contains(dstR)) {
149+
return false;
150+
}
151+
152+
// If they are requesting a subset, we have to have a temp allocation for full image, and
153+
// then copy the subset into their allocation
154+
SkBitmap full;
155+
SkPixmap fullPM;
156+
const SkPixmap* dstPM = &pmap;
157+
if (srcR != dstR) {
158+
if (!full.tryAllocPixels(pmap.info().makeWH(genW, genH))) {
159+
return false;
160+
}
161+
if (!full.peekPixels(&fullPM)) {
162+
return false;
163+
}
164+
dstPM = &fullPM;
165+
}
166+
167+
if (!gen->getPixels(dstPM->info(), dstPM->writable_addr(), dstPM->rowBytes())) {
168+
return false;
169+
}
170+
171+
if (srcR != dstR) {
172+
if (!full.readPixels(pmap, originX, originY)) {
173+
return false;
174+
}
175+
}
176+
return true;
177+
}
178+
132179
bool SkImage_Lazy::getROPixels(SkBitmap* bitmap, SkImage::CachingHint chint) const {
133180
auto check_output_bitmap = [bitmap]() {
134181
SkASSERT(bitmap->isImmutable());
@@ -145,14 +192,17 @@ bool SkImage_Lazy::getROPixels(SkBitmap* bitmap, SkImage::CachingHint chint) con
145192
if (SkImage::kAllow_CachingHint == chint) {
146193
SkPixmap pmap;
147194
SkBitmapCache::RecPtr cacheRec = SkBitmapCache::Alloc(desc, this->imageInfo(), &pmap);
148-
if (!cacheRec || !ScopedGenerator(fSharedGenerator)->getPixels(pmap)) {
195+
if (!cacheRec ||
196+
!generate_pixels(ScopedGenerator(fSharedGenerator), pmap,
197+
fOrigin.x(), fOrigin.y())) {
149198
return false;
150199
}
151200
SkBitmapCache::Add(std::move(cacheRec), bitmap);
152201
this->notifyAddedToRasterCache();
153202
} else {
154203
if (!bitmap->tryAllocPixels(this->imageInfo()) ||
155-
!ScopedGenerator(fSharedGenerator)->getPixels(bitmap->pixmap())) {
204+
!generate_pixels(ScopedGenerator(fSharedGenerator), bitmap->pixmap(), fOrigin.x(),
205+
fOrigin.y())) {
156206
return false;
157207
}
158208
bitmap->setImmutable();
@@ -196,13 +246,14 @@ GrSurfaceProxyView SkImage_Lazy::refView(GrRecordingContext* context, GrMipmappe
196246
}
197247
#endif
198248

199-
sk_sp<SkImage> SkImage_Lazy::onMakeSubset(const SkIRect& subset, GrDirectContext* direct) const {
200-
// TODO: can we do this more efficiently, by telling the generator we want to
201-
// "realize" a subset?
249+
sk_sp<SkImage> SkImage_Lazy::onMakeSubset(const SkIRect& subset, GrDirectContext*) const {
250+
SkASSERT(this->bounds().contains(subset));
251+
SkASSERT(this->bounds() != subset);
202252

203-
auto pixels = direct ? this->makeTextureImage(direct)
204-
: this->makeRasterImage();
205-
return pixels ? pixels->makeSubset(subset, direct) : nullptr;
253+
const SkIRect generatorSubset = subset.makeOffset(fOrigin);
254+
const SkColorType colorType = this->colorType();
255+
Validator validator(fSharedGenerator, &generatorSubset, &colorType, this->refColorSpace());
256+
return validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
206257
}
207258

208259
sk_sp<SkImage> SkImage_Lazy::onMakeColorTypeAndColorSpace(SkColorType targetCT,
@@ -214,7 +265,9 @@ sk_sp<SkImage> SkImage_Lazy::onMakeColorTypeAndColorSpace(SkColorType targetCT,
214265
SkColorSpace::Equals(targetCS.get(), fOnMakeColorTypeAndSpaceResult->colorSpace())) {
215266
return fOnMakeColorTypeAndSpaceResult;
216267
}
217-
Validator validator(fSharedGenerator, &targetCT, targetCS);
268+
const SkIRect generatorSubset =
269+
SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), this->width(), this->height());
270+
Validator validator(fSharedGenerator, &generatorSubset, &targetCT, targetCS);
218271
sk_sp<SkImage> result = validator ? sk_sp<SkImage>(new SkImage_Lazy(&validator)) : nullptr;
219272
if (result) {
220273
fOnMakeColorTypeAndSpaceResult = result;
@@ -232,7 +285,7 @@ sk_sp<SkImage> SkImage_Lazy::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS)
232285
if (bitmap.tryAllocPixels(this->imageInfo().makeColorSpace(std::move(newCS)))) {
233286
SkPixmap pixmap = bitmap.pixmap();
234287
pixmap.setColorSpace(this->refColorSpace());
235-
if (ScopedGenerator(fSharedGenerator)->getPixels(pixmap)) {
288+
if (generate_pixels(ScopedGenerator(fSharedGenerator), pixmap, fOrigin.x(), fOrigin.y())) {
236289
bitmap.setImmutable();
237290
return SkImage::MakeFromBitmap(bitmap);
238291
}
@@ -242,17 +295,47 @@ sk_sp<SkImage> SkImage_Lazy::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS)
242295

243296
sk_sp<SkImage> SkImage::MakeFromGenerator(std::unique_ptr<SkImageGenerator> generator) {
244297
SkImage_Lazy::Validator
245-
validator(SharedGenerator::Make(std::move(generator)), nullptr, nullptr);
298+
validator(SharedGenerator::Make(std::move(generator)), nullptr, nullptr, nullptr);
246299

247300
return validator ? sk_make_sp<SkImage_Lazy>(&validator) : nullptr;
248301
}
249302

250303
sk_sp<SkImage> SkImage::DecodeToRaster(const void* encoded, size_t length, const SkIRect* subset) {
251-
auto img = SkImage::MakeFromEncoded(SkData::MakeWithoutCopy(encoded, length));
252-
if (img && subset) {
253-
img = img->makeSubset(*subset);
304+
// The generator will not outlive this function, so we can wrap the encoded data without copy
305+
auto gen = SkImageGenerator::MakeFromEncoded(SkData::MakeWithoutCopy(encoded, length));
306+
if (!gen) {
307+
return nullptr;
308+
}
309+
SkImageInfo info = gen->getInfo();
310+
if (info.isEmpty()) {
311+
return nullptr;
312+
}
313+
314+
SkIPoint origin = {0, 0};
315+
if (subset) {
316+
if (!SkIRect::MakeWH(info.width(), info.height()).contains(*subset)) {
317+
return nullptr;
318+
}
319+
info = info.makeDimensions(subset->size());
320+
origin = {subset->x(), subset->y()};
321+
}
322+
323+
size_t rb = info.minRowBytes();
324+
if (rb == 0) {
325+
return nullptr; // rb was too big
326+
}
327+
size_t size = info.computeByteSize(rb);
328+
if (size == SIZE_MAX) {
329+
return nullptr;
254330
}
255-
return img ? img->makeRasterImage() : nullptr;
331+
auto data = SkData::MakeUninitialized(size);
332+
333+
SkPixmap pmap(info, data->writable_data(), rb);
334+
if (!generate_pixels(gen.get(), pmap, origin.x(), origin.y())) {
335+
return nullptr;
336+
}
337+
338+
return SkImage::MakeRasterData(info, data, rb);
256339
}
257340

258341
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -514,7 +597,7 @@ GrSurfaceProxyView SkImage_Lazy::lockTextureProxyView(GrRecordingContext* ctx,
514597
// 2. Ask the generator to natively create one.
515598
{
516599
ScopedGenerator generator(fSharedGenerator);
517-
if (auto view = generator->generateTexture(ctx, this->imageInfo(), {0,0}, mipMapped,
600+
if (auto view = generator->generateTexture(ctx, this->imageInfo(), fOrigin, mipMapped,
518601
texGenPolicy)) {
519602
SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath,
520603
kLockTexturePathCount);

src/image/SkImage_Lazy.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,24 @@ class SharedGenerator;
2222
class SkImage_Lazy : public SkImage_Base {
2323
public:
2424
struct Validator {
25-
Validator(sk_sp<SharedGenerator>, const SkColorType*, sk_sp<SkColorSpace>);
25+
Validator(sk_sp<SharedGenerator>, const SkIRect* subset, const SkColorType* colorType,
26+
sk_sp<SkColorSpace> colorSpace);
2627

2728
operator bool() const { return fSharedGenerator.get(); }
2829

2930
sk_sp<SharedGenerator> fSharedGenerator;
3031
SkImageInfo fInfo;
32+
SkIPoint fOrigin;
3133
sk_sp<SkColorSpace> fColorSpace;
3234
uint32_t fUniqueID;
3335
};
3436

3537
SkImage_Lazy(Validator* validator);
3638

39+
SkIRect onGetSubset() const override {
40+
return SkIRect::MakeXYWH(fOrigin.fX, fOrigin.fY, this->width(), this->height());
41+
}
42+
3743
bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY,
3844
CachingHint) const override;
3945
#if SK_SUPPORT_GPU
@@ -79,6 +85,7 @@ class SkImage_Lazy : public SkImage_Base {
7985
// cropped by onMakeSubset and its color type/space may be changed by
8086
// onMakeColorTypeAndColorSpace.
8187
sk_sp<SharedGenerator> fSharedGenerator;
88+
const SkIPoint fOrigin;
8289

8390
// Repeated calls to onMakeColorTypeAndColorSpace will result in a proliferation of unique IDs
8491
// and SkImage_Lazy instances. Cache the result of the last successful call.

0 commit comments

Comments
 (0)