Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(516)

Unified Diff: src/gpu/SkGr.cpp

Issue 1249543003: Creating functions for uploading a mipmapped texture. (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: Fixing merge mistakes Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/gpu/SkGr.cpp
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 09c83b929a8c575b1a2b9e15116c76abc4968c5c..3b99bc80fa89f4607218b1a3b5e92e4babd45be0 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -5,9 +5,12 @@
* found in the LICENSE file.
*/
+#include "GrTextureMaker.h"
+
#include "SkGr.h"
#include "GrCaps.h"
+#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrXferProcessor.h"
#include "GrYUVProvider.h"
@@ -19,13 +22,19 @@
#include "SkErrorInternals.h"
#include "SkGrPixelRef.h"
#include "SkMessageBus.h"
+#include "SkMath.h"
+#include "SkMipMap.h"
+#include "SkMipMapLevel.h"
#include "SkPixelRef.h"
#include "SkResourceCache.h"
#include "SkTextureCompressor.h"
+#include "SkTypes.h"
#include "SkYUVPlanesCache.h"
#include "effects/GrBicubicEffect.h"
+#include "effects/GrConstColorProcessor.h"
#include "effects/GrDitherEffect.h"
#include "effects/GrPorterDuffXferProcessor.h"
+#include "effects/GrXfermodeFragmentProcessor.h"
#include "effects/GrYUVtoRGBEffect.h"
#ifndef SK_IGNORE_ETC1_SUPPORT
@@ -92,56 +101,42 @@ static void build_index8_data(void* buffer, const SkBitmap& bitmap) {
////////////////////////////////////////////////////////////////////////////////
-struct Stretch {
- enum Type {
- kNone_Type,
- kBilerp_Type,
- kNearest_Type
- } fType;
- int fWidth;
- int fHeight;
-};
-
-static void get_stretch(const GrContext* ctx, int width, int height,
- const GrTextureParams* params, Stretch* stretch) {
- stretch->fType = Stretch::kNone_Type;
+static void get_stretch(const GrCaps& caps, int width, int height,
+ const GrTextureParams& params, SkGrStretch* stretch) {
+ stretch->fType = SkGrStretch::kNone_Type;
bool doStretch = false;
- if (params && params->isTiled() && !ctx->caps()->npotTextureTileSupport() &&
+ if (params.isTiled() && !caps.npotTextureTileSupport() &&
(!SkIsPow2(width) || !SkIsPow2(height))) {
doStretch = true;
- stretch->fWidth = GrNextPow2(SkTMax(width, ctx->caps()->minTextureSize()));
- stretch->fHeight = GrNextPow2(SkTMax(height, ctx->caps()->minTextureSize()));
- } else if (width < ctx->caps()->minTextureSize() || height < ctx->caps()->minTextureSize()) {
+ stretch->fWidth = GrNextPow2(SkTMax(width, caps.minTextureSize()));
+ stretch->fHeight = GrNextPow2(SkTMax(height, caps.minTextureSize()));
+ } else if (width < caps.minTextureSize() || height < caps.minTextureSize()) {
// The small texture issues appear to be with tiling. Hence it seems ok to scale them
// up using the GPU. If issues persist we may need to CPU-stretch.
doStretch = true;
- stretch->fWidth = SkTMax(width, ctx->caps()->minTextureSize());
- stretch->fHeight = SkTMax(height, ctx->caps()->minTextureSize());
+ stretch->fWidth = SkTMax(width, caps.minTextureSize());
+ stretch->fHeight = SkTMax(height, caps.minTextureSize());
}
if (doStretch) {
- if (params) {
- switch(params->filterMode()) {
- case GrTextureParams::kNone_FilterMode:
- stretch->fType = Stretch::kNearest_Type;
- break;
- case GrTextureParams::kBilerp_FilterMode:
- case GrTextureParams::kMipMap_FilterMode:
- stretch->fType = Stretch::kBilerp_Type;
- break;
- }
- } else {
- stretch->fType = Stretch::kBilerp_Type;
+ switch(params.filterMode()) {
+ case GrTextureParams::kNone_FilterMode:
+ stretch->fType = SkGrStretch::kNearest_Type;
+ break;
+ case GrTextureParams::kBilerp_FilterMode:
+ case GrTextureParams::kMipMap_FilterMode:
+ stretch->fType = SkGrStretch::kBilerp_Type;
+ break;
}
} else {
stretch->fWidth = -1;
stretch->fHeight = -1;
- stretch->fType = Stretch::kNone_Type;
+ stretch->fType = SkGrStretch::kNone_Type;
}
}
-static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretch,
- GrUniqueKey* stretchedKey) {
- if (origKey.isValid() && Stretch::kNone_Type != stretch.fType) {
+bool GrMakeStretchedKey(const GrUniqueKey& origKey, const SkGrStretch& stretch,
+ GrUniqueKey* stretchedKey) {
+ if (origKey.isValid() && SkGrStretch::kNone_Type != stretch.fType) {
uint32_t width = SkToU16(stretch.fWidth);
uint32_t height = SkToU16(stretch.fHeight);
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
@@ -155,53 +150,39 @@ static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretc
return false;
}
-static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset) {
+static void make_unstretched_key(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset, bool isMipMapped = false) {
SkASSERT(SkIsU16(subset.width()));
SkASSERT(SkIsU16(subset.height()));
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey::Builder builder(key, kDomain, 4);
+ GrUniqueKey::Builder builder(key, kDomain, 5);
builder[0] = imageID;
builder[1] = subset.x();
builder[2] = subset.y();
builder[3] = subset.width() | (subset.height() << 16);
+ builder[4] = isMipMapped;
}
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& subset,
- const GrCaps& caps, SkImageUsageType usage) {
- const Stretch::Type stretches[] = {
- Stretch::kNone_Type, // kUntiled_SkImageUsageType
- Stretch::kNearest_Type, // kTiled_Unfiltered_SkImageUsageType
- Stretch::kBilerp_Type, // kTiled_Filtered_SkImageUsageType
- };
-
- const bool isPow2 = SkIsPow2(subset.width()) && SkIsPow2(subset.height());
- const bool needToStretch = !isPow2 &&
- usage != kUntiled_SkImageUsageType &&
- !caps.npotTextureTileSupport();
-
- if (needToStretch) {
+ const GrCaps& caps, const GrTextureParams& params) {
+ SkGrStretch stretch;
+ get_stretch(caps, subset.width(), subset.height(), params, &stretch);
+ if (SkGrStretch::kNone_Type != stretch.fType) {
GrUniqueKey tmpKey;
make_unstretched_key(&tmpKey, imageID, subset);
-
- Stretch stretch;
- stretch.fType = stretches[usage];
- stretch.fWidth = SkNextPow2(subset.width());
- stretch.fHeight = SkNextPow2(subset.height());
- if (!make_stretched_key(tmpKey, stretch, key)) {
- goto UNSTRETCHED;
+ if (!GrMakeStretchedKey(tmpKey, stretch, key)) {
+ *key = tmpKey;
}
} else {
- UNSTRETCHED:
make_unstretched_key(key, imageID, subset);
}
}
-static void make_image_keys(uint32_t imageID, const SkIRect& subset, const Stretch& stretch,
+static void make_image_keys(uint32_t imageID, const SkIRect& subset, const SkGrStretch& stretch,
GrUniqueKey* key, GrUniqueKey* stretchedKey) {
make_unstretched_key(key, imageID, subset);
- if (Stretch::kNone_Type != stretch.fType) {
- make_stretched_key(*key, stretch, stretchedKey);
+ if (SkGrStretch::kNone_Type != stretch.fType) {
+ GrMakeStretchedKey(*key, stretch, stretchedKey);
}
}
@@ -231,6 +212,18 @@ private:
} // namespace
+static void add_key_and_invalidation_listener(GrContext* ctx,
+ const GrUniqueKey& optionalKey,
+ SkPixelRef* pixelRefForInvalidationNotification,
+ GrTexture& result) {
+ if (optionalKey.isValid()) {
+ if (pixelRefForInvalidationNotification) {
+ BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
+ pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
+ }
+ ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, &result);
+ }
+}
GrTexture* GrCreateTextureForPixels(GrContext* ctx,
const GrUniqueKey& optionalKey,
@@ -239,23 +232,33 @@ GrTexture* GrCreateTextureForPixels(GrContext* ctx,
const void* pixels,
size_t rowBytes) {
GrTexture* result = ctx->textureProvider()->createTexture(desc, true, pixels, rowBytes);
- if (result && optionalKey.isValid()) {
- if (pixelRefForInvalidationNotification) {
- BitmapInvalidator* listener = new BitmapInvalidator(optionalKey);
- pixelRefForInvalidationNotification->addGenIDChangeListener(listener);
- }
- ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, result);
+ if (result) {
+ add_key_and_invalidation_listener(ctx, optionalKey, pixelRefForInvalidationNotification,
+ *result);
}
return result;
}
+GrTexture* GrCreateTextureForPixels(GrContext* ctx,
+ const GrUniqueKey& optionalKey,
+ GrSurfaceDesc desc,
+ SkPixelRef* pixelRefForInvalidationNotification,
+ const SkTArray<SkMipMapLevel>& texels) {
+ GrTexture* result = ctx->textureProvider()->createTexture(desc, true, texels);
+ if (result) {
+ add_key_and_invalidation_listener(ctx, optionalKey, pixelRefForInvalidationNotification,
+ *result);
+ }
+ return result;
+}
+
// creates a new texture that is the input texture scaled up. If optionalKey is valid it will be
// set on the new texture. stretch controls whether the scaling is done using nearest or bilerp
// filtering and the size to stretch the texture to.
-GrTexture* stretch_texture(GrTexture* inputTexture, const Stretch& stretch,
+GrTexture* stretch_texture(GrTexture* inputTexture, const SkGrStretch& stretch,
SkPixelRef* pixelRef,
const GrUniqueKey& optionalKey) {
- SkASSERT(Stretch::kNone_Type != stretch.fType);
+ SkASSERT(SkGrStretch::kNone_Type != stretch.fType);
GrContext* context = inputTexture->getContext();
SkASSERT(context);
@@ -301,7 +304,7 @@ GrTexture* stretch_texture(GrTexture* inputTexture, const Stretch& stretch,
// If filtering is not desired then we want to ensure all texels in the resampled image are
// copies of texels from the original.
GrTextureParams params(SkShader::kClamp_TileMode,
- Stretch::kBilerp_Type == stretch.fType ?
+ SkGrStretch::kBilerp_Type == stretch.fType ?
GrTextureParams::kBilerp_FilterMode :
GrTextureParams::kNone_FilterMode);
paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
@@ -309,13 +312,12 @@ GrTexture* stretch_texture(GrTexture* inputTexture, const Stretch& stretch,
SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
SkRect localRect = SkRect::MakeWH(1.f, 1.f);
- SkAutoTUnref<GrDrawContext> drawContext(context->drawContext());
+ SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(stretched->asRenderTarget()));
if (!drawContext) {
return nullptr;
}
- drawContext->drawNonAARectToRect(stretched->asRenderTarget(), GrClip::WideOpen(), paint,
- SkMatrix::I(), rect, localRect);
+ drawContext->drawNonAARectToRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, localRect);
return stretched.detach();
}
@@ -421,7 +423,7 @@ static GrTexture* load_yuv_texture(GrContext* ctx, const GrUniqueKey& optionalKe
pixelRef->addGenIDChangeListener(listener);
ctx->textureProvider()->assignUniqueKeyToTexture(optionalKey, texture);
}
- return texture;
+ return texture;
}
static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
@@ -480,19 +482,19 @@ static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx,
bitmap->getPixels(), bitmap->rowBytes());
}
-static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const Stretch& stretch) {
+static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const SkGrStretch& stretch) {
SkBitmap stretched;
stretched.allocN32Pixels(stretch.fWidth, stretch.fHeight);
SkCanvas canvas(stretched);
SkPaint paint;
switch (stretch.fType) {
- case Stretch::kNearest_Type:
+ case SkGrStretch::kNearest_Type:
paint.setFilterQuality(kNone_SkFilterQuality);
break;
- case Stretch::kBilerp_Type:
+ case SkGrStretch::kBilerp_Type:
paint.setFilterQuality(kLow_SkFilterQuality);
break;
- case Stretch::kNone_Type:
+ case SkGrStretch::kNone_Type:
SkDEBUGFAIL("Shouldn't get here.");
break;
}
@@ -501,39 +503,14 @@ static SkBitmap stretch_on_cpu(const SkBitmap& bmp, const Stretch& stretch) {
return stretched;
}
-static GrTexture* create_bitmap_texture(GrContext* ctx,
- const SkBitmap& bmp,
- const Stretch& stretch,
- const GrUniqueKey& unstretchedKey,
- const GrUniqueKey& stretchedKey) {
- if (Stretch::kNone_Type != stretch.fType) {
- SkAutoTUnref<GrTexture> unstretched;
- // Check if we have the unstretched version in the cache, if not create it.
- if (unstretchedKey.isValid()) {
- unstretched.reset(ctx->textureProvider()->findAndRefTextureByUniqueKey(unstretchedKey));
- }
- if (!unstretched) {
- unstretched.reset(create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey));
- if (!unstretched) {
- // We might not have been able to create a unstrecthed texture because it is smaller
- // than the min texture size. In that case do cpu stretching.
- SkBitmap stretchedBmp = stretch_on_cpu(bmp, stretch);
- return create_unstretched_bitmap_texture(ctx, stretchedBmp, stretchedKey);
- }
- }
- return stretch_texture(unstretched, stretch, bmp.pixelRef(), stretchedKey);
- }
- return create_unstretched_bitmap_texture(ctx, bmp, unstretchedKey);
-}
-
bool GrIsImageInCache(const GrContext* ctx, uint32_t imageID, const SkIRect& subset,
- GrTexture* nativeTexture, const GrTextureParams* params) {
- Stretch stretch;
- get_stretch(ctx, subset.width(), subset.height(), params, &stretch);
+ GrTexture* nativeTexture, const GrTextureParams& params) {
+ SkGrStretch stretch;
+ get_stretch(*ctx->caps(), subset.width(), subset.height(), params, &stretch);
// Handle the case where the bitmap/image is explicitly texture backed.
if (nativeTexture) {
- if (Stretch::kNone_Type == stretch.fType) {
+ if (SkGrStretch::kNone_Type == stretch.fType) {
return true;
}
const GrUniqueKey& key = nativeTexture->getUniqueKey();
@@ -541,100 +518,168 @@ bool GrIsImageInCache(const GrContext* ctx, uint32_t imageID, const SkIRect& sub
return false;
}
GrUniqueKey stretchedKey;
- make_stretched_key(key, stretch, &stretchedKey);
+ GrMakeStretchedKey(key, stretch, &stretchedKey);
return ctx->textureProvider()->existsTextureWithUniqueKey(stretchedKey);
}
GrUniqueKey key, stretchedKey;
make_image_keys(imageID, subset, stretch, &key, &stretchedKey);
return ctx->textureProvider()->existsTextureWithUniqueKey(
- (Stretch::kNone_Type == stretch.fType) ? key : stretchedKey);
+ (SkGrStretch::kNone_Type == stretch.fType) ? key : stretchedKey);
}
-bool GrIsBitmapInCache(const GrContext* ctx, const SkBitmap& bitmap,
- const GrTextureParams* params) {
- if (bitmap.isVolatile()) {
- return false; // we don't cache volatile bitmaps.
+static GrTexture* generate_mipmaps(const SkBitmap& bitmap,
+ GrContext* ctx) {
+ // Make sure the value of the int fits inside a uint32_t
+ if (bitmap.width() <= 0 && bitmap.height() <= 0) {
+ return nullptr;
}
- return GrIsImageInCache(ctx, bitmap.getGenerationID(), bitmap.getSubset(), bitmap.getTexture(),
- params);
-}
+ SkASSERT(sizeof(int) <= sizeof(uint32_t));
+ const uint32_t baseWidth = static_cast<uint32_t>(bitmap.width());
+ const uint32_t baseHeight = static_cast<uint32_t>(bitmap.height());
+
+ // OpenGL's spec requires that each mipmap level has height/width equal to
+ // max(1, floor(original_height / 2^i)
+ // (or original_height) where i is the mipmap level.
+ // Keep scaling down until both axes are size 1.
+
+ const uint32_t largestAxis = SkTMax(baseWidth, baseHeight);
+ const int leadingZeros = SkCLZ(largestAxis);
+ // If the value 00011010 has 3 leading 0s, it has 5 significant bits
+ // (the bits which are not leading zeros)
+ const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros;
+ if (significantBits < 0)
+ {
+ return nullptr;
+ }
+ const uint32_t unsignedSignificantBits = static_cast<uint32_t>(significantBits);
+ const uint32_t mipLevelCount = unsignedSignificantBits;
+
+ GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info());
+ const bool isMipMapped = mipLevelCount > 1;
+ desc.fIsMipMapped = isMipMapped;
+
+ /*
+ SkAutoPixmapUnlock srcUnlocker;
+ if (!bitmap.requestLock(&srcUnlocker)) {
+ return nullptr;
+ }
+ const SkPixmap& srcPixmap = srcUnlocker.pixmap();
+ if (nullptr == srcPixmap.addr()) {
+ return nullptr;
+ }
+ */
-GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
- const SkBitmap& bitmap,
- const GrTextureParams* params) {
+ SkTArray<SkMipMapLevel> texels(mipLevelCount);
+ //SkMipMapLevel baseLevel(srcPixmap.addr(), bitmap.rowBytes(), baseWidth, baseHeight);
+ SkMipMapLevel baseLevel(bitmap.getPixels(), bitmap.rowBytes(), baseWidth, baseHeight);
+ texels.push_back(baseLevel);
- Stretch stretch;
- get_stretch(ctx, bitmap.width(), bitmap.height(), params, &stretch);
+ SkTArray<SkBitmap> mipLevelBitmaps(mipLevelCount - 1);
+ mipLevelBitmaps.push_back_n(mipLevelCount - 1);
- GrTexture* result = bitmap.getTexture();
- if (result) {
- if (Stretch::kNone_Type == stretch.fType) {
- return SkRef(result);
+ for (uint32_t i = 1; i < mipLevelCount; i++) {
+ SkBitmap& currentMipBitmap = mipLevelBitmaps[i - 1];
+
+ uint32_t twoToTheMipLevel = 1 << (i + 1);
+ uint32_t currentMipLevelWidth = SkTMax(1u, baseWidth / twoToTheMipLevel);
+ uint32_t currentMipLevelHeight = SkTMax(1u, baseHeight / twoToTheMipLevel);
+
+ SkImageInfo info = SkImageInfo::Make(currentMipLevelWidth, currentMipLevelHeight,
+ currentMipBitmap.colorType(),
+ bitmap.alphaType());
+ if (!currentMipBitmap.tryAllocPixels(info))
+ {
+ return nullptr;
}
- GrUniqueKey stretchedKey;
- // Don't create a key for the resized version if the bmp is volatile.
- if (!bitmap.isVolatile()) {
- const GrUniqueKey& key = result->getUniqueKey();
- if (key.isValid()) {
- make_stretched_key(key, stretch, &stretchedKey);
- GrTexture* stretched =
- ctx->textureProvider()->findAndRefTextureByUniqueKey(stretchedKey);
- if (stretched) {
- return stretched;
- }
- }
+
+ SkCanvas canvas(currentMipBitmap);
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0));
+
+ /*
+ SkAutoPixmapUnlock mipUnlocker;
+ if (!currentMipBitmap.requestLock(&mipUnlocker)) {
+ return nullptr;
}
- return stretch_texture(result, stretch, bitmap.pixelRef(), stretchedKey);
+ const SkPixmap& mipPixmap = mipUnlocker.pixmap();
+ if (nullptr == mipPixmap.addr()) {
+ return nullptr;
+ }
+ */
+
+ SkMipMapLevel currentMipLevel(currentMipBitmap.getPixels(),
+ //SkMipMapLevel currentMipLevel(mipPixmap.addr(),
+ currentMipBitmap.rowBytes(),
+ currentMipLevelWidth, currentMipLevelHeight);
+ texels.push_back(currentMipLevel);
}
- GrUniqueKey key, resizedKey;
- if (!bitmap.isVolatile()) {
- // If the bitmap isn't changing try to find a cached copy first.
- make_image_keys(bitmap.getGenerationID(), bitmap.getSubset(), stretch, &key, &resizedKey);
+ GrUniqueKey unstretchedKey;
+ make_unstretched_key(&unstretchedKey, bitmap.getGenerationID(), bitmap.getSubset(), isMipMapped);
+
+ return GrCreateTextureForPixels(ctx, unstretchedKey, desc, bitmap.pixelRef(), texels);
+}
+
+
+class Bitmap_GrTextureMaker : public GrTextureMaker {
+public:
+ Bitmap_GrTextureMaker(const SkBitmap& bitmap)
+ : INHERITED(bitmap.width(), bitmap.height())
+ , fBitmap(bitmap)
+ {}
+
+protected:
+ GrTexture* onRefUnstretchedTexture(GrContext* ctx, const GrTextureParams* params) override {
+ GrTexture* texture = fBitmap.getTexture();
+
+ if (params && params->filterMode() == GrTextureParams::kMipMap_FilterMode) {
+ return generate_mipmaps(fBitmap, ctx);
+ }
+
+ if (texture) {
+ return SkRef(texture);
+ }
+
+ GrUniqueKey unstretchedKey;
+ make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
- result = ctx->textureProvider()->findAndRefTextureByUniqueKey(
- resizedKey.isValid() ? resizedKey : key);
+ GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(unstretchedKey);
if (result) {
return result;
}
+ return create_unstretched_bitmap_texture(ctx, fBitmap, unstretchedKey);
}
- result = create_bitmap_texture(ctx, bitmap, stretch, key, resizedKey);
- if (result) {
- return result;
- }
+ bool onMakeStretchedKey(const SkGrStretch& stretch, GrUniqueKey* stretchedKey) override {
+ if (fBitmap.isVolatile()) {
+ return false;
+ }
- SkErrorInternals::SetError( kInternalError_SkError,
- "---- failed to create texture for cache [%d %d]\n",
- bitmap.width(), bitmap.height());
+ GrUniqueKey unstretchedKey;
+ make_unstretched_key(&unstretchedKey, fBitmap.getGenerationID(), fBitmap.getSubset());
+ return GrMakeStretchedKey(unstretchedKey, stretch, stretchedKey);
+ }
- return nullptr;
-}
+ void onNotifyStretchCached(const GrUniqueKey& stretchedKey) override {
+ fBitmap.pixelRef()->addGenIDChangeListener(new BitmapInvalidator(stretchedKey));
+ }
-// TODO: make this be the canonical signature, and turn the version that takes GrTextureParams*
-// into a wrapper that contains the inverse of these tables.
-GrTexture* GrRefCachedBitmapTexture(GrContext* ctx,
- const SkBitmap& bitmap,
- SkImageUsageType usage) {
- // Just need a params that will trigger the correct cache key / etc, since the usage doesn't
- // tell us the specifics about filter level or specific tiling.
+ bool onGetROBitmap(SkBitmap* bitmap) override {
+ *bitmap = fBitmap;
+ return true;
+ }
- const SkShader::TileMode tiles[] = {
- SkShader::kClamp_TileMode, // kUntiled_SkImageUsageType
- SkShader::kRepeat_TileMode, // kTiled_Unfiltered_SkImageUsageType
- SkShader::kRepeat_TileMode, // kTiled_Filtered_SkImageUsageType
- };
+private:
+ const SkBitmap fBitmap;
- const GrTextureParams::FilterMode filters[] = {
- GrTextureParams::kNone_FilterMode, // kUntiled_SkImageUsageType
- GrTextureParams::kNone_FilterMode, // kTiled_Unfiltered_SkImageUsageType
- GrTextureParams::kBilerp_FilterMode, // kTiled_Filtered_SkImageUsageType
- };
+ typedef GrTextureMaker INHERITED;
+};
- GrTextureParams params(tiles[usage], filters[usage]);
- return GrRefCachedBitmapTexture(ctx, bitmap, &params);
+GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap,
+ const GrTextureParams& params) {
+ return Bitmap_GrTextureMaker(bitmap).refCachedTexture(ctx, params);
}
///////////////////////////////////////////////////////////////////////////////
@@ -706,46 +751,142 @@ bool GrPixelConfig2ColorAndProfileType(GrPixelConfig config, SkColorType* ctOut,
return true;
}
-///////////////////////////////////////////////////////////////////////////////
-bool SkPaint2GrPaintNoShader(GrContext* context, const SkPaint& skPaint, GrColor paintColor,
- bool constantColor, GrPaint* grPaint) {
+////////////////////////////////////////////////////////////////////////////////////////////////
+static inline bool blend_requires_shader(const SkXfermode::Mode mode, bool primitiveIsSrc) {
+ if (primitiveIsSrc) {
+ return SkXfermode::kSrc_Mode != mode;
+ } else {
+ return SkXfermode::kDst_Mode != mode;
+ }
+}
+
+static inline bool skpaint_to_grpaint_impl(GrContext* context,
+ const SkPaint& skPaint,
+ const SkMatrix& viewM,
+ const GrFragmentProcessor** shaderProcessor,
+ SkXfermode::Mode* primColorMode,
+ bool primitiveIsSrc,
+ GrPaint* grPaint) {
grPaint->setAntiAlias(skPaint.isAntiAlias());
- SkXfermode* mode = skPaint.getXfermode();
- GrXPFactory* xpFactory = nullptr;
- if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
- // Fall back to src-over
- // return false here?
- xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode);
+ // Setup the initial color considering the shader, the SkPaint color, and the presence or not
+ // of per-vertex colors.
+ SkAutoTUnref<const GrFragmentProcessor> aufp;
+ const GrFragmentProcessor* shaderFP = nullptr;
+ if (!primColorMode || blend_requires_shader(*primColorMode, primitiveIsSrc)) {
+ if (shaderProcessor) {
+ shaderFP = *shaderProcessor;
+ } else if (const SkShader* shader = skPaint.getShader()) {
+ aufp.reset(shader->asFragmentProcessor(context, viewM, nullptr,
+ skPaint.getFilterQuality()));
+ shaderFP = aufp;
+ if (!shaderFP) {
+ return false;
+ }
+ }
}
- SkASSERT(xpFactory);
- grPaint->setXPFactory(xpFactory)->unref();
- //set the color of the paint to the one of the parameter
- grPaint->setColor(paintColor);
+ // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
+ // a known constant value. In that case we can simply apply a color filter during this
+ // conversion without converting the color filter to a GrFragmentProcessor.
+ bool applyColorFilterToPaintColor = false;
+ if (shaderFP) {
+ if (primColorMode) {
+ // There is a blend between the primitive color and the shader color. The shader sees
+ // the opaque paint color. The shader's output is blended using the provided mode by
+ // the primitive color. The blended color is then modulated by the paint's alpha.
+
+ // The geometry processor will insert the primitive color to start the color chain, so
+ // the GrPaint color will be ignored.
+
+ GrColor shaderInput = SkColorToOpaqueGrColor(skPaint.getColor());
+
+ shaderFP = GrFragmentProcessor::OverrideInput(shaderFP, shaderInput);
+ aufp.reset(shaderFP);
+
+ if (primitiveIsSrc) {
+ shaderFP = GrXfermodeFragmentProcessor::CreateFromDstProcessor(shaderFP,
+ *primColorMode);
+ } else {
+ shaderFP = GrXfermodeFragmentProcessor::CreateFromSrcProcessor(shaderFP,
+ *primColorMode);
+ }
+ aufp.reset(shaderFP);
+ // The above may return null if compose results in a pass through of the prim color.
+ if (shaderFP) {
+ grPaint->addColorFragmentProcessor(shaderFP);
+ }
+
+ GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
+ if (GrColor_WHITE != paintAlpha) {
+ grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create(
+ paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref();
+ }
+ } else {
+ // The shader's FP sees the paint unpremul color
+ grPaint->setColor(SkColorToUnpremulGrColor(skPaint.getColor()));
+ grPaint->addColorFragmentProcessor(shaderFP);
+ }
+ } else {
+ if (primColorMode) {
+ // There is a blend between the primitive color and the paint color. The blend considers
+ // the opaque paint color. The paint's alpha is applied to the post-blended color.
+ SkAutoTUnref<const GrFragmentProcessor> processor(
+ GrConstColorProcessor::Create(SkColorToOpaqueGrColor(skPaint.getColor()),
+ GrConstColorProcessor::kIgnore_InputMode));
+ if (primitiveIsSrc) {
+ processor.reset(GrXfermodeFragmentProcessor::CreateFromDstProcessor(processor,
+ *primColorMode));
+ } else {
+ processor.reset(GrXfermodeFragmentProcessor::CreateFromSrcProcessor(processor,
+ *primColorMode));
+
+ }
+ if (processor) {
+ grPaint->addColorFragmentProcessor(processor);
+ }
+
+ grPaint->setColor(SkColorToOpaqueGrColor(skPaint.getColor()));
+
+ GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
+ if (GrColor_WHITE != paintAlpha) {
+ grPaint->addColorFragmentProcessor(GrConstColorProcessor::Create(
+ paintAlpha, GrConstColorProcessor::kModulateRGBA_InputMode))->unref();
+ }
+ } else {
+ // No shader, no primitive color.
+ grPaint->setColor(SkColorToPremulGrColor(skPaint.getColor()));
+ applyColorFilterToPaintColor = true;
+ }
+ }
SkColorFilter* colorFilter = skPaint.getColorFilter();
if (colorFilter) {
- // if the source color is a constant then apply the filter here once rather than per pixel
- // in a shader.
- if (constantColor) {
- SkColor filtered = colorFilter->filterColor(skPaint.getColor());
- grPaint->setColor(SkColor2GrColor(filtered));
+ if (applyColorFilterToPaintColor) {
+ grPaint->setColor(SkColorToPremulGrColor(colorFilter->filterColor(skPaint.getColor())));
} else {
- SkTDArray<const GrFragmentProcessor*> array;
- // return false if failed?
- if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(),
- &array)) {
- for (int i = 0; i < array.count(); ++i) {
- grPaint->addColorFragmentProcessor(array[i]);
- array[i]->unref();
- }
+ SkAutoTUnref<const GrFragmentProcessor> cfFP(
+ colorFilter->asFragmentProcessor(context));
+ if (cfFP) {
+ grPaint->addColorFragmentProcessor(cfFP);
+ } else {
+ return false;
}
}
}
+ SkXfermode* mode = skPaint.getXfermode();
+ GrXPFactory* xpFactory = nullptr;
+ if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
+ // Fall back to src-over
+ // return false here?
+ xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode);
+ }
+ SkASSERT(xpFactory);
+ grPaint->setXPFactory(xpFactory)->unref();
+
#ifndef SK_IGNORE_GPU_DITHER
if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) {
grPaint->addColorFragmentProcessor(GrDitherEffect::Create())->unref();
@@ -754,29 +895,49 @@ bool SkPaint2GrPaintNoShader(GrContext* context, const SkPaint& skPaint, GrColor
return true;
}
-bool SkPaint2GrPaint(GrContext* context,const SkPaint& skPaint, const SkMatrix& viewM,
- bool constantColor, GrPaint* grPaint) {
- SkShader* shader = skPaint.getShader();
- if (nullptr == shader) {
- return SkPaint2GrPaintNoShader(context, skPaint, SkColor2GrColor(skPaint.getColor()),
- constantColor, grPaint);
- }
-
- GrColor paintColor = SkColor2GrColor(skPaint.getColor());
+bool SkPaintToGrPaint(GrContext* context, const SkPaint& skPaint, const SkMatrix& viewM,
+ GrPaint* grPaint) {
+ return skpaint_to_grpaint_impl(context, skPaint, viewM, nullptr, nullptr, false, grPaint);
+}
- const GrFragmentProcessor* fp = shader->asFragmentProcessor(context, viewM, NULL,
- skPaint.getFilterQuality(), grPaint->getProcessorDataManager());
- if (!fp) {
+/** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
+bool SkPaintToGrPaintReplaceShader(GrContext* context,
+ const SkPaint& skPaint,
+ const GrFragmentProcessor* shaderFP,
+ GrPaint* grPaint) {
+ if (!shaderFP) {
return false;
}
- grPaint->addColorFragmentProcessor(fp)->unref();
- constantColor = false;
+ return skpaint_to_grpaint_impl(context, skPaint, SkMatrix::I(), &shaderFP, nullptr, false,
+ grPaint);
+}
- // The grcolor is automatically set when calling asFragmentProcessor.
- // If the shader can be seen as an effect it returns true and adds its effect to the grpaint.
- return SkPaint2GrPaintNoShader(context, skPaint, paintColor, constantColor, grPaint);
+/** Ignores the SkShader (if any) on skPaint. */
+bool SkPaintToGrPaintNoShader(GrContext* context,
+ const SkPaint& skPaint,
+ GrPaint* grPaint) {
+ // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
+ static const GrFragmentProcessor* kNullShaderFP = nullptr;
+ static const GrFragmentProcessor** kIgnoreShader = &kNullShaderFP;
+ return skpaint_to_grpaint_impl(context, skPaint, SkMatrix::I(), kIgnoreShader, nullptr, false,
+ grPaint);
}
+/** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
+be setup as a vertex attribute using the specified SkXfermode::Mode. */
+bool SkPaintToGrPaintWithXfermode(GrContext* context,
+ const SkPaint& skPaint,
+ const SkMatrix& viewM,
+ SkXfermode::Mode primColorMode,
+ bool primitiveIsSrc,
+ GrPaint* grPaint) {
+ return skpaint_to_grpaint_impl(context, skPaint, viewM, nullptr, &primColorMode, primitiveIsSrc,
+ grPaint);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
SkImageInfo GrMakeInfoFromTexture(GrTexture* tex, int w, int h, bool isOpaque) {
#ifdef SK_DEBUG
const GrSurfaceDesc& desc = tex->desc();
@@ -840,3 +1001,54 @@ GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality pain
}
return textureFilterMode;
}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrTexture* GrTextureMaker::refCachedTexture(GrContext* ctx, const GrTextureParams& params) {
+ SkGrStretch stretch;
+ get_stretch(*ctx->caps(), this->width(), this->height(), params, &stretch);
+
+ if (SkGrStretch::kNone_Type == stretch.fType) {
+ return this->onRefUnstretchedTexture(ctx, &params);
+ }
+
+ GrUniqueKey stretchedKey;
+ if (this->onMakeStretchedKey(stretch, &stretchedKey)) {
+ GrTexture* result = ctx->textureProvider()->findAndRefTextureByUniqueKey(stretchedKey);
+ if (result) {
+ return result;
+ }
+ }
+
+ GrTexture* result = this->onGenerateStretchedTexture(ctx, stretch, &params);
+ if (!result) {
+ return nullptr;
+ }
+
+ if (stretchedKey.isValid()) {
+ ctx->textureProvider()->assignUniqueKeyToTexture(stretchedKey, result);
+ this->onNotifyStretchCached(stretchedKey);
+ }
+ return result;
+}
+
+GrTexture* GrTextureMaker::onGenerateStretchedTexture(GrContext* ctx, const SkGrStretch& stretch, const GrTextureParams* params) {
+ if (this->width() < ctx->caps()->minTextureSize() ||
+ this->height() < ctx->caps()->minTextureSize())
+ {
+ // we can't trust our ability to use HW to perform the stretch, so we request
+ // a raster instead, and perform the stretch on the CPU.
+ SkBitmap bitmap;
+ if (!this->onGetROBitmap(&bitmap)) {
+ return nullptr;
+ }
+ SkBitmap stretchedBmp = stretch_on_cpu(bitmap, stretch);
+ return create_unstretched_bitmap_texture(ctx, stretchedBmp, GrUniqueKey());
+ } else {
+ SkAutoTUnref<GrTexture> unstretched(this->onRefUnstretchedTexture(ctx, params));
+ if (!unstretched) {
+ return nullptr;
+ }
+ return stretch_texture(unstretched, stretch, nullptr, GrUniqueKey());
+ }
+}
« include/gpu/GrContext.h ('K') | « src/gpu/SkGpuDevice.cpp ('k') | src/gpu/SkGrPixelRef.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698