diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h index 25f3caaded..38cf9019cf 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -180,6 +180,9 @@ public: int maxRenderTargetSize() const { return fMaxRenderTargetSize; } int maxTextureSize() const { return fMaxTextureSize; } + /** 0 unless GPU has problems with small textures */ + int minTextureSize() const { return fMinTextureSize; } + // Will be 0 if MSAA is not supported int maxSampleCount() const { return fMaxSampleCount; } @@ -229,6 +232,7 @@ protected: int fMaxRenderTargetSize; int fMaxTextureSize; + int fMinTextureSize; int fMaxSampleCount; // The first entry for each config is without msaa and the second is with. diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h index d8d59fac3a..231aa30a3f 100644 --- a/include/gpu/GrContextOptions.h +++ b/include/gpu/GrContextOptions.h @@ -15,6 +15,7 @@ struct GrContextOptions { : fDrawPathToCompressedTexture(false) , fSuppressPrints(false) , fMaxTextureSizeOverride(SK_MaxS32) + , fMinTextureSizeOverride(0) , fSuppressDualSourceBlending(false) , fGeometryBufferMapThreshold(1 << 15) {} @@ -31,6 +32,7 @@ struct GrContextOptions { detected values. */ int fMaxTextureSizeOverride; + int fMinTextureSizeOverride; bool fSuppressDualSourceBlending; /** fGeometryBufferMapThreshold gives a threshold (in bytes) for when Gr should diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 1f277b7f7e..aaa585e3bb 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -98,6 +98,7 @@ GrCaps::GrCaps(const GrContextOptions& options) { fMaxRenderTargetSize = 0; fMaxTextureSize = 0; + fMinTextureSize = 0; fMaxSampleCount = 0; memset(fConfigRenderSupport, 0, sizeof(fConfigRenderSupport)); @@ -110,6 +111,7 @@ GrCaps::GrCaps(const GrContextOptions& options) { void GrCaps::applyOptionsOverrides(const GrContextOptions& options) { fMaxTextureSize = SkTMin(fMaxTextureSize, options.fMaxTextureSizeOverride); + fMinTextureSize = SkTMax(fMinTextureSize, options.fMinTextureSizeOverride); } static SkString map_flags_to_string(uint32_t flags) { @@ -148,6 +150,7 @@ SkString GrCaps::dump() const { r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]); r.appendf("Max Texture Size : %d\n", fMaxTextureSize); + r.appendf("Min Texture Size : %d\n", fMinTextureSize); r.appendf("Max Render Target Size : %d\n", fMaxRenderTargetSize); r.appendf("Max Sample Count : %d\n", fMaxSampleCount); diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 70c81f930a..a87caf7a70 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -88,34 +88,59 @@ static void build_index8_data(void* buffer, const SkBitmap& bitmap) { //////////////////////////////////////////////////////////////////////////////// -enum Stretch { - kNo_Stretch, - kBilerp_Stretch, - kNearest_Stretch +struct Stretch { + enum Type { + kNone_Type, + kBilerp_Type, + kNearest_Type + } fType; + int fWidth; + int fHeight; }; -static Stretch get_stretch_type(const GrContext* ctx, int width, int height, - const GrTextureParams* params) { - if (params && params->isTiled()) { - if (!ctx->caps()->npotTextureTileSupport() && (!SkIsPow2(width) || !SkIsPow2(height))) { - switch(params->filterMode()) { - case GrTextureParams::kNone_FilterMode: - return kNearest_Stretch; - case GrTextureParams::kBilerp_FilterMode: - case GrTextureParams::kMipMap_FilterMode: - return kBilerp_Stretch; - } - } +static void get_stretch(const GrContext* ctx, int width, int height, + const GrTextureParams* params, Stretch* stretch) { + stretch->fType = Stretch::kNone_Type; + bool doStretch = false; + if (params && params->isTiled() && !ctx->caps()->npotTextureTileSupport() && + (!SkIsPow2(width) || !SkIsPow2(height))) { + doStretch = true; + stretch->fWidth = GrNextPow2(width); + stretch->fHeight = GrNextPow2(height); + } else if (width < ctx->caps()->minTextureSize() || + height < ctx->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()); + } + if (doStretch) { + 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->fWidth = -1; + stretch->fHeight = -1; + stretch->fType = Stretch::kNone_Type; } - return kNo_Stretch; } -static bool make_stretched_key(const GrUniqueKey& origKey, Stretch stretch, +static bool make_stretched_key(const GrUniqueKey& origKey, const Stretch& stretch, GrUniqueKey* stretchedKey) { - if (origKey.isValid() && kNo_Stretch != stretch) { + if (origKey.isValid() && Stretch::kNone_Type != stretch.fType) { + uint32_t width = SkToU16(stretch.fWidth); + uint32_t height = SkToU16(stretch.fHeight); static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 1); - builder[0] = stretch; + GrUniqueKey::Builder builder(stretchedKey, origKey, kDomain, 3); + builder[0] = stretch.fType; + builder[1] = width | (height << 16); builder.finish(); return true; } @@ -140,11 +165,11 @@ static void make_unstretched_key(const SkBitmap& bitmap, GrUniqueKey* key) { } static void make_bitmap_keys(const SkBitmap& bitmap, - Stretch stretch, + const Stretch& stretch, GrUniqueKey* key, GrUniqueKey* stretchedKey) { make_unstretched_key(bitmap, key); - if (kNo_Stretch != stretch) { + if (Stretch::kNone_Type != stretch.fType) { make_stretched_key(*key, stretch, stretchedKey); } } @@ -189,13 +214,13 @@ static GrTexture* create_texture_for_bmp(GrContext* ctx, return result; } -// creates a new texture that is the input texture scaled up to the next power of two in -// width or height. If optionalKey is valid it will be set on the new texture. stretch -// controls whether the scaling is done using nearest or bilerp filtering. -GrTexture* stretch_texture_to_next_pot(GrTexture* inputTexture, Stretch stretch, - SkPixelRef* pixelRef, - const GrUniqueKey& optionalKey) { - SkASSERT(kNo_Stretch != stretch); +// 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, + SkPixelRef* pixelRef, + const GrUniqueKey& optionalKey) { + SkASSERT(Stretch::kNone_Type != stretch.fType); GrContext* context = inputTexture->getContext(); SkASSERT(context); @@ -204,8 +229,8 @@ GrTexture* stretch_texture_to_next_pot(GrTexture* inputTexture, Stretch stretch, // Either it's a cache miss or the original wasn't cached to begin with. GrSurfaceDesc rtDesc = inputTexture->desc(); rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag; - rtDesc.fWidth = GrNextPow2(rtDesc.fWidth); - rtDesc.fHeight = GrNextPow2(rtDesc.fHeight); + rtDesc.fWidth = stretch.fWidth; + rtDesc.fHeight = stretch.fHeight; rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig); // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise, @@ -241,8 +266,9 @@ GrTexture* stretch_texture_to_next_pot(GrTexture* inputTexture, 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, - kBilerp_Stretch == stretch ? GrTextureParams::kBilerp_FilterMode : - GrTextureParams::kNone_FilterMode); + Stretch::kBilerp_Type == stretch.fType ? + GrTextureParams::kBilerp_FilterMode : + GrTextureParams::kNone_FilterMode); paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params); SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight)); @@ -479,10 +505,10 @@ static GrTexture* create_unstretched_bitmap_texture(GrContext* ctx, static GrTexture* create_bitmap_texture(GrContext* ctx, const SkBitmap& bmp, - Stretch stretch, + const Stretch& stretch, const GrUniqueKey& unstretchedKey, const GrUniqueKey& stretchedKey) { - if (kNo_Stretch != stretch) { + if (Stretch::kNone_Type != stretch.fType) { SkAutoTUnref unstretched; // Check if we have the unstretched version in the cache, if not create it. if (unstretchedKey.isValid()) { @@ -494,8 +520,7 @@ static GrTexture* create_bitmap_texture(GrContext* ctx, return NULL; } } - GrTexture* stretched = stretch_texture_to_next_pot(unstretched, stretch, bmp.pixelRef(), - stretchedKey); + GrTexture* stretched = stretch_texture(unstretched, stretch, bmp.pixelRef(), stretchedKey); return stretched; } @@ -506,12 +531,13 @@ static GrTexture* create_bitmap_texture(GrContext* ctx, bool GrIsBitmapInCache(const GrContext* ctx, const SkBitmap& bitmap, const GrTextureParams* params) { - Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), params); + Stretch stretch; + get_stretch(ctx, bitmap.width(), bitmap.height(), params, &stretch); // Handle the case where the bitmap is explicitly texture backed. GrTexture* texture = bitmap.getTexture(); if (texture) { - if (kNo_Stretch == stretch) { + if (Stretch::kNone_Type == stretch.fType) { return true; } // No keys for volatile bitmaps. @@ -535,18 +561,19 @@ bool GrIsBitmapInCache(const GrContext* ctx, GrUniqueKey key, stretchedKey; make_bitmap_keys(bitmap, stretch, &key, &stretchedKey); return ctx->textureProvider()->existsTextureWithUniqueKey( - (kNo_Stretch == stretch) ? key : stretchedKey); + (Stretch::kNone_Type == stretch.fType) ? key : stretchedKey); } GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, const SkBitmap& bitmap, const GrTextureParams* params) { - Stretch stretch = get_stretch_type(ctx, bitmap.width(), bitmap.height(), params); + Stretch stretch; + get_stretch(ctx, bitmap.width(), bitmap.height(), params, &stretch); GrTexture* result = bitmap.getTexture(); if (result) { - if (kNo_Stretch == stretch) { + if (Stretch::kNone_Type == stretch.fType) { return SkRef(result); } GrUniqueKey stretchedKey; @@ -562,7 +589,7 @@ GrTexture* GrRefCachedBitmapTexture(GrContext* ctx, } } } - return stretch_texture_to_next_pot(result, stretch, bitmap.pixelRef(), stretchedKey); + return stretch_texture(result, stretch, bitmap.pixelRef(), stretchedKey); } GrUniqueKey key, resizedKey; diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 13ce5070a6..99bc6da1fa 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -294,6 +294,11 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { // attachment, hence this min: fMaxRenderTargetSize = SkTMin(fMaxTextureSize, fMaxRenderTargetSize); + // This GPU seems to have problems when tiling small textures + if (kPowerVR54x_GrGLRenderer == ctxInfo.renderer()) { + fMinTextureSize = 16; + } + fGpuTracingSupport = ctxInfo.hasExtension("GL_EXT_debug_marker"); // Disable scratch texture reuse on Mali and Adreno devices