Stretch small textures up to 16 pixels on PowerVR 54x
authorbsalomon <bsalomon@google.com>
Mon, 1 Jun 2015 14:13:42 +0000 (07:13 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 1 Jun 2015 14:13:42 +0000 (07:13 -0700)
Review URL: https://codereview.chromium.org/1161183002

include/gpu/GrCaps.h
include/gpu/GrContextOptions.h
src/gpu/GrCaps.cpp
src/gpu/SkGr.cpp
src/gpu/gl/GrGLCaps.cpp

index 25f3caa..38cf901 100644 (file)
@@ -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.
index d8d59fa..231aa30 100644 (file)
@@ -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
index 1f277b7..aaa585e 100644 (file)
@@ -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);
 
index 70c81f9..a87caf7 100644 (file)
@@ -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<GrTexture> 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;
index 13ce507..99bc6da 100644 (file)
@@ -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