Reland "Push SkYUVAInfo into GrYUVToRGBEffect."
This is a reland of b60255033ddeb6a7e80f5699b0883b580d30dcbf
Original change's description:
> Push SkYUVAInfo into GrYUVToRGBEffect.
>
> Wrap up SkYUVAInfo and proxies into new type GrYUVATextureProxies.
>
> Bug: skia:10632
> Change-Id: Ic907d78a1a40af3c8ef838021749839c422d62dc
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/353042
> Commit-Queue: Brian Salomon <bsalomon@google.com>
> Reviewed-by: Jim Van Verth <jvanverth@google.com>
Bug: skia:10632
Change-Id: I1878609153e3fc763620cb71a85d3b012f915155
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/353621
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/gm/yuvtorgbsubset.cpp b/gm/yuvtorgbsubset.cpp
index 642dc35..04081c3 100644
--- a/gm/yuvtorgbsubset.cpp
+++ b/gm/yuvtorgbsubset.cpp
@@ -16,14 +16,15 @@
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
-#include "include/private/GrTypesPriv.h"
-#include "src/core/SkYUVAInfoLocation.h"
+#include "include/core/SkYUVAInfo.h"
+#include "include/core/SkYUVAPixmaps.h"
#include "src/gpu/GrBitmapTextureMaker.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrPaint.h"
#include "src/gpu/GrSamplerState.h"
#include "src/gpu/GrSurfaceDrawContext.h"
#include "src/gpu/GrTextureProxy.h"
+#include "src/gpu/GrYUVATextureProxies.h"
#include "src/gpu/effects/GrYUVtoRGBEffect.h"
#include <memory>
@@ -31,10 +32,6 @@
class SkCanvas;
-#define YSIZE 8
-#define USIZE 4
-#define VSIZE 4
-
namespace skiagm {
//////////////////////////////////////////////////////////////////////////////
@@ -55,13 +52,16 @@
SkISize onISize() override { return {1310, 540}; }
- void onOnceBeforeDraw() override {
- SkImageInfo yinfo = SkImageInfo::MakeA8(YSIZE, YSIZE);
- fBitmaps[0].allocPixels(yinfo);
- SkImageInfo uinfo = SkImageInfo::MakeA8(USIZE, USIZE);
- fBitmaps[1].allocPixels(uinfo);
- SkImageInfo vinfo = SkImageInfo::MakeA8(VSIZE, VSIZE);
- fBitmaps[2].allocPixels(vinfo);
+ void makePixmaps() {
+ SkYUVAInfo yuvaInfo = SkYUVAInfo({8, 8},
+ SkYUVAInfo::PlaneConfig::kY_U_V,
+ SkYUVAInfo::Subsampling::k420,
+ kJPEG_Full_SkYUVColorSpace);
+ SkColorType colorTypes[] = {kAlpha_8_SkColorType,
+ kAlpha_8_SkColorType,
+ kAlpha_8_SkColorType};
+ SkYUVAPixmapInfo pmapInfo(yuvaInfo, colorTypes, nullptr);
+ fPixmaps = SkYUVAPixmaps::Allocate(pmapInfo);
unsigned char innerY[16] = {149, 160, 130, 105,
160, 130, 105, 149,
@@ -70,45 +70,62 @@
unsigned char innerU[4] = {43, 75, 145, 200};
unsigned char innerV[4] = {88, 180, 200, 43};
int outerYUV[] = {128, 128, 128};
+ SkBitmap bitmaps[3];
for (int i = 0; i < 3; ++i) {
- fBitmaps[i].eraseColor(SkColorSetARGB(outerYUV[i], 0, 0, 0));
+ bitmaps[i].installPixels(fPixmaps.plane(i));
+ bitmaps[i].eraseColor(SkColorSetARGB(outerYUV[i], 0, 0, 0));
}
SkPixmap innerYPM(SkImageInfo::MakeA8(4, 4), innerY, 4);
SkPixmap innerUPM(SkImageInfo::MakeA8(2, 2), innerU, 2);
SkPixmap innerVPM(SkImageInfo::MakeA8(2, 2), innerV, 2);
- fBitmaps[0].writePixels(innerYPM, 2, 2);
- fBitmaps[1].writePixels(innerUPM, 1, 1);
- fBitmaps[2].writePixels(innerVPM, 1, 1);
- for (auto& fBitmap : fBitmaps) {
- fBitmap.setImmutable();
- }
+ bitmaps[0].writePixels(innerYPM, 2, 2);
+ bitmaps[1].writePixels(innerUPM, 1, 1);
+ bitmaps[2].writePixels(innerVPM, 1, 1);
}
- DrawResult onDraw(GrRecordingContext* context, GrSurfaceDrawContext* surfaceDrawContext,
- SkCanvas* canvas, SkString* errorMsg) override {
- GrSurfaceProxyView views[3];
-
- for (int i = 0; i < 3; ++i) {
- GrBitmapTextureMaker maker(context, fBitmaps[i], GrImageTexGenPolicy::kDraw);
+ DrawResult onGpuSetup(GrDirectContext* context, SkString* errorMsg) override {
+ if (!context) {
+ return DrawResult::kSkip;
+ }
+ if (!fPixmaps.isValid()) {
+ this->makePixmaps();
+ }
+ GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
+ GrColorType colorTypes[SkYUVAInfo::kMaxPlanes];
+ for (int i = 0; i < fPixmaps.numPlanes(); ++i) {
+ SkBitmap bitmap;
+ bitmap.installPixels(fPixmaps.plane(i));
+ bitmap.setImmutable();
+ GrBitmapTextureMaker maker(
+ context, bitmap, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
views[i] = maker.view(GrMipmapped::kNo);
if (!views[i]) {
*errorMsg = "Failed to create proxy";
- return DrawResult::kFail;
+ return context->abandoned() ? DrawResult::kSkip : DrawResult::kFail;
}
+ colorTypes[i] = SkColorTypeToGrColorType(bitmap.colorType());
}
+ fProxies = GrYUVATextureProxies(fPixmaps.yuvaInfo(), views, colorTypes);
+ if (!fProxies.isValid()) {
+ *errorMsg = "Failed to create GrYUVATextureProxies";
+ return DrawResult::kFail;
+ }
+ return DrawResult::kOk;
+ }
+ void onGpuTeardown() override { fProxies = {}; }
+
+ DrawResult onDraw(GrRecordingContext* context,
+ GrSurfaceDrawContext* surfaceDrawContext,
+ SkCanvas* canvas,
+ SkString* errorMsg) override {
static const GrSamplerState::Filter kFilters[] = {GrSamplerState::Filter::kNearest,
GrSamplerState::Filter::kLinear};
static const SkRect kColorRect = SkRect::MakeLTRB(2.f, 2.f, 6.f, 6.f);
- SkYUVAInfo::YUVALocations yuvaLocations = {{
- { 0, SkColorChannel::kA},
- { 1, SkColorChannel::kA},
- { 2, SkColorChannel::kA},
- {-1, SkColorChannel::kA}
- }};
// Outset to visualize wrap modes.
- SkRect rect = SkRect::MakeWH(YSIZE, YSIZE).makeOutset(YSIZE/2, YSIZE/2);
+ SkRect rect = SkRect::Make(fProxies.yuvaInfo().dimensions());
+ rect = rect.makeOutset(fProxies.yuvaInfo().width()/2.f, fProxies.yuvaInfo().height()/2.f);
SkScalar y = kTestPad;
// Rows are filter modes.
@@ -129,9 +146,8 @@
samplerState.setWrapModeY(wm);
}
const auto& caps = *context->priv().caps();
- std::unique_ptr<GrFragmentProcessor> fp(
- GrYUVtoRGBEffect::Make(views, yuvaLocations, kJPEG_SkYUVColorSpace,
- samplerState, caps, SkMatrix::I(), subset));
+ std::unique_ptr<GrFragmentProcessor> fp =
+ GrYUVtoRGBEffect::Make(fProxies, samplerState, caps, SkMatrix::I(), subset);
if (fp) {
GrPaint grPaint;
grPaint.setColorFragmentProcessor(std::move(fp));
@@ -145,10 +161,11 @@
}
return DrawResult::kOk;
- }
+ }
private:
- SkBitmap fBitmaps[3];
+ SkYUVAPixmaps fPixmaps;
+ GrYUVATextureProxies fProxies;
static constexpr SkScalar kTestPad = 10.f;
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 6bff75a..daa2e41 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -277,6 +277,8 @@
"$_src/gpu/GrXferProcessor.cpp",
"$_src/gpu/GrXferProcessor.h",
"$_src/gpu/GrYUVABackendTextures.cpp",
+ "$_src/gpu/GrYUVATextureProxies.cpp",
+ "$_src/gpu/GrYUVATextureProxies.h",
# Ops
"$_src/gpu/effects/GrBezierEffect.cpp",
diff --git a/include/core/SkYUVAInfo.h b/include/core/SkYUVAInfo.h
index 3683335..a3cf210 100644
--- a/include/core/SkYUVAInfo.h
+++ b/include/core/SkYUVAInfo.h
@@ -93,6 +93,16 @@
static constexpr int kMaxPlanes = 4;
+ /** ratio of Y/A values to U/V values in x and y. */
+ static std::tuple<int, int> SubsamplingFactors(Subsampling);
+
+ /**
+ * SubsamplingFactors(Subsampling) if planedIdx refers to a U/V plane and otherwise {1, 1} if
+ * inputs are valid. Invalid inputs consist of incompatible PlaneConfig/Subsampling/planeIdx
+ * combinations. {0, 0} is returned for invalid inputs.
+ */
+ static std::tuple<int, int> PlaneSubsamplingFactors(PlaneConfig, Subsampling, int planeIdx);
+
/**
* Given image dimensions, a planer configuration, subsampling, and origin, determine the
* expected size of each plane. Returns the number of expected planes. planeDimensions[0]
@@ -146,6 +156,10 @@
PlaneConfig planeConfig() const { return fPlaneConfig; }
Subsampling subsampling() const { return fSubsampling; }
+ std::tuple<int, int> planeSubsamplingFactors(int planeIdx) const {
+ return PlaneSubsamplingFactors(fPlaneConfig, fSubsampling, planeIdx);
+ }
+
/**
* Dimensions of the full resolution image (after planes have been oriented to how the image
* is displayed as indicated by fOrigin).
@@ -160,6 +174,10 @@
SkEncodedOrigin origin() const { return fOrigin; }
+ SkMatrix originMatrix() const {
+ return SkEncodedOriginToMatrix(fOrigin, this->width(), this->height());
+ }
+
bool hasAlpha() const { return HasAlpha(fPlaneConfig); }
/**
@@ -199,6 +217,12 @@
*/
SkYUVAInfo makeSubsampling(SkYUVAInfo::Subsampling) const;
+ /**
+ * Makes a SkYUVAInfo that is identical to this one but with the passed dimensions. If the
+ * passed dimensions is empty then the result will be an invalid SkYUVAInfo.
+ */
+ SkYUVAInfo makeDimensions(SkISize) const;
+
bool operator==(const SkYUVAInfo& that) const;
bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); }
diff --git a/src/core/SkYUVAInfo.cpp b/src/core/SkYUVAInfo.cpp
index 8e4ce2b..74b3a84 100644
--- a/src/core/SkYUVAInfo.cpp
+++ b/src/core/SkYUVAInfo.cpp
@@ -24,6 +24,54 @@
config != SkYUVAInfo::PlaneConfig::kUYVA);
}
+std::tuple<int, int> SkYUVAInfo::SubsamplingFactors(Subsampling subsampling) {
+ switch (subsampling) {
+ case Subsampling::kUnknown: return {0, 0};
+ case Subsampling::k444: return {1, 1};
+ case Subsampling::k422: return {2, 1};
+ case Subsampling::k420: return {2, 2};
+ case Subsampling::k440: return {1, 2};
+ case Subsampling::k411: return {4, 1};
+ case Subsampling::k410: return {4, 2};
+ }
+ SkUNREACHABLE;
+}
+
+std::tuple<int, int> SkYUVAInfo::PlaneSubsamplingFactors(PlaneConfig planeConfig,
+ Subsampling subsampling,
+ int planeIdx) {
+ if (!is_plane_config_compatible_with_subsampling(planeConfig, subsampling) ||
+ planeIdx < 0 ||
+ planeIdx > NumPlanes(planeConfig)) {
+ return {0, 0};
+ }
+ bool isSubsampledPlane = false;
+ switch (planeConfig) {
+ case PlaneConfig::kUnknown: SkUNREACHABLE;
+
+ case PlaneConfig::kY_U_V:
+ case PlaneConfig::kY_V_U:
+ case PlaneConfig::kY_U_V_A:
+ case PlaneConfig::kY_V_U_A:
+ isSubsampledPlane = planeIdx == 1 || planeIdx == 2;
+ break;
+
+ case PlaneConfig::kY_UV:
+ case PlaneConfig::kY_VU:
+ case PlaneConfig::kY_UV_A:
+ case PlaneConfig::kY_VU_A:
+ isSubsampledPlane = planeIdx == 1;
+ break;
+
+ case PlaneConfig::kYUV:
+ case PlaneConfig::kUYV:
+ case PlaneConfig::kYUVA:
+ case PlaneConfig::kUYVA:
+ break;
+ }
+ return isSubsampledPlane ? SubsamplingFactors(subsampling) : std::make_tuple(1, 1);
+}
+
int SkYUVAInfo::PlaneDimensions(SkISize imageDimensions,
PlaneConfig planeConfig,
Subsampling subsampling,
@@ -310,13 +358,11 @@
}
SkYUVAInfo SkYUVAInfo::makeSubsampling(SkYUVAInfo::Subsampling subsampling) const {
- return {fDimensions,
- fPlaneConfig,
- subsampling,
- fYUVColorSpace,
- fOrigin,
- fSitingX,
- fSitingY};
+ return {fDimensions, fPlaneConfig, subsampling, fYUVColorSpace, fOrigin, fSitingX, fSitingY};
+}
+
+SkYUVAInfo SkYUVAInfo::makeDimensions(SkISize dimensions) const {
+ return {dimensions, fPlaneConfig, fSubsampling, fYUVColorSpace, fOrigin, fSitingX, fSitingY};
}
bool SkYUVAInfo::operator==(const SkYUVAInfo& that) const {
diff --git a/src/gpu/GrImageTextureMaker.cpp b/src/gpu/GrImageTextureMaker.cpp
index d8a4e71..2934e30 100644
--- a/src/gpu/GrImageTextureMaker.cpp
+++ b/src/gpu/GrImageTextureMaker.cpp
@@ -77,12 +77,16 @@
}
const auto& caps = *fImage->context()->priv().caps();
- auto fp = GrYUVtoRGBEffect::Make(fImage->fViews, fImage->fYUVALocations, fImage->fYUVColorSpace,
- samplerState, caps, textureMatrix, subset, domain);
+ auto fp = GrYUVtoRGBEffect::Make(fImage->fYUVAProxies,
+ samplerState,
+ caps,
+ textureMatrix,
+ subset,
+ domain);
if (fImage->fFromColorSpace) {
- fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->fFromColorSpace.get(),
- fImage->alphaType(), fImage->colorSpace(),
- kPremul_SkAlphaType);
+ fp = GrColorSpaceXformEffect::Make(std::move(fp),
+ fImage->fFromColorSpace.get(), fImage->alphaType(),
+ fImage->colorSpace(), kPremul_SkAlphaType);
}
return fp;
}
@@ -96,12 +100,12 @@
SkImage::CubicResampler kernel) {
const auto& caps = *fImage->context()->priv().caps();
GrSamplerState samplerState(wrapX, wrapY, GrSamplerState::Filter::kNearest);
- auto fp = GrYUVtoRGBEffect::Make(fImage->fViews, fImage->fYUVALocations, fImage->fYUVColorSpace,
- samplerState, caps, SkMatrix::I(), subset, domain);
+ auto fp = GrYUVtoRGBEffect::Make(fImage->fYUVAProxies, samplerState, caps, SkMatrix::I(),
+ subset, domain);
fp = GrBicubicEffect::Make(std::move(fp),
fImage->alphaType(),
textureMatrix,
- kernel /*GrBicubicEffect::gMitchell*/,
+ kernel,
GrBicubicEffect::Direction::kXY);
if (fImage->fFromColorSpace) {
fp = GrColorSpaceXformEffect::Make(std::move(fp),
diff --git a/src/gpu/GrYUVATextureProxies.cpp b/src/gpu/GrYUVATextureProxies.cpp
new file mode 100644
index 0000000..4715a0f
--- /dev/null
+++ b/src/gpu/GrYUVATextureProxies.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 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/GrYUVATextureProxies.h"
+
+#ifdef SK_DEBUG
+static int num_channels(uint32_t channelFlags) {
+ switch (channelFlags) {
+ case kRed_SkColorChannelFlag : return 1;
+ case kAlpha_SkColorChannelFlag : return 1;
+ case kGray_SkColorChannelFlag : return 1;
+ case kGrayAlpha_SkColorChannelFlags : return 2;
+ case kRG_SkColorChannelFlags : return 2;
+ case kRGB_SkColorChannelFlags : return 3;
+ case kRGBA_SkColorChannelFlags : return 4;
+
+ default:
+ SkDEBUGFAILF("Unexpected channel combination 0x%08x", channelFlags);
+ return 0;
+ }
+}
+#endif
+
+GrYUVATextureProxies::GrYUVATextureProxies(const SkYUVAInfo& yuvaInfo,
+ sk_sp<GrSurfaceProxy> proxies[SkYUVAInfo::kMaxPlanes],
+ GrSurfaceOrigin textureOrigin)
+ : fYUVAInfo(yuvaInfo), fTextureOrigin(textureOrigin) {
+ int n = yuvaInfo.numPlanes();
+ if (n == 0) {
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+ uint32_t textureChannelMasks[SkYUVAInfo::kMaxPlanes];
+ for (int i = 0; i < n; ++i) {
+ if (!proxies[i]) {
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+ textureChannelMasks[i] = proxies[i]->backendFormat().channelMask();
+ }
+ fYUVALocations = yuvaInfo.toYUVALocations(textureChannelMasks);
+ if (fYUVALocations[0].fPlane < 0) {
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+ fMipmapped = GrMipmapped::kYes;
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
+ if (!proxies[i]) {
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+ SkASSERT(proxies[i]->asTextureProxy());
+ if (proxies[i]->asTextureProxy()->mipmapped() == GrMipmapped::kNo) {
+ fMipmapped = GrMipmapped::kNo;
+ }
+ fProxies[i] = std::move(proxies[i]);
+ }
+ SkASSERT(this->isValid());
+}
+
+GrYUVATextureProxies::GrYUVATextureProxies(const SkYUVAInfo& yuvaInfo,
+ GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes],
+ GrColorType colorTypes[SkYUVAInfo::kMaxPlanes])
+ : fYUVAInfo(yuvaInfo) {
+ uint32_t pixmapChannelMasks[SkYUVAInfo::kMaxPlanes];
+ int n = yuvaInfo.numPlanes();
+ if (n == 0) {
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+ fMipmapped = GrMipmapped::kYes;
+ for (int i = 0; i < n; ++i) {
+ pixmapChannelMasks[i] = GrColorTypeChannelFlags(colorTypes[i]);
+ SkASSERT(num_channels(pixmapChannelMasks[i]) <=
+ num_channels(views[i].proxy()->backendFormat().channelMask()));
+ if (!views[i] || views[i].origin() != views[0].origin()) {
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+ if (views[i].proxy()->asTextureProxy()->mipmapped() == GrMipmapped::kNo) {
+ fMipmapped = GrMipmapped::kNo;
+ }
+ }
+ // Initial locations refer to the CPU pixmap channels.
+ fYUVALocations = yuvaInfo.toYUVALocations(pixmapChannelMasks);
+ if (fYUVALocations[0].fPlane < 0) {
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+
+ // Run each location through the proxy view's swizzle to get the actual texture format channel.
+ for (int i = 0; i < SkYUVAInfo::kYUVAChannelCount; ++i) {
+ int plane = fYUVALocations[i].fPlane;
+ if (plane >= 0) {
+ int chanAsIdx = static_cast<int>(fYUVALocations[i].fChannel);
+ switch (views[plane].swizzle()[chanAsIdx]) {
+ case 'r': fYUVALocations[i].fChannel = SkColorChannel::kR; break;
+ case 'g': fYUVALocations[i].fChannel = SkColorChannel::kG; break;
+ case 'b': fYUVALocations[i].fChannel = SkColorChannel::kB; break;
+ case 'a': fYUVALocations[i].fChannel = SkColorChannel::kA; break;
+
+ default:
+ SkDEBUGFAILF("Unexpected swizzle value: %c", views[i].swizzle()[chanAsIdx]);
+ *this = {};
+ SkASSERT(!this->isValid());
+ return;
+ }
+ }
+ }
+ for (int i = 0; i < n; ++i) {
+ fProxies[i] = views[i].detachProxy();
+ }
+ fTextureOrigin = views[0].origin();
+ SkASSERT(this->isValid());
+}
diff --git a/src/gpu/GrYUVATextureProxies.h b/src/gpu/GrYUVATextureProxies.h
new file mode 100644
index 0000000..c6c4a68
--- /dev/null
+++ b/src/gpu/GrYUVATextureProxies.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrYUVATextureProxies_DEFINED
+#define GrYUVATextureProxies_DEFINED
+
+#include "include/core/SkYUVAInfo.h"
+#include "src/core/SkYUVAInfoLocation.h"
+#include "src/gpu/GrSurfaceProxy.h"
+#include "src/gpu/GrSurfaceProxyView.h"
+
+class GrSurfaceProxyView;
+
+class GrYUVATextureProxies {
+public:
+ GrYUVATextureProxies() = default;
+
+ /** Assumes all planes are sampled with a default "rgba" swizzle. */
+ GrYUVATextureProxies(const SkYUVAInfo&,
+ sk_sp<GrSurfaceProxy>[SkYUVAInfo::kMaxPlanes],
+ GrSurfaceOrigin textureOrigin);
+
+ /**
+ * When uploading pixmaps to textures it is important that we account for how the original
+ * pixmaps' channels are swizzled into the texture during upload. This will compute a swizzle
+ * for each texture based on the original color types and the views' swizzles. The views must
+ * all have the same origin or the result will be an invalid GrYUVATextureProxies.
+ */
+ GrYUVATextureProxies(const SkYUVAInfo&,
+ GrSurfaceProxyView[SkYUVAInfo::kMaxPlanes],
+ GrColorType[SkYUVAInfo::kMaxPlanes]);
+
+ GrYUVATextureProxies(const GrYUVATextureProxies&) = default;
+ GrYUVATextureProxies(GrYUVATextureProxies&&) = default;
+
+ GrYUVATextureProxies& operator=(const GrYUVATextureProxies&) = default;
+ GrYUVATextureProxies& operator=(GrYUVATextureProxies&&) = default;
+
+ const SkYUVAInfo& yuvaInfo() const { return fYUVAInfo; }
+
+ int numPlanes() const { return fYUVAInfo.numPlanes(); }
+
+ GrSurfaceOrigin textureOrigin() const { return fTextureOrigin; }
+
+ // Overall set of YUVA proxies is mip mapped if each plane is mip mapped.
+ GrMipmapped mipmapped() const { return fMipmapped; }
+
+ GrSurfaceProxy* proxy(int i) const { return fProxies[i].get(); }
+
+ const std::array<sk_sp<GrSurfaceProxy>, SkYUVAInfo::kMaxPlanes>& proxies() const {
+ return fProxies;
+ }
+
+ sk_sp<GrSurfaceProxy> refProxy(int i) const { return fProxies[i]; }
+
+ GrSurfaceProxyView makeView(int i) const {
+ return {fProxies[i], fTextureOrigin, GrSwizzle::RGBA()};
+ }
+
+ bool isValid() const { return fYUVAInfo.isValid(); }
+
+ const SkYUVAInfo::YUVALocations& yuvaLocations() const { return fYUVALocations; }
+
+private:
+ std::array<sk_sp<GrSurfaceProxy>, SkYUVAInfo::kMaxPlanes> fProxies;
+ SkYUVAInfo fYUVAInfo;
+ GrSurfaceOrigin fTextureOrigin = kTopLeft_GrSurfaceOrigin;
+ GrMipmapped fMipmapped = GrMipmapped::kNo;
+ SkYUVAInfo::YUVALocations fYUVALocations = {};
+};
+
+#endif
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index a8f516e..45361d4 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -7,8 +7,10 @@
#include "src/gpu/effects/GrYUVtoRGBEffect.h"
+#include "include/core/SkYUVAInfo.h"
#include "src/core/SkYUVMath.h"
#include "src/gpu/GrTexture.h"
+#include "src/gpu/GrYUVATextureProxies.h"
#include "src/gpu/effects/GrMatrixEffect.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
@@ -16,88 +18,82 @@
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
-static void border_colors(SkYUVColorSpace cs,
- const SkYUVAInfo::YUVALocations& locations,
- float planeBorders[4][4]) {
+static void border_colors(const GrYUVATextureProxies& yuvaProxies, float planeBorders[4][4]) {
float m[20];
- SkColorMatrix_RGB2YUV(cs, m);
- int i = 0;
- for (auto [plane, channel] : locations) {
+ SkColorMatrix_RGB2YUV(yuvaProxies.yuvaInfo().yuvColorSpace(), m);
+ for (int i = 0; i < SkYUVAInfo::kYUVAChannelCount; ++i) {
+ auto [plane, channel] = yuvaProxies.yuvaLocations()[i];
if (plane == -1) {
- continue;
+ return;
}
auto c = static_cast<int>(channel);
planeBorders[plane][c] = m[i*5 + 4];
- ++i;
}
}
-std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(
- GrSurfaceProxyView views[],
- const SkYUVAInfo::YUVALocations& locations,
- SkYUVColorSpace yuvColorSpace,
- GrSamplerState samplerState,
- const GrCaps& caps,
- const SkMatrix& localMatrix,
- const SkRect* subset,
- const SkRect* domain) {
- int numPlanes;
- SkAssertResult(SkYUVAInfo::YUVALocation::AreValidLocations(locations, &numPlanes));
-
- const SkISize yDimensions =
- views[locations[SkYUVAInfo::YUVAChannels::kY].fPlane].proxy()->dimensions();
+std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const GrYUVATextureProxies& yuvaProxies,
+ GrSamplerState samplerState,
+ const GrCaps& caps,
+ const SkMatrix& localMatrix,
+ const SkRect* subset,
+ const SkRect* domain) {
+ int numPlanes = yuvaProxies.yuvaInfo().numPlanes();
+ if (!yuvaProxies.isValid()) {
+ return nullptr;
+ }
bool usesBorder = samplerState.wrapModeX() == GrSamplerState::WrapMode::kClampToBorder ||
samplerState.wrapModeY() == GrSamplerState::WrapMode::kClampToBorder;
float planeBorders[4][4] = {};
if (usesBorder) {
- border_colors(yuvColorSpace, locations, planeBorders);
+ border_colors(yuvaProxies, planeBorders);
}
bool snap[2] = {false, false};
- std::unique_ptr<GrFragmentProcessor> planeFPs[4];
+ std::unique_ptr<GrFragmentProcessor> planeFPs[SkYUVAInfo::kMaxPlanes];
for (int i = 0; i < numPlanes; ++i) {
- SkISize dimensions = views[i].proxy()->dimensions();
- SkTCopyOnFirstWrite<SkMatrix> planeMatrix(&SkMatrix::I());
+ GrSurfaceProxyView view = yuvaProxies.makeView(i);
+ SkMatrix planeMatrix = yuvaProxies.yuvaInfo().originMatrix();
+ // The returned matrix is a view matrix but we need a local matrix.
+ SkAssertResult(planeMatrix.invert(&planeMatrix));
SkRect planeSubset;
SkRect planeDomain;
bool makeLinearWithSnap = false;
- float sx = 1.f,
- sy = 1.f;
- if (dimensions != yDimensions) {
+ auto [ssx, ssy] = yuvaProxies.yuvaInfo().planeSubsamplingFactors(i);
+ SkASSERT(ssx > 0 && ssx <= 4);
+ SkASSERT(ssy > 0 && ssy <= 2);
+ float scaleX = 1.f;
+ float scaleY = 1.f;
+ if (ssx > 1 || ssy > 1) {
// JPEG chroma subsampling of odd dimensions produces U and V planes with the ceiling of
// the image size divided by the subsampling factor (2). Our API for creating YUVA
// doesn't capture the intended subsampling (and we should fix that). This fixes up 2x
// subsampling for images with odd widths/heights (e.g. JPEG 420 or 422).
- sx = (float)dimensions.width() / yDimensions.width();
- sy = (float)dimensions.height() / yDimensions.height();
- if ((yDimensions.width() & 0b1) && dimensions.width() == yDimensions.width() / 2 + 1) {
- sx = 0.5f;
- }
- if ((yDimensions.height() & 0b1) &&
- dimensions.height() == yDimensions.height() / 2 + 1) {
- sy = 0.5f;
- }
- *planeMatrix.writable() = SkMatrix::Scale(sx, sy);
+ scaleX = 1.f/ssx;
+ scaleY = 1.f/ssy;
+ // We would want to add a translation to this matrix to handle other sitings.
+ SkASSERT(yuvaProxies.yuvaInfo().sitingX() == SkYUVAInfo::Siting::kCentered);
+ SkASSERT(yuvaProxies.yuvaInfo().sitingY() == SkYUVAInfo::Siting::kCentered);
+ planeMatrix.postConcat(SkMatrix::Scale(scaleX, scaleY));
if (subset) {
- planeSubset = {subset->fLeft * sx,
- subset->fTop * sy,
- subset->fRight * sx,
- subset->fBottom * sy};
+ planeSubset = {subset->fLeft *scaleX,
+ subset->fTop *scaleY,
+ subset->fRight *scaleX,
+ subset->fBottom*scaleY};
}
if (domain) {
- planeDomain = {domain->fLeft * sx,
- domain->fTop * sy,
- domain->fRight * sx,
- domain->fBottom * sy};
+ planeDomain = {domain->fLeft *scaleX,
+ domain->fTop *scaleY,
+ domain->fRight *scaleX,
+ domain->fBottom*scaleY};
}
// This promotion of nearest to linear filtering for UV planes exists to mimic
// libjpeg[-turbo]'s do_fancy_upsampling option. We will filter the subsampled plane,
// however we want to filter at a fixed point for each logical image pixel to simulate
// nearest neighbor.
if (samplerState.filter() == GrSamplerState::Filter::kNearest) {
- bool snapX = (sx != 1.f),
- snapY = (sy != 1.f);
+ bool snapX = (ssx != 1),
+ snapY = (ssy != 1);
makeLinearWithSnap = snapX || snapY;
snap[0] |= snapX;
snap[1] |= snapY;
@@ -131,30 +127,53 @@
// planeSubset but allows linear filtering to read pixels from the plane that are
// just outside planeSubset.
SkRect* domainRect = domain ? &planeDomain : nullptr;
- planeFPs[i] = GrTextureEffect::MakeCustomLinearFilterInset(
- views[i], kUnknown_SkAlphaType, *planeMatrix, samplerState.wrapModeX(),
- samplerState.wrapModeY(), planeSubset, domainRect, {sx / 2.f, sy / 2.f},
- caps, planeBorders[i]);
+ planeFPs[i] = GrTextureEffect::MakeCustomLinearFilterInset(std::move(view),
+ kUnknown_SkAlphaType,
+ planeMatrix,
+ samplerState.wrapModeX(),
+ samplerState.wrapModeY(),
+ planeSubset,
+ domainRect,
+ {scaleX/2.f, scaleY/2.f},
+ caps,
+ planeBorders[i]);
} else if (domain) {
- planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType,
- *planeMatrix, samplerState, planeSubset,
- planeDomain, caps, planeBorders[i]);
+ planeFPs[i] = GrTextureEffect::MakeSubset(std::move(view),
+ kUnknown_SkAlphaType,
+ planeMatrix,
+ samplerState,
+ planeSubset,
+ planeDomain,
+ caps,
+ planeBorders[i]);
} else {
- planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType,
- *planeMatrix, samplerState, planeSubset,
- caps, planeBorders[i]);
+ planeFPs[i] = GrTextureEffect::MakeSubset(std::move(view),
+ kUnknown_SkAlphaType,
+ planeMatrix,
+ samplerState,
+ planeSubset,
+ caps,
+ planeBorders[i]);
}
} else {
GrSamplerState planeSampler = samplerState;
if (makeLinearWithSnap) {
planeSampler.setFilterMode(GrSamplerState::Filter::kLinear);
}
- planeFPs[i] = GrTextureEffect::Make(views[i], kUnknown_SkAlphaType, *planeMatrix,
- planeSampler, caps, planeBorders[i]);
+ planeFPs[i] = GrTextureEffect::Make(std::move(view),
+ kUnknown_SkAlphaType,
+ planeMatrix,
+ planeSampler,
+ caps,
+ planeBorders[i]);
}
}
- auto fp = std::unique_ptr<GrFragmentProcessor>(
- new GrYUVtoRGBEffect(planeFPs, numPlanes, locations, snap, yuvColorSpace));
+ std::unique_ptr<GrFragmentProcessor> fp(
+ new GrYUVtoRGBEffect(planeFPs,
+ numPlanes,
+ yuvaProxies.yuvaLocations(),
+ snap,
+ yuvaProxies.yuvaInfo().yuvColorSpace()));
return GrMatrixEffect::Make(localMatrix, std::move(fp));
}
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.h b/src/gpu/effects/GrYUVtoRGBEffect.h
index 3f1d090..92a8bf3 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.h
+++ b/src/gpu/effects/GrYUVtoRGBEffect.h
@@ -12,11 +12,11 @@
#include "src/core/SkYUVAInfoLocation.h"
#include "src/gpu/GrFragmentProcessor.h"
+class GrYUVATextureProxies;
+
class GrYUVtoRGBEffect : public GrFragmentProcessor {
public:
- static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView views[],
- const SkYUVAInfo::YUVALocations&,
- SkYUVColorSpace yuvColorSpace,
+ static std::unique_ptr<GrFragmentProcessor> Make(const GrYUVATextureProxies& yuvaProxies,
GrSamplerState samplerState,
const GrCaps&,
const SkMatrix& localMatrix = SkMatrix::I(),
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index ffe40bc..483949e 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -39,6 +39,7 @@
#include "src/gpu/GrTextureAdjuster.h"
#include "src/gpu/GrTextureProxy.h"
#include "src/gpu/GrTextureProxyPriv.h"
+#include "src/gpu/GrYUVATextureProxies.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/gl/GrGLTexture.h"
diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp
index a528f84..90172a2 100644
--- a/src/image/SkImage_GpuBase.cpp
+++ b/src/image/SkImage_GpuBase.cpp
@@ -12,6 +12,7 @@
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/GrRecordingContext.h"
+#include "include/gpu/GrYUVABackendTextures.h"
#include "src/core/SkBitmapCache.h"
#include "src/core/SkTLList.h"
#include "src/gpu/GrDirectContextPriv.h"
@@ -22,6 +23,7 @@
#include "src/gpu/GrSurfaceDrawContext.h"
#include "src/gpu/GrTexture.h"
#include "src/gpu/GrTextureAdjuster.h"
+#include "src/gpu/GrYUVATextureProxies.h"
#include "src/gpu/effects/GrYUVtoRGBEffect.h"
#include "src/image/SkImage_Gpu.h"
#include "src/image/SkReadPixelsRec.h"
diff --git a/src/image/SkImage_GpuBase.h b/src/image/SkImage_GpuBase.h
index ed68a7c..ad6c8b6 100644
--- a/src/image/SkImage_GpuBase.h
+++ b/src/image/SkImage_GpuBase.h
@@ -60,11 +60,6 @@
static bool ValidateCompressedBackendTexture(const GrCaps*, const GrBackendTexture& tex,
SkAlphaType);
- static SkAlphaType GetAlphaTypeFromYUVALocations(const SkYUVAInfo::YUVALocations locations) {
- return locations[SkYUVAInfo::YUVAChannels::kA].fPlane >= 0 ? kPremul_SkAlphaType
- : kOpaque_SkAlphaType;
- }
-
using PromiseImageTextureContext = SkDeferredDisplayListRecorder::PromiseImageTextureContext;
using PromiseImageTextureFulfillProc =
SkDeferredDisplayListRecorder::PromiseImageTextureFulfillProc;
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index e38fd34..9a91ba3 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -34,33 +34,21 @@
static constexpr auto kAssumedColorType = kRGBA_8888_SkColorType;
SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrImageContext> context,
- SkISize size,
uint32_t uniqueID,
- SkYUVColorSpace colorSpace,
- GrSurfaceProxyView views[],
- int numViews,
- const SkYUVAInfo::YUVALocations& yuvaLocations,
+ GrYUVATextureProxies proxies,
sk_sp<SkColorSpace> imageColorSpace)
: INHERITED(std::move(context),
- size,
+ proxies.yuvaInfo().dimensions(),
uniqueID,
kAssumedColorType,
- // If an alpha channel is present we always switch to kPremul. This is because,
+ // If an alpha channel is present we always use kPremul. This is because,
// although the planar data is always un-premul, the final interleaved RGB image
// is/would-be premul.
- GetAlphaTypeFromYUVALocations(yuvaLocations),
+ proxies.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType : kOpaque_SkAlphaType,
std::move(imageColorSpace))
- , fNumViews(numViews)
- , fYUVALocations(yuvaLocations)
- , fYUVColorSpace(colorSpace) {
- // The caller should have done this work, just verifying
- SkDEBUGCODE(int textureCount;)
- SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(fYUVALocations, &textureCount));
- SkASSERT(textureCount == fNumViews);
-
- for (int i = 0; i < numViews; ++i) {
- fViews[i] = std::move(views[i]);
- }
+ , fYUVAProxies(std::move(proxies)) {
+ // The caller should have checked this, just verifying.
+ SkASSERT(fYUVAProxies.isValid());
}
// For onMakeColorSpace()
@@ -71,55 +59,46 @@
image->dimensions(),
kNeedNewImageUniqueID,
kAssumedColorType,
- // If an alpha channel is present we always switch to kPremul. This is because,
- // although the planar data is always un-premul, the final interleaved RGB image
- // is/would-be premul.
- GetAlphaTypeFromYUVALocations(image->fYUVALocations),
+ image->alphaType(),
std::move(targetCS))
- , fNumViews(image->fNumViews)
- , fYUVALocations(image->fYUVALocations)
- , fYUVColorSpace(image->fYUVColorSpace)
+ , fYUVAProxies(image->fYUVAProxies)
+ , fRGBView(image->fRGBView)
// Since null fFromColorSpace means no GrColorSpaceXform, we turn a null
// image->refColorSpace() into an explicit SRGB.
, fFromColorSpace(image->colorSpace() ? image->refColorSpace() : SkColorSpace::MakeSRGB()) {
- // The caller should have done this work, just verifying
- SkDEBUGCODE(int textureCount;)
- SkASSERT(SkYUVAInfo::YUVALocation::AreValidLocations(image->fYUVALocations, &textureCount));
- SkASSERT(textureCount == fNumViews);
-
- if (image->fRGBView.proxy()) {
- fRGBView = image->fRGBView; // we ref in this case, not move
- } else {
- for (int i = 0; i < fNumViews; ++i) {
- fViews[i] = image->fViews[i]; // we ref in this case, not move
- }
- }
+ // We should either have a RGB proxy *or* a set of YUVA proxies.
+ SkASSERT(fYUVAProxies.isValid() != SkToBool(image->fRGBView));
}
bool SkImage_GpuYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const {
// We shouldn't get here if the planes were already flattened to RGBA.
- SkASSERT(fViews[0].proxy() && !fRGBView.proxy());
+ SkASSERT(fYUVAProxies.isValid() && !fRGBView);
if (!context || !fContext->priv().matches(context)) {
return false;
}
- GrSurfaceProxyView newViews[4];
if (!context->priv().caps()->mipmapSupport()) {
// We succeed in this case by doing nothing.
return true;
}
- for (int i = 0; i < fNumViews; ++i) {
- auto* t = fViews[i].asTextureProxy();
+ int n = fYUVAProxies.yuvaInfo().numPlanes();
+ sk_sp<GrSurfaceProxy> newProxies[4];
+ for (int i = 0; i < n; ++i) {
+ auto* t = fYUVAProxies.proxy(i)->asTextureProxy();
if (t->mipmapped() == GrMipmapped::kNo && (t->width() > 1 || t->height() > 1)) {
- if (!(newViews[i] = GrCopyBaseMipMapToView(context, fViews[i]))) {
+ auto newView = GrCopyBaseMipMapToView(context, fYUVAProxies.makeView(i));
+ if (!newView) {
return false;
}
+ SkASSERT(newView.swizzle() == fYUVAProxies.makeView(i).swizzle());
+ newProxies[i] = newView.detachProxy();
} else {
- newViews[i] = fViews[i];
+ newProxies[i] = fYUVAProxies.refProxy(i);
}
}
- for (int i = 0; i < fNumViews; ++i) {
- fViews[i] = std::move(newViews[i]);
- }
+ fYUVAProxies = GrYUVATextureProxies(fYUVAProxies.yuvaInfo(),
+ newProxies,
+ fYUVAProxies.textureOrigin());
+ SkASSERT(fYUVAProxies.isValid());
return true;
}
@@ -136,15 +115,19 @@
return GrSemaphoresSubmitted::kNo;
}
- GrSurfaceProxy* proxies[4] = {fViews[0].proxy(), fViews[1].proxy(), fViews[2].proxy(),
- fViews[3].proxy()};
- size_t numProxies = fNumViews;
- if (fRGBView.proxy()) {
+ GrSurfaceProxy* proxies[SkYUVAInfo::kMaxPlanes] = {};
+ size_t numProxies;
+ if (fRGBView) {
// Either we've already flushed the flattening draw or the flattening is unflushed. In the
// latter case it should still be ok to just pass fRGBView proxy because it in turn depends
// on the planar proxies and will cause all of their work to flush as well.
proxies[0] = fRGBView.proxy();
numProxies = 1;
+ } else {
+ numProxies = fYUVAProxies.numPlanes();
+ for (size_t i = 0; i < numProxies; ++i) {
+ proxies[i] = fYUVAProxies.proxy(i);
+ }
}
return dContext->priv().flushSurfaces({proxies, numProxies},
SkSurface::BackendSurfaceAccess::kNoAccess,
@@ -153,49 +136,6 @@
GrTextureProxy* SkImage_GpuYUVA::peekProxy() const { return fRGBView.asTextureProxy(); }
-bool SkImage_GpuYUVA::MakeTempTextureProxies(GrRecordingContext* rContext,
- const GrBackendTexture yuvaTextures[],
- int numTextures,
- const SkYUVAInfo::YUVALocations& yuvaLocations,
- GrSurfaceOrigin imageOrigin,
- GrSurfaceProxyView tempViews[4],
- sk_sp<GrRefCntedCallback> releaseHelper) {
- GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
- for (int textureIndex = 0; textureIndex < numTextures; ++textureIndex) {
- const GrBackendFormat& backendFormat = yuvaTextures[textureIndex].getBackendFormat();
- if (!backendFormat.isValid()) {
- return false;
- }
-
- SkASSERT(yuvaTextures[textureIndex].isValid());
-
- auto proxy = proxyProvider->wrapBackendTexture(yuvaTextures[textureIndex],
- kBorrow_GrWrapOwnership,
- GrWrapCacheable::kNo,
- kRead_GrIOType,
- releaseHelper);
- if (!proxy) {
- return false;
- }
- tempViews[textureIndex] =
- GrSurfaceProxyView(std::move(proxy), imageOrigin, GrSwizzle("rgba"));
-#ifdef SK_DEBUG
- // Check that each texture contains the channel data for the corresponding YUVA location
- auto formatChannelMask = backendFormat.channelMask();
- if (formatChannelMask & kGray_SkColorChannelFlag) {
- formatChannelMask |= kRGB_SkColorChannelFlags;
- }
- for (int i = 0; i < SkYUVAInfo::kYUVAChannelCount; ++i) {
- if (yuvaLocations[i].fPlane == textureIndex) {
- uint32_t channelAsMask = 1 << static_cast<int>(yuvaLocations[i].fChannel);
- SkASSERT(channelAsMask & formatChannelMask);
- }
- }
-#endif
- }
- return true;
-}
-
void SkImage_GpuYUVA::flattenToRGB(GrRecordingContext* context) const {
if (fRGBView.proxy()) {
return;
@@ -222,23 +162,18 @@
const GrCaps& caps = *context->priv().caps();
- auto fp = GrYUVtoRGBEffect::Make(
- fViews, fYUVALocations, fYUVColorSpace, GrSamplerState::Filter::kNearest, caps);
+ auto fp = GrYUVtoRGBEffect::Make(fYUVAProxies, GrSamplerState::Filter::kNearest, caps);
if (fFromColorSpace) {
- auto colorSpaceXform = GrColorSpaceXform::Make(fFromColorSpace.get(),
- this->alphaType(),
- this->colorSpace(),
- this->alphaType());
- fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(colorSpaceXform));
+ fp = GrColorSpaceXformEffect::Make(std::move(fp),
+ fFromColorSpace.get(), this->alphaType(),
+ this->colorSpace(), this->alphaType());
}
surfaceFillContext->fillWithFP(std::move(fp));
fRGBView = surfaceFillContext->readSurfaceView();
SkASSERT(fRGBView.swizzle() == GrSwizzle());
- for (auto& v : fViews) {
- v.reset();
- }
+ fYUVAProxies = {};
}
GrSurfaceProxyView SkImage_GpuYUVA::refMippedView(GrRecordingContext* context) const {
@@ -286,9 +221,7 @@
}
sk_sp<SkImage> SkImage_GpuYUVA::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
- return sk_make_sp<SkImage_GpuYUVA>(fContext, this->dimensions(), kNeedNewImageUniqueID,
- fYUVColorSpace, fViews, fNumViews, fYUVALocations,
- std::move(newCS));
+ return sk_sp<SkImage>(new SkImage_GpuYUVA(fContext, this, std::move(newCS)));
}
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -300,32 +233,36 @@
ReleaseContext releaseContext) {
auto releaseHelper = GrRefCntedCallback::Make(textureReleaseProc, releaseContext);
- SkYUVAInfo::YUVALocations yuvaLocations = yuvaTextures.toYUVALocations();
+ GrProxyProvider* proxyProvider = context->priv().proxyProvider();
+ int numPlanes = yuvaTextures.yuvaInfo().numPlanes();
+ sk_sp<GrSurfaceProxy> proxies[SkYUVAInfo::kMaxPlanes];
+ for (int plane = 0; plane < numPlanes; ++plane) {
+ proxies[plane] = proxyProvider->wrapBackendTexture(yuvaTextures.texture(plane),
+ kBorrow_GrWrapOwnership,
+ GrWrapCacheable::kNo,
+ kRead_GrIOType,
+ releaseHelper);
+ if (!proxies[plane]) {
+ return {};
+ }
+ }
+ GrYUVATextureProxies yuvaProxies(yuvaTextures.yuvaInfo(),
+ proxies,
+ yuvaTextures.textureOrigin());
- GrSurfaceProxyView tempViews[4];
- if (!SkImage_GpuYUVA::MakeTempTextureProxies(context,
- yuvaTextures.textures().data(),
- yuvaTextures.numPlanes(),
- yuvaLocations,
- yuvaTextures.textureOrigin(),
- tempViews,
- std::move(releaseHelper))) {
+ if (!yuvaProxies.isValid()) {
return nullptr;
}
return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context),
- yuvaTextures.yuvaInfo().dimensions(),
kNeedNewImageUniqueID,
- yuvaTextures.yuvaInfo().yuvColorSpace(),
- tempViews,
- yuvaTextures.numPlanes(),
- yuvaLocations,
+ yuvaProxies,
imageColorSpace);
}
sk_sp<SkImage> SkImage::MakeFromYUVAPixmaps(GrRecordingContext* context,
const SkYUVAPixmaps& pixmaps,
- GrMipMapped buildMips,
+ GrMipmapped buildMips,
bool limitToMaxTextureSize,
sk_sp<SkColorSpace> imageColorSpace) {
if (!context) {
@@ -336,8 +273,6 @@
return nullptr;
}
- SkYUVAInfo::YUVALocations yuvaLocations = pixmaps.toYUVALocations();
-
// SkImage_GpuYUVA doesn't yet support different encoded origins.
if (pixmaps.yuvaInfo().origin() != kTopLeft_SkEncodedOrigin) {
return nullptr;
@@ -347,45 +282,58 @@
buildMips = GrMipMapped::kNo;
}
- // Make proxies
- GrSurfaceProxyView tempViews[4];
+ // Resize the pixmaps if necessary.
int numPlanes = pixmaps.numPlanes();
int maxTextureSize = context->priv().caps()->maxTextureSize();
- for (int i = 0; i < numPlanes; ++i) {
- const SkPixmap* pixmap = &pixmaps.plane(i);
- SkAutoPixmapStorage resized;
- int maxDim = std::max(pixmap->width(), pixmap->height());
- if (maxDim > maxTextureSize) {
- if (!limitToMaxTextureSize) {
- return nullptr;
- }
- float scale = static_cast<float>(maxTextureSize)/maxDim;
- int newWidth = std::min(static_cast<int>(pixmap->width() *scale), maxTextureSize);
- int newHeight = std::min(static_cast<int>(pixmap->height()*scale), maxTextureSize);
- SkImageInfo info = pixmap->info().makeWH(newWidth, newHeight);
- SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
- if (!resized.tryAlloc(info) || !pixmap->scalePixels(resized, sampling)) {
- return nullptr;
- }
- pixmap = &resized;
- }
- // Turn the pixmap into a GrTextureProxy
- SkBitmap bmp;
- bmp.installPixels(*pixmap);
- GrBitmapTextureMaker bitmapMaker(context, bmp, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
- tempViews[i] = bitmapMaker.view(buildMips);
- if (!tempViews[i]) {
+ int maxDim = std::max(pixmaps.yuvaInfo().width(), pixmaps.yuvaInfo().height());
+
+ SkYUVAPixmaps tempPixmaps;
+ const SkYUVAPixmaps* pixmapsToUpload = &pixmaps;
+ // We assume no plane is larger than the image size (and at least one plane is as big).
+ if (maxDim > maxTextureSize) {
+ if (!limitToMaxTextureSize) {
return nullptr;
}
+ float scale = static_cast<float>(maxTextureSize)/maxDim;
+ SkISize newDimensions = {
+ std::min(static_cast<int>(pixmaps.yuvaInfo().width() *scale), maxTextureSize),
+ std::min(static_cast<int>(pixmaps.yuvaInfo().height()*scale), maxTextureSize)
+ };
+ SkYUVAInfo newInfo = pixmaps.yuvaInfo().makeDimensions(newDimensions);
+ SkYUVAPixmapInfo newPixmapInfo(newInfo, pixmaps.dataType(), /*row bytes*/ nullptr);
+ tempPixmaps = SkYUVAPixmaps::Allocate(newPixmapInfo);
+ SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kNone);
+ if (!tempPixmaps.isValid()) {
+ return nullptr;
+ }
+ for (int i = 0; i < numPlanes; ++i) {
+ if (!pixmaps.plane(i).scalePixels(tempPixmaps.plane(i), sampling)) {
+ return nullptr;
+ }
+ }
+ pixmapsToUpload = &tempPixmaps;
}
+ // Convert to texture proxies.
+ GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
+ GrColorType pixmapColorTypes[SkYUVAInfo::kMaxPlanes];
+ for (int i = 0; i < numPlanes; ++i) {
+ // Turn the pixmap into a GrTextureProxy
+ SkBitmap bmp;
+ bmp.installPixels(pixmapsToUpload->plane(i));
+ GrBitmapTextureMaker bitmapMaker(context, bmp, GrImageTexGenPolicy::kNew_Uncached_Budgeted);
+ views[i] = bitmapMaker.view(buildMips);
+ if (!views[i]) {
+ return nullptr;
+ }
+ pixmapColorTypes[i] = SkColorTypeToGrColorType(bmp.colorType());
+ }
+
+ GrYUVATextureProxies yuvaProxies(pixmapsToUpload->yuvaInfo(), views, pixmapColorTypes);
+ SkASSERT(yuvaProxies.isValid());
return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context),
- pixmaps.yuvaInfo().dimensions(),
kNeedNewImageUniqueID,
- pixmaps.yuvaInfo().yuvColorSpace(),
- tempViews,
- numPlanes,
- yuvaLocations,
+ std::move(yuvaProxies),
std::move(imageColorSpace));
}
@@ -413,7 +361,6 @@
releaseHelpers[i] = GrRefCntedCallback::Make(textureReleaseProc, textureContexts[i]);
}
- SkYUVAInfo::YUVALocations yuvaLocations = yuvaBackendTextureInfo.toYUVALocations();
if (yuvaBackendTextureInfo.yuvaInfo().origin() != SkEncodedOrigin::kDefault_SkEncodedOrigin) {
// SkImage_GpuYUVA does not support this yet. This will get removed
// when the old APIs are gone and we only have to support YUVA configs described by
@@ -434,23 +381,24 @@
}
// Make a lazy proxy for each plane and wrap in a view.
- GrSurfaceProxyView views[4];
- for (int texIdx = 0; texIdx < n; ++texIdx) {
- auto proxy = MakePromiseImageLazyProxy(context,
- planeDimensions[texIdx],
- yuvaBackendTextureInfo.planeFormat(texIdx),
+ sk_sp<GrSurfaceProxy> proxies[4];
+ for (int i = 0; i < n; ++i) {
+ proxies[i] = MakePromiseImageLazyProxy(context,
+ planeDimensions[i],
+ yuvaBackendTextureInfo.planeFormat(i),
GrMipmapped::kNo,
textureFulfillProc,
- std::move(releaseHelpers[texIdx]));
- if (!proxy) {
+ std::move(releaseHelpers[i]));
+ if (!proxies[i]) {
return nullptr;
}
- views[texIdx] = GrSurfaceProxyView(std::move(proxy), yuvaBackendTextureInfo.textureOrigin(),
- GrSwizzle("rgba"));
}
-
- return sk_make_sp<SkImage_GpuYUVA>(
- sk_ref_sp(context), yuvaBackendTextureInfo.yuvaInfo().dimensions(),
- kNeedNewImageUniqueID, yuvaBackendTextureInfo.yuvColorSpace(), views, n, yuvaLocations,
- std::move(imageColorSpace));
+ GrYUVATextureProxies yuvaTextureProxies(yuvaBackendTextureInfo.yuvaInfo(),
+ proxies,
+ yuvaBackendTextureInfo.textureOrigin());
+ SkASSERT(yuvaTextureProxies.isValid());
+ return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context),
+ kNeedNewImageUniqueID,
+ std::move(yuvaTextureProxies),
+ std::move(imageColorSpace));
}
diff --git a/src/image/SkImage_GpuYUVA.h b/src/image/SkImage_GpuYUVA.h
index 2378e0e..ddaf2bb 100644
--- a/src/image/SkImage_GpuYUVA.h
+++ b/src/image/SkImage_GpuYUVA.h
@@ -10,13 +10,14 @@
#include "include/gpu/GrBackendSurface.h"
#include "src/core/SkCachedData.h"
+#include "src/gpu/GrYUVATextureProxies.h"
#include "src/image/SkImage_GpuBase.h"
class GrDirectContext;
class GrRecordingContext;
class GrTexture;
-// Wraps the 3 or 4 planes of a YUVA image for consumption by the GPU.
+// Wraps the 1 to 4 planes of a YUVA image for consumption by the GPU.
// Initially any direct rendering will be done by passing the individual planes to a shader.
// Once any method requests a flattened image (e.g., onReadPixels), the flattened RGB
// proxy will be stored and used for any future rendering.
@@ -25,12 +26,8 @@
friend class GrYUVAImageTextureMaker;
SkImage_GpuYUVA(sk_sp<GrImageContext>,
- SkISize size,
uint32_t uniqueID,
- SkYUVColorSpace,
- GrSurfaceProxyView views[],
- int numViews,
- const SkYUVAInfo::YUVALocations&,
+ GrYUVATextureProxies proxies,
sk_sp<SkColorSpace>);
GrSemaphoresSubmitted onFlush(GrDirectContext*, const GrFlushInfo&) override;
@@ -42,7 +39,8 @@
const GrSurfaceProxyView* view(GrRecordingContext* context) const override;
bool onIsTextureBacked() const override {
- SkASSERT(fViews[0].proxy() || fRGBView.proxy());
+ // We should have YUVA proxies or a RGBA proxy,but not both.
+ SkASSERT(fYUVAProxies.isValid() != SkToBool(fRGBView));
return true;
}
@@ -61,7 +59,7 @@
#if GR_TEST_UTILS
bool testingOnly_IsFlattened() const {
// We should only have the flattened proxy or the planar proxies at one point in time.
- SkASSERT(SkToBool(fRGBView.proxy()) != SkToBool(fViews[0].proxy()));
+ SkASSERT(SkToBool(fRGBView) != fYUVAProxies.isValid());
return SkToBool(fRGBView.proxy());
}
#endif
@@ -76,25 +74,17 @@
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContexts[]);
- static bool MakeTempTextureProxies(GrRecordingContext*,
- const GrBackendTexture yuvaTextures[],
- int numTextures,
- const SkYUVAInfo::YUVALocations&,
- GrSurfaceOrigin imageOrigin,
- GrSurfaceProxyView tempViews[4],
- sk_sp<GrRefCntedCallback> releaseHelper);
-
private:
SkImage_GpuYUVA(sk_sp<GrImageContext>, const SkImage_GpuYUVA* image, sk_sp<SkColorSpace>);
void flattenToRGB(GrRecordingContext*) const;
- // This array will usually only be sparsely populated.
- // The actual non-null fields are dictated by the 'fYUVAIndices' indices
- mutable GrSurfaceProxyView fViews[4];
- int fNumViews;
- SkYUVAInfo::YUVALocations fYUVALocations;
- const SkYUVColorSpace fYUVColorSpace;
+ mutable GrYUVATextureProxies fYUVAProxies;
+
+ // This is only allocated when the image needs to be flattened rather than
+ // using the separate YUVA planes. From thence forth we will only use the
+ // the RGBView.
+ mutable GrSurfaceProxyView fRGBView;
// If this is non-null then the planar data should be converted from fFromColorSpace to
// this->colorSpace(). Otherwise we assume the planar data (post YUV->RGB conversion) is already
@@ -106,10 +96,6 @@
mutable sk_sp<SkColorSpace> fOnMakeColorSpaceTarget;
mutable sk_sp<SkImage> fOnMakeColorSpaceResult;
- // This is only allocated when the image needs to be flattened rather than
- // using the separate YUVA planes. From thence forth we will only use the
- // the RGBView.
- mutable GrSurfaceProxyView fRGBView;
using INHERITED = SkImage_GpuBase;
};
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index b1582a8..37e3afd 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -30,7 +30,8 @@
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrSamplerState.h"
-#include "src/gpu/GrSurfaceDrawContext.h"
+#include "src/gpu/GrSurfaceFillContext.h"
+#include "src/gpu/GrYUVATextureProxies.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrYUVtoRGBEffect.h"
#endif
@@ -267,7 +268,8 @@
return {};
}
- GrSurfaceProxyView yuvViews[SkYUVAInfo::kMaxPlanes];
+ GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
+ GrColorType pixmapColorTypes[SkYUVAInfo::kMaxPlanes];
for (int i = 0; i < yuvaPixmaps.numPlanes(); ++i) {
// If the sizes of the components are not all the same we choose to create exact-match
// textures for the smaller ones rather than add a texture domain to the draw.
@@ -296,11 +298,12 @@
bitmap.setImmutable();
GrBitmapTextureMaker maker(ctx, bitmap, fit);
- yuvViews[i] = maker.view(GrMipmapped::kNo);
+ views[i] = maker.view(GrMipmapped::kNo);
- if (!yuvViews[i]) {
+ if (!views[i]) {
return {};
}
+ pixmapColorTypes[i] = SkColorTypeToGrColorType(bitmap.colorType());
}
// TODO: investigate preallocating mip maps here
@@ -320,12 +323,13 @@
return {};
}
- std::unique_ptr<GrFragmentProcessor> yuvToRgbProcessor =
- GrYUVtoRGBEffect::Make(yuvViews,
- yuvaPixmaps.toYUVALocations(),
- yuvaPixmaps.yuvaInfo().yuvColorSpace(),
- GrSamplerState::Filter::kNearest,
- *ctx->priv().caps());
+ GrYUVATextureProxies yuvaProxies(yuvaPixmaps.yuvaInfo(), views, pixmapColorTypes);
+ SkAssertResult(yuvaProxies.isValid());
+
+ std::unique_ptr<GrFragmentProcessor> fp = GrYUVtoRGBEffect::Make(
+ yuvaProxies,
+ GrSamplerState::Filter::kNearest,
+ *ctx->priv().caps());
// The pixels after yuv->rgb will be in the generator's color space.
// If onMakeColorTypeAndColorSpace has been called then this will not match this image's
@@ -340,18 +344,11 @@
// If the caller expects the pixels in a different color space than the one from the image,
// apply a color conversion to do this.
- std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
- GrColorSpaceXformEffect::Make(std::move(yuvToRgbProcessor),
- srcColorSpace, kOpaque_SkAlphaType,
- dstColorSpace, kOpaque_SkAlphaType);
- SkMatrix m = SkEncodedOriginToMatrix(yuvaPixmaps.yuvaInfo().origin(),
- this->width(),
- this->height());
- // The returned matrix is a view matrix but we need a local matrix.
- SkAssertResult(m.invert(&m));
- surfaceFillContext->fillWithFP(m, std::move(colorConversionProcessor));
+ fp = GrColorSpaceXformEffect::Make(std::move(fp),
+ srcColorSpace, kOpaque_SkAlphaType,
+ dstColorSpace, kOpaque_SkAlphaType);
+ surfaceFillContext->fillWithFP(std::move(fp));
- SkASSERT(surfaceFillContext->asTextureProxy());
return surfaceFillContext->readSurfaceView();
}