OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkAutoPixmapStorage.h" | 8 #include "SkAutoPixmapStorage.h" |
9 #include "GrCaps.h" | 9 #include "GrCaps.h" |
10 #include "GrContext.h" | 10 #include "GrContext.h" |
11 #include "GrDrawContext.h" | 11 #include "GrDrawContext.h" |
12 #include "GrImageIDTextureAdjuster.h" | 12 #include "GrImageIDTextureAdjuster.h" |
| 13 #include "GrTexturePriv.h" |
13 #include "effects/GrYUVEffect.h" | 14 #include "effects/GrYUVEffect.h" |
14 #include "SkCanvas.h" | 15 #include "SkCanvas.h" |
15 #include "SkBitmapCache.h" | 16 #include "SkBitmapCache.h" |
16 #include "SkGrPriv.h" | 17 #include "SkGrPriv.h" |
17 #include "SkImage_Gpu.h" | 18 #include "SkImage_Gpu.h" |
18 #include "SkMipMap.h" | 19 #include "SkMipMap.h" |
19 #include "SkPixelRef.h" | 20 #include "SkPixelRef.h" |
20 | 21 |
| 22 namespace { |
| 23 bool shouldUseMipMaps(const SkImage::DeferredTextureImageUsageParams & param) { |
| 24 bool shouldUseMipMaps = false; |
| 25 |
| 26 // Use mipmaps if either |
| 27 // 1.) it is a perspective matrix, or |
| 28 // 2.) the quality is med/high and the scale is < 1 |
| 29 if (param.fMatrix.hasPerspective()) { |
| 30 shouldUseMipMaps = true; |
| 31 } |
| 32 if (param.fQuality == kMedium_SkFilterQuality || |
| 33 param.fQuality == kHigh_SkFilterQuality) { |
| 34 SkScalar minAxisScale = param.fMatrix.getMinScale(); |
| 35 if (minAxisScale != -1.f && minAxisScale < 1.f) { |
| 36 shouldUseMipMaps = true; |
| 37 } |
| 38 } |
| 39 |
| 40 return shouldUseMipMaps; |
| 41 } |
| 42 } |
| 43 |
21 SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrText
ure* tex, | 44 SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrText
ure* tex, |
22 sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted) | 45 sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted) |
23 : INHERITED(w, h, uniqueID) | 46 : INHERITED(w, h, uniqueID) |
24 , fTexture(SkRef(tex)) | 47 , fTexture(SkRef(tex)) |
25 , fAlphaType(at) | 48 , fAlphaType(at) |
26 , fBudgeted(budgeted) | 49 , fBudgeted(budgeted) |
27 , fColorSpace(std::move(colorSpace)) | 50 , fColorSpace(std::move(colorSpace)) |
28 , fAddedRasterVersionToCache(false) | 51 , fAddedRasterVersionToCache(false) |
29 { | 52 { |
30 SkASSERT(tex->width() == w); | 53 SkASSERT(tex->width() == w); |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 } | 378 } |
356 | 379 |
357 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 380 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
358 | 381 |
359 class DeferredTextureImage { | 382 class DeferredTextureImage { |
360 public: | 383 public: |
361 SkImage* newImage(GrContext* context, SkBudgeted) const; | 384 SkImage* newImage(GrContext* context, SkBudgeted) const; |
362 | 385 |
363 private: | 386 private: |
364 uint32_t fContextUniqueID; | 387 uint32_t fContextUniqueID; |
| 388 // Right now, the gamma treatment is only considered when generating mipmaps |
| 389 SkSourceGammaTreatment fGammaTreatment; |
365 struct MipMapLevelData { | 390 struct MipMapLevelData { |
366 void* fPixelData; | 391 void* fPixelData; |
367 size_t fRowBytes; | 392 size_t fRowBytes; |
368 }; | 393 }; |
369 struct Data { | 394 struct Data { |
370 SkImageInfo fInfo; | 395 SkImageInfo fInfo; |
371 int fColorTableCnt; | 396 int fColorTableCnt; |
372 uint32_t* fColorTableData; | 397 uint32_t* fColorTableData; |
373 int fMipMapLevelCount; | 398 int fMipMapLevelCount; |
374 // The fMipMapLevelData array may contain more than 1 element. | 399 // The fMipMapLevelData array may contain more than 1 element. |
375 // It contains fMipMapLevelCount elements. | 400 // It contains fMipMapLevelCount elements. |
376 // That means this struct's size is not known at compile-time. | 401 // That means this struct's size is not known at compile-time. |
377 MipMapLevelData fMipMapLevelData[1]; | 402 MipMapLevelData fMipMapLevelData[1]; |
378 }; | 403 }; |
379 Data fData; | 404 Data fData; |
380 | 405 |
381 friend class SkImage; | 406 friend class SkImage; |
382 }; | 407 }; |
383 | 408 |
384 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
y, | 409 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox
y, |
385 const DeferredTextureImageUsageParam
s params[], | 410 const DeferredTextureImageUsageParam
s params[], |
386 int paramCnt, void* buffer) const { | 411 int paramCnt, void* buffer, |
| 412 SkSourceGammaTreatment gammaTreatmen
t) const { |
387 // Extract relevant min/max values from the params array. | 413 // Extract relevant min/max values from the params array. |
388 int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel; | 414 int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel; |
389 SkFilterQuality highestFilterQuality = params[0].fQuality; | 415 SkFilterQuality highestFilterQuality = params[0].fQuality; |
| 416 bool useMipMaps = shouldUseMipMaps(params[0]); |
390 for (int i = 1; i < paramCnt; ++i) { | 417 for (int i = 1; i < paramCnt; ++i) { |
391 if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel) | 418 if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel) |
392 lowestPreScaleMipLevel = params[i].fPreScaleMipLevel; | 419 lowestPreScaleMipLevel = params[i].fPreScaleMipLevel; |
393 if (highestFilterQuality < params[i].fQuality) | 420 if (highestFilterQuality < params[i].fQuality) |
394 highestFilterQuality = params[i].fQuality; | 421 highestFilterQuality = params[i].fQuality; |
| 422 useMipMaps |= shouldUseMipMaps(params[i]); |
395 } | 423 } |
396 | 424 |
397 const bool fillMode = SkToBool(buffer); | 425 const bool fillMode = SkToBool(buffer); |
398 if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) { | 426 if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) { |
399 return 0; | 427 return 0; |
400 } | 428 } |
401 | 429 |
402 // Calculate scaling parameters. | 430 // Calculate scaling parameters. |
403 bool isScaled = lowestPreScaleMipLevel != 0; | 431 bool isScaled = lowestPreScaleMipLevel != 0; |
404 | 432 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 return 0; | 482 return 0; |
455 } | 483 } |
456 } else { | 484 } else { |
457 if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHi
nt)) { | 485 if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHi
nt)) { |
458 return 0; | 486 return 0; |
459 } | 487 } |
460 } | 488 } |
461 SkASSERT(!pixmap.ctable()); | 489 SkASSERT(!pixmap.ctable()); |
462 } | 490 } |
463 } | 491 } |
| 492 SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaTyp
e; |
464 int mipMapLevelCount = 1; | 493 int mipMapLevelCount = 1; |
| 494 if (useMipMaps) { |
| 495 // SkMipMap only deals with the mipmap levels it generates, which does |
| 496 // not include the base level. |
| 497 // That means it generates and holds levels 1-x instead of 0-x. |
| 498 // So the total mipmap level count is 1 more than what |
| 499 // SkMipMap::ComputeLevelCount returns. |
| 500 mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scale
dSize.height()) + 1; |
| 501 |
| 502 // We already initialized pixelSize to the size of the base level. |
| 503 // SkMipMap will generate the extra mipmap levels. Their sizes need to |
| 504 // be added to the total. |
| 505 // Index 0 here does not refer to the base mipmap level -- it is |
| 506 // SkMipMap's first generated mipmap level (level 1). |
| 507 for (int currentMipMapLevelIndex = mipMapLevelCount - 1; currentMipMapLe
velIndex >= 0; |
| 508 currentMipMapLevelIndex--) { |
| 509 SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), sca
ledSize.height(), |
| 510 currentMipMapLevelIndex
); |
| 511 SkImageInfo mipInfo = SkImageInfo::MakeN32(mipSize.fWidth, mipSize.f
Height, at); |
| 512 pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullpt
r)); |
| 513 } |
| 514 } |
465 size_t size = 0; | 515 size_t size = 0; |
466 size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage)); | 516 size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage)); |
467 size += dtiSize; | 517 size += dtiSize; |
468 size += mipMapLevelCount * sizeof(DeferredTextureImage::MipMapLevelData); | 518 size += mipMapLevelCount * sizeof(DeferredTextureImage::MipMapLevelData); |
469 size_t pixelOffset = size; | 519 size_t pixelOffset = size; |
470 size += pixelSize; | 520 size += pixelSize; |
471 size_t ctOffset = size; | 521 size_t ctOffset = size; |
472 size += ctSize; | 522 size += ctSize; |
473 if (!fillMode) { | 523 if (!fillMode) { |
474 return size; | 524 return size; |
475 } | 525 } |
476 intptr_t bufferAsInt = reinterpret_cast<intptr_t>(buffer); | 526 intptr_t bufferAsInt = reinterpret_cast<intptr_t>(buffer); |
477 void* pixels = reinterpret_cast<void*>(bufferAsInt + pixelOffset); | 527 void* pixels = reinterpret_cast<void*>(bufferAsInt + pixelOffset); |
478 SkPMColor* ct = nullptr; | 528 SkPMColor* ct = nullptr; |
479 if (ctSize) { | 529 if (ctSize) { |
480 ct = reinterpret_cast<SkPMColor*>(bufferAsInt + ctOffset); | 530 ct = reinterpret_cast<SkPMColor*>(bufferAsInt + ctOffset); |
481 } | 531 } |
482 | 532 |
483 memcpy(pixels, pixmap.addr(), pixmap.getSafeSize()); | 533 memcpy(pixels, pixmap.addr(), pixmap.getSafeSize()); |
484 if (ctSize) { | 534 if (ctSize) { |
485 memcpy(ct, pixmap.ctable()->readColors(), ctSize); | 535 memcpy(ct, pixmap.ctable()->readColors(), ctSize); |
486 } | 536 } |
487 | 537 |
488 SkASSERT(info == pixmap.info()); | 538 SkASSERT(info == pixmap.info()); |
489 size_t rowBytes = pixmap.rowBytes(); | 539 size_t rowBytes = pixmap.rowBytes(); |
490 DeferredTextureImage* dti = new (buffer) DeferredTextureImage(); | 540 DeferredTextureImage* dti = new (buffer) DeferredTextureImage(); |
491 dti->fContextUniqueID = proxy.fContextUniqueID; | 541 dti->fContextUniqueID = proxy.fContextUniqueID; |
| 542 dti->fGammaTreatment = gammaTreatment; |
492 dti->fData.fInfo = info; | 543 dti->fData.fInfo = info; |
493 dti->fData.fColorTableCnt = ctCount; | 544 dti->fData.fColorTableCnt = ctCount; |
494 dti->fData.fColorTableData = ct; | 545 dti->fData.fColorTableData = ct; |
495 dti->fData.fMipMapLevelCount = mipMapLevelCount; | 546 dti->fData.fMipMapLevelCount = mipMapLevelCount; |
496 dti->fData.fMipMapLevelData[0].fPixelData = pixels; | 547 dti->fData.fMipMapLevelData[0].fPixelData = pixels; |
497 dti->fData.fMipMapLevelData[0].fRowBytes = rowBytes; | 548 dti->fData.fMipMapLevelData[0].fRowBytes = rowBytes; |
| 549 |
| 550 // Fill in the mipmap levels if they exist |
| 551 intptr_t mipLevelPtr = bufferAsInt + pixelOffset + SkAlign8(SkAutoPixmapStor
age::AllocSize( |
| 552 info, nullptr)); |
| 553 if (useMipMaps) { |
| 554 SkAutoTDelete<SkMipMap> mipmaps(SkMipMap::Build(pixmap, gammaTreatment,
nullptr)); |
| 555 // SkMipMap holds only the mipmap levels it generates. |
| 556 // A programmer can use the data they provided to SkMipMap::Build as lev
el 0. |
| 557 // So the SkMipMap provides levels 1-x but it stores them in its own |
| 558 // range 0-(x-1). |
| 559 for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLeve
lCount - 1; |
| 560 generatedMipLevelIndex++) { |
| 561 SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), sca
ledSize.height(), |
| 562 generatedMipLevelIndex)
; |
| 563 SkImageInfo mipInfo = SkImageInfo::MakeN32(mipSize.fWidth, mipSize.f
Height, at); |
| 564 SkMipMap::Level mipLevel; |
| 565 mipmaps->getLevel(generatedMipLevelIndex, &mipLevel); |
| 566 memcpy(reinterpret_cast<void*>(mipLevelPtr), mipLevel.fPixmap.addr()
, |
| 567 mipLevel.fPixmap.getSafeSize()); |
| 568 dti->fData.fMipMapLevelData[generatedMipLevelIndex + 1].fPixelData = |
| 569 reinterpret_cast<void*>(mipLevelPtr); |
| 570 dti->fData.fMipMapLevelData[generatedMipLevelIndex + 1].fRowBytes = |
| 571 mipLevel.fPixmap.rowBytes(); |
| 572 mipLevelPtr += SkAlign8(mipLevel.fPixmap.getSafeSize()); |
| 573 } |
| 574 } |
498 return size; | 575 return size; |
499 } | 576 } |
500 | 577 |
501 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, con
st void* data, | 578 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, con
st void* data, |
502 SkBudgeted budgeted) { | 579 SkBudgeted budgeted) { |
503 if (!data) { | 580 if (!data) { |
504 return nullptr; | 581 return nullptr; |
505 } | 582 } |
506 const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImag
e*>(data); | 583 const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImag
e*>(data); |
507 | 584 |
508 if (!context || context->uniqueID() != dti->fContextUniqueID) { | 585 if (!context || context->uniqueID() != dti->fContextUniqueID) { |
509 return nullptr; | 586 return nullptr; |
510 } | 587 } |
511 SkAutoTUnref<SkColorTable> colorTable; | 588 SkAutoTUnref<SkColorTable> colorTable; |
512 if (dti->fData.fColorTableCnt) { | 589 if (dti->fData.fColorTableCnt) { |
513 SkASSERT(dti->fData.fColorTableData); | 590 SkASSERT(dti->fData.fColorTableData); |
514 colorTable.reset(new SkColorTable(dti->fData.fColorTableData, dti->fData
.fColorTableCnt)); | 591 colorTable.reset(new SkColorTable(dti->fData.fColorTableData, dti->fData
.fColorTableCnt)); |
515 } | 592 } |
516 SkASSERT(dti->fData.fMipMapLevelCount == 1); | 593 int mipLevelCount = dti->fData.fMipMapLevelCount; |
517 SkPixmap pixmap; | 594 SkASSERT(mipLevelCount >= 1); |
518 pixmap.reset(dti->fData.fInfo, dti->fData.fMipMapLevelData[0].fPixelData, | 595 if (mipLevelCount == 1) { |
519 dti->fData.fMipMapLevelData[0].fRowBytes, colorTable.get()); | 596 SkPixmap pixmap; |
520 return SkImage::MakeTextureFromPixmap(context, pixmap, budgeted); | 597 pixmap.reset(dti->fData.fInfo, dti->fData.fMipMapLevelData[0].fPixelData
, |
| 598 dti->fData.fMipMapLevelData[0].fRowBytes, colorTable.get())
; |
| 599 return SkImage::MakeTextureFromPixmap(context, pixmap, budgeted); |
| 600 } else { |
| 601 SkAutoTDeleteArray<GrMipLevel> texels(new GrMipLevel[mipLevelCount]); |
| 602 for (int i = 0; i < mipLevelCount; i++) { |
| 603 texels[i].fPixels = dti->fData.fMipMapLevelData[i].fPixelData; |
| 604 texels[i].fRowBytes = dti->fData.fMipMapLevelData[i].fRowBytes; |
| 605 } |
| 606 |
| 607 return SkImage::MakeTextureFromMipMap(context, dti->fData.fInfo, texels.
get(), |
| 608 mipLevelCount, SkBudgeted::kYes, |
| 609 dti->fGammaTreatment); |
| 610 } |
521 } | 611 } |
522 | 612 |
523 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 613 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
524 | 614 |
525 GrTexture* GrDeepCopyTexture(GrTexture* src, SkBudgeted budgeted) { | 615 GrTexture* GrDeepCopyTexture(GrTexture* src, SkBudgeted budgeted) { |
526 GrContext* ctx = src->getContext(); | 616 GrContext* ctx = src->getContext(); |
527 | 617 |
528 GrSurfaceDesc desc = src->desc(); | 618 GrSurfaceDesc desc = src->desc(); |
529 GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, nullp
tr, 0); | 619 GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, nullp
tr, 0); |
530 if (!dst) { | 620 if (!dst) { |
531 return nullptr; | 621 return nullptr; |
532 } | 622 } |
533 | 623 |
534 const SkIRect srcR = SkIRect::MakeWH(desc.fWidth, desc.fHeight); | 624 const SkIRect srcR = SkIRect::MakeWH(desc.fWidth, desc.fHeight); |
535 const SkIPoint dstP = SkIPoint::Make(0, 0); | 625 const SkIPoint dstP = SkIPoint::Make(0, 0); |
536 ctx->copySurface(dst, src, srcR, dstP); | 626 ctx->copySurface(dst, src, srcR, dstP); |
537 ctx->flushSurfaceWrites(dst); | 627 ctx->flushSurfaceWrites(dst); |
538 return dst; | 628 return dst; |
539 } | 629 } |
540 | 630 |
541 sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo&
info, | 631 sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo&
info, |
542 const GrMipLevel* texels, int mipL
evelCount, | 632 const GrMipLevel* texels, int mipL
evelCount, |
543 SkBudgeted budgeted) { | 633 SkBudgeted budgeted, |
| 634 SkSourceGammaTreatment gammaTreatm
ent) { |
544 if (!ctx) { | 635 if (!ctx) { |
545 return nullptr; | 636 return nullptr; |
546 } | 637 } |
547 SkAutoTUnref<GrTexture> texture(GrUploadMipMapToTexture(ctx, info, texels, m
ipLevelCount)); | 638 SkAutoTUnref<GrTexture> texture(GrUploadMipMapToTexture(ctx, info, texels, m
ipLevelCount)); |
548 if (!texture) { | 639 if (!texture) { |
549 return nullptr; | 640 return nullptr; |
550 } | 641 } |
| 642 texture->texturePriv().setGammaTreatment(gammaTreatment); |
551 return sk_make_sp<SkImage_Gpu>(texture->width(), texture->height(), kNeedNew
ImageUniqueID, | 643 return sk_make_sp<SkImage_Gpu>(texture->width(), texture->height(), kNeedNew
ImageUniqueID, |
552 info.alphaType(), texture, sk_ref_sp(info.col
orSpace()), | 644 info.alphaType(), texture, sk_ref_sp(info.col
orSpace()), |
553 budgeted); | 645 budgeted); |
554 } | 646 } |
OLD | NEW |