blob: 6e94cebfa0ae075e50e210a4c0fdae0b3adf2486 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/graphite/Image_YUVA_Graphite.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkImage.h"
#include "include/core/SkSurface.h"
#include "include/core/SkYUVAInfo.h"
#include "include/core/SkYUVAPixmaps.h"
#include "include/gpu/GpuTypes.h"
#include "include/gpu/graphite/Image.h"
#include "include/gpu/graphite/Recorder.h"
#include "include/gpu/graphite/Surface.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/Image_Graphite.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/ResourceProvider.h"
#include "src/gpu/graphite/Texture.h"
#include "src/gpu/graphite/TextureProxy.h"
#include "src/gpu/graphite/TextureProxyView.h"
#include "src/gpu/graphite/TextureUtils.h"
#include "src/shaders/SkImageShader.h"
namespace {
constexpr auto kAssumedColorType = kRGBA_8888_SkColorType;
}
namespace skgpu::graphite {
static SkAlphaType yuva_alpha_type(const SkYUVAInfo& yuvaInfo) {
// If an alpha channel is present we always use kPremul. This is because, although the planar
// data is always un-premul, the final interleaved RGBA sample produced in the shader is premul
// (and similar if flattened).
return yuvaInfo.hasAlpha() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
}
Image_YUVA::Image_YUVA(YUVATextureProxies proxies,
sk_sp<SkColorSpace> imageColorSpace)
: Image_Base(SkImageInfo::Make(proxies.yuvaInfo().dimensions(),
kAssumedColorType,
yuva_alpha_type(proxies.yuvaInfo()),
std::move(imageColorSpace)),
kNeedNewImageUniqueID)
, fYUVAProxies(std::move(proxies)) {
// The caller should have checked this, just verifying.
SkASSERT(fYUVAProxies.isValid());
}
Image_YUVA::~Image_YUVA() = default;
sk_sp<Image_YUVA> Image_YUVA::Make(const Caps* caps,
const SkYUVAInfo& yuvaInfo,
SkSpan<TextureProxyView> planes,
sk_sp<SkColorSpace> imageColorSpace) {
if (!yuvaInfo.isValid()) {
return nullptr;
}
SkImageInfo info = SkImageInfo::Make(
yuvaInfo.dimensions(), kAssumedColorType, yuva_alpha_type(yuvaInfo), imageColorSpace);
if (!SkImageInfoIsValid(info)) {
return nullptr;
}
YUVATextureProxies yuvaTextureProxies(caps, yuvaInfo, planes);
if (!yuvaTextureProxies.isValid()) {
return nullptr;
}
return sk_make_sp<Image_YUVA>(std::move(yuvaTextureProxies), std::move(imageColorSpace));
}
sk_sp<Image_YUVA> Image_YUVA::WrapImages(const Caps* caps,
const SkYUVAInfo& yuvaInfo,
SkSpan<const sk_sp<SkImage>> images,
sk_sp<SkColorSpace> imageColorSpace) {
if (SkTo<int>(images.size()) < yuvaInfo.numPlanes()) {
return nullptr;
}
TextureProxyView planes[SkYUVAInfo::kMaxPlanes];
for (int i = 0; i < yuvaInfo.numPlanes(); ++i) {
planes[i] = AsView(images[i]);
if (!planes[i]) {
// A null image, or not graphite-backed, or not backed by a single texture.
return nullptr;
}
// YUVATextureProxies expects to sample from the red channel for single-channel
// textures, so reset the swizzle for alpha-only textures to compensate for that
if (images[i]->isAlphaOnly()) {
planes[i] = planes[i].makeSwizzle(Swizzle("aaaa"));
}
}
sk_sp<Image_YUVA> image = Make(caps, yuvaInfo, SkSpan(planes), std::move(imageColorSpace));
if (image) {
// Unlike the other factories, this YUVA image shares the texture proxies with each plane
// Image, so if those are linked to Devices, it must inherit those same links.
for (int plane = 0; plane < yuvaInfo.numPlanes(); ++plane) {
SkASSERT(as_IB(images[plane])->isGraphiteBacked());
image->linkDevices(static_cast<Image_Base*>(images[plane].get()));
}
}
return image;
}
size_t Image_YUVA::textureSize() const {
size_t size = 0;
for (int i = 0; i < fYUVAProxies.numPlanes(); ++i) {
if (fYUVAProxies.proxy(i)->texture()) {
size += fYUVAProxies.proxy(i)->texture()->gpuMemorySize();
}
}
return size;
}
sk_sp<SkImage> Image_YUVA::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
sk_sp<Image_YUVA> view = sk_make_sp<Image_YUVA>(fYUVAProxies, std::move(newCS));
// The new Image object shares the same texture planes, so it should also share linked Devices
view->linkDevices(this);
return view;
}
} // namespace skgpu::graphite