/* * Copyright 2020 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tools/gpu/ManagedBackendTexture.h" #include "include/core/SkBitmap.h" #include "include/core/SkImageInfo.h" #include "src/core/SkMipmap.h" #include "src/gpu/RefCntedCallback.h" #ifdef SK_GANESH #include "include/private/gpu/ganesh/GrTypesPriv.h" #endif #ifdef SK_GRAPHITE #include "include/gpu/graphite/Recorder.h" #include "src/gpu/graphite/Caps.h" #endif using Mipmapped = skgpu::Mipmapped; using Protected = skgpu::Protected; using Renderable = skgpu::Renderable; #ifdef SK_GANESH namespace { struct Context { GrGpuFinishedProc fWrappedProc = nullptr; GrGpuFinishedContext fWrappedContext = nullptr; sk_sp fMBETs[SkYUVAInfo::kMaxPlanes]; }; } // anonymous namespace namespace sk_gpu_test { void ManagedBackendTexture::ReleaseProc(void* ctx) { std::unique_ptr context(static_cast(ctx)); if (context->fWrappedProc) { context->fWrappedProc(context->fWrappedContext); } } ManagedBackendTexture::~ManagedBackendTexture() { if (fDContext && fTexture.isValid()) { fDContext->deleteBackendTexture(fTexture); } } void* ManagedBackendTexture::releaseContext(GrGpuFinishedProc wrappedProc, GrGpuFinishedContext wrappedCtx) const { // Make sure we don't get a wrapped ctx without a wrapped proc SkASSERT(!wrappedCtx || wrappedProc); return new Context{wrappedProc, wrappedCtx, {sk_ref_sp(this)}}; } void* ManagedBackendTexture::MakeYUVAReleaseContext( const sk_sp mbets[SkYUVAInfo::kMaxPlanes]) { auto context = new Context; for (int i = 0; i < SkYUVAInfo::kMaxPlanes; ++i) { context->fMBETs[i] = mbets[i]; } return context; } sk_sp ManagedBackendTexture::refCountedCallback() const { return skgpu::RefCntedCallback::Make(ReleaseProc, this->releaseContext()); } void ManagedBackendTexture::wasAdopted() { fTexture = {}; } sk_sp ManagedBackendTexture::MakeFromInfo(GrDirectContext* dContext, const SkImageInfo& ii, Mipmapped mipmapped, Renderable renderable, Protected isProtected) { return MakeWithoutData(dContext, ii.width(), ii.height(), ii.colorType(), mipmapped, renderable, isProtected); } sk_sp ManagedBackendTexture::MakeFromBitmap(GrDirectContext* dContext, const SkBitmap& src, Mipmapped mipmapped, Renderable renderable, Protected isProtected) { SkPixmap srcPixmap; if (!src.peekPixels(&srcPixmap)) { return nullptr; } return MakeFromPixmap(dContext, srcPixmap, mipmapped, renderable, isProtected); } sk_sp ManagedBackendTexture::MakeFromPixmap(GrDirectContext* dContext, const SkPixmap& src, Mipmapped mipmapped, Renderable renderable, Protected isProtected) { std::vector levels({src}); std::unique_ptr mm; if (mipmapped == Mipmapped::kYes) { mm.reset(SkMipmap::Build(src, nullptr)); if (!mm) { return nullptr; } for (int i = 0; i < mm->countLevels(); ++i) { SkMipmap::Level level; SkAssertResult(mm->getLevel(i, &level)); levels.push_back(level.fPixmap); } } return MakeWithData(dContext, levels.data(), static_cast(levels.size()), kTopLeft_GrSurfaceOrigin, renderable, isProtected); } } // namespace sk_gpu_test #endif // SK_GANESH #ifdef SK_GRAPHITE using Recorder = skgpu::graphite::Recorder; namespace { struct MBETContext { MBETContext(const sk_sp& tex) : fMBETs{tex, nullptr, nullptr, nullptr} {} MBETContext(const sk_sp mbets[SkYUVAInfo::kMaxPlanes]) : fMBETs{mbets[0], mbets[1], mbets[2], mbets[3]} {} sk_sp fMBETs[SkYUVAInfo::kMaxPlanes]; }; } // anonymous namespace namespace sk_gpu_test { void ManagedGraphiteTexture::ReleaseProc(void* ctx) { std::unique_ptr context(static_cast(ctx)); } void ManagedGraphiteTexture::FinishedProc(void* ctx, skgpu::CallbackResult) { std::unique_ptr context(static_cast(ctx)); } void ManagedGraphiteTexture::ImageReleaseProc(void* ctx) { std::unique_ptr context(static_cast(ctx)); } ManagedGraphiteTexture::~ManagedGraphiteTexture() { if (fContext && fTexture.isValid()) { fContext->deleteBackendTexture(fTexture); } } void* ManagedGraphiteTexture::releaseContext() const { return new MBETContext{{sk_ref_sp(this)}}; } void* ManagedGraphiteTexture::MakeYUVAReleaseContext( const sk_sp mbets[SkYUVAInfo::kMaxPlanes]) { return new MBETContext(mbets); } sk_sp ManagedGraphiteTexture::refCountedCallback() const { return skgpu::RefCntedCallback::Make(FinishedProc, this->releaseContext()); } sk_sp ManagedGraphiteTexture::MakeUnInit(Recorder* recorder, const SkImageInfo& ii, Mipmapped mipmapped, Renderable renderable, Protected isProtected) { sk_sp mbet(new ManagedGraphiteTexture); mbet->fContext = recorder->priv().context(); const skgpu::graphite::Caps* caps = recorder->priv().caps(); skgpu::graphite::TextureInfo info = caps->getDefaultSampledTextureInfo(ii.colorType(), mipmapped, isProtected, renderable); mbet->fTexture = recorder->createBackendTexture(ii.dimensions(), info); if (!mbet->fTexture.isValid()) { return nullptr; } recorder->addFinishInfo({mbet->releaseContext(), FinishedProc}); return mbet; } sk_sp ManagedGraphiteTexture::MakeFromPixmap(Recorder* recorder, const SkPixmap& src, Mipmapped mipmapped, Renderable renderable, Protected isProtected) { sk_sp mbet = MakeUnInit(recorder, src.info(), mipmapped, renderable, isProtected); if (!mbet) { return nullptr; } std::vector levels({src}); std::unique_ptr mm; if (mipmapped == Mipmapped::kYes) { mm.reset(SkMipmap::Build(src, nullptr)); if (!mm) { return nullptr; } for (int i = 0; i < mm->countLevels(); ++i) { SkMipmap::Level level; SkAssertResult(mm->getLevel(i, &level)); levels.push_back(level.fPixmap); } } if (!recorder->updateBackendTexture(mbet->fTexture, levels.data(), static_cast(levels.size()))) { return nullptr; } return mbet; } sk_sp ManagedGraphiteTexture::MakeMipmappedFromPixmaps( Recorder* recorder, SkSpan levels, skgpu::Renderable renderable, skgpu::Protected isProtected) { if (levels.empty()) { return nullptr; } sk_sp mbet = MakeUnInit(recorder, levels[0].info(), Mipmapped::kYes, renderable, isProtected); if (!recorder->updateBackendTexture(mbet->fTexture, levels.data(), static_cast(levels.size()))) { return nullptr; } return mbet; } sk_sp ManagedGraphiteTexture::MakeFromCompressedData( Recorder* recorder, SkISize dimensions, SkTextureCompressionType compression, sk_sp src, skgpu::Mipmapped mipmapped, skgpu::Protected isProtected) { sk_sp mbet(new ManagedGraphiteTexture); mbet->fContext = recorder->priv().context(); const skgpu::graphite::Caps* caps = recorder->priv().caps(); skgpu::graphite::TextureInfo info = caps->getDefaultCompressedTextureInfo(compression, mipmapped, isProtected); mbet->fTexture = recorder->createBackendTexture(dimensions, info); if (!mbet->fTexture.isValid()) { return nullptr; } recorder->addFinishInfo({mbet->releaseContext(), FinishedProc}); if (!recorder->updateCompressedBackendTexture(mbet->fTexture, src->data(), src->size())) { return nullptr; } return mbet; } } // namespace sk_gpu_test #endif // SK_GRAPHITE