Merge the 2021-09-05 SPL branch from AOSP-Partner
* security-aosp-pi-release:
Only treat PNG_COLOR_TYPE_RGB as 565
Change-Id: I205e28262c888b81014fb6f09097dbbf3b7e25f2
diff --git a/include/android/SkAndroidFrameworkUtils.h b/include/android/SkAndroidFrameworkUtils.h
index 46d2516..3554b88 100644
--- a/include/android/SkAndroidFrameworkUtils.h
+++ b/include/android/SkAndroidFrameworkUtils.h
@@ -9,10 +9,12 @@
#define SkAndroidFrameworkUtils_DEFINED
#include "SkTypes.h"
+#include "SkRefCnt.h"
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
class SkCanvas;
+class SkSurface;
/**
* SkAndroidFrameworkUtils expose private APIs used only by Android framework.
@@ -32,6 +34,8 @@
static bool clipWithStencil(SkCanvas* canvas);
#endif //SK_SUPPORT_GPU
+ static sk_sp<SkSurface> getSurfaceFromCanvas(SkCanvas* canvas);
+
static void SafetyNetLog(const char*);
};
diff --git a/include/config/SkUserConfigManual.h b/include/config/SkUserConfigManual.h
index 69b2d17..58e4eb3 100644
--- a/include/config/SkUserConfigManual.h
+++ b/include/config/SkUserConfigManual.h
@@ -7,7 +7,6 @@
#ifndef SkUserConfigManual_DEFINED
#define SkUserConfigManual_DEFINED
- #define GR_GL_CUSTOM_SETUP_HEADER "gl/GrGLConfig_chrome.h"
#define GR_TEST_UTILS 1
#define SK_BUILD_FOR_ANDROID_FRAMEWORK
#define SK_DEFAULT_FONT_CACHE_LIMIT (768 * 1024)
@@ -17,6 +16,8 @@
// Disable these Ganesh features
#define SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
#define SK_DISABLE_RENDER_TARGET_SORTING
+ // Check error is expensive. HWUI historically also doesn't check its allocations
+ #define GR_GL_CHECK_ALLOC_WITH_GET_ERROR 0
// Legacy flags
#define SK_IGNORE_GPU_DITHER
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index 5a3887e..944f9dc 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -543,6 +543,17 @@
*/
sk_sp<SkImage> makeImageSnapshot();
+ /**
+ * Like the no-parameter version, this returns an image of the current surface contents.
+ * This variant takes a rectangle specifying the subset of the surface that is of interest.
+ * These bounds will be sanitized before being used.
+ * - If bounds extends beyond the surface, it will be trimmed to just the intersection of
+ * it and the surface.
+ * - If bounds does not intersect the surface, then this returns nullptr.
+ * - If bounds == the surface, then this is the same as calling the no-parameter variant.
+ */
+ sk_sp<SkImage> makeImageSnapshot(const SkIRect& bounds);
+
/** Draws SkSurface contents to canvas, with its top-left corner at (x, y).
If SkPaint paint is not nullptr, apply SkColorFilter, color alpha, SkImageFilter,
diff --git a/src/android/SkAndroidFrameworkUtils.cpp b/src/android/SkAndroidFrameworkUtils.cpp
index f0a7b8a..3fa43d2 100644
--- a/src/android/SkAndroidFrameworkUtils.cpp
+++ b/src/android/SkAndroidFrameworkUtils.cpp
@@ -8,6 +8,7 @@
#include "SkAndroidFrameworkUtils.h"
#include "SkCanvas.h"
#include "SkDevice.h"
+#include "SkSurface_Base.h"
#if SK_SUPPORT_GPU
#include "GrStyle.h"
@@ -54,9 +55,13 @@
}
#endif //SK_SUPPORT_GPU
+sk_sp<SkSurface> SkAndroidFrameworkUtils::getSurfaceFromCanvas(SkCanvas* canvas) {
+ sk_sp<SkSurface> surface(SkSafeRef(canvas->getSurfaceBase()));
+ return surface;
+}
+
void SkAndroidFrameworkUtils::SafetyNetLog(const char* bugNumber) {
android_errorWriteLog(0x534e4554, bugNumber);
}
#endif // SK_BUILD_FOR_ANDROID_FRAMEWORK
-
diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp
index 171ae52..350be5c 100644
--- a/src/codec/SkWbmpCodec.cpp
+++ b/src/codec/SkWbmpCodec.cpp
@@ -184,6 +184,13 @@
return kUnimplemented;
}
+ if (!valid_color_type(dstInfo) ||
+ !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType()))
+ {
+ return kInvalidConversion;
+ }
+
+ // Initialize the swizzler
fSwizzler = SkSwizzler::Make(this->getEncodedInfo(), nullptr, dstInfo, options);
SkASSERT(fSwizzler);
diff --git a/src/gpu/GrAHardwareBufferImageGenerator.cpp b/src/gpu/GrAHardwareBufferImageGenerator.cpp
index 085d27a..ec06dcb 100644
--- a/src/gpu/GrAHardwareBufferImageGenerator.cpp
+++ b/src/gpu/GrAHardwareBufferImageGenerator.cpp
@@ -29,6 +29,14 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <cutils/properties.h>
+
+// Direct access to private framework and HAL data to workaround Adreno 330 driver bugs.
+// DO NOT actually call anything from these headers; they are included only to access private
+// structs.
+#include "../../../../frameworks/native/libs/nativebase/include/nativebase/nativebase.h"
+#include "../../../../hardware/qcom/display/libgralloc/gralloc_priv.h"
+
class BufferCleanupHelper {
public:
BufferCleanupHelper(EGLImageKHR image, EGLDisplay display)
@@ -146,21 +154,118 @@
}
#endif
-sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::makeProxy(GrContext* context) {
- if (context->abandoned() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
- // Check if GrContext is not abandoned and the backend is GL.
+namespace {
+
+sk_sp<GrTexture> createGLTextureFromPrivateHandle(GrContext* context,
+ const SkImageInfo& info, const AHardwareBuffer* hardware_buffer) {
+
+ if (!hardware_buffer) {
+ SkDebugf("createGLTextureFromPrivateHandle: Cannot work without AHardwareBuffer");
return nullptr;
}
- auto proxyProvider = context->contextPriv().proxyProvider();
-
- // return a cached GrTexture if invoked with the same context
- if (fOriginalTexture && fOwningContextID == context->uniqueID()) {
- return proxyProvider->createWrapped(sk_ref_sp(fOriginalTexture),
- kTopLeft_GrSurfaceOrigin);
+ GrPixelConfig pixelConfig = kUnknown_GrPixelConfig;
+ size_t bytesPerPixel = 0;
+ GrGLenum format = GL_INVALID_ENUM;
+ GrGLenum type = GL_INVALID_ENUM;
+ switch (info.colorType()) {
+ case kRGBA_8888_SkColorType:
+ pixelConfig = kRGBA_8888_GrPixelConfig;
+ bytesPerPixel = 4;
+ format = GL_RGBA;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ case kRGB_565_SkColorType:
+ pixelConfig = kRGB_565_GrPixelConfig;
+ bytesPerPixel = 2;
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ default:
+ SkDebugf("createGLTextureFromPrivateHandle: Unsupported color type %i", int(info.colorType()));
+ return nullptr;
}
- while (GL_NO_ERROR != glGetError()) {} //clear GL errors
+ EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardware_buffer);
+ const native_handle_t* native_handle = reinterpret_cast<const ANativeWindowBuffer*>(clientBuffer)->handle;
+ const bool handleIsAsExpected = private_handle_t::validate(native_handle) == 0;
+ if (!handleIsAsExpected) {
+ SkDebugf("createGLTextureFromPrivateHandle: GraphicBuffer doesn't seem to map to gralloc private handle.");
+ return nullptr;
+ }
+ const private_handle_t* hnd = static_cast<const private_handle_t*>(native_handle);
+
+ const int imageWidth = info.width();
+ const int imageHeight = info.height();
+ const int bufferWidth = hnd->width; // May be aligned and be larger than the actual image.
+ const int bufferHeight = hnd->height;
+ if (imageWidth > bufferWidth || imageHeight > bufferHeight) {
+ SkDebugf("createGLTextureFromPrivateHandle: image is larger than the buffer. This is not supposed to happen.");
+ return nullptr;
+ }
+ const size_t bufferRowBytes = bufferWidth * bytesPerPixel;
+ // We access as many rows as the image has, aligned to the width of the buffer.
+ const size_t minBufferSize = bufferRowBytes * imageHeight;
+ if (hnd->size < 0 || static_cast<size_t>(hnd->size) < minBufferSize) {
+ SkDebugf("createGLTextureFromPrivateHandle: buffer is smaller than expected or invalid.");
+ return nullptr;
+ }
+
+ const char* bufferData = reinterpret_cast<const char*>(hnd->base);
+
+ GrGLuint texID;
+ glGenTextures(1, &texID);
+ glBindTexture(GL_TEXTURE_2D, texID);
+
+ if (imageWidth == bufferWidth) {
+ // Take the quick path if possible
+ glTexImage2D(GL_TEXTURE_2D, 0, format, imageWidth, imageHeight, 0, format, type, bufferData);
+ } else {
+ // The buffer has some extra space for alignment. Copy row by row.
+ // First allocate the texture storage without filling it.
+ glTexImage2D(GL_TEXTURE_2D, 0, format, imageWidth, imageHeight, 0, format, type, 0);
+ for (int y = 0; y < imageHeight; ++y) {
+ const void* bufferRowAddr = bufferData + static_cast<size_t>(y) * bufferRowBytes;
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, imageWidth, 1, format, type, bufferRowAddr);
+ }
+ }
+ int gl_error;
+ bool has_gl_error = false;
+ while (GL_NO_ERROR != (gl_error = glGetError())) {
+ SkDebugf("createGLTextureFromPrivateHandle: glGetError reports %i", gl_error);
+ has_gl_error = true;
+ }
+ if (has_gl_error) {
+ SkDebugf("createGLTextureFromPrivateHandle: discarding results, because we had GL errors.");
+ glDeleteTextures(1, &texID);
+ return nullptr;
+ }
+
+ GrGLTextureInfo textureInfo;
+ textureInfo.fTarget = GL_TEXTURE_2D;
+ textureInfo.fID = texID;
+
+ GrBackendTexture backendTex(imageWidth, imageHeight, pixelConfig, textureInfo);
+ if (backendTex.width() <= 0 || backendTex.height() <= 0) {
+ SkDebugf("createGLTextureFromPrivateHandle: Failed at GrBackendTexture initialization.");
+ glDeleteTextures(1, &texID);
+ return nullptr;
+ }
+ sk_sp<GrTexture> tex = context->contextPriv().resourceProvider()->wrapBackendTexture(
+ backendTex, kAdopt_GrWrapOwnership);
+ if (!tex) {
+ SkDebugf("createGLTextureFromPrivateHandle: Failed at wrapBackendTexture()");
+ glDeleteTextures(1, &texID);
+ return nullptr;
+ }
+ // Compared to the regular code, we don't need a release helper: We gave up ownership of the GL
+ // texture and don't create any other resources (like the EGLImage).
+
+ return tex;
+}
+
+sk_sp<GrTexture> createNativeBufferTexture(GrContext* context, const SkImageInfo& info,
+ const AHardwareBuffer* fGraphicBuffer, void(*deleteImageTexture)(void*)) {
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(fGraphicBuffer);
EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
@@ -200,7 +305,7 @@
textureInfo.fID = texID;
GrPixelConfig pixelConfig;
- switch (getInfo().colorType()) {
+ switch (info.colorType()) {
case kRGBA_8888_SkColorType:
pixelConfig = kRGBA_8888_GrPixelConfig;
break;
@@ -216,7 +321,7 @@
return nullptr;
}
- GrBackendTexture backendTex(getInfo().width(), getInfo().height(), pixelConfig, textureInfo);
+ GrBackendTexture backendTex(info.width(), info.height(), pixelConfig, textureInfo);
if (backendTex.width() <= 0 || backendTex.height() <= 0) {
glDeleteTextures(1, &texID);
eglDestroyImageKHR(display, image);
@@ -234,6 +339,50 @@
tex->setRelease(std::move(releaseHelper));
+ return tex;
+}
+
+} // anonymous namespace
+
+sk_sp<GrTextureProxy> GrAHardwareBufferImageGenerator::makeProxy(GrContext* context) {
+ if (context->abandoned() || kOpenGL_GrBackend != context->contextPriv().getBackend()) {
+ // Check if GrContext is not abandoned and the backend is GL.
+ return nullptr;
+ }
+
+ auto proxyProvider = context->contextPriv().proxyProvider();
+
+ // return a cached GrTexture if invoked with the same context
+ if (fOriginalTexture && fOwningContextID == context->uniqueID()) {
+ return proxyProvider->createWrapped(sk_ref_sp(fOriginalTexture),
+ kTopLeft_GrSurfaceOrigin);
+ }
+
+ while (GL_NO_ERROR != glGetError()) {} //clear GL errors
+
+ // On Adreno 330 drivers sampling from EGLImage bound to GL_TEXTURE_EXTERNAL_OES texture targets
+ // leads to artifacts. Copy image data into a regular GL texture instead.
+ static const bool gl_tex_workaround_enabled =
+ [] () -> bool {
+ const int value = property_get_bool("skia.force_gl_texture", 0);
+ SkDebugf("GrAHardwareBufferImageGenerator::makeProxy skia.force_gl_texture=%i", value);
+ return bool(value);
+ }();
+
+ sk_sp<GrTexture> tex;
+ if (gl_tex_workaround_enabled) {
+ tex = createGLTextureFromPrivateHandle(context, getInfo(), fGraphicBuffer);
+ }
+
+ if (!tex) {
+ // The workaround is disabled or failed. Fall back to regular, native buffer access.
+ tex = createNativeBufferTexture(context, getInfo(), fGraphicBuffer, &deleteImageTexture);
+ }
+
+ if (!tex) {
+ return nullptr;
+ }
+
// We fail this assert, if the context has changed. This will be fully handled after
// skbug.com/6812 is ready.
SkASSERT(!fOriginalTexture);
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index 26ee40e..bf8e6d9 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -157,6 +157,20 @@
return asSB(this)->refCachedImage();
}
+sk_sp<SkImage> SkSurface::makeImageSnapshot(const SkIRect& srcBounds) {
+ const SkIRect surfBounds = { 0, 0, fWidth, fHeight };
+ SkIRect bounds = srcBounds;
+ if (!bounds.intersect(surfBounds)) {
+ return nullptr;
+ }
+ SkASSERT(!bounds.isEmpty());
+ if (bounds == surfBounds) {
+ return this->makeImageSnapshot();
+ } else {
+ return asSB(this)->onNewImageSnapshot(&bounds);
+ }
+}
+
sk_sp<SkSurface> SkSurface::makeSurface(const SkImageInfo& info) {
return asSB(this)->onNewSurface(info);
}
@@ -255,7 +269,7 @@
sk_sp<SkSurface> onNewSurface(const SkImageInfo& info) override {
return MakeNull(info.width(), info.height());
}
- sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; }
+ sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subsetOrNull) override { return nullptr; }
void onWritePixels(const SkPixmap&, int x, int y) override {}
void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {}
void onCopyOnWrite(ContentChangeMode) override {}
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 56a09cf..1ad2f83 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -42,8 +42,11 @@
* This needs to be able to outlive the surface itself (if need be), and
* must faithfully represent the current contents, even if the surface
* is changed after this called (e.g. it is drawn to via its canvas).
+ *
+ * If a subset is specified, the the impl must make a copy, rather than try to wait
+ * on copy-on-write.
*/
- virtual sk_sp<SkImage> onNewImageSnapshot() = 0;
+ virtual sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset = nullptr) = 0;
virtual void onWritePixels(const SkPixmap&, int x, int y) = 0;
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 78dcd59..5276d1f 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -88,7 +88,7 @@
origin, &this->props());
}
-sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() {
+sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(const SkIRect* subset) {
GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
if (!rtc) {
return nullptr;
@@ -103,10 +103,14 @@
SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
- // If the original render target is a buffer originally created by the client, then we don't
- // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
- // copy-on-write.
- if (!srcProxy || rtc->priv().refsWrappedObjects()) {
+
+ if (subset) {
+ srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), *subset,
+ budgeted);
+ } else if (!srcProxy || rtc->priv().refsWrappedObjects()) {
+ // If the original render target is a buffer originally created by the client, then we don't
+ // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
+ // copy-on-write.
SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), budgeted);
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index 9699b01..5254007 100644
--- a/src/image/SkSurface_Gpu.h
+++ b/src/image/SkSurface_Gpu.h
@@ -26,7 +26,7 @@
bool onGetRenderTargetHandle(GrBackendObject*, BackendHandleAccess) override;
SkCanvas* onNewCanvas() override;
sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
- sk_sp<SkImage> onNewImageSnapshot() override;
+ sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset) override;
void onWritePixels(const SkPixmap&, int x, int y) override;
void onCopyOnWrite(ContentChangeMode) override;
void onDiscard() override;
diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp
index 47d5542..bfb5f39 100644
--- a/src/image/SkSurface_Raster.cpp
+++ b/src/image/SkSurface_Raster.cpp
@@ -21,7 +21,7 @@
SkCanvas* onNewCanvas() override;
sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
- sk_sp<SkImage> onNewImageSnapshot() override;
+ sk_sp<SkImage> onNewImageSnapshot(const SkIRect* subset) override;
void onWritePixels(const SkPixmap&, int x, int y) override;
void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override;
void onCopyOnWrite(ContentChangeMode) override;
@@ -131,7 +131,16 @@
canvas->drawBitmap(fBitmap, x, y, paint);
}
-sk_sp<SkImage> SkSurface_Raster::onNewImageSnapshot() {
+sk_sp<SkImage> SkSurface_Raster::onNewImageSnapshot(const SkIRect* subset) {
+ if (subset) {
+ SkASSERT(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()).contains(*subset));
+ SkBitmap dst;
+ dst.allocPixels(fBitmap.info().makeWH(subset->width(), subset->height()));
+ SkAssertResult(fBitmap.readPixels(dst.pixmap(), subset->left(), subset->top()));
+ dst.setImmutable(); // key, so MakeFromBitmap doesn't make a copy of the buffer
+ return SkImage::MakeFromBitmap(dst);
+ }
+
SkCopyPixelsMode cpm = kIfMutable_SkCopyPixelsMode;
if (fWeOwnThePixels) {
// SkImage_raster requires these pixels are immutable for its full lifetime.