Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca050286 authored by Nolan Scobie's avatar Nolan Scobie
Browse files

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
parent acb53f92
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ filegroup {
        "skia/SkiaGLRenderEngine.cpp",
        "skia/SkiaVkRenderEngine.cpp",
        "skia/VulkanInterface.cpp",
        "skia/compat/GaneshBackendTexture.cpp",
        "skia/compat/GaneshGpuContext.cpp",
        "skia/debug/CaptureTimer.cpp",
        "skia/debug/CommonPool.cpp",
+19 −130
Original line number Diff line number Diff line
@@ -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 @@ void AutoBackendTexture::releaseImageProc(SkImages::ReleaseContext releaseContex
    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()) {
    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()) {
                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;
}

+10 −19
Original line number Diff line number Diff line
@@ -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 @@ public:
    // 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 @@ public:
            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 @@ public:
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 @@ private:
    // 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
+10 −6
Original line number Diff line number Diff line
@@ -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 @@ void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
        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 @@ std::shared_ptr<AutoBackendTexture::LocalRef> SkiaRenderEngine::getOrCreateBacke
            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 {
+161 −0
Original line number Diff line number Diff line
/*
 * 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
Loading