Support hardware bitmaps in bitmap shaders

Test: hwuimacro bitmapShaderEglImage --onscreen.
bug:30999911
Change-Id: I9d16a1c217a4474841794cf27ce49e3f7823678e
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index e410d71..9c4cb09 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -133,7 +133,7 @@
 
     // Shaders
     bool hasBitmap;
-    bool isBitmapNpot;
+    bool useShaderBasedWrap;
 
     bool hasVertexAlpha;
     bool useShadowAlphaInterp;
@@ -180,7 +180,7 @@
         modulate = false;
 
         hasBitmap = false;
-        isBitmapNpot = false;
+        useShaderBasedWrap = false;
 
         hasGradient = false;
         gradientType = kGradientLinear;
@@ -234,7 +234,7 @@
         if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
         if (hasBitmap) {
             key |= PROGRAM_KEY_BITMAP;
-            if (isBitmapNpot) {
+            if (useShaderBasedWrap) {
                 key |= PROGRAM_KEY_BITMAP_NPOT;
                 key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
                 key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 1afc978..0c2309f 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -707,7 +707,7 @@
     if (blendFramebuffer) {
         generateBlend(shader, "blendFramebuffer", description.framebufferMode);
     }
-    if (description.isBitmapNpot) {
+    if (description.useShaderBasedWrap) {
         generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
     }
     if (description.hasGradient) {
@@ -736,7 +736,7 @@
             shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
         }
         if (description.hasBitmap) {
-            if (!description.isBitmapNpot) {
+            if (!description.useShaderBasedWrap) {
                 shader.append(gFS_Main_FetchBitmap);
             } else {
                 shader.append(gFS_Main_FetchBitmapNpot);
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 971c2a3..34e6a06 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -58,7 +58,7 @@
 }
 
 static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
-    caches->textureState().bindTexture(texture->id());
+    caches->textureState().bindTexture(texture->target(), texture->id());
     texture->setWrapST(wrapS, wrapT);
 }
 
@@ -218,10 +218,13 @@
     const float height = outData->bitmapTexture->height();
 
     description->hasBitmap = true;
-    if (!caches.extensions().hasNPot()
+    // gralloc doesn't support non-clamp modes
+    if (hwuiBitmap->isHardware() || (!caches.extensions().hasNPot()
             && (!isPowerOfTwo(width) || !isPowerOfTwo(height))
-            && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode)) {
-        description->isBitmapNpot = true;
+            && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) {
+        // need non-clamp mode, but it's not supported for this draw,
+        // so enable custom shader logic to mimic
+        description->useShaderBasedWrap = true;
         description->bitmapWrapS = gTileModes[xy[0]];
         description->bitmapWrapT = gTileModes[xy[1]];
 
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 2077b0e..c028f115 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -413,7 +413,6 @@
     case PixelStorageType::Heap:
         return mPixelStorage.heap.address;
     case PixelStorageType::Hardware:
-        LOG_ALWAYS_FATAL_IF("Can't get address for hardware bitmap");
         return nullptr;
     }
 }
@@ -470,6 +469,12 @@
     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
 }
 
+void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
+    outBitmap->setInfo(info(), rowBytes());
+    outBitmap->setPixelRef(this);
+    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
+}
+
 void Bitmap::getBounds(SkRect* bounds) const {
     SkASSERT(bounds);
     bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 3940381..663238c 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -85,6 +85,10 @@
 
     void getSkBitmap(SkBitmap* outBitmap);
 
+    // Ugly hack: in case of hardware bitmaps, it sets nullptr as pixels pointer
+    // so it would crash if anyone tries to render this bitmap.
+    void getSkBitmapForShaders(SkBitmap* outBitmap);
+
     int getAshmemFd() const;
     size_t getAllocationByteCount() const;
 
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
new file mode 100644
index 0000000..9b0b950
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestSceneBase.h"
+#include "utils/Color.h"
+#include "tests/common/BitmapAllocationTestUtils.h"
+
+class BitmapShaders;
+
+static bool _BitmapShaders(
+        BitmapAllocationTestUtils::registerBitmapAllocationScene<BitmapShaders>(
+                "bitmapShader", "Draws bitmap shaders with repeat and mirror modes."));
+
+class BitmapShaders : public TestScene {
+public:
+    BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
+        : TestScene()
+        , mAllocator(allocator) { }
+
+    sp<RenderNode> card;
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
+        sk_sp<Bitmap> hwuiBitmap = mAllocator(200, 200, kRGBA_8888_SkColorType,
+                            [](SkBitmap& skBitmap) {
+            skBitmap.eraseColor(Color::White);
+            SkCanvas skCanvas(skBitmap);
+            SkPaint skPaint;
+            skPaint.setColor(Color::Red_500);
+            skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
+            skPaint.setColor(Color::Blue_500);
+            skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
+        });
+
+        SkBitmap bitmap;
+        SkPaint paint;
+        hwuiBitmap->getSkBitmapForShaders(&bitmap);
+
+        sk_sp<SkShader> repeatShader = SkMakeBitmapShader(bitmap,
+                SkShader::TileMode::kRepeat_TileMode,
+                SkShader::TileMode::kRepeat_TileMode,
+                nullptr,
+                kNever_SkCopyPixelsMode,
+                nullptr);
+        paint.setShader(std::move(repeatShader));
+        canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint);
+
+        sk_sp<SkShader> mirrorShader = SkMakeBitmapShader(bitmap,
+                SkShader::TileMode::kMirror_TileMode,
+                SkShader::TileMode::kMirror_TileMode,
+                nullptr,
+                kNever_SkCopyPixelsMode,
+                nullptr);
+        paint.setShader(std::move(mirrorShader));
+        canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint);
+    }
+
+    void doFrame(int frameNr) override { }
+
+    BitmapAllocationTestUtils::BitmapAllocator mAllocator;
+};
\ No newline at end of file