Create and plumb SkiaBackendTexture abstraction layer over GrBackendTexture
This means AutoBackendTexture is not aware of backend-specific texture
type and API details, and will be able to accept either a Ganesh or
Graphite variant of SkiaBackendTexture.
Also delegated SkiaBackendTexture creation to SkiaGpuContext, so that
backend-specific contexts handle creating backend-specifc textures.
Test: manual validation (GL+VK) & existing tests (refactor)
Bug: b/293371537
Change-Id: Ia65306cc825b71fe0b89c7f8545ce1c71a81d86b
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 02e7337..8aeef9f 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -20,71 +20,21 @@
#define LOG_TAG "RenderEngine"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <SkImage.h>
-#include <android/hardware_buffer.h>
-#include <include/gpu/ganesh/SkImageGanesh.h>
-#include <include/gpu/ganesh/SkSurfaceGanesh.h>
-#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
-#include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
-#include <include/gpu/vk/GrVkTypes.h>
-#include "ColorSpaces.h"
-#include "log/log_main.h"
-#include "utils/Trace.h"
+#include <include/core/SkImage.h>
+#include <include/core/SkSurface.h>
+
+#include "compat/SkiaBackendTexture.h"
+
+#include <log/log_main.h>
+#include <utils/Trace.h>
namespace android {
namespace renderengine {
namespace skia {
-AutoBackendTexture::AutoBackendTexture(SkiaGpuContext* context, AHardwareBuffer* buffer,
- bool isOutputBuffer, CleanupManager& cleanupMgr)
- : mGrContext(context->grDirectContext()),
- mCleanupMgr(cleanupMgr),
- mIsOutputBuffer(isOutputBuffer) {
- ATRACE_CALL();
-
- AHardwareBuffer_Desc desc;
- AHardwareBuffer_describe(buffer, &desc);
- bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
- GrBackendFormat backendFormat;
-
- GrBackendApi backend = mGrContext->backend();
- if (backend == GrBackendApi::kOpenGL) {
- backendFormat =
- GrAHardwareBufferUtils::GetGLBackendFormat(mGrContext.get(), desc.format, false);
- mBackendTexture =
- GrAHardwareBufferUtils::MakeGLBackendTexture(mGrContext.get(), buffer, desc.width,
- desc.height, &mDeleteProc,
- &mUpdateProc, &mImageCtx,
- createProtectedImage, backendFormat,
- isOutputBuffer);
- } else if (backend == GrBackendApi::kVulkan) {
- backendFormat = GrAHardwareBufferUtils::GetVulkanBackendFormat(mGrContext.get(), buffer,
- desc.format, false);
- mBackendTexture =
- GrAHardwareBufferUtils::MakeVulkanBackendTexture(mGrContext.get(), buffer,
- desc.width, desc.height,
- &mDeleteProc, &mUpdateProc,
- &mImageCtx, createProtectedImage,
- backendFormat, isOutputBuffer);
- } else {
- LOG_ALWAYS_FATAL("Unexpected backend %u", static_cast<unsigned>(backend));
- }
-
- mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
- if (!mBackendTexture.isValid() || !desc.width || !desc.height) {
- LOG_ALWAYS_FATAL("Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d "
- "isWriteable:%d format:%d",
- this, desc.width, desc.height, createProtectedImage, isOutputBuffer,
- desc.format);
- }
-}
-
-AutoBackendTexture::~AutoBackendTexture() {
- if (mBackendTexture.isValid()) {
- mDeleteProc(mImageCtx);
- mBackendTexture = {};
- }
-}
+AutoBackendTexture::AutoBackendTexture(std::unique_ptr<SkiaBackendTexture> backendTexture,
+ CleanupManager& cleanupMgr)
+ : mCleanupMgr(cleanupMgr), mBackendTexture(std::move(backendTexture)) {}
void AutoBackendTexture::unref(bool releaseLocalResources) {
if (releaseLocalResources) {
@@ -112,93 +62,32 @@
textureRelease->unref(false);
}
-void logFatalTexture(const char* msg, const GrBackendTexture& tex, ui::Dataspace dataspace,
- SkColorType colorType) {
- switch (tex.backend()) {
- case GrBackendApi::kOpenGL: {
- GrGLTextureInfo textureInfo;
- bool retrievedTextureInfo = GrBackendTextures::GetGLTextureInfo(tex, &textureInfo);
- LOG_ALWAYS_FATAL("%s isTextureValid:%d dataspace:%d"
- "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
- "texType: %i\n\t\tGrGLTextureInfo: success: %i fTarget: %u fFormat: %u"
- " colorType %i",
- msg, tex.isValid(), static_cast<int32_t>(dataspace), tex.width(),
- tex.height(), tex.hasMipmaps(), tex.isProtected(),
- static_cast<int>(tex.textureType()), retrievedTextureInfo,
- textureInfo.fTarget, textureInfo.fFormat, colorType);
- break;
- }
- case GrBackendApi::kVulkan: {
- GrVkImageInfo imageInfo;
- bool retrievedImageInfo = GrBackendTextures::GetVkImageInfo(tex, &imageInfo);
- LOG_ALWAYS_FATAL("%s isTextureValid:%d dataspace:%d"
- "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
- "texType: %i\n\t\tVkImageInfo: success: %i fFormat: %i "
- "fSampleCount: %u fLevelCount: %u colorType %i",
- msg, tex.isValid(), static_cast<int32_t>(dataspace), tex.width(),
- tex.height(), tex.hasMipmaps(), tex.isProtected(),
- static_cast<int>(tex.textureType()), retrievedImageInfo,
- imageInfo.fFormat, imageInfo.fSampleCount, imageInfo.fLevelCount,
- colorType);
- break;
- }
- default:
- LOG_ALWAYS_FATAL("%s Unexpected backend %u", msg, static_cast<unsigned>(tex.backend()));
- break;
- }
-}
-
sk_sp<SkImage> AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaType alphaType) {
ATRACE_CALL();
- if (mBackendTexture.isValid()) {
- mUpdateProc(mImageCtx, mGrContext.get());
- }
-
- auto colorType = mColorType;
- if (alphaType == kOpaque_SkAlphaType) {
- if (colorType == kRGBA_8888_SkColorType) {
- colorType = kRGB_888x_SkColorType;
- }
- }
-
- sk_sp<SkImage> image =
- SkImages::BorrowTextureFrom(mGrContext.get(), mBackendTexture, kTopLeft_GrSurfaceOrigin,
- colorType, alphaType, toSkColorSpace(dataspace),
- releaseImageProc, this);
- if (image.get()) {
- // The following ref will be counteracted by releaseProc, when SkImage is discarded.
- ref();
- }
+ sk_sp<SkImage> image = mBackendTexture->makeImage(alphaType, dataspace, releaseImageProc, this);
+ // The following ref will be counteracted by releaseProc, when SkImage is discarded.
+ ref();
mImage = image;
mDataspace = dataspace;
- if (!mImage) {
- logFatalTexture("Unable to generate SkImage.", mBackendTexture, dataspace, colorType);
- }
return mImage;
}
sk_sp<SkSurface> AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace) {
ATRACE_CALL();
- LOG_ALWAYS_FATAL_IF(!mIsOutputBuffer, "You can't generate a SkSurface for a read-only texture");
+ LOG_ALWAYS_FATAL_IF(!mBackendTexture->isOutputBuffer(),
+ "You can't generate an SkSurface for a read-only texture");
if (!mSurface.get() || mDataspace != dataspace) {
sk_sp<SkSurface> surface =
- SkSurfaces::WrapBackendTexture(mGrContext.get(), mBackendTexture,
- kTopLeft_GrSurfaceOrigin, 0, mColorType,
- toSkColorSpace(dataspace), nullptr,
- releaseSurfaceProc, this);
- if (surface.get()) {
- // The following ref will be counteracted by releaseProc, when SkSurface is discarded.
- ref();
- }
+ mBackendTexture->makeSurface(dataspace, releaseSurfaceProc, this);
+ // The following ref will be counteracted by releaseProc, when SkSurface is discarded.
+ ref();
+
mSurface = surface;
}
mDataspace = dataspace;
- if (!mSurface) {
- logFatalTexture("Unable to generate SkSurface.", mBackendTexture, dataspace, mColorType);
- }
return mSurface;
}
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index 1d5b565..74daf47 100644
--- a/libs/renderengine/skia/AutoBackendTexture.h
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -16,7 +16,6 @@
#pragma once
-#include <GrAHardwareBufferUtils.h>
#include <GrDirectContext.h>
#include <SkImage.h>
#include <SkSurface.h>
@@ -24,9 +23,9 @@
#include <ui/GraphicTypes.h>
#include "android-base/macros.h"
-#include "compat/SkiaGpuContext.h"
+#include "compat/SkiaBackendTexture.h"
-#include <mutex>
+#include <memory>
#include <vector>
namespace android {
@@ -81,9 +80,8 @@
// of shared ownership with Skia objects, so we wrap it here instead.
class LocalRef {
public:
- LocalRef(SkiaGpuContext* context, AHardwareBuffer* buffer, bool isOutputBuffer,
- CleanupManager& cleanupMgr) {
- mTexture = new AutoBackendTexture(context, buffer, isOutputBuffer, cleanupMgr);
+ LocalRef(std::unique_ptr<SkiaBackendTexture> backendTexture, CleanupManager& cleanupMgr) {
+ mTexture = new AutoBackendTexture(std::move(backendTexture), cleanupMgr);
mTexture->ref();
}
@@ -105,7 +103,7 @@
return mTexture->getOrCreateSurface(dataspace);
}
- SkColorType colorType() const { return mTexture->mColorType; }
+ SkColorType colorType() const { return mTexture->mBackendTexture->internalColorType(); }
DISALLOW_COPY_AND_ASSIGN(LocalRef);
@@ -116,12 +114,13 @@
private:
DISALLOW_COPY_AND_ASSIGN(AutoBackendTexture);
- // Creates a GrBackendTexture whose contents come from the provided buffer.
- AutoBackendTexture(SkiaGpuContext* context, AHardwareBuffer* buffer, bool isOutputBuffer,
+ // Creates an AutoBackendTexture to manage the lifecycle of a given SkiaBackendTexture, which is
+ // in turn backed by an underlying backend-specific texture type.
+ AutoBackendTexture(std::unique_ptr<SkiaBackendTexture> backendTexture,
CleanupManager& cleanupMgr);
// The only way to invoke dtor is with unref, when mUsageCount is 0.
- ~AutoBackendTexture();
+ ~AutoBackendTexture() = default;
void ref() { mUsageCount++; }
@@ -137,24 +136,16 @@
// Makes a new SkSurface from the texture content, if needed.
sk_sp<SkSurface> getOrCreateSurface(ui::Dataspace dataspace);
- GrBackendTexture mBackendTexture;
- GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
- GrAHardwareBufferUtils::UpdateImageProc mUpdateProc;
- GrAHardwareBufferUtils::TexImageCtx mImageCtx;
-
- // TODO: b/293371537 - Graphite abstractions for ABT.
- const sk_sp<GrDirectContext> mGrContext = nullptr;
CleanupManager& mCleanupMgr;
static void releaseSurfaceProc(SkSurface::ReleaseContext releaseContext);
static void releaseImageProc(SkImages::ReleaseContext releaseContext);
+ std::unique_ptr<SkiaBackendTexture> mBackendTexture;
int mUsageCount = 0;
- const bool mIsOutputBuffer;
sk_sp<SkImage> mImage = nullptr;
sk_sp<SkSurface> mSurface = nullptr;
ui::Dataspace mDataspace = ui::Dataspace::UNKNOWN;
- SkColorType mColorType = kUnknown_SkColorType;
};
} // namespace skia
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 27daeba..9e8fe68 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -80,6 +80,7 @@
#include "filters/KawaseBlurFilter.h"
#include "filters/LinearEffect.h"
#include "log/log_main.h"
+#include "skia/compat/SkiaBackendTexture.h"
#include "skia/debug/SkiaCapture.h"
#include "skia/debug/SkiaMemoryReporter.h"
#include "skia/filters/StretchShaderFactory.h"
@@ -417,9 +418,11 @@
if (FlagManager::getInstance().renderable_buffer_usage()) {
isRenderable = buffer->getUsage() & GRALLOC_USAGE_HW_RENDER;
}
- std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
- std::make_shared<AutoBackendTexture::LocalRef>(context, buffer->toAHardwareBuffer(),
- isRenderable, mTextureCleanupMgr);
+ std::unique_ptr<SkiaBackendTexture> backendTexture =
+ context->makeBackendTexture(buffer->toAHardwareBuffer(), isRenderable);
+ auto imageTextureRef =
+ std::make_shared<AutoBackendTexture::LocalRef>(std::move(backendTexture),
+ mTextureCleanupMgr);
cache.insert({buffer->getId(), imageTextureRef});
}
}
@@ -470,9 +473,10 @@
return it->second;
}
}
- return std::make_shared<AutoBackendTexture::LocalRef>(getActiveContext(),
- buffer->toAHardwareBuffer(),
- isOutputBuffer, mTextureCleanupMgr);
+ std::unique_ptr<SkiaBackendTexture> backendTexture =
+ getActiveContext()->makeBackendTexture(buffer->toAHardwareBuffer(), isOutputBuffer);
+ return std::make_shared<AutoBackendTexture::LocalRef>(std::move(backendTexture),
+ mTextureCleanupMgr);
}
bool SkiaRenderEngine::canSkipPostRenderCleanup() const {
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.cpp b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
new file mode 100644
index 0000000..d246466
--- /dev/null
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2024 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 "GaneshBackendTexture.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <include/core/SkImage.h>
+#include <include/gpu/GrDirectContext.h>
+#include <include/gpu/ganesh/SkImageGanesh.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
+#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
+#include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
+#include <include/gpu/vk/GrVkTypes.h>
+
+#include "skia/ColorSpaces.h"
+#include "skia/compat/SkiaBackendTexture.h"
+
+#include <android/hardware_buffer.h>
+#include <log/log_main.h>
+#include <utils/Trace.h>
+
+namespace android::renderengine::skia {
+
+GaneshBackendTexture::GaneshBackendTexture(sk_sp<GrDirectContext> grContext,
+ AHardwareBuffer* buffer, bool isOutputBuffer)
+ : SkiaBackendTexture(buffer, isOutputBuffer), mGrContext(grContext) {
+ ATRACE_CALL();
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(buffer, &desc);
+ const bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+
+ GrBackendFormat backendFormat;
+ const GrBackendApi graphicsApi = grContext->backend();
+ if (graphicsApi == GrBackendApi::kOpenGL) {
+ backendFormat =
+ GrAHardwareBufferUtils::GetGLBackendFormat(grContext.get(), desc.format, false);
+ mBackendTexture =
+ GrAHardwareBufferUtils::MakeGLBackendTexture(grContext.get(), buffer, desc.width,
+ desc.height, &mDeleteProc,
+ &mUpdateProc, &mImageCtx,
+ createProtectedImage, backendFormat,
+ isOutputBuffer);
+ } else if (graphicsApi == GrBackendApi::kVulkan) {
+ backendFormat = GrAHardwareBufferUtils::GetVulkanBackendFormat(grContext.get(), buffer,
+ desc.format, false);
+ mBackendTexture =
+ GrAHardwareBufferUtils::MakeVulkanBackendTexture(grContext.get(), buffer,
+ desc.width, desc.height,
+ &mDeleteProc, &mUpdateProc,
+ &mImageCtx, createProtectedImage,
+ backendFormat, isOutputBuffer);
+ } else {
+ LOG_ALWAYS_FATAL("Unexpected graphics API %u", static_cast<unsigned>(graphicsApi));
+ }
+
+ if (!mBackendTexture.isValid() || !desc.width || !desc.height) {
+ LOG_ALWAYS_FATAL("Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d "
+ "isWriteable:%d format:%d",
+ this, desc.width, desc.height, createProtectedImage, isOutputBuffer,
+ desc.format);
+ }
+}
+
+GaneshBackendTexture::~GaneshBackendTexture() {
+ if (mBackendTexture.isValid()) {
+ mDeleteProc(mImageCtx);
+ mBackendTexture = {};
+ }
+}
+
+sk_sp<SkImage> GaneshBackendTexture::makeImage(SkAlphaType alphaType, ui::Dataspace dataspace,
+ TextureReleaseProc releaseImageProc,
+ ReleaseContext releaseContext) {
+ if (mBackendTexture.isValid()) {
+ mUpdateProc(mImageCtx, mGrContext.get());
+ }
+
+ const SkColorType colorType = colorTypeForImage(alphaType);
+ sk_sp<SkImage> image =
+ SkImages::BorrowTextureFrom(mGrContext.get(), mBackendTexture, kTopLeft_GrSurfaceOrigin,
+ colorType, alphaType, toSkColorSpace(dataspace),
+ releaseImageProc, releaseContext);
+ if (!image) {
+ logFatalTexture("Unable to generate SkImage.", dataspace, colorType);
+ }
+ return image;
+}
+
+sk_sp<SkSurface> GaneshBackendTexture::makeSurface(ui::Dataspace dataspace,
+ TextureReleaseProc releaseSurfaceProc,
+ ReleaseContext releaseContext) {
+ const SkColorType colorType = internalColorType();
+ sk_sp<SkSurface> surface =
+ SkSurfaces::WrapBackendTexture(mGrContext.get(), mBackendTexture,
+ kTopLeft_GrSurfaceOrigin, 0, colorType,
+ toSkColorSpace(dataspace), nullptr, releaseSurfaceProc,
+ releaseContext);
+ if (!surface) {
+ logFatalTexture("Unable to generate SkSurface.", dataspace, colorType);
+ }
+ return surface;
+}
+
+void GaneshBackendTexture::logFatalTexture(const char* msg, ui::Dataspace dataspace,
+ SkColorType colorType) {
+ switch (mBackendTexture.backend()) {
+ case GrBackendApi::kOpenGL: {
+ GrGLTextureInfo textureInfo;
+ bool retrievedTextureInfo =
+ GrBackendTextures::GetGLTextureInfo(mBackendTexture, &textureInfo);
+ LOG_ALWAYS_FATAL("%s isTextureValid:%d dataspace:%d"
+ "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
+ "texType: %i\n\t\tGrGLTextureInfo: success: %i fTarget: %u fFormat: %u"
+ " colorType %i",
+ msg, mBackendTexture.isValid(), static_cast<int32_t>(dataspace),
+ mBackendTexture.width(), mBackendTexture.height(),
+ mBackendTexture.hasMipmaps(), mBackendTexture.isProtected(),
+ static_cast<int>(mBackendTexture.textureType()), retrievedTextureInfo,
+ textureInfo.fTarget, textureInfo.fFormat, colorType);
+ break;
+ }
+ case GrBackendApi::kVulkan: {
+ GrVkImageInfo imageInfo;
+ bool retrievedImageInfo =
+ GrBackendTextures::GetVkImageInfo(mBackendTexture, &imageInfo);
+ LOG_ALWAYS_FATAL("%s isTextureValid:%d dataspace:%d"
+ "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
+ "texType: %i\n\t\tVkImageInfo: success: %i fFormat: %i "
+ "fSampleCount: %u fLevelCount: %u colorType %i",
+ msg, mBackendTexture.isValid(), static_cast<int32_t>(dataspace),
+ mBackendTexture.width(), mBackendTexture.height(),
+ mBackendTexture.hasMipmaps(), mBackendTexture.isProtected(),
+ static_cast<int>(mBackendTexture.textureType()), retrievedImageInfo,
+ imageInfo.fFormat, imageInfo.fSampleCount, imageInfo.fLevelCount,
+ colorType);
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("%s Unexpected backend %u", msg,
+ static_cast<unsigned>(mBackendTexture.backend()));
+ break;
+ }
+}
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/GaneshBackendTexture.h b/libs/renderengine/skia/compat/GaneshBackendTexture.h
new file mode 100644
index 0000000..5cf8647
--- /dev/null
+++ b/libs/renderengine/skia/compat/GaneshBackendTexture.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include "SkiaBackendTexture.h"
+#include "ui/GraphicTypes.h"
+
+#include <include/android/GrAHardwareBufferUtils.h>
+#include <include/core/SkColorSpace.h>
+#include <include/gpu/GrDirectContext.h>
+
+#include <android-base/macros.h>
+
+namespace android::renderengine::skia {
+
+class GaneshBackendTexture : public SkiaBackendTexture {
+public:
+ // Creates an internal GrBackendTexture whose contents come from the provided buffer.
+ GaneshBackendTexture(sk_sp<GrDirectContext> grContext, AHardwareBuffer* buffer,
+ bool isOutputBuffer);
+
+ ~GaneshBackendTexture() override;
+
+ sk_sp<SkImage> makeImage(SkAlphaType alphaType, ui::Dataspace dataspace,
+ TextureReleaseProc releaseImageProc,
+ ReleaseContext releaseContext) override;
+
+ sk_sp<SkSurface> makeSurface(ui::Dataspace dataspace, TextureReleaseProc releaseSurfaceProc,
+ ReleaseContext releaseContext) override;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(GaneshBackendTexture);
+
+ void logFatalTexture(const char* msg, ui::Dataspace dataspace, SkColorType colorType);
+
+ const sk_sp<GrDirectContext> mGrContext;
+ GrBackendTexture mBackendTexture;
+ GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+ GrAHardwareBufferUtils::UpdateImageProc mUpdateProc;
+ GrAHardwareBufferUtils::TexImageCtx mImageCtx;
+};
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.cpp b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
index 51c6a6c..87f00e4 100644
--- a/libs/renderengine/skia/compat/GaneshGpuContext.cpp
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
@@ -27,8 +27,13 @@
#include <include/gpu/gl/GrGLInterface.h>
#include <include/gpu/vk/GrVkBackendContext.h>
+#include "../AutoBackendTexture.h"
+#include "GaneshBackendTexture.h"
+#include "skia/compat/SkiaBackendTexture.h"
+
#include <android-base/macros.h>
#include <log/log_main.h>
+#include <memory>
namespace android::renderengine::skia {
@@ -66,6 +71,11 @@
return mGrContext;
}
+std::unique_ptr<SkiaBackendTexture> GaneshGpuContext::makeBackendTexture(AHardwareBuffer* buffer,
+ bool isOutputBuffer) {
+ return std::make_unique<GaneshBackendTexture>(mGrContext, buffer, isOutputBuffer);
+}
+
sk_sp<SkSurface> GaneshGpuContext::createRenderTarget(SkImageInfo imageInfo) {
constexpr int kSampleCount = 1; // enable AA
constexpr SkSurfaceProps* kProps = nullptr;
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.h b/libs/renderengine/skia/compat/GaneshGpuContext.h
index 59001ec..ec0162d 100644
--- a/libs/renderengine/skia/compat/GaneshGpuContext.h
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.h
@@ -29,6 +29,9 @@
sk_sp<GrDirectContext> grDirectContext() override;
+ std::unique_ptr<SkiaBackendTexture> makeBackendTexture(AHardwareBuffer* buffer,
+ bool isOutputBuffer) override;
+
sk_sp<SkSurface> createRenderTarget(SkImageInfo imageInfo) override;
size_t getMaxRenderTargetSize() const override;
diff --git a/libs/renderengine/skia/compat/SkiaBackendTexture.h b/libs/renderengine/skia/compat/SkiaBackendTexture.h
new file mode 100644
index 0000000..09877a5
--- /dev/null
+++ b/libs/renderengine/skia/compat/SkiaBackendTexture.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include <include/android/GrAHardwareBufferUtils.h>
+#include <include/core/SkColorSpace.h>
+#include <include/gpu/GrDirectContext.h>
+
+#include <android/hardware_buffer.h>
+#include <ui/GraphicTypes.h>
+
+namespace android::renderengine::skia {
+
+/**
+ * Abstraction over a Skia backend-specific texture type.
+ *
+ * This class does not do any lifecycle management, and should typically be wrapped in an
+ * AutoBackendTexture::LocalRef. Typically created via SkiaGpuContext::makeBackendTexture(...).
+ */
+class SkiaBackendTexture {
+public:
+ SkiaBackendTexture(AHardwareBuffer* buffer, bool isOutputBuffer)
+ : mIsOutputBuffer(isOutputBuffer) {
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(buffer, &desc);
+
+ mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
+ }
+ virtual ~SkiaBackendTexture() = default;
+
+ // These two definitions mirror Skia's own types used for texture release callbacks, which are
+ // re-declared multiple times between context-specific implementation headers for Ganesh vs.
+ // Graphite, and within the context of SkImages vs. SkSurfaces. Our own re-declaration allows us
+ // to not pull in any implementation-specific headers here.
+ using ReleaseContext = void*;
+ using TextureReleaseProc = void (*)(ReleaseContext);
+
+ // Guaranteed to be non-null (crashes otherwise). An opaque alphaType may coerce the internal
+ // color type to RBGX.
+ virtual sk_sp<SkImage> makeImage(SkAlphaType alphaType, ui::Dataspace dataspace,
+ TextureReleaseProc releaseImageProc,
+ ReleaseContext releaseContext) = 0;
+
+ // Guaranteed to be non-null (crashes otherwise).
+ virtual sk_sp<SkSurface> makeSurface(ui::Dataspace dataspace,
+ TextureReleaseProc releaseSurfaceProc,
+ ReleaseContext releaseContext) = 0;
+
+ bool isOutputBuffer() const { return mIsOutputBuffer; }
+
+ SkColorType internalColorType() const { return mColorType; }
+
+protected:
+ // Strip alpha channel from rawColorType if alphaType is opaque (note: only works for RGBA_8888)
+ SkColorType colorTypeForImage(SkAlphaType alphaType) const {
+ if (alphaType == kOpaque_SkAlphaType) {
+ // TODO: b/40043126 - Support RGBX SkColorType for F16 and support it and 101010x as a
+ // source
+ if (internalColorType() == kRGBA_8888_SkColorType) {
+ return kRGB_888x_SkColorType;
+ }
+ }
+ return internalColorType();
+ }
+
+private:
+ const bool mIsOutputBuffer;
+ SkColorType mColorType = kUnknown_SkColorType;
+};
+
+} // namespace android::renderengine::skia
diff --git a/libs/renderengine/skia/compat/SkiaGpuContext.h b/libs/renderengine/skia/compat/SkiaGpuContext.h
index ba167f3..ddf1642 100644
--- a/libs/renderengine/skia/compat/SkiaGpuContext.h
+++ b/libs/renderengine/skia/compat/SkiaGpuContext.h
@@ -24,8 +24,12 @@
#include <include/gpu/gl/GrGLInterface.h>
#include <include/gpu/vk/GrVkBackendContext.h>
+#include "SkiaBackendTexture.h"
+
#include <log/log.h>
+#include <memory>
+
namespace android::renderengine::skia {
/**
@@ -52,6 +56,9 @@
LOG_ALWAYS_FATAL("grDirectContext() called on a non-Ganesh instance of SkiaGpuContext!");
}
+ virtual std::unique_ptr<SkiaBackendTexture> makeBackendTexture(AHardwareBuffer* buffer,
+ bool isOutputBuffer) = 0;
+
/**
* Notes:
* - The surface doesn't count against Skia's caching budgets.