Impl. tiled bitmaps in drawImageRect with per-edge AA flags
Bug: skia:3803 Change-Id: If2b529bf9167e2a94784d8797ce28a9618e86d11 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/276203 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
520c5fd7b2
commit
4723724bac
@ -13,7 +13,6 @@
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/core/SkVertices.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
#include "include/private/SkImageInfoPriv.h"
|
||||
#include "include/private/SkShadowFlags.h"
|
||||
#include "include/private/SkTo.h"
|
||||
#include "src/core/SkCanvasPriv.h"
|
||||
@ -34,7 +33,6 @@
|
||||
#include "src/gpu/GrBlurUtils.h"
|
||||
#include "src/gpu/GrContextPriv.h"
|
||||
#include "src/gpu/GrGpu.h"
|
||||
#include "src/gpu/GrImageInfo.h"
|
||||
#include "src/gpu/GrImageTextureMaker.h"
|
||||
#include "src/gpu/GrRenderTargetContextPriv.h"
|
||||
#include "src/gpu/GrStyle.h"
|
||||
@ -42,7 +40,6 @@
|
||||
#include "src/gpu/GrTextureAdjuster.h"
|
||||
#include "src/gpu/GrTracing.h"
|
||||
#include "src/gpu/SkGr.h"
|
||||
#include "src/gpu/effects/GrBicubicEffect.h"
|
||||
#include "src/gpu/geometry/GrShape.h"
|
||||
#include "src/gpu/text/GrTextTarget.h"
|
||||
#include "src/image/SkImage_Base.h"
|
||||
@ -635,10 +632,6 @@ void SkGpuDevice::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool
|
||||
paint, this->localToDevice(), shape);
|
||||
}
|
||||
|
||||
const GrCaps* SkGpuDevice::caps() const {
|
||||
return fContext->priv().caps();
|
||||
}
|
||||
|
||||
void SkGpuDevice::drawSprite(const SkBitmap& bitmap,
|
||||
int left, int top, const SkPaint& paint) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
@ -769,76 +762,8 @@ void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const
|
||||
void SkGpuDevice::drawBitmapRect(const SkBitmap& bitmap,
|
||||
const SkRect* src, const SkRect& origDst,
|
||||
const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
// The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must
|
||||
// be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which
|
||||
// in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds
|
||||
// then we use the src-to-dst mapping to compute a new clipped dst rect.
|
||||
const SkRect* dst = &origDst;
|
||||
const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
|
||||
// Compute matrix from the two rectangles
|
||||
if (!src) {
|
||||
src = &bmpBounds;
|
||||
}
|
||||
|
||||
SkMatrix srcToDstMatrix;
|
||||
if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) {
|
||||
return;
|
||||
}
|
||||
SkRect tmpSrc, tmpDst;
|
||||
if (src != &bmpBounds) {
|
||||
if (!bmpBounds.contains(*src)) {
|
||||
tmpSrc = *src;
|
||||
if (!tmpSrc.intersect(bmpBounds)) {
|
||||
return; // nothing to draw
|
||||
}
|
||||
src = &tmpSrc;
|
||||
srcToDstMatrix.mapRect(&tmpDst, *src);
|
||||
dst = &tmpDst;
|
||||
}
|
||||
}
|
||||
|
||||
int maxTileSize = this->caps()->maxTileSize();
|
||||
|
||||
// The tile code path doesn't currently support AA, so if the paint asked for aa and we could
|
||||
// draw untiled, then we bypass checking for tiling purely for optimization reasons.
|
||||
bool useCoverageAA = fRenderTargetContext->numSamples() <= 1 &&
|
||||
paint.isAntiAlias() && bitmap.width() <= maxTileSize &&
|
||||
bitmap.height() <= maxTileSize;
|
||||
|
||||
bool skipTileCheck = useCoverageAA || paint.getMaskFilter();
|
||||
|
||||
if (!skipTileCheck) {
|
||||
int tileSize;
|
||||
SkIRect clippedSrcRect;
|
||||
|
||||
bool doBicubic;
|
||||
GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
|
||||
bitmap.width(), bitmap.height(), paint.getFilterQuality(), this->localToDevice(),
|
||||
srcToDstMatrix, fContext->priv().options().fSharpenMipmappedTextures, &doBicubic);
|
||||
|
||||
int tileFilterPad;
|
||||
|
||||
if (doBicubic) {
|
||||
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
|
||||
} else if (GrSamplerState::Filter::kNearest == textureFilterMode) {
|
||||
tileFilterPad = 0;
|
||||
} else {
|
||||
tileFilterPad = 1;
|
||||
}
|
||||
|
||||
int maxTileSizeForFilter = this->caps()->maxTileSize() - 2 * tileFilterPad;
|
||||
if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(),
|
||||
this->localToDevice(), srcToDstMatrix, src,
|
||||
maxTileSizeForFilter, &tileSize, &clippedSrcRect)) {
|
||||
this->drawTiledBitmap(bitmap, this->localToDevice(), srcToDstMatrix, *src,
|
||||
clippedSrcRect, textureFilterMode, paint, constraint, tileSize,
|
||||
doBicubic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
GrBitmapTextureMaker maker(fContext.get(), bitmap, GrBitmapTextureMaker::Cached::kYes);
|
||||
this->drawTextureProducer(&maker, src, dst, constraint, this->localToDevice(), paint);
|
||||
sk_sp<SkImage> asImage = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
|
||||
this->drawImageRect(asImage.get(), src, origDst, paint, constraint);
|
||||
}
|
||||
|
||||
sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkBitmap& bitmap) {
|
||||
|
@ -157,71 +157,19 @@ private:
|
||||
|
||||
GrClipStackClip clip() const { return GrClipStackClip(&this->cs()); }
|
||||
|
||||
const GrCaps* caps() const;
|
||||
|
||||
/**
|
||||
* Helper functions called by drawBitmapCommon. By the time these are called the SkDraw's
|
||||
* matrix, clip, and the device's render target has already been set on GrContext.
|
||||
*/
|
||||
|
||||
// The tileSize and clippedSrcRect will be valid only if true is returned.
|
||||
bool shouldTileImageID(uint32_t imageID,
|
||||
const SkIRect& imageRect,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& srcToDstRectMatrix,
|
||||
const SkRect* srcRectPtr,
|
||||
int maxTileSize,
|
||||
int* tileSize,
|
||||
SkIRect* clippedSubset) const;
|
||||
// Just returns the predicate, not the out-tileSize or out-clippedSubset, as they are not
|
||||
// needed at the moment.
|
||||
bool shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
|
||||
SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
|
||||
const SkMatrix& viewMatrix, const SkMatrix& srcToDstRect) const;
|
||||
|
||||
sk_sp<SkSpecialImage> filterTexture(SkSpecialImage*,
|
||||
int left, int top,
|
||||
SkIPoint* offset,
|
||||
const SkImageFilter* filter);
|
||||
|
||||
// Splits bitmap into tiles of tileSize and draws them using separate textures for each tile.
|
||||
void drawTiledBitmap(const SkBitmap& bitmap,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& srcToDstMatrix,
|
||||
const SkRect& srcRect,
|
||||
const SkIRect& clippedSrcRect,
|
||||
GrSamplerState::Filter,
|
||||
const SkPaint& paint,
|
||||
SkCanvas::SrcRectConstraint,
|
||||
int tileSize,
|
||||
bool bicubic);
|
||||
|
||||
// Used by drawTiledBitmap to draw each tile.
|
||||
void drawBitmapTile(const SkBitmap&,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkRect& dstRect,
|
||||
const SkRect& srcRect,
|
||||
GrSamplerState::Filter,
|
||||
const SkPaint& paint,
|
||||
SkCanvas::SrcRectConstraint,
|
||||
bool bicubic,
|
||||
bool needsTextureDomain);
|
||||
|
||||
// If not null, dstClip must be contained inside dst and will also respect the edge AA flags.
|
||||
// If 'preViewMatrix' is not null, final CTM will be this->ctm() * preViewMatrix.
|
||||
void drawImageQuad(const SkImage*, const SkRect* src, const SkRect* dst,
|
||||
const SkPoint dstClip[4], GrAA aa, GrQuadAAFlags aaFlags,
|
||||
const SkMatrix* preViewMatrix, const SkPaint&, SkCanvas::SrcRectConstraint);
|
||||
|
||||
// TODO(michaelludwig): This can be removed once drawBitmapRect is removed from SkDevice
|
||||
// so that drawImageQuad is the sole entry point into the draw-single-image op
|
||||
void drawTextureProducer(GrTextureProducer*,
|
||||
const SkRect* srcRect,
|
||||
const SkRect* dstRect,
|
||||
SkCanvas::SrcRectConstraint,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPaint&);
|
||||
|
||||
// FIXME(michaelludwig) - Should be removed in favor of using drawImageQuad with edge flags to
|
||||
// for every element in the SkLatticeIter.
|
||||
void drawProducerLattice(GrTextureProducer*, std::unique_ptr<SkLatticeIter>, const SkRect& dst,
|
||||
const SkPaint&);
|
||||
|
||||
|
@ -153,27 +153,28 @@ static void determine_clipped_src_rect(int width, int height,
|
||||
}
|
||||
}
|
||||
|
||||
} // temporary anonymous namespace boundary before shouldTileImageID is removed from SkGPUDevice
|
||||
|
||||
bool SkGpuDevice::shouldTileImageID(uint32_t imageID,
|
||||
const SkIRect& imageRect,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& srcToDstRect,
|
||||
const SkRect* srcRectPtr,
|
||||
int maxTileSize,
|
||||
int* tileSize,
|
||||
SkIRect* clippedSubset) const {
|
||||
// tileSize and clippedSubset are valid if true is returned
|
||||
static bool should_tile_image_id(GrContext* context,
|
||||
SkISize rtSize,
|
||||
const GrClip& clip,
|
||||
uint32_t imageID,
|
||||
const SkISize& imageSize,
|
||||
const SkMatrix& ctm,
|
||||
const SkMatrix& srcToDst,
|
||||
const SkRect* src,
|
||||
int maxTileSize,
|
||||
int* tileSize,
|
||||
SkIRect* clippedSubset) {
|
||||
// if it's larger than the max tile size, then we have no choice but tiling.
|
||||
if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) {
|
||||
determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
|
||||
this->clip(), viewMatrix, srcToDstRect, imageRect.size(),
|
||||
srcRectPtr, clippedSubset);
|
||||
if (imageSize.width() > maxTileSize || imageSize.height() > maxTileSize) {
|
||||
determine_clipped_src_rect(rtSize.width(), rtSize.height(), clip, ctm, srcToDst,
|
||||
imageSize, src, clippedSubset);
|
||||
*tileSize = determine_tile_size(*clippedSubset, maxTileSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the image would only produce 4 tiles of the smaller size, don't bother tiling it.
|
||||
const size_t area = imageRect.width() * imageRect.height();
|
||||
const size_t area = imageSize.width() * imageSize.height();
|
||||
if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
|
||||
return false;
|
||||
}
|
||||
@ -186,15 +187,14 @@ bool SkGpuDevice::shouldTileImageID(uint32_t imageID,
|
||||
// assumption here is that sw bitmap size is a good proxy for its size as
|
||||
// a texture
|
||||
size_t bmpSize = area * sizeof(SkPMColor); // assume 32bit pixels
|
||||
size_t cacheSize = fContext->getResourceCacheLimit();
|
||||
size_t cacheSize = context->getResourceCacheLimit();
|
||||
if (bmpSize < cacheSize / 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Figure out how much of the src we will need based on the src rect and clipping. Reject if
|
||||
// tiling memory savings would be < 50%.
|
||||
determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(),
|
||||
this->clip(), viewMatrix, srcToDstRect, imageRect.size(), srcRectPtr,
|
||||
determine_clipped_src_rect(rtSize.width(), rtSize.height(), clip, ctm, srcToDst, imageSize, src,
|
||||
clippedSubset);
|
||||
*tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
|
||||
size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) *
|
||||
@ -204,45 +204,10 @@ bool SkGpuDevice::shouldTileImageID(uint32_t imageID,
|
||||
return usedTileBytes * 2 < bmpSize;
|
||||
}
|
||||
|
||||
bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr,
|
||||
SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& srcToDstRect) const {
|
||||
// If image is explicitly texture backed then we shouldn't get here.
|
||||
SkASSERT(!image->isTextureBacked());
|
||||
|
||||
bool doBicubic;
|
||||
GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
|
||||
image->width(), image->height(), quality, viewMatrix, srcToDstRect,
|
||||
fContext->priv().options().fSharpenMipmappedTextures, &doBicubic);
|
||||
|
||||
int tileFilterPad;
|
||||
if (doBicubic) {
|
||||
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
|
||||
} else if (GrSamplerState::Filter::kNearest == textureFilterMode) {
|
||||
tileFilterPad = 0;
|
||||
} else {
|
||||
tileFilterPad = 1;
|
||||
}
|
||||
|
||||
int maxTileSize = this->caps()->maxTileSize() - 2 * tileFilterPad;
|
||||
|
||||
// these are output, which we safely ignore, as we just want to know the predicate
|
||||
int outTileSize;
|
||||
SkIRect outClippedSrcRect;
|
||||
|
||||
return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, srcToDstRect,
|
||||
srcRectPtr, maxTileSize, &outTileSize, &outClippedSrcRect);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// This method outsets 'iRect' by 'outset' all around and then clamps its extents to
|
||||
// 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
|
||||
// of 'iRect' for all possible outsets/clamps.
|
||||
static inline void clamped_outset_with_offset(SkIRect* iRect,
|
||||
int outset,
|
||||
SkPoint* offset,
|
||||
static inline void clamped_outset_with_offset(SkIRect* iRect, int outset, SkPoint* offset,
|
||||
const SkIRect& clamp) {
|
||||
iRect->outset(outset, outset);
|
||||
|
||||
@ -424,7 +389,9 @@ static void draw_texture_producer(GrContext* context,
|
||||
GrAA aa,
|
||||
GrQuadAAFlags aaFlags,
|
||||
SkCanvas::SrcRectConstraint constraint,
|
||||
GrSamplerState::WrapMode wm) {
|
||||
GrSamplerState::WrapMode wm,
|
||||
GrSamplerState::Filter fm,
|
||||
bool doBicubic) {
|
||||
if (wm == GrSamplerState::WrapMode::kClamp && !producer->isPlanar() &&
|
||||
can_use_draw_texture(paint)) {
|
||||
// We've done enough checks above to allow us to pass ClampNearest() and not check for
|
||||
@ -454,10 +421,6 @@ static void draw_texture_producer(GrContext* context,
|
||||
if (mf && as_MFB(mf)->hasFragmentProcessor()) {
|
||||
mf = nullptr;
|
||||
}
|
||||
bool doBicubic;
|
||||
GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode(
|
||||
producer->width(), producer->height(), paint.getFilterQuality(), ctm, srcToDst,
|
||||
context->priv().options().fSharpenMipmappedTextures, &doBicubic);
|
||||
const GrSamplerState::Filter* filterMode = doBicubic ? nullptr : &fm;
|
||||
|
||||
GrTextureProducer::FilterConstraint constraintMode;
|
||||
@ -540,36 +503,26 @@ static void draw_texture_producer(GrContext* context,
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Break 'bitmap' into several tiles to draw it since it has already
|
||||
// been determined to be too large to fit in VRAM
|
||||
void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkMatrix& dstMatrix,
|
||||
const SkRect& srcRect,
|
||||
const SkIRect& clippedSrcIRect,
|
||||
GrSamplerState::Filter filter,
|
||||
const SkPaint& origPaint,
|
||||
SkCanvas::SrcRectConstraint constraint,
|
||||
int tileSize,
|
||||
bool bicubic) {
|
||||
// This is the funnel for all paths that draw tiled bitmaps/images. Log histogram entries.
|
||||
SK_HISTOGRAM_BOOLEAN("DrawTiled", true);
|
||||
LogDrawScaleFactor(viewMatrix, SkMatrix::I(), origPaint.getFilterQuality());
|
||||
|
||||
const SkPaint* paint = &origPaint;
|
||||
SkPaint tempPaint;
|
||||
if (origPaint.isAntiAlias() && fRenderTargetContext->numSamples() <= 1) {
|
||||
// Drop antialiasing to avoid seams at tile boundaries.
|
||||
tempPaint = origPaint;
|
||||
tempPaint.setAntiAlias(false);
|
||||
paint = &tempPaint;
|
||||
}
|
||||
void draw_tiled_bitmap(GrContext* context,
|
||||
GrRenderTargetContext* rtc,
|
||||
const GrClip& clip,
|
||||
const SkBitmap& bitmap,
|
||||
int tileSize,
|
||||
const SkMatrix& ctm,
|
||||
const SkMatrix& srcToDst,
|
||||
const SkRect& srcRect,
|
||||
const SkIRect& clippedSrcIRect,
|
||||
const SkPaint& paint,
|
||||
GrAA aa,
|
||||
SkCanvas::SrcRectConstraint constraint,
|
||||
GrSamplerState::WrapMode wm,
|
||||
GrSamplerState::Filter fm,
|
||||
bool doBicubic) {
|
||||
SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
|
||||
|
||||
int nx = bitmap.width() / tileSize;
|
||||
int ny = bitmap.height() / tileSize;
|
||||
|
||||
for (int x = 0; x <= nx; x++) {
|
||||
for (int y = 0; y <= ny; y++) {
|
||||
SkRect tileR;
|
||||
@ -589,8 +542,8 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
|
||||
SkVector offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
|
||||
SkIntToScalar(iTileR.fTop));
|
||||
SkRect rectToDraw = tileR;
|
||||
dstMatrix.mapRect(&rectToDraw);
|
||||
if (filter != GrSamplerState::Filter::kNearest || bicubic) {
|
||||
srcToDst.mapRect(&rectToDraw);
|
||||
if (fm != GrSamplerState::Filter::kNearest || doBicubic) {
|
||||
SkIRect iClampRect;
|
||||
|
||||
if (SkCanvas::kFast_SrcRectConstraint == constraint) {
|
||||
@ -603,94 +556,53 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
|
||||
// not bleed across the original clamped edges)
|
||||
srcRect.roundOut(&iClampRect);
|
||||
}
|
||||
int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
|
||||
int outset = doBicubic ? GrBicubicEffect::kFilterTexelPad : 1;
|
||||
clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
|
||||
}
|
||||
|
||||
SkBitmap tmpB;
|
||||
if (bitmap.extractSubset(&tmpB, iTileR)) {
|
||||
// We should have already handled bitmaps larger than the max texture size.
|
||||
SkASSERT(tmpB.width() <= context->priv().caps()->maxTextureSize() &&
|
||||
tmpB.height() <= context->priv().caps()->maxTextureSize());
|
||||
// We should be respecting the max tile size by the time we get here.
|
||||
SkASSERT(tmpB.width() <= context->priv().caps()->maxTileSize() &&
|
||||
tmpB.height() <= context->priv().caps()->maxTileSize());
|
||||
|
||||
GrBitmapTextureMaker tileProducer(context, tmpB, GrBitmapTextureMaker::Cached::kYes,
|
||||
SkBackingFit::kExact);
|
||||
|
||||
GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
|
||||
if (aa == GrAA::kYes) {
|
||||
// If the entire bitmap was anti-aliased, turn on AA for the outside tile edges.
|
||||
if (tileR.fLeft <= srcRect.fLeft) {
|
||||
aaFlags |= GrQuadAAFlags::kLeft;
|
||||
}
|
||||
if (tileR.fRight >= srcRect.fRight) {
|
||||
aaFlags |= GrQuadAAFlags::kRight;
|
||||
}
|
||||
if (tileR.fTop <= srcRect.fTop) {
|
||||
aaFlags |= GrQuadAAFlags::kTop;
|
||||
}
|
||||
if (tileR.fBottom >= srcRect.fBottom) {
|
||||
aaFlags |= GrQuadAAFlags::kBottom;
|
||||
}
|
||||
}
|
||||
|
||||
// now offset it to make it "local" to our tmp bitmap
|
||||
tileR.offset(-offset.fX, -offset.fY);
|
||||
// de-optimized this determination
|
||||
bool needsTextureDomain = true;
|
||||
this->drawBitmapTile(tmpB,
|
||||
viewMatrix,
|
||||
rectToDraw,
|
||||
tileR,
|
||||
filter,
|
||||
*paint,
|
||||
constraint,
|
||||
bicubic,
|
||||
needsTextureDomain);
|
||||
SkMatrix offsetSrcToDst = srcToDst;
|
||||
offsetSrcToDst.preTranslate(offset.fX, offset.fY);
|
||||
|
||||
draw_texture_producer(context, rtc, clip, ctm, paint, &tileProducer, tileR,
|
||||
rectToDraw, nullptr, offsetSrcToDst, aa, aaFlags, constraint,
|
||||
wm, fm, doBicubic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkRect& dstRect,
|
||||
const SkRect& srcRect,
|
||||
GrSamplerState::Filter filter,
|
||||
const SkPaint& paint,
|
||||
SkCanvas::SrcRectConstraint constraint,
|
||||
bool bicubic,
|
||||
bool needsTextureDomain) {
|
||||
// We should have already handled bitmaps larger than the max texture size.
|
||||
SkASSERT(bitmap.width() <= this->caps()->maxTextureSize() &&
|
||||
bitmap.height() <= this->caps()->maxTextureSize());
|
||||
// We should be respecting the max tile size by the time we get here.
|
||||
SkASSERT(bitmap.width() <= this->caps()->maxTileSize() &&
|
||||
bitmap.height() <= this->caps()->maxTileSize());
|
||||
|
||||
GrMipMapped mipMapped = filter == GrSamplerState::Filter::kMipMap ? GrMipMapped::kYes
|
||||
: GrMipMapped::kNo;
|
||||
GrSurfaceProxyView view = GrRefCachedBitmapView(fContext.get(), bitmap, mipMapped);
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute a matrix that maps the rect we will draw to the src rect.
|
||||
SkMatrix texMatrix = SkMatrix::MakeRectToRect(dstRect, srcRect, SkMatrix::kFill_ScaleToFit);
|
||||
|
||||
SkAlphaType srcAlphaType = bitmap.alphaType();
|
||||
|
||||
// Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
|
||||
// the rest from the SkPaint.
|
||||
std::unique_ptr<GrFragmentProcessor> fp;
|
||||
|
||||
const auto& caps = *this->caps();
|
||||
if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) {
|
||||
if (bicubic) {
|
||||
static constexpr auto kDir = GrBicubicEffect::Direction::kXY;
|
||||
fp = GrBicubicEffect::MakeSubset(std::move(view), srcAlphaType, texMatrix,
|
||||
GrSamplerState::WrapMode::kClamp,
|
||||
GrSamplerState::WrapMode::kClamp, srcRect, kDir, caps);
|
||||
} else {
|
||||
fp = GrTextureEffect::MakeSubset(std::move(view), srcAlphaType, texMatrix, filter,
|
||||
srcRect, caps);
|
||||
}
|
||||
} else if (bicubic) {
|
||||
SkASSERT(GrSamplerState::Filter::kNearest == filter);
|
||||
static constexpr auto kDir = GrBicubicEffect::Direction::kXY;
|
||||
fp = GrBicubicEffect::Make(std::move(view), srcAlphaType, texMatrix, kDir);
|
||||
} else {
|
||||
fp = GrTextureEffect::Make(std::move(view), srcAlphaType, texMatrix, filter);
|
||||
}
|
||||
|
||||
fp = GrColorSpaceXformEffect::Make(std::move(fp), bitmap.colorSpace(), bitmap.alphaType(),
|
||||
fRenderTargetContext->colorInfo().colorSpace());
|
||||
GrPaint grPaint;
|
||||
if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext->colorInfo(), paint,
|
||||
viewMatrix, std::move(fp),
|
||||
kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Coverage-based AA would cause seams between tiles.
|
||||
GrAA aa = GrAA(paint.isAntiAlias() && fRenderTargetContext->numSamples() > 1);
|
||||
fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), aa, viewMatrix, dstRect);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -721,6 +633,13 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
|
||||
ctm.preConcat(*preViewMatrix);
|
||||
}
|
||||
|
||||
bool doBicubic;
|
||||
GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode(
|
||||
image->width(), image->height(), paint.getFilterQuality(), ctm, srcToDst,
|
||||
fContext->priv().options().fSharpenMipmappedTextures, &doBicubic);
|
||||
|
||||
auto clip = this->clip();
|
||||
|
||||
// YUVA images can be stored in multiple images with different plane resolutions, so this
|
||||
// uses an effect to combine them dynamically on the GPU. This is done before requesting a
|
||||
// pinned texture proxy because YUV images force-flatten to RGBA in that scenario.
|
||||
@ -729,9 +648,9 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
|
||||
LogDrawScaleFactor(ctm, srcToDst, paint.getFilterQuality());
|
||||
|
||||
GrYUVAImageTextureMaker maker(fContext.get(), image);
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), this->clip(), ctm, paint,
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, ctm, paint,
|
||||
&maker, src, dst, dstClip, srcToDst, aa, aaFlags, constraint,
|
||||
wrapMode);
|
||||
wrapMode, fm, doBicubic);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -752,21 +671,44 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
|
||||
}
|
||||
|
||||
GrTextureAdjuster adjuster(fContext.get(), std::move(view), colorInfo, pinnedUniqueID);
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), this->clip(), ctm, paint,
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, ctm, paint,
|
||||
&adjuster, src, dst, dstClip, srcToDst, aa, aaFlags, constraint,
|
||||
wrapMode);
|
||||
wrapMode, fm, doBicubic);
|
||||
return;
|
||||
}
|
||||
|
||||
// Next up, try tiling the image
|
||||
// TODO (michaelludwig): Implement this with per-edge AA flags to handle seaming properly
|
||||
// instead of going through drawBitmapRect (which will be removed from SkDevice in the future)
|
||||
SkBitmap bm;
|
||||
if (this->shouldTileImage(image, &src, constraint, paint.getFilterQuality(), ctm, srcToDst)) {
|
||||
// only support tiling as bitmap at the moment, so force raster-version
|
||||
if (as_IB(image)->getROPixels(&bm)) {
|
||||
this->drawBitmapRect(bm, &src, dst, paint, constraint);
|
||||
return;
|
||||
// Next up, determine if the image must be tiled
|
||||
{
|
||||
// If image is explicitly already texture backed then we shouldn't get here.
|
||||
SkASSERT(!image->isTextureBacked());
|
||||
|
||||
int tileFilterPad;
|
||||
if (doBicubic) {
|
||||
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
|
||||
} else if (GrSamplerState::Filter::kNearest == fm) {
|
||||
tileFilterPad = 0;
|
||||
} else {
|
||||
tileFilterPad = 1;
|
||||
}
|
||||
int maxTileSize = fContext->priv().caps()->maxTileSize() - 2 * tileFilterPad;
|
||||
int tileSize;
|
||||
SkIRect clippedSubset;
|
||||
if (should_tile_image_id(fContext.get(), SkISize::Make(fRenderTargetContext->width(),
|
||||
fRenderTargetContext->height()),
|
||||
clip, image->unique(), image->dimensions(), ctm, srcToDst, &src,
|
||||
maxTileSize, &tileSize, &clippedSubset)) {
|
||||
// Extract pixels on the CPU, since we have to split into separate textures before
|
||||
// sending to the GPU.
|
||||
SkBitmap bm;
|
||||
if (as_IB(image)->getROPixels(&bm)) {
|
||||
// This is the funnel for all paths that draw tiled bitmaps/images. Log histogram
|
||||
SK_HISTOGRAM_BOOLEAN("DrawTiled", true);
|
||||
LogDrawScaleFactor(ctm, srcToDst, paint.getFilterQuality());
|
||||
draw_tiled_bitmap(fContext.get(), fRenderTargetContext.get(), clip, bm, tileSize,
|
||||
ctm, srcToDst, src, clippedSubset, paint, aa, constraint,
|
||||
wrapMode, fm, doBicubic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -778,17 +720,19 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
|
||||
// texture creation.
|
||||
if (image->isLazyGenerated()) {
|
||||
GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), this->clip(), ctm, paint,
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, ctm, paint,
|
||||
&maker, src, dst, dstClip, srcToDst, aa, aaFlags, constraint,
|
||||
wrapMode);
|
||||
wrapMode, fm, doBicubic);
|
||||
return;
|
||||
}
|
||||
|
||||
SkBitmap bm;
|
||||
if (as_IB(image)->getROPixels(&bm)) {
|
||||
GrBitmapTextureMaker maker(fContext.get(), bm, GrBitmapTextureMaker::Cached::kYes,
|
||||
SkBackingFit::kExact);
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), this->clip(), ctm, paint,
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, ctm, paint,
|
||||
&maker, src, dst, dstClip, srcToDst, aa, aaFlags, constraint,
|
||||
wrapMode);
|
||||
wrapMode, fm, doBicubic);
|
||||
}
|
||||
|
||||
// Otherwise don't know how to draw it
|
||||
@ -921,32 +865,3 @@ void SkGpuDevice::drawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[], int co
|
||||
}
|
||||
draw(count);
|
||||
}
|
||||
|
||||
// TODO (michaelludwig) - to be removed when drawBitmapRect doesn't need it anymore
|
||||
void SkGpuDevice::drawTextureProducer(GrTextureProducer* producer,
|
||||
const SkRect* srcRect,
|
||||
const SkRect* dstRect,
|
||||
SkCanvas::SrcRectConstraint constraint,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkPaint& paint) {
|
||||
// The texture refactor split the old logic of drawTextureProducer into the beginning of
|
||||
// drawImageQuad() and into the static draw_texture_producer. Replicate necessary logic that
|
||||
// drawImageQuad() handles.
|
||||
SkRect src;
|
||||
SkRect dst;
|
||||
SkMatrix srcToDst;
|
||||
ImageDrawMode mode = optimize_sample_area(producer->dimensions(), srcRect, dstRect, nullptr,
|
||||
&src, &dst, &srcToDst);
|
||||
if (mode == ImageDrawMode::kSkip) {
|
||||
return;
|
||||
}
|
||||
// There's no dstClip to worry about and the producer is already made so we wouldn't be able
|
||||
// to tell it to use decals if we had to
|
||||
SkASSERT(mode != ImageDrawMode::kDecal);
|
||||
|
||||
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), this->clip(), viewMatrix,
|
||||
paint, producer, src, dst, /* clip */ nullptr, srcToDst,
|
||||
GrAA(paint.isAntiAlias()),
|
||||
paint.isAntiAlias() ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
|
||||
constraint, GrSamplerState::WrapMode::kClamp);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user