Support GL_RGB textures and render targets.

Bug= skia:7533

Change-Id: Iba30e90dbf2574368b773bb5cf2ebd5219559717
Reviewed-on: https://skia-review.googlesource.com/108188
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp
index f00d092..1f57581 100644
--- a/tests/WritePixelsTest.cpp
+++ b/tests/WritePixelsTest.cpp
@@ -7,6 +7,7 @@
 
 #include "SkCanvas.h"
 #include "SkColorData.h"
+#include "SkImageInfoPriv.h"
 #include "SkMathPriv.h"
 #include "SkSurface.h"
 #include "Test.h"
@@ -67,7 +68,8 @@
             result[2] = r;
             result[3] = a;
             break;
-        case kRGBA_8888_SkColorType:
+        case kRGBA_8888_SkColorType:  // fallthrough
+        case kRGB_888x_SkColorType:
             result[0] = r;
             result[1] = g;
             result[2] = b;
@@ -144,6 +146,7 @@
     }
     switch (ct) {
         case kRGBA_8888_SkColorType:
+        case kRGB_888x_SkColorType:  // fallthrough
             color = SkSwizzle_RGBA_to_PMColor(color);
             break;
         case kBGRA_8888_SkColorType:
@@ -176,8 +179,32 @@
            SkAbs32(aB - bB) <= 1;
 }
 
-static bool check_write(skiatest::Reporter* reporter, SkSurface* surf, const SkBitmap& bitmap,
-                       int writeX, int writeY) {
+bool write_should_succeed(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, bool isGPU) {
+    if (!SkImageInfoValidConversion(dstInfo, srcInfo)) {
+        return false;
+    }
+    if (!isGPU) {
+        return true;
+    }
+    // The GPU backend supports writing unpremul data to a premul dst but not vice versa.
+    if (srcInfo.alphaType() == kPremul_SkAlphaType &&
+        dstInfo.alphaType() == kUnpremul_SkAlphaType) {
+        return false;
+    }
+    if (!SkColorTypeIsAlwaysOpaque(srcInfo.colorType()) &&
+        SkColorTypeIsAlwaysOpaque(dstInfo.colorType())) {
+        return false;
+    }
+    // The source has no alpha value and the dst is only alpha
+    if (SkColorTypeIsAlwaysOpaque(srcInfo.colorType()) &&
+        SkColorTypeIsAlphaOnly(dstInfo.colorType())) {
+        return false;
+    }
+    return true;
+}
+
+static bool check_write(skiatest::Reporter* reporter, SkSurface* surf, SkAlphaType surfaceAlphaType,
+                        const SkBitmap& bitmap, int writeX, int writeY) {
     size_t canvasRowBytes;
     const uint32_t* canvasPixels;
 
@@ -215,6 +242,10 @@
                 bool mul = (kUnpremul_SkAlphaType == bmInfo.alphaType());
                 SkPMColor bmpPMColor = convert_to_PMColor(bmInfo.colorType(), bmInfo.alphaType(),
                                                           bmpColor8888);
+                if (bmInfo.alphaType() == kOpaque_SkAlphaType ||
+                    surfaceAlphaType == kOpaque_SkAlphaType) {
+                    bmpPMColor |= 0xFF000000;
+                }
                 if (!check_pixel(bmpPMColor, canvasPixel, mul)) {
                     ERRORF(reporter, "Expected canvas pixel at %d, %d to be 0x%08x, got 0x%08x. "
                            "Write performed premul: %d", cx, cy, bmpPMColor, canvasPixel, mul);
@@ -293,7 +324,8 @@
     REPORTER_ASSERT(reporter, genID1 != genID2);
 }
 
-static void test_write_pixels(skiatest::Reporter* reporter, SkSurface* surface) {
+static void test_write_pixels(skiatest::Reporter* reporter, SkSurface* surface,
+                              const SkImageInfo& surfaceInfo) {
     const SkIRect testRects[] = {
         // entire thing
         DEV_RECT,
@@ -347,10 +379,11 @@
         SkColorType fColorType;
         SkAlphaType fAlphaType;
     } gSrcConfigs[] = {
-        { kRGBA_8888_SkColorType, kPremul_SkAlphaType },
-        { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType },
-        { kBGRA_8888_SkColorType, kPremul_SkAlphaType },
-        { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType },
+            {kRGBA_8888_SkColorType, kPremul_SkAlphaType},
+            {kRGBA_8888_SkColorType, kUnpremul_SkAlphaType},
+            {kRGB_888x_SkColorType, kOpaque_SkAlphaType},
+            {kBGRA_8888_SkColorType, kPremul_SkAlphaType},
+            {kBGRA_8888_SkColorType, kUnpremul_SkAlphaType},
     };
     for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) {
         const SkIRect& rect = testRects[r];
@@ -359,6 +392,7 @@
                 const SkColorType ct = gSrcConfigs[c].fColorType;
                 const SkAlphaType at = gSrcConfigs[c].fAlphaType;
 
+                bool isGPU = SkToBool(surface->getCanvas()->getGrContext());
                 fill_surface(surface);
                 SkBitmap bmp;
                 REPORTER_ASSERT(reporter, setup_bitmap(&bmp, ct, at, rect.width(),
@@ -369,19 +403,21 @@
                 surface->writePixels(bmp, rect.fLeft, rect.fTop);
 
                 uint32_t idAfter = surface->generationID();
-                REPORTER_ASSERT(reporter, check_write(reporter, surface, bmp,
-                                                      rect.fLeft, rect.fTop));
+                REPORTER_ASSERT(reporter, check_write(reporter, surface, surfaceInfo.alphaType(),
+                                                      bmp, rect.fLeft, rect.fTop));
 
                 // we should change the genID iff pixels were actually written.
                 SkIRect canvasRect = SkIRect::MakeSize(canvas->getBaseLayerSize());
                 SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.fTop,
                                                       bmp.width(), bmp.height());
-                bool intersects = SkIRect::Intersects(canvasRect, writeRect) ;
-                REPORTER_ASSERT(reporter, intersects == (idBefore != idAfter));
+                bool expectSuccess = SkIRect::Intersects(canvasRect, writeRect) &&
+                                     write_should_succeed(surfaceInfo, bmp.info(), isGPU);
+                REPORTER_ASSERT(reporter, expectSuccess == (idBefore != idAfter));
             }
         }
     }
 }
+
 DEF_TEST(WritePixels, reporter) {
     const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
     for (auto& tightRowBytes : { true, false }) {
@@ -394,9 +430,10 @@
         }
         auto surface(SkSurface::MakeRasterDirectReleaseProc(info, pixels, rowBytes,
                                                             free_pixels, nullptr));
-        test_write_pixels(reporter, surface.get());
+        test_write_pixels(reporter, surface.get(), info);
     }
 }
+
 #if SK_SUPPORT_GPU
 static void test_write_pixels(skiatest::Reporter* reporter, GrContext* context, int sampleCnt) {
     const SkImageInfo ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
@@ -405,7 +442,7 @@
                                                              SkBudgeted::kNo, ii, sampleCnt,
                                                              origin, nullptr));
         if (surface) {
-            test_write_pixels(reporter, surface.get());
+            test_write_pixels(reporter, surface.get(), ii);
         }
     }
 }
@@ -425,11 +462,15 @@
     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
         GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
                 nullptr, DEV_W, DEV_H, kSkia8888_GrPixelConfig, true, GrMipMapped::kNo);
+        if (!backendTex.isValid()) {
+            continue;
+        }
         SkColorType colorType = kN32_SkColorType;
         sk_sp<SkSurface> surface(SkSurface::MakeFromBackendTextureAsRenderTarget(
                 context, backendTex, origin, sampleCnt, colorType, nullptr, nullptr));
         if (surface) {
-            test_write_pixels(reporter, surface.get());
+            auto ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
+            test_write_pixels(reporter, surface.get(), ii);
         }
         gpu->deleteTestingOnlyBackendTexture(backendTex);
     }