Merge "Fix erroneous self deletion on SkImage creation failure"

This commit is contained in:
Nolan Scobie
2022-11-14 15:43:02 +00:00
committed by Gerrit Code Review
5 changed files with 98 additions and 4 deletions

View File

@@ -674,6 +674,7 @@ cc_test {
srcs: [
"tests/unit/main.cpp",
"tests/unit/ABitmapTests.cpp",
"tests/unit/AutoBackendTextureReleaseTests.cpp",
"tests/unit/CacheManagerTests.cpp",
"tests/unit/CanvasContextTests.cpp",
"tests/unit/CanvasOpTests.cpp",

View File

@@ -32,9 +32,17 @@ AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
GrBackendFormat backendFormat =
GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
LOG_ALWAYS_FATAL_IF(!backendFormat.isValid(),
__FILE__ " Invalid GrBackendFormat. GrBackendApi==%" PRIu32
", AHardwareBuffer_Format==%" PRIu32 ".",
static_cast<int>(context->backend()), desc.format);
mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
context, buffer, desc.width, desc.height, &mDeleteProc, &mUpdateProc, &mImageCtx,
createProtectedImage, backendFormat, false);
LOG_ALWAYS_FATAL_IF(!mBackendTexture.isValid(),
__FILE__ " Invalid GrBackendTexture. Width==%" PRIu32 ", height==%" PRIu32
", protected==%d",
desc.width, desc.height, createProtectedImage);
}
void AutoBackendTextureRelease::unref(bool releaseImage) {
@@ -74,13 +82,13 @@ void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
// The following ref will be counteracted by Skia calling releaseProc, either during
// MakeFromTexture if there is a failure, or later when SkImage is discarded. It must
// be called before MakeFromTexture, otherwise Skia may remove HWUI's ref on failure.
ref();
mImage = SkImage::MakeFromTexture(
context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType,
uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this);
if (mImage.get()) {
// The following ref will be counteracted by releaseProc, when SkImage is discarded.
ref();
}
}
void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {

View File

@@ -25,6 +25,9 @@
namespace android {
namespace uirenderer {
// Friend TestUtils serves as a proxy for any test cases that require access to private members.
class TestUtils;
/**
* AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object
* that keeps GPU resources alive until the last SkImage object using them is destroyed.
@@ -66,6 +69,9 @@ private:
// mImage is the SkImage created from mBackendTexture.
sk_sp<SkImage> mImage;
// Friend TestUtils serves as a proxy for any test cases that require access to private members.
friend class TestUtils;
};
} /* namespace uirenderer */

View File

@@ -16,6 +16,7 @@
#pragma once
#include <AutoBackendTextureRelease.h>
#include <DisplayList.h>
#include <Matrix.h>
#include <Properties.h>
@@ -283,6 +284,11 @@ public:
static SkRect getClipBounds(const SkCanvas* canvas);
static SkRect getLocalClipBounds(const SkCanvas* canvas);
static int getUsageCount(const AutoBackendTextureRelease* textureRelease) {
EXPECT_NE(nullptr, textureRelease);
return textureRelease->mUsageCount;
}
struct CallCounts {
int sync = 0;
int contextDestroyed = 0;

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2022 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 <gtest/gtest.h>
#include "AutoBackendTextureRelease.h"
#include "tests/common/TestUtils.h"
using namespace android;
using namespace android::uirenderer;
AHardwareBuffer* allocHardwareBuffer() {
AHardwareBuffer* buffer;
AHardwareBuffer_Desc desc = {
.width = 16,
.height = 16,
.layers = 1,
.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
.usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY,
};
constexpr int kSucceeded = 0;
int status = AHardwareBuffer_allocate(&desc, &buffer);
EXPECT_EQ(kSucceeded, status);
return buffer;
}
// Expands to AutoBackendTextureRelease_makeImage_invalid_RenderThreadTest,
// set as friend in AutoBackendTextureRelease.h
RENDERTHREAD_TEST(AutoBackendTextureRelease, makeImage_invalid) {
AHardwareBuffer* buffer = allocHardwareBuffer();
AutoBackendTextureRelease* textureRelease =
new AutoBackendTextureRelease(renderThread.getGrContext(), buffer);
EXPECT_EQ(1, TestUtils::getUsageCount(textureRelease));
// SkImage::MakeFromTexture should fail if given null GrDirectContext.
textureRelease->makeImage(buffer, HAL_DATASPACE_UNKNOWN, /*context = */ nullptr);
EXPECT_EQ(1, TestUtils::getUsageCount(textureRelease));
textureRelease->unref(true);
AHardwareBuffer_release(buffer);
}
// Expands to AutoBackendTextureRelease_makeImage_valid_RenderThreadTest,
// set as friend in AutoBackendTextureRelease.h
RENDERTHREAD_TEST(AutoBackendTextureRelease, makeImage_valid) {
AHardwareBuffer* buffer = allocHardwareBuffer();
AutoBackendTextureRelease* textureRelease =
new AutoBackendTextureRelease(renderThread.getGrContext(), buffer);
EXPECT_EQ(1, TestUtils::getUsageCount(textureRelease));
textureRelease->makeImage(buffer, HAL_DATASPACE_UNKNOWN, renderThread.getGrContext());
EXPECT_EQ(2, TestUtils::getUsageCount(textureRelease));
textureRelease->unref(true);
AHardwareBuffer_release(buffer);
}