PixelCopy fixes

Bug: 27708453

Fixes some issues with camera sources. Previously
it was using GL_TEXTURE_2D target which doesn't
work properly if the source is YUV. It is critical
to ensure GL_TEXTURE_EXTERNAL_OES is used throughout
so the right sampler is used.

Change-Id: I0dcd8941ba08331f24809467b0e828663a38e93b
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 7d4f410..fdbe76a 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -471,6 +471,21 @@
     return *this;
 }
 
+GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
+
+    mOutGlop->fill.texture = { &texture,
+            GL_TEXTURE_EXTERNAL_OES, GL_LINEAR, GL_CLAMP_TO_EDGE,
+            nullptr };
+
+    setFill(SK_ColorWHITE, 1.0f, SkXfermode::kSrc_Mode, Blend::ModeOrderSwap::NoSwap,
+            nullptr, nullptr);
+
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    return *this;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Transform
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 6e5797d..b6c186d 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -70,6 +70,10 @@
     GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
             float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage);
     GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
+    // TODO: Texture should probably know and own its target.
+    // setFillLayer() forces it to GL_TEXTURE which isn't always correct.
+    // Similarly setFillLayer normally forces its own wrap & filter mode
+    GlopBuilder& setFillExternalTexture(Texture& texture);
 
     GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) {
         return setTransform(*snapshot.transform, transformFlags);
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index d7df77c..4a32589 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -101,24 +101,51 @@
     // Setup the source
     sp<GraphicBuffer> sourceBuffer;
     sp<Fence> sourceFence;
-    // FIXME: Waiting on an API from libgui for this
-    // surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence);
+    status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence);
+    if (err != NO_ERROR) {
+        ALOGW("Failed to get last queued buffer, error = %d", err);
+        return false;
+    }
     if (!sourceBuffer.get()) {
         ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
         return false;
     }
-    int err = sourceFence->wait(500 /* ms */);
+    err = sourceFence->wait(500 /* ms */);
     if (err != NO_ERROR) {
         ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
         return false;
     }
-    Image sourceImage(sourceBuffer);
-    if (!sourceImage.getTexture()) {
-        ALOGW("Failed to make an EGLImage from the GraphicBuffer");
+
+    // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
+    // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
+    // to be able to properly sample from the buffer.
+
+    // Create the EGLImage object that maps the GraphicBuffer
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer();
+    EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+
+    EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
+            EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+
+    if (sourceImage == EGL_NO_IMAGE_KHR) {
+        ALOGW("Error creating image (%#x)", eglGetError());
         return false;
     }
+    GLuint sourceTexId;
+    // Create a 2D texture to sample from the EGLImage
+    glGenTextures(1, &sourceTexId);
+    Caches::getInstance().textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, sourceImage);
+
+    GLenum status = GL_NO_ERROR;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        ALOGW("Error creating image (%#x)", status);
+        return false;
+    }
+
     Texture sourceTexture(caches);
-    sourceTexture.wrap(sourceImage.getTexture(),
+    sourceTexture.wrap(sourceTexId,
             sourceBuffer->getWidth(), sourceBuffer->getHeight(), 0 /* total lie */);
 
     {
@@ -133,8 +160,7 @@
         GlopBuilder(renderState, caches, &glop)
                 .setRoundRectClipState(nullptr)
                 .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
-                .setFillLayer(sourceTexture, nullptr, 1.0f, SkXfermode::kSrc_Mode,
-                        Blend::ModeOrderSwap::NoSwap)
+                .setFillExternalTexture(sourceTexture)
                 .setTransform(Matrix4::identity(), TransformFlags::None)
                 .setModelViewMapUnitToRect(destRect)
                 .build();