2018-10-03 16:12:26 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2018 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "gm/gm.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkBitmap.h"
|
|
|
|
#include "include/core/SkBlendMode.h"
|
|
|
|
#include "include/core/SkCanvas.h"
|
|
|
|
#include "include/core/SkColor.h"
|
|
|
|
#include "include/core/SkColorFilter.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkColorPriv.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkColorSpace.h"
|
|
|
|
#include "include/core/SkFont.h"
|
|
|
|
#include "include/core/SkFontStyle.h"
|
|
|
|
#include "include/core/SkFontTypes.h"
|
|
|
|
#include "include/core/SkImage.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkImageGenerator.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkImageInfo.h"
|
|
|
|
#include "include/core/SkMatrix.h"
|
|
|
|
#include "include/core/SkPaint.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkPath.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkPixmap.h"
|
|
|
|
#include "include/core/SkPoint.h"
|
|
|
|
#include "include/core/SkRect.h"
|
|
|
|
#include "include/core/SkRefCnt.h"
|
|
|
|
#include "include/core/SkScalar.h"
|
|
|
|
#include "include/core/SkSize.h"
|
|
|
|
#include "include/core/SkString.h"
|
|
|
|
#include "include/core/SkTypeface.h"
|
|
|
|
#include "include/core/SkTypes.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/gpu/GrBackendSurface.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/gpu/GrConfig.h"
|
2020-07-01 18:45:24 +00:00
|
|
|
#include "include/gpu/GrDirectContext.h"
|
2020-07-01 16:55:01 +00:00
|
|
|
#include "include/gpu/GrRecordingContext.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/gpu/GrTypes.h"
|
2022-02-15 21:30:59 +00:00
|
|
|
#include "include/private/SkHalf.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/private/SkTArray.h"
|
|
|
|
#include "include/private/SkTDArray.h"
|
2020-10-16 16:04:18 +00:00
|
|
|
#include "include/private/SkTPin.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/private/SkTemplates.h"
|
2022-04-12 13:59:38 +00:00
|
|
|
#include "include/private/gpu/ganesh/GrTypesPriv.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/utils/SkTextUtils.h"
|
2020-09-18 18:09:51 +00:00
|
|
|
#include "src/core/SkConvertPixels.h"
|
2019-10-31 14:24:12 +00:00
|
|
|
#include "src/core/SkYUVMath.h"
|
2022-04-07 15:20:24 +00:00
|
|
|
#include "src/gpu/ganesh/GrCaps.h"
|
|
|
|
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "tools/ToolUtils.h"
|
2020-06-19 18:27:14 +00:00
|
|
|
#include "tools/gpu/YUVUtils.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <initializer_list>
|
|
|
|
#include <memory>
|
|
|
|
#include <utility>
|
|
|
|
|
2018-10-03 16:12:26 +00:00
|
|
|
static const int kTileWidthHeight = 128;
|
|
|
|
static const int kLabelWidth = 64;
|
|
|
|
static const int kLabelHeight = 32;
|
2020-09-21 14:50:30 +00:00
|
|
|
static const int kSubsetPadding = 8;
|
2018-10-03 16:12:26 +00:00
|
|
|
static const int kPad = 1;
|
|
|
|
|
|
|
|
enum YUVFormat {
|
2019-06-10 21:20:12 +00:00
|
|
|
// 4:2:0 formats, 24 bpp
|
|
|
|
kP016_YUVFormat, // 16-bit Y plane + 2x2 down sampled interleaved U/V plane (2 textures)
|
|
|
|
// 4:2:0 formats, "15 bpp" (but really 24 bpp)
|
|
|
|
kP010_YUVFormat, // same as kP016 except "10 bpp". Note that it is the same memory layout
|
|
|
|
// except that the bottom 6 bits are zeroed out (2 textures)
|
|
|
|
// TODO: we're cheating a bit w/ P010 and just treating it as unorm 16. This means its
|
|
|
|
// fully saturated values are 65504 rather than 65535 (that is just .9995 out of 1.0 though).
|
|
|
|
|
2019-09-18 17:56:54 +00:00
|
|
|
// This is laid out the same as kP016 and kP010 but uses F16 unstead of U16. In this case
|
|
|
|
// the 10 bits/channel vs 16 bits/channel distinction isn't relevant.
|
|
|
|
kP016F_YUVFormat,
|
|
|
|
|
2019-06-10 21:20:12 +00:00
|
|
|
// 4:4:4 formats, 64 bpp
|
|
|
|
kY416_YUVFormat, // 16-bit AVYU values all interleaved (1 texture)
|
|
|
|
|
2018-10-03 16:12:26 +00:00
|
|
|
// 4:4:4 formats, 32 bpp
|
2019-06-10 21:20:12 +00:00
|
|
|
kAYUV_YUVFormat, // 8-bit YUVA values all interleaved (1 texture)
|
|
|
|
kY410_YUVFormat, // AVYU w/ 10bpp for YUV and 2 for A all interleaved (1 texture)
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
// 4:2:0 formats, 12 bpp
|
2019-06-10 21:20:12 +00:00
|
|
|
kNV12_YUVFormat, // 8-bit Y plane + 2x2 down sampled interleaved U/V planes (2 textures)
|
|
|
|
kNV21_YUVFormat, // same as kNV12 but w/ U/V reversed in the interleaved texture (2 textures)
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2019-06-10 21:20:12 +00:00
|
|
|
kI420_YUVFormat, // 8-bit Y plane + separate 2x2 down sampled U and V planes (3 textures)
|
|
|
|
kYV12_YUVFormat, // 8-bit Y plane + separate 2x2 down sampled V and U planes (3 textures)
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
kLast_YUVFormat = kYV12_YUVFormat
|
|
|
|
};
|
|
|
|
|
2020-09-18 18:09:51 +00:00
|
|
|
// Does the YUVFormat contain a slot for alpha? If not an external alpha plane is required for
|
|
|
|
// transparency.
|
|
|
|
static bool has_alpha_channel(YUVFormat format) {
|
|
|
|
switch (format) {
|
|
|
|
case kP016_YUVFormat: return false;
|
|
|
|
case kP010_YUVFormat: return false;
|
|
|
|
case kP016F_YUVFormat: return false;
|
|
|
|
case kY416_YUVFormat: return true;
|
|
|
|
case kAYUV_YUVFormat: return true;
|
|
|
|
case kY410_YUVFormat: return true;
|
|
|
|
case kNV12_YUVFormat: return false;
|
|
|
|
case kNV21_YUVFormat: return false;
|
|
|
|
case kI420_YUVFormat: return false;
|
|
|
|
case kYV12_YUVFormat: return false;
|
|
|
|
}
|
|
|
|
SkUNREACHABLE;
|
|
|
|
}
|
|
|
|
|
2020-04-08 19:57:08 +00:00
|
|
|
class YUVAPlanarConfig {
|
|
|
|
public:
|
2021-01-19 17:11:07 +00:00
|
|
|
YUVAPlanarConfig(YUVFormat format, bool opaque, SkEncodedOrigin origin) : fOrigin(origin) {
|
2020-09-18 18:09:51 +00:00
|
|
|
switch (format) {
|
|
|
|
case kP016_YUVFormat:
|
|
|
|
case kP010_YUVFormat:
|
|
|
|
case kP016F_YUVFormat:
|
|
|
|
case kNV12_YUVFormat:
|
|
|
|
if (opaque) {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_UV;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
} else {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_UV_A;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kY416_YUVFormat:
|
|
|
|
case kY410_YUVFormat:
|
|
|
|
if (opaque) {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kUYV;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k444;
|
2020-09-18 18:09:51 +00:00
|
|
|
} else {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kUYVA;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k444;
|
2020-09-18 18:09:51 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kAYUV_YUVFormat:
|
|
|
|
if (opaque) {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kYUV;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k444;
|
2020-09-18 18:09:51 +00:00
|
|
|
} else {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kYUVA;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k444;
|
2020-09-18 18:09:51 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kNV21_YUVFormat:
|
|
|
|
if (opaque) {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_VU;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
} else {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_VU_A;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kI420_YUVFormat:
|
|
|
|
if (opaque) {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_U_V;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
} else {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_U_V_A;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kYV12_YUVFormat:
|
|
|
|
if (opaque) {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_V_U;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
} else {
|
2020-11-11 21:34:19 +00:00
|
|
|
fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_V_U_A;
|
|
|
|
fSubsampling = SkYUVAInfo::Subsampling::k420;
|
2020-09-18 18:09:51 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-04-08 19:57:08 +00:00
|
|
|
|
2020-11-11 21:34:19 +00:00
|
|
|
int numPlanes() const { return SkYUVAInfo::NumPlanes(fPlaneConfig); }
|
2020-04-08 19:57:08 +00:00
|
|
|
|
2020-09-21 14:50:30 +00:00
|
|
|
SkYUVAPixmaps makeYUVAPixmaps(SkISize dimensions,
|
|
|
|
SkYUVColorSpace yuvColorSpace,
|
|
|
|
const SkBitmap bitmaps[],
|
|
|
|
int numBitmaps) const;
|
|
|
|
|
2020-04-08 19:57:08 +00:00
|
|
|
private:
|
2020-11-11 21:34:19 +00:00
|
|
|
SkYUVAInfo::PlaneConfig fPlaneConfig;
|
|
|
|
SkYUVAInfo::Subsampling fSubsampling;
|
2021-01-19 17:11:07 +00:00
|
|
|
SkEncodedOrigin fOrigin;
|
2020-04-08 19:57:08 +00:00
|
|
|
};
|
|
|
|
|
2020-09-21 14:50:30 +00:00
|
|
|
SkYUVAPixmaps YUVAPlanarConfig::makeYUVAPixmaps(SkISize dimensions,
|
|
|
|
SkYUVColorSpace yuvColorSpace,
|
|
|
|
const SkBitmap bitmaps[],
|
|
|
|
int numBitmaps) const {
|
2021-01-19 17:11:07 +00:00
|
|
|
SkYUVAInfo info(dimensions, fPlaneConfig, fSubsampling, yuvColorSpace, fOrigin);
|
2020-09-21 14:50:30 +00:00
|
|
|
SkPixmap pmaps[SkYUVAInfo::kMaxPlanes];
|
|
|
|
int n = info.numPlanes();
|
|
|
|
if (numBitmaps < n) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
pmaps[i] = bitmaps[i].pixmap();
|
|
|
|
}
|
|
|
|
return SkYUVAPixmaps::FromExternalPixmaps(info, pmaps);
|
|
|
|
}
|
|
|
|
|
2018-10-03 16:12:26 +00:00
|
|
|
// All the planes we need to construct the various YUV formats
|
|
|
|
struct PlaneData {
|
|
|
|
SkBitmap fYFull;
|
|
|
|
SkBitmap fUFull;
|
|
|
|
SkBitmap fVFull;
|
|
|
|
SkBitmap fAFull;
|
|
|
|
SkBitmap fUQuarter; // 2x2 downsampled U channel
|
|
|
|
SkBitmap fVQuarter; // 2x2 downsampled V channel
|
2019-09-11 21:03:28 +00:00
|
|
|
|
|
|
|
SkBitmap fFull;
|
|
|
|
SkBitmap fQuarter; // 2x2 downsampled YUVA
|
2018-10-03 16:12:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Add a portion of a circle to 'path'. The points 'o1' and 'o2' are on the border of the circle
|
|
|
|
// and have tangents 'v1' and 'v2'.
|
|
|
|
static void add_arc(SkPath* path,
|
|
|
|
const SkPoint& o1, const SkVector& v1,
|
|
|
|
const SkPoint& o2, const SkVector& v2,
|
|
|
|
SkTDArray<SkRect>* circles, bool takeLongWayRound) {
|
|
|
|
|
|
|
|
SkVector v3 = { -v1.fY, v1.fX };
|
|
|
|
SkVector v4 = { v2.fY, -v2.fX };
|
|
|
|
|
|
|
|
SkScalar t = ((o2.fX - o1.fX) * v4.fY - (o2.fY - o1.fY) * v4.fX) / v3.cross(v4);
|
|
|
|
SkPoint center = { o1.fX + t * v3.fX, o1.fY + t * v3.fY };
|
|
|
|
|
|
|
|
SkRect r = { center.fX - t, center.fY - t, center.fX + t, center.fY + t };
|
|
|
|
|
|
|
|
if (circles) {
|
|
|
|
circles->push_back(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
SkVector startV = o1 - center, endV = o2 - center;
|
|
|
|
startV.normalize();
|
|
|
|
endV.normalize();
|
|
|
|
|
|
|
|
SkScalar startDeg = SkRadiansToDegrees(SkScalarATan2(startV.fY, startV.fX));
|
|
|
|
SkScalar endDeg = SkRadiansToDegrees(SkScalarATan2(endV.fY, endV.fX));
|
|
|
|
|
|
|
|
startDeg += 360.0f;
|
|
|
|
startDeg = fmodf(startDeg, 360.0f);
|
|
|
|
|
|
|
|
endDeg += 360.0f;
|
|
|
|
endDeg = fmodf(endDeg, 360.0f);
|
|
|
|
|
|
|
|
if (endDeg < startDeg) {
|
|
|
|
endDeg += 360.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkScalar sweepDeg = SkTAbs(endDeg - startDeg);
|
|
|
|
if (!takeLongWayRound) {
|
|
|
|
sweepDeg = sweepDeg - 360;
|
|
|
|
}
|
|
|
|
|
|
|
|
path->arcTo(r, startDeg, sweepDeg, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static SkPath create_splat(const SkPoint& o, SkScalar innerRadius, SkScalar outerRadius,
|
|
|
|
SkScalar ratio, int numLobes, SkTDArray<SkRect>* circles) {
|
|
|
|
if (numLobes <= 1) {
|
|
|
|
return SkPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
SkPath p;
|
|
|
|
|
|
|
|
int numDivisions = 2 * numLobes;
|
|
|
|
SkScalar fullLobeDegrees = 360.0f / numLobes;
|
|
|
|
SkScalar outDegrees = ratio * fullLobeDegrees / (ratio + 1.0f);
|
|
|
|
SkScalar innerDegrees = fullLobeDegrees / (ratio + 1.0f);
|
|
|
|
SkMatrix outerStep, innerStep;
|
|
|
|
outerStep.setRotate(outDegrees);
|
|
|
|
innerStep.setRotate(innerDegrees);
|
|
|
|
SkVector curV = SkVector::Make(0.0f, 1.0f);
|
|
|
|
|
|
|
|
if (circles) {
|
|
|
|
circles->push_back(SkRect::MakeLTRB(o.fX - innerRadius, o.fY - innerRadius,
|
|
|
|
o.fX + innerRadius, o.fY + innerRadius));
|
|
|
|
}
|
|
|
|
|
|
|
|
p.moveTo(o.fX + innerRadius * curV.fX, o.fY + innerRadius * curV.fY);
|
|
|
|
|
|
|
|
for (int i = 0; i < numDivisions; ++i) {
|
|
|
|
|
|
|
|
SkVector nextV;
|
|
|
|
if (0 == (i % 2)) {
|
|
|
|
nextV = outerStep.mapVector(curV.fX, curV.fY);
|
|
|
|
|
|
|
|
SkPoint top = SkPoint::Make(o.fX + outerRadius * curV.fX,
|
|
|
|
o.fY + outerRadius * curV.fY);
|
|
|
|
SkPoint nextTop = SkPoint::Make(o.fX + outerRadius * nextV.fX,
|
|
|
|
o.fY + outerRadius * nextV.fY);
|
|
|
|
|
|
|
|
p.lineTo(top);
|
|
|
|
add_arc(&p, top, curV, nextTop, nextV, circles, true);
|
|
|
|
} else {
|
|
|
|
nextV = innerStep.mapVector(curV.fX, curV.fY);
|
|
|
|
|
|
|
|
SkPoint bot = SkPoint::Make(o.fX + innerRadius * curV.fX,
|
|
|
|
o.fY + innerRadius * curV.fY);
|
|
|
|
SkPoint nextBot = SkPoint::Make(o.fX + innerRadius * nextV.fX,
|
|
|
|
o.fY + innerRadius * nextV.fY);
|
|
|
|
|
|
|
|
p.lineTo(bot);
|
|
|
|
add_arc(&p, bot, curV, nextBot, nextV, nullptr, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
curV = nextV;
|
|
|
|
}
|
|
|
|
|
|
|
|
p.close();
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2019-03-21 13:00:20 +00:00
|
|
|
static SkBitmap make_bitmap(SkColorType colorType, const SkPath& path,
|
2019-04-12 19:03:02 +00:00
|
|
|
const SkTDArray<SkRect>& circles, bool opaque, bool padWithRed) {
|
2021-01-19 17:11:07 +00:00
|
|
|
const SkColor kGreen = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 178, 240, 104));
|
|
|
|
const SkColor kBlue = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 173, 167, 252));
|
|
|
|
const SkColor kYellow = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 255, 221, 117));
|
|
|
|
const SkColor kMagenta = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 255, 60, 217));
|
|
|
|
const SkColor kCyan = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 45, 237, 205));
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2020-09-21 14:50:30 +00:00
|
|
|
int widthHeight = kTileWidthHeight + (padWithRed ? 2 * kSubsetPadding : 0);
|
2019-04-12 19:03:02 +00:00
|
|
|
|
|
|
|
SkImageInfo ii = SkImageInfo::Make(widthHeight, widthHeight,
|
2019-03-21 13:00:20 +00:00
|
|
|
colorType, kPremul_SkAlphaType);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
SkBitmap bm;
|
|
|
|
bm.allocPixels(ii);
|
|
|
|
|
2019-03-21 13:00:20 +00:00
|
|
|
std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(ii,
|
|
|
|
bm.getPixels(),
|
|
|
|
bm.rowBytes());
|
2019-04-12 19:03:02 +00:00
|
|
|
if (padWithRed) {
|
|
|
|
canvas->clear(SK_ColorRED);
|
2020-09-21 14:50:30 +00:00
|
|
|
canvas->translate(kSubsetPadding, kSubsetPadding);
|
2019-04-12 19:03:02 +00:00
|
|
|
canvas->clipRect(SkRect::MakeWH(kTileWidthHeight, kTileWidthHeight));
|
|
|
|
}
|
2018-10-03 16:12:26 +00:00
|
|
|
canvas->clear(opaque ? kGreen : SK_ColorTRANSPARENT);
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setAntiAlias(false); // serialize-8888 doesn't seem to work well w/ partial transparency
|
|
|
|
paint.setColor(kBlue);
|
|
|
|
|
|
|
|
canvas->drawPath(path, paint);
|
|
|
|
|
|
|
|
paint.setBlendMode(SkBlendMode::kSrc);
|
|
|
|
for (int i = 0; i < circles.count(); ++i) {
|
2021-01-19 17:11:07 +00:00
|
|
|
SkColor color;
|
|
|
|
switch (i % 3) {
|
|
|
|
case 0: color = kYellow; break;
|
|
|
|
case 1: color = kMagenta; break;
|
|
|
|
default: color = kCyan; break;
|
|
|
|
}
|
|
|
|
paint.setColor(color);
|
|
|
|
paint.setAlpha(opaque ? 0xFF : 0x40);
|
2018-10-03 16:12:26 +00:00
|
|
|
SkRect r = circles[i];
|
|
|
|
r.inset(r.width()/4, r.height()/4);
|
|
|
|
canvas->drawOval(r, paint);
|
|
|
|
}
|
|
|
|
|
|
|
|
return bm;
|
|
|
|
}
|
|
|
|
|
2019-10-31 14:24:12 +00:00
|
|
|
static void convert_rgba_to_yuva(const float mtx[20], SkColor col, uint8_t yuv[4]) {
|
|
|
|
const uint8_t r = SkColorGetR(col);
|
|
|
|
const uint8_t g = SkColorGetG(col);
|
|
|
|
const uint8_t b = SkColorGetB(col);
|
2018-10-04 14:44:53 +00:00
|
|
|
|
2020-02-06 17:52:25 +00:00
|
|
|
yuv[0] = SkTPin(SkScalarRoundToInt(mtx[ 0]*r + mtx[ 1]*g + mtx[ 2]*b + mtx[ 4]*255), 0, 255);
|
|
|
|
yuv[1] = SkTPin(SkScalarRoundToInt(mtx[ 5]*r + mtx[ 6]*g + mtx[ 7]*b + mtx[ 9]*255), 0, 255);
|
|
|
|
yuv[2] = SkTPin(SkScalarRoundToInt(mtx[10]*r + mtx[11]*g + mtx[12]*b + mtx[14]*255), 0, 255);
|
2018-10-04 14:44:53 +00:00
|
|
|
yuv[3] = SkColorGetA(col);
|
|
|
|
}
|
|
|
|
|
2021-01-19 17:11:07 +00:00
|
|
|
static void extract_planes(const SkBitmap& origBM,
|
|
|
|
SkYUVColorSpace yuvColorSpace,
|
|
|
|
SkEncodedOrigin origin,
|
|
|
|
PlaneData* planes) {
|
|
|
|
SkImageInfo ii = origBM.info();
|
|
|
|
if (SkEncodedOriginSwapsWidthHeight(origin)) {
|
|
|
|
ii = ii.makeWH(ii.height(), ii.width());
|
|
|
|
}
|
|
|
|
SkBitmap orientedBM;
|
|
|
|
orientedBM.allocPixels(ii);
|
|
|
|
SkCanvas canvas(orientedBM);
|
|
|
|
SkMatrix matrix = SkEncodedOriginToMatrix(origin, origBM.width(), origBM.height());
|
|
|
|
SkAssertResult(matrix.invert(&matrix));
|
|
|
|
canvas.concat(matrix);
|
2021-01-25 00:49:21 +00:00
|
|
|
canvas.drawImage(origBM.asImage(), 0, 0);
|
2021-01-19 17:11:07 +00:00
|
|
|
|
|
|
|
if (yuvColorSpace == kIdentity_SkYUVColorSpace) {
|
2019-03-06 17:36:47 +00:00
|
|
|
// To test the identity color space we use JPEG YUV planes
|
|
|
|
yuvColorSpace = kJPEG_SkYUVColorSpace;
|
|
|
|
}
|
|
|
|
|
2021-01-19 17:11:07 +00:00
|
|
|
SkASSERT(!(ii.width() % 2));
|
|
|
|
SkASSERT(!(ii.height() % 2));
|
2019-09-30 19:12:27 +00:00
|
|
|
planes->fYFull.allocPixels(
|
2021-01-19 17:11:07 +00:00
|
|
|
SkImageInfo::Make(ii.dimensions(), kGray_8_SkColorType, kUnpremul_SkAlphaType));
|
2019-09-30 19:12:27 +00:00
|
|
|
planes->fUFull.allocPixels(
|
2021-01-19 17:11:07 +00:00
|
|
|
SkImageInfo::Make(ii.dimensions(), kGray_8_SkColorType, kUnpremul_SkAlphaType));
|
2019-09-30 19:12:27 +00:00
|
|
|
planes->fVFull.allocPixels(
|
2021-01-19 17:11:07 +00:00
|
|
|
SkImageInfo::Make(ii.dimensions(), kGray_8_SkColorType, kUnpremul_SkAlphaType));
|
|
|
|
planes->fAFull.allocPixels(SkImageInfo::MakeA8(ii.dimensions()));
|
|
|
|
planes->fUQuarter.allocPixels(SkImageInfo::Make(ii.width()/2, ii.height()/2,
|
2019-08-02 21:17:35 +00:00
|
|
|
kGray_8_SkColorType, kUnpremul_SkAlphaType));
|
2021-01-19 17:11:07 +00:00
|
|
|
planes->fVQuarter.allocPixels(SkImageInfo::Make(ii.width()/2, ii.height()/2,
|
2019-08-02 21:17:35 +00:00
|
|
|
kGray_8_SkColorType, kUnpremul_SkAlphaType));
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2019-09-30 19:12:27 +00:00
|
|
|
planes->fFull.allocPixels(
|
2021-01-19 17:11:07 +00:00
|
|
|
SkImageInfo::Make(ii.dimensions(), kRGBA_F32_SkColorType, kUnpremul_SkAlphaType));
|
|
|
|
planes->fQuarter.allocPixels(SkImageInfo::Make(ii.width()/2, ii.height()/2,
|
2019-09-11 21:03:28 +00:00
|
|
|
kRGBA_F32_SkColorType, kUnpremul_SkAlphaType));
|
|
|
|
|
2019-10-31 14:24:12 +00:00
|
|
|
float mtx[20];
|
|
|
|
SkColorMatrix_RGB2YUV(yuvColorSpace, mtx);
|
|
|
|
|
2019-09-11 21:03:28 +00:00
|
|
|
SkColor4f* dst = (SkColor4f *) planes->fFull.getAddr(0, 0);
|
2021-01-19 17:11:07 +00:00
|
|
|
for (int y = 0; y < orientedBM.height(); ++y) {
|
|
|
|
for (int x = 0; x < orientedBM.width(); ++x) {
|
|
|
|
SkColor col = orientedBM.getColor(x, y);
|
2018-10-04 14:44:53 +00:00
|
|
|
|
|
|
|
uint8_t yuva[4];
|
|
|
|
|
2019-10-31 14:24:12 +00:00
|
|
|
convert_rgba_to_yuva(mtx, col, yuva);
|
2018-10-04 14:44:53 +00:00
|
|
|
|
|
|
|
*planes->fYFull.getAddr8(x, y) = yuva[0];
|
|
|
|
*planes->fUFull.getAddr8(x, y) = yuva[1];
|
|
|
|
*planes->fVFull.getAddr8(x, y) = yuva[2];
|
|
|
|
*planes->fAFull.getAddr8(x, y) = yuva[3];
|
2019-09-11 21:03:28 +00:00
|
|
|
|
|
|
|
// TODO: render in F32 rather than converting here
|
|
|
|
dst->fR = yuva[0] / 255.0f;
|
|
|
|
dst->fG = yuva[1] / 255.0f;
|
|
|
|
dst->fB = yuva[2] / 255.0f;
|
|
|
|
dst->fA = yuva[3] / 255.0f;
|
|
|
|
++dst;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-11 21:03:28 +00:00
|
|
|
dst = (SkColor4f *) planes->fQuarter.getAddr(0, 0);
|
2021-01-19 17:11:07 +00:00
|
|
|
for (int y = 0; y < orientedBM.height()/2; ++y) {
|
|
|
|
for (int x = 0; x < orientedBM.width()/2; ++x) {
|
2019-09-11 21:03:28 +00:00
|
|
|
uint32_t yAccum = 0, uAccum = 0, vAccum = 0, aAccum = 0;
|
|
|
|
|
|
|
|
yAccum += *planes->fYFull.getAddr8(2*x, 2*y);
|
|
|
|
yAccum += *planes->fYFull.getAddr8(2*x+1, 2*y);
|
|
|
|
yAccum += *planes->fYFull.getAddr8(2*x, 2*y+1);
|
|
|
|
yAccum += *planes->fYFull.getAddr8(2*x+1, 2*y+1);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
uAccum += *planes->fUFull.getAddr8(2*x, 2*y);
|
|
|
|
uAccum += *planes->fUFull.getAddr8(2*x+1, 2*y);
|
|
|
|
uAccum += *planes->fUFull.getAddr8(2*x, 2*y+1);
|
|
|
|
uAccum += *planes->fUFull.getAddr8(2*x+1, 2*y+1);
|
|
|
|
|
|
|
|
*planes->fUQuarter.getAddr8(x, y) = uAccum / 4.0f;
|
|
|
|
|
|
|
|
vAccum += *planes->fVFull.getAddr8(2*x, 2*y);
|
|
|
|
vAccum += *planes->fVFull.getAddr8(2*x+1, 2*y);
|
|
|
|
vAccum += *planes->fVFull.getAddr8(2*x, 2*y+1);
|
|
|
|
vAccum += *planes->fVFull.getAddr8(2*x+1, 2*y+1);
|
|
|
|
|
2018-10-04 14:44:53 +00:00
|
|
|
*planes->fVQuarter.getAddr8(x, y) = vAccum / 4.0f;
|
2019-09-11 21:03:28 +00:00
|
|
|
|
|
|
|
aAccum += *planes->fAFull.getAddr8(2*x, 2*y);
|
|
|
|
aAccum += *planes->fAFull.getAddr8(2*x+1, 2*y);
|
|
|
|
aAccum += *planes->fAFull.getAddr8(2*x, 2*y+1);
|
|
|
|
aAccum += *planes->fAFull.getAddr8(2*x+1, 2*y+1);
|
|
|
|
|
|
|
|
// TODO: render in F32 rather than converting here
|
|
|
|
dst->fR = yAccum / (4.0f * 255.0f);
|
|
|
|
dst->fG = uAccum / (4.0f * 255.0f);
|
|
|
|
dst->fB = vAccum / (4.0f * 255.0f);
|
|
|
|
dst->fA = aAccum / (4.0f * 255.0f);
|
|
|
|
++dst;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 19:05:35 +00:00
|
|
|
// Create a 2x2 downsampled SkBitmap. It is stored in an RG texture. It can optionally be
|
2019-09-11 21:03:28 +00:00
|
|
|
// uv (i.e., NV12) or vu (i.e., NV21).
|
2019-06-10 21:20:12 +00:00
|
|
|
static SkBitmap make_quarter_2_channel(const SkBitmap& fullY,
|
|
|
|
const SkBitmap& quarterU,
|
|
|
|
const SkBitmap& quarterV,
|
|
|
|
bool uv) {
|
|
|
|
SkBitmap result;
|
|
|
|
|
|
|
|
result.allocPixels(SkImageInfo::Make(fullY.width()/2,
|
|
|
|
fullY.height()/2,
|
2019-09-19 20:05:48 +00:00
|
|
|
kR8G8_unorm_SkColorType,
|
2019-06-10 21:20:12 +00:00
|
|
|
kUnpremul_SkAlphaType));
|
|
|
|
|
|
|
|
for (int y = 0; y < fullY.height()/2; ++y) {
|
|
|
|
for (int x = 0; x < fullY.width()/2; ++x) {
|
|
|
|
uint8_t u8 = *quarterU.getAddr8(x, y);
|
|
|
|
uint8_t v8 = *quarterV.getAddr8(x, y);
|
|
|
|
|
|
|
|
if (uv) {
|
2019-09-04 19:05:35 +00:00
|
|
|
*result.getAddr16(x, y) = (v8 << 8) | u8;
|
2019-06-10 21:20:12 +00:00
|
|
|
} else {
|
2019-09-04 19:05:35 +00:00
|
|
|
*result.getAddr16(x, y) = (u8 << 8) | v8;
|
2019-06-10 21:20:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-18 17:56:54 +00:00
|
|
|
// Create some flavor of a 16bits/channel bitmap from a RGBA_F32 source
|
|
|
|
static SkBitmap make_16(const SkBitmap& src, SkColorType dstCT,
|
|
|
|
std::function<void(uint16_t* dstPixel, const float* srcPixel)> convert) {
|
2019-09-11 21:03:28 +00:00
|
|
|
SkASSERT(src.colorType() == kRGBA_F32_SkColorType);
|
|
|
|
|
|
|
|
SkBitmap result;
|
|
|
|
|
2019-09-30 19:12:27 +00:00
|
|
|
result.allocPixels(SkImageInfo::Make(src.dimensions(), dstCT, kUnpremul_SkAlphaType));
|
2019-09-11 21:03:28 +00:00
|
|
|
|
|
|
|
for (int y = 0; y < src.height(); ++y) {
|
|
|
|
for (int x = 0; x < src.width(); ++x) {
|
2019-09-18 17:56:54 +00:00
|
|
|
const float* srcPixel = (const float*) src.getAddr(x, y);
|
|
|
|
uint16_t* dstPixel = (uint16_t*) result.getAddr(x, y);
|
2019-09-11 21:03:28 +00:00
|
|
|
|
2019-09-18 17:56:54 +00:00
|
|
|
convert(dstPixel, srcPixel);
|
2019-09-11 21:03:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-18 17:56:54 +00:00
|
|
|
static uint16_t flt_2_uint16(float flt) { return SkScalarRoundToInt(flt * 65535.0f); }
|
2019-09-11 21:03:28 +00:00
|
|
|
|
2020-04-08 19:57:08 +00:00
|
|
|
// Recombine the separate planes into some YUV format. Returns the number of planes.
|
|
|
|
static int create_YUV(const PlaneData& planes,
|
|
|
|
YUVFormat yuvFormat,
|
|
|
|
SkBitmap resultBMs[],
|
|
|
|
bool opaque) {
|
2018-10-03 16:12:26 +00:00
|
|
|
int nextLayer = 0;
|
|
|
|
|
|
|
|
switch (yuvFormat) {
|
2019-06-10 21:20:12 +00:00
|
|
|
case kY416_YUVFormat: {
|
2019-09-19 20:05:48 +00:00
|
|
|
resultBMs[nextLayer++] = make_16(planes.fFull, kR16G16B16A16_unorm_SkColorType,
|
2019-09-18 17:56:54 +00:00
|
|
|
[] (uint16_t* dstPixel, const float* srcPixel) {
|
|
|
|
dstPixel[0] = flt_2_uint16(srcPixel[1]); // U
|
|
|
|
dstPixel[1] = flt_2_uint16(srcPixel[0]); // Y
|
|
|
|
dstPixel[2] = flt_2_uint16(srcPixel[2]); // V
|
|
|
|
dstPixel[3] = flt_2_uint16(srcPixel[3]); // A
|
|
|
|
});
|
2019-06-10 21:20:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-10-17 19:27:19 +00:00
|
|
|
case kAYUV_YUVFormat: {
|
2018-10-03 16:12:26 +00:00
|
|
|
SkBitmap yuvaFull;
|
|
|
|
|
2018-10-20 02:09:28 +00:00
|
|
|
yuvaFull.allocPixels(SkImageInfo::Make(planes.fYFull.width(), planes.fYFull.height(),
|
|
|
|
kRGBA_8888_SkColorType, kUnpremul_SkAlphaType));
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
for (int y = 0; y < planes.fYFull.height(); ++y) {
|
|
|
|
for (int x = 0; x < planes.fYFull.width(); ++x) {
|
|
|
|
|
|
|
|
uint8_t Y = *planes.fYFull.getAddr8(x, y);
|
|
|
|
uint8_t U = *planes.fUFull.getAddr8(x, y);
|
|
|
|
uint8_t V = *planes.fVFull.getAddr8(x, y);
|
|
|
|
uint8_t A = *planes.fAFull.getAddr8(x, y);
|
|
|
|
|
|
|
|
// NOT premul!
|
2018-10-20 02:09:28 +00:00
|
|
|
// V and Y swapped to match RGBA layout
|
2019-03-21 13:00:20 +00:00
|
|
|
SkColor c = SkColorSetARGB(A, V, U, Y);
|
|
|
|
*yuvaFull.getAddr32(x, y) = c;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resultBMs[nextLayer++] = yuvaFull;
|
|
|
|
break;
|
|
|
|
}
|
2019-03-21 13:00:20 +00:00
|
|
|
case kY410_YUVFormat: {
|
|
|
|
SkBitmap yuvaFull;
|
2019-05-21 17:51:11 +00:00
|
|
|
uint32_t Y, U, V;
|
|
|
|
uint8_t A;
|
2019-03-21 13:00:20 +00:00
|
|
|
|
|
|
|
yuvaFull.allocPixels(SkImageInfo::Make(planes.fYFull.width(), planes.fYFull.height(),
|
|
|
|
kRGBA_1010102_SkColorType,
|
|
|
|
kUnpremul_SkAlphaType));
|
|
|
|
|
|
|
|
for (int y = 0; y < planes.fYFull.height(); ++y) {
|
|
|
|
for (int x = 0; x < planes.fYFull.width(); ++x) {
|
|
|
|
|
2019-05-21 17:51:11 +00:00
|
|
|
Y = SkScalarRoundToInt((*planes.fYFull.getAddr8(x, y) / 255.0f) * 1023.0f);
|
|
|
|
U = SkScalarRoundToInt((*planes.fUFull.getAddr8(x, y) / 255.0f) * 1023.0f);
|
|
|
|
V = SkScalarRoundToInt((*planes.fVFull.getAddr8(x, y) / 255.0f) * 1023.0f);
|
|
|
|
A = SkScalarRoundToInt((*planes.fAFull.getAddr8(x, y) / 255.0f) * 3.0f);
|
2019-03-21 13:00:20 +00:00
|
|
|
|
|
|
|
// NOT premul!
|
2020-04-08 19:57:08 +00:00
|
|
|
*yuvaFull.getAddr32(x, y) = (A << 30) | (V << 20) | (Y << 10) | (U << 0);
|
2019-03-21 13:00:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resultBMs[nextLayer++] = yuvaFull;
|
|
|
|
break;
|
|
|
|
}
|
2019-06-10 21:20:12 +00:00
|
|
|
case kP016_YUVFormat: // fall through
|
2019-09-11 21:03:28 +00:00
|
|
|
case kP010_YUVFormat: {
|
2019-09-19 20:05:48 +00:00
|
|
|
resultBMs[nextLayer++] = make_16(planes.fFull, kA16_unorm_SkColorType,
|
2019-09-18 17:56:54 +00:00
|
|
|
[tenBitsPP = (yuvFormat == kP010_YUVFormat)]
|
|
|
|
(uint16_t* dstPixel, const float* srcPixel) {
|
|
|
|
uint16_t val16 = flt_2_uint16(srcPixel[0]);
|
|
|
|
dstPixel[0] = tenBitsPP ? (val16 & 0xFFC0)
|
|
|
|
: val16;
|
|
|
|
});
|
2019-09-19 20:05:48 +00:00
|
|
|
resultBMs[nextLayer++] = make_16(planes.fQuarter, kR16G16_unorm_SkColorType,
|
2019-09-18 17:56:54 +00:00
|
|
|
[tenBitsPP = (yuvFormat == kP010_YUVFormat)]
|
|
|
|
(uint16_t* dstPixel, const float* srcPixel) {
|
|
|
|
uint16_t u16 = flt_2_uint16(srcPixel[1]);
|
|
|
|
uint16_t v16 = flt_2_uint16(srcPixel[2]);
|
|
|
|
dstPixel[0] = tenBitsPP ? (u16 & 0xFFC0) : u16;
|
|
|
|
dstPixel[1] = tenBitsPP ? (v16 & 0xFFC0) : v16;
|
|
|
|
});
|
2019-09-11 21:03:28 +00:00
|
|
|
if (!opaque) {
|
2020-04-08 19:57:08 +00:00
|
|
|
resultBMs[nextLayer++] = make_16(planes.fFull, kA16_unorm_SkColorType,
|
|
|
|
[tenBitsPP = (yuvFormat == kP010_YUVFormat)]
|
|
|
|
(uint16_t* dstPixel, const float* srcPixel) {
|
|
|
|
uint16_t val16 = flt_2_uint16(srcPixel[3]);
|
|
|
|
dstPixel[0] = tenBitsPP ? (val16 & 0xFFC0)
|
|
|
|
: val16;
|
|
|
|
});
|
2019-09-18 17:56:54 +00:00
|
|
|
}
|
2020-04-08 19:57:08 +00:00
|
|
|
return nextLayer;
|
2019-09-18 17:56:54 +00:00
|
|
|
}
|
|
|
|
case kP016F_YUVFormat: {
|
2019-09-19 20:05:48 +00:00
|
|
|
resultBMs[nextLayer++] = make_16(planes.fFull, kA16_float_SkColorType,
|
2019-09-18 17:56:54 +00:00
|
|
|
[] (uint16_t* dstPixel, const float* srcPixel) {
|
|
|
|
dstPixel[0] = SkFloatToHalf(srcPixel[0]);
|
|
|
|
});
|
2019-09-19 20:05:48 +00:00
|
|
|
resultBMs[nextLayer++] = make_16(planes.fQuarter, kR16G16_float_SkColorType,
|
2019-09-18 17:56:54 +00:00
|
|
|
[] (uint16_t* dstPixel, const float* srcPixel) {
|
|
|
|
dstPixel[0] = SkFloatToHalf(srcPixel[1]);
|
|
|
|
dstPixel[1] = SkFloatToHalf(srcPixel[2]);
|
|
|
|
});
|
|
|
|
if (!opaque) {
|
2020-04-08 19:57:08 +00:00
|
|
|
resultBMs[nextLayer++] = make_16(planes.fFull, kA16_float_SkColorType,
|
|
|
|
[] (uint16_t* dstPixel, const float* srcPixel) {
|
|
|
|
dstPixel[0] = SkFloatToHalf(srcPixel[3]);
|
|
|
|
});
|
2019-09-11 21:03:28 +00:00
|
|
|
}
|
2020-04-08 19:57:08 +00:00
|
|
|
return nextLayer;
|
2019-09-11 21:03:28 +00:00
|
|
|
}
|
2018-10-03 16:12:26 +00:00
|
|
|
case kNV12_YUVFormat: {
|
2019-06-10 21:20:12 +00:00
|
|
|
SkBitmap uvQuarter = make_quarter_2_channel(planes.fYFull,
|
|
|
|
planes.fUQuarter,
|
|
|
|
planes.fVQuarter, true);
|
2018-10-03 16:12:26 +00:00
|
|
|
resultBMs[nextLayer++] = planes.fYFull;
|
|
|
|
resultBMs[nextLayer++] = uvQuarter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case kNV21_YUVFormat: {
|
2019-06-10 21:20:12 +00:00
|
|
|
SkBitmap vuQuarter = make_quarter_2_channel(planes.fYFull,
|
|
|
|
planes.fUQuarter,
|
|
|
|
planes.fVQuarter, false);
|
2018-10-03 16:12:26 +00:00
|
|
|
resultBMs[nextLayer++] = planes.fYFull;
|
|
|
|
resultBMs[nextLayer++] = vuQuarter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case kI420_YUVFormat:
|
|
|
|
resultBMs[nextLayer++] = planes.fYFull;
|
|
|
|
resultBMs[nextLayer++] = planes.fUQuarter;
|
|
|
|
resultBMs[nextLayer++] = planes.fVQuarter;
|
|
|
|
break;
|
|
|
|
case kYV12_YUVFormat:
|
|
|
|
resultBMs[nextLayer++] = planes.fYFull;
|
|
|
|
resultBMs[nextLayer++] = planes.fVQuarter;
|
|
|
|
resultBMs[nextLayer++] = planes.fUQuarter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-09-18 18:09:51 +00:00
|
|
|
if (!opaque && !has_alpha_channel(yuvFormat)) {
|
2020-04-08 19:57:08 +00:00
|
|
|
resultBMs[nextLayer++] = planes.fAFull;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
2020-04-08 19:57:08 +00:00
|
|
|
return nextLayer;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void draw_col_label(SkCanvas* canvas, int x, int yuvColorSpace, bool opaque) {
|
2020-07-23 18:22:22 +00:00
|
|
|
static const char* kYUVColorSpaceNames[] = {"JPEG", "601", "709F", "709L",
|
|
|
|
"2020_8F", "2020_8L", "2020_10F", "2020_10L",
|
|
|
|
"2020_12F", "2020_12L", "Identity"};
|
2019-12-18 15:43:10 +00:00
|
|
|
static_assert(SK_ARRAY_COUNT(kYUVColorSpaceNames) == kLastEnum_SkYUVColorSpace + 1);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2019-01-02 17:21:01 +00:00
|
|
|
SkPaint paint;
|
2019-03-20 16:12:10 +00:00
|
|
|
SkFont font(ToolUtils::create_portable_typeface(nullptr, SkFontStyle::Bold()), 16);
|
2019-01-02 17:21:01 +00:00
|
|
|
font.setEdging(SkFont::Edging::kAlias);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
SkRect textRect;
|
|
|
|
SkString colLabel;
|
|
|
|
|
|
|
|
colLabel.printf("%s", kYUVColorSpaceNames[yuvColorSpace]);
|
2019-05-07 19:38:46 +00:00
|
|
|
font.measureText(colLabel.c_str(), colLabel.size(), SkTextEncoding::kUTF8, &textRect);
|
2018-10-03 16:12:26 +00:00
|
|
|
int y = textRect.height();
|
|
|
|
|
2019-01-02 17:21:01 +00:00
|
|
|
SkTextUtils::DrawString(canvas, colLabel.c_str(), x, y, font, paint, SkTextUtils::kCenter_Align);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
colLabel.printf("%s", opaque ? "Opaque" : "Transparent");
|
2018-10-25 20:12:39 +00:00
|
|
|
|
2019-05-07 19:38:46 +00:00
|
|
|
font.measureText(colLabel.c_str(), colLabel.size(), SkTextEncoding::kUTF8, &textRect);
|
2018-10-03 16:12:26 +00:00
|
|
|
y += textRect.height();
|
|
|
|
|
2019-01-02 17:21:01 +00:00
|
|
|
SkTextUtils::DrawString(canvas, colLabel.c_str(), x, y, font, paint, SkTextUtils::kCenter_Align);
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void draw_row_label(SkCanvas* canvas, int y, int yuvFormat) {
|
2019-06-10 21:20:12 +00:00
|
|
|
static const char* kYUVFormatNames[] = {
|
2019-09-18 17:56:54 +00:00
|
|
|
"P016", "P010", "P016F", "Y416", "AYUV", "Y410", "NV12", "NV21", "I420", "YV12"
|
2019-06-10 21:20:12 +00:00
|
|
|
};
|
2019-12-18 15:43:10 +00:00
|
|
|
static_assert(SK_ARRAY_COUNT(kYUVFormatNames) == kLast_YUVFormat + 1);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2019-01-02 17:21:01 +00:00
|
|
|
SkPaint paint;
|
2019-03-20 16:12:10 +00:00
|
|
|
SkFont font(ToolUtils::create_portable_typeface(nullptr, SkFontStyle::Bold()), 16);
|
2019-01-02 17:21:01 +00:00
|
|
|
font.setEdging(SkFont::Edging::kAlias);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
|
|
|
SkRect textRect;
|
|
|
|
SkString rowLabel;
|
|
|
|
|
|
|
|
rowLabel.printf("%s", kYUVFormatNames[yuvFormat]);
|
2019-05-07 19:38:46 +00:00
|
|
|
font.measureText(rowLabel.c_str(), rowLabel.size(), SkTextEncoding::kUTF8, &textRect);
|
2018-10-03 16:12:26 +00:00
|
|
|
y += kTileWidthHeight/2 + textRect.height()/2;
|
|
|
|
|
2019-01-07 14:36:09 +00:00
|
|
|
canvas->drawString(rowLabel, 0, y, font, paint);
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 17:36:47 +00:00
|
|
|
static sk_sp<SkColorFilter> yuv_to_rgb_colorfilter() {
|
|
|
|
static const float kJPEGConversionMatrix[20] = {
|
2019-04-30 16:18:54 +00:00
|
|
|
1.0f, 0.0f, 1.402f, 0.0f, -180.0f/255,
|
|
|
|
1.0f, -0.344136f, -0.714136f, 0.0f, 136.0f/255,
|
|
|
|
1.0f, 1.772f, 0.0f, 0.0f, -227.6f/255,
|
2019-03-06 17:36:47 +00:00
|
|
|
0.0f, 0.0f, 0.0f, 1.0f, 0.0f
|
|
|
|
};
|
|
|
|
|
2019-04-30 16:18:54 +00:00
|
|
|
return SkColorFilters::Matrix(kJPEGConversionMatrix);
|
2019-03-06 17:36:47 +00:00
|
|
|
}
|
|
|
|
|
2018-10-03 16:12:26 +00:00
|
|
|
namespace skiagm {
|
|
|
|
|
|
|
|
// This GM creates an opaque and transparent bitmap, extracts the planes and then recombines
|
|
|
|
// them into various YUV formats. It then renders the results in the grid:
|
|
|
|
//
|
2019-03-21 13:00:20 +00:00
|
|
|
// JPEG 601 709 Identity
|
|
|
|
// Transparent Opaque Transparent Opaque Transparent Opaque Transparent Opaque
|
2019-06-10 21:20:12 +00:00
|
|
|
// originals
|
|
|
|
// P016
|
|
|
|
// P010
|
2019-09-18 17:56:54 +00:00
|
|
|
// P016F
|
2019-06-10 21:20:12 +00:00
|
|
|
// Y416
|
2018-10-03 16:12:26 +00:00
|
|
|
// AYUV
|
2019-03-21 13:00:20 +00:00
|
|
|
// Y410
|
2018-10-03 16:12:26 +00:00
|
|
|
// NV12
|
|
|
|
// NV21
|
|
|
|
// I420
|
|
|
|
// YV12
|
|
|
|
class WackyYUVFormatsGM : public GM {
|
|
|
|
public:
|
2020-10-16 14:05:21 +00:00
|
|
|
using Type = sk_gpu_test::LazyYUVImage::Type;
|
2020-09-21 14:50:30 +00:00
|
|
|
|
2020-10-16 14:05:21 +00:00
|
|
|
WackyYUVFormatsGM(bool useTargetColorSpace, bool useSubset, Type type)
|
|
|
|
: fUseTargetColorSpace(useTargetColorSpace), fUseSubset(useSubset), fImageType(type) {
|
2018-10-03 16:12:26 +00:00
|
|
|
this->setBGColor(0xFFCCCCCC);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
SkString onShortName() override {
|
2019-01-11 18:32:45 +00:00
|
|
|
SkString name("wacky_yuv_formats");
|
|
|
|
if (fUseTargetColorSpace) {
|
|
|
|
name += "_cs";
|
|
|
|
}
|
2020-09-21 14:50:30 +00:00
|
|
|
if (fUseSubset) {
|
2019-04-12 19:03:02 +00:00
|
|
|
name += "_domain";
|
|
|
|
}
|
2020-09-21 14:50:30 +00:00
|
|
|
switch (fImageType) {
|
2020-10-16 14:05:21 +00:00
|
|
|
case Type::kFromPixmaps:
|
2020-09-21 14:50:30 +00:00
|
|
|
name += "_frompixmaps";
|
|
|
|
break;
|
2020-10-16 14:05:21 +00:00
|
|
|
case Type::kFromTextures:
|
2020-09-21 14:50:30 +00:00
|
|
|
break;
|
2020-10-16 14:05:21 +00:00
|
|
|
case Type::kFromGenerator:
|
2020-09-21 14:50:30 +00:00
|
|
|
name += "_imggen";
|
|
|
|
break;
|
2020-09-18 18:09:51 +00:00
|
|
|
}
|
2019-03-21 13:00:20 +00:00
|
|
|
|
2019-01-11 18:32:45 +00:00
|
|
|
return name;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SkISize onISize() override {
|
2019-09-18 17:56:54 +00:00
|
|
|
int numCols = 2 * (kLastEnum_SkYUVColorSpace + 1); // opacity x #-color-spaces
|
|
|
|
int numRows = 1 + (kLast_YUVFormat + 1); // original + #-yuv-formats
|
2020-09-21 14:50:30 +00:00
|
|
|
int wh = SkScalarCeilToInt(kTileWidthHeight * (fUseSubset ? 1.5f : 1.f));
|
2019-04-12 19:03:02 +00:00
|
|
|
return SkISize::Make(kLabelWidth + numCols * (wh + kPad),
|
|
|
|
kLabelHeight + numRows * (wh + kPad));
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
2020-06-19 16:29:57 +00:00
|
|
|
void createBitmaps() {
|
2018-10-03 16:12:26 +00:00
|
|
|
SkPoint origin = { kTileWidthHeight/2.0f, kTileWidthHeight/2.0f };
|
|
|
|
float outerRadius = kTileWidthHeight/2.0f - 20.0f;
|
|
|
|
float innerRadius = 20.0f;
|
|
|
|
|
|
|
|
{
|
|
|
|
// transparent
|
|
|
|
SkTDArray<SkRect> circles;
|
|
|
|
SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 5, &circles);
|
2020-09-21 14:50:30 +00:00
|
|
|
fOriginalBMs[0] = make_bitmap(kRGBA_8888_SkColorType, path, circles, false, fUseSubset);
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// opaque
|
|
|
|
SkTDArray<SkRect> circles;
|
|
|
|
SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 7, &circles);
|
2020-09-21 14:50:30 +00:00
|
|
|
fOriginalBMs[1] = make_bitmap(kRGBA_8888_SkColorType, path, circles, true, fUseSubset);
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
2019-01-11 18:32:45 +00:00
|
|
|
|
|
|
|
if (fUseTargetColorSpace) {
|
|
|
|
fTargetColorSpace = SkColorSpace::MakeSRGB()->makeColorSpin();
|
|
|
|
}
|
2018-10-05 17:30:43 +00:00
|
|
|
}
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2020-07-17 15:59:01 +00:00
|
|
|
bool createImages(GrDirectContext* dContext) {
|
2021-01-19 17:11:07 +00:00
|
|
|
int origin = 0;
|
2018-10-03 16:12:26 +00:00
|
|
|
for (bool opaque : { false, true }) {
|
|
|
|
for (int cs = kJPEG_SkYUVColorSpace; cs <= kLastEnum_SkYUVColorSpace; ++cs) {
|
|
|
|
PlaneData planes;
|
2021-01-19 17:11:07 +00:00
|
|
|
extract_planes(fOriginalBMs[opaque],
|
|
|
|
static_cast<SkYUVColorSpace>(cs),
|
|
|
|
static_cast<SkEncodedOrigin>(origin + 1), // valid origins are 1...8
|
|
|
|
&planes);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2020-04-08 19:57:08 +00:00
|
|
|
for (int f = kP016_YUVFormat; f <= kLast_YUVFormat; ++f) {
|
|
|
|
auto format = static_cast<YUVFormat>(f);
|
2018-10-03 16:12:26 +00:00
|
|
|
SkBitmap resultBMs[4];
|
2019-03-21 13:00:20 +00:00
|
|
|
|
2020-09-21 14:50:30 +00:00
|
|
|
int numPlanes = create_YUV(planes, format, resultBMs, opaque);
|
2021-01-19 17:11:07 +00:00
|
|
|
const YUVAPlanarConfig planarConfig(format,
|
|
|
|
opaque,
|
|
|
|
static_cast<SkEncodedOrigin>(origin + 1));
|
2020-10-16 14:05:21 +00:00
|
|
|
SkYUVAPixmaps pixmaps =
|
|
|
|
planarConfig.makeYUVAPixmaps(fOriginalBMs[opaque].dimensions(),
|
|
|
|
static_cast<SkYUVColorSpace>(cs),
|
|
|
|
resultBMs,
|
|
|
|
numPlanes);
|
|
|
|
auto lazyYUV = sk_gpu_test::LazyYUVImage::Make(std::move(pixmaps));
|
|
|
|
|
|
|
|
fImages[opaque][cs][format] = lazyYUV->refImage(dContext, fImageType);
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
2021-01-19 17:11:07 +00:00
|
|
|
origin = (origin + 1) % 8;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-19 16:29:57 +00:00
|
|
|
|
2020-07-17 15:59:01 +00:00
|
|
|
if (dContext) {
|
2020-06-19 16:29:57 +00:00
|
|
|
// Some backends (e.g., Vulkan) require all work be completed for backend textures
|
|
|
|
// before they are deleted. Since we don't know when we'll next have access to a
|
|
|
|
// direct context, flush all the work now.
|
2020-07-17 15:59:01 +00:00
|
|
|
dContext->flush();
|
|
|
|
dContext->submit(true);
|
2020-06-19 16:29:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
2020-07-17 15:59:01 +00:00
|
|
|
DrawResult onGpuSetup(GrDirectContext* dContext, SkString* errorMsg) override {
|
2020-06-19 16:29:57 +00:00
|
|
|
this->createBitmaps();
|
2018-10-05 17:30:43 +00:00
|
|
|
|
2020-07-17 15:59:01 +00:00
|
|
|
if (dContext && dContext->abandoned()) {
|
2020-06-19 16:29:57 +00:00
|
|
|
// This isn't a GpuGM so a null 'context' is okay but an abandoned context
|
|
|
|
// if forbidden.
|
|
|
|
return DrawResult::kSkip;
|
|
|
|
}
|
|
|
|
|
2020-09-21 14:50:30 +00:00
|
|
|
// Only the generator is expected to work with the CPU backend.
|
2020-10-16 14:05:21 +00:00
|
|
|
if (fImageType != Type::kFromGenerator && !dContext) {
|
2020-09-21 14:50:30 +00:00
|
|
|
return DrawResult::kSkip;
|
|
|
|
}
|
|
|
|
|
2020-07-17 15:59:01 +00:00
|
|
|
if (!this->createImages(dContext)) {
|
2020-06-19 16:29:57 +00:00
|
|
|
*errorMsg = "Failed to create YUV images";
|
|
|
|
return DrawResult::kFail;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DrawResult::kOk;
|
|
|
|
}
|
|
|
|
|
2020-06-25 16:38:53 +00:00
|
|
|
void onGpuTeardown() override {
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
for (int j = 0; j <= kLastEnum_SkYUVColorSpace; ++j) {
|
|
|
|
for (int k = 0; k <= kLast_YUVFormat; ++k) {
|
|
|
|
fImages[i][j][k] = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-19 16:29:57 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2020-09-21 14:50:30 +00:00
|
|
|
auto direct = GrAsDirectContext(canvas->recordingContext());
|
|
|
|
|
2020-01-29 13:37:01 +00:00
|
|
|
float cellWidth = kTileWidthHeight, cellHeight = kTileWidthHeight;
|
2020-09-21 14:50:30 +00:00
|
|
|
if (fUseSubset) {
|
2020-01-29 13:37:01 +00:00
|
|
|
cellWidth *= 1.5f;
|
|
|
|
cellHeight *= 1.5f;
|
|
|
|
}
|
|
|
|
|
2020-09-21 14:50:30 +00:00
|
|
|
SkRect srcRect = SkRect::Make(fOriginalBMs[0].dimensions());
|
2019-04-12 19:03:02 +00:00
|
|
|
SkRect dstRect = SkRect::MakeXYWH(kLabelWidth, 0.f, srcRect.width(), srcRect.height());
|
2020-09-21 14:50:30 +00:00
|
|
|
|
2019-04-12 19:03:02 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint = SkCanvas::kFast_SrcRectConstraint;
|
2020-09-21 14:50:30 +00:00
|
|
|
if (fUseSubset) {
|
|
|
|
srcRect.inset(kSubsetPadding, kSubsetPadding);
|
2019-04-12 19:03:02 +00:00
|
|
|
// Draw a larger rectangle to ensure bilerp filtering would normally read outside the
|
|
|
|
// srcRect and hit the red pixels, if strict constraint weren't used.
|
|
|
|
dstRect.fRight = kLabelWidth + 1.5f * srcRect.width();
|
|
|
|
dstRect.fBottom = 1.5f * srcRect.height();
|
|
|
|
constraint = SkCanvas::kStrict_SrcRectConstraint;
|
|
|
|
}
|
|
|
|
|
2021-01-24 02:14:47 +00:00
|
|
|
SkSamplingOptions sampling(SkFilterMode::kLinear);
|
2018-10-03 16:12:26 +00:00
|
|
|
for (int cs = kJPEG_SkYUVColorSpace; cs <= kLastEnum_SkYUVColorSpace; ++cs) {
|
2019-03-06 17:36:47 +00:00
|
|
|
SkPaint paint;
|
|
|
|
if (kIdentity_SkYUVColorSpace == cs) {
|
|
|
|
// The identity color space needs post processing to appear correctly
|
|
|
|
paint.setColorFilter(yuv_to_rgb_colorfilter());
|
|
|
|
}
|
|
|
|
|
2018-10-03 16:12:26 +00:00
|
|
|
for (int opaque : { 0, 1 }) {
|
2019-04-12 19:03:02 +00:00
|
|
|
dstRect.offsetTo(dstRect.fLeft, kLabelHeight);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2020-01-29 13:37:01 +00:00
|
|
|
draw_col_label(canvas, dstRect.fLeft + cellWidth / 2, cs, opaque);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2021-01-25 22:49:32 +00:00
|
|
|
canvas->drawImageRect(fOriginalBMs[opaque].asImage(), srcRect, dstRect,
|
|
|
|
SkSamplingOptions(), nullptr, constraint);
|
2020-01-29 13:37:01 +00:00
|
|
|
dstRect.offset(0.f, cellHeight + kPad);
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2019-06-10 21:20:12 +00:00
|
|
|
for (int format = kP016_YUVFormat; format <= kLast_YUVFormat; ++format) {
|
2019-04-12 19:03:02 +00:00
|
|
|
draw_row_label(canvas, dstRect.fTop, format);
|
2019-01-11 18:32:45 +00:00
|
|
|
if (fUseTargetColorSpace && fImages[opaque][cs][format]) {
|
2019-03-06 17:36:47 +00:00
|
|
|
// Making a CS-specific version of a kIdentity_SkYUVColorSpace YUV image
|
|
|
|
// doesn't make a whole lot of sense. The colorSpace conversion will
|
|
|
|
// operate on the YUV components rather than the RGB components.
|
2019-01-11 18:32:45 +00:00
|
|
|
sk_sp<SkImage> csImage =
|
2020-07-15 14:37:50 +00:00
|
|
|
fImages[opaque][cs][format]->makeColorSpace(fTargetColorSpace, direct);
|
2021-01-24 02:14:47 +00:00
|
|
|
canvas->drawImageRect(csImage, srcRect, dstRect, sampling,
|
|
|
|
&paint, constraint);
|
2019-01-11 18:32:45 +00:00
|
|
|
} else {
|
2020-01-29 13:37:01 +00:00
|
|
|
canvas->drawImageRect(fImages[opaque][cs][format], srcRect, dstRect,
|
2021-01-24 02:14:47 +00:00
|
|
|
sampling, &paint, constraint);
|
2019-01-11 18:32:45 +00:00
|
|
|
}
|
2020-01-29 13:37:01 +00:00
|
|
|
dstRect.offset(0.f, cellHeight + kPad);
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
|
2020-01-29 13:37:01 +00:00
|
|
|
dstRect.offset(cellWidth + kPad, 0.f);
|
2018-10-03 16:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2019-03-21 13:00:20 +00:00
|
|
|
SkBitmap fOriginalBMs[2];
|
|
|
|
sk_sp<SkImage> fImages[2][kLastEnum_SkYUVColorSpace + 1][kLast_YUVFormat + 1];
|
|
|
|
bool fUseTargetColorSpace;
|
2020-09-21 14:50:30 +00:00
|
|
|
bool fUseSubset;
|
2020-10-16 14:05:21 +00:00
|
|
|
Type fImageType;
|
2019-03-21 13:00:20 +00:00
|
|
|
sk_sp<SkColorSpace> fTargetColorSpace;
|
2018-10-03 16:12:26 +00:00
|
|
|
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = GM;
|
2018-10-03 16:12:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2020-09-21 14:50:30 +00:00
|
|
|
DEF_GM(return new WackyYUVFormatsGM(/* target cs */ false,
|
|
|
|
/* subset */ false,
|
2020-10-16 14:05:21 +00:00
|
|
|
WackyYUVFormatsGM::Type::kFromTextures);)
|
2020-09-21 14:50:30 +00:00
|
|
|
DEF_GM(return new WackyYUVFormatsGM(/* target cs */ false,
|
|
|
|
/* subset */ true,
|
2020-10-16 14:05:21 +00:00
|
|
|
WackyYUVFormatsGM::Type::kFromTextures);)
|
2020-09-21 14:50:30 +00:00
|
|
|
DEF_GM(return new WackyYUVFormatsGM(/* target cs */ true,
|
|
|
|
/* subset */ false,
|
2020-10-16 14:05:21 +00:00
|
|
|
WackyYUVFormatsGM::Type::kFromTextures);)
|
2020-09-21 14:50:30 +00:00
|
|
|
DEF_GM(return new WackyYUVFormatsGM(/* target cs */ false,
|
|
|
|
/* subset */ false,
|
2020-10-16 14:05:21 +00:00
|
|
|
WackyYUVFormatsGM::Type::kFromGenerator);)
|
2020-09-21 14:50:30 +00:00
|
|
|
DEF_GM(return new WackyYUVFormatsGM(/* target cs */ false,
|
|
|
|
/* subset */ false,
|
2020-10-16 14:05:21 +00:00
|
|
|
WackyYUVFormatsGM::Type::kFromPixmaps);)
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
|
2021-06-03 14:14:16 +00:00
|
|
|
class YUVMakeColorSpaceGM : public GM {
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
public:
|
|
|
|
YUVMakeColorSpaceGM() {
|
|
|
|
this->setBGColor(0xFFCCCCCC);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
SkString onShortName() override {
|
|
|
|
return SkString("yuv_make_color_space");
|
|
|
|
}
|
|
|
|
|
|
|
|
SkISize onISize() override {
|
|
|
|
int numCols = 4; // (transparent, opaque) x (untagged, tagged)
|
2020-06-19 16:29:57 +00:00
|
|
|
int numRows = 5; // original, YUV, subset, makeNonTextureImage, readPixels
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
return SkISize::Make(numCols * (kTileWidthHeight + kPad) + kPad,
|
|
|
|
numRows * (kTileWidthHeight + kPad) + kPad);
|
|
|
|
}
|
|
|
|
|
2020-06-19 16:29:57 +00:00
|
|
|
void createBitmaps() {
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
SkPoint origin = { kTileWidthHeight/2.0f, kTileWidthHeight/2.0f };
|
|
|
|
float outerRadius = kTileWidthHeight/2.0f - 20.0f;
|
|
|
|
float innerRadius = 20.0f;
|
|
|
|
|
|
|
|
{
|
|
|
|
// transparent
|
|
|
|
SkTDArray<SkRect> circles;
|
|
|
|
SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 5, &circles);
|
2019-04-12 19:03:02 +00:00
|
|
|
fOriginalBMs[0] = make_bitmap(kN32_SkColorType, path, circles, false, false);
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// opaque
|
|
|
|
SkTDArray<SkRect> circles;
|
|
|
|
SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 7, &circles);
|
2019-04-12 19:03:02 +00:00
|
|
|
fOriginalBMs[1] = make_bitmap(kN32_SkColorType, path, circles, true, false);
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fTargetColorSpace = SkColorSpace::MakeSRGB()->makeColorSpin();
|
|
|
|
}
|
|
|
|
|
2020-07-01 18:45:24 +00:00
|
|
|
bool createImages(GrDirectContext* context) {
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
for (bool opaque : { false, true }) {
|
|
|
|
PlaneData planes;
|
2021-01-19 17:11:07 +00:00
|
|
|
extract_planes(fOriginalBMs[opaque],
|
|
|
|
kJPEG_SkYUVColorSpace,
|
|
|
|
kTopLeft_SkEncodedOrigin,
|
|
|
|
&planes);
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
|
|
|
|
SkBitmap resultBMs[4];
|
2019-03-21 13:00:20 +00:00
|
|
|
|
2020-04-08 19:57:08 +00:00
|
|
|
create_YUV(planes, kAYUV_YUVFormat, resultBMs, opaque);
|
2019-03-21 13:00:20 +00:00
|
|
|
|
2021-01-19 17:11:07 +00:00
|
|
|
YUVAPlanarConfig planarConfig(kAYUV_YUVFormat, opaque, kTopLeft_SkEncodedOrigin);
|
2020-06-19 16:29:57 +00:00
|
|
|
|
2020-10-16 14:05:21 +00:00
|
|
|
auto yuvaPixmaps = planarConfig.makeYUVAPixmaps(fOriginalBMs[opaque].dimensions(),
|
|
|
|
kJPEG_Full_SkYUVColorSpace,
|
|
|
|
resultBMs,
|
|
|
|
SK_ARRAY_COUNT(resultBMs));
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (sk_sp<SkColorSpace> cs : {sk_sp<SkColorSpace>(nullptr),
|
|
|
|
SkColorSpace::MakeSRGB()}) {
|
|
|
|
auto lazyYUV = sk_gpu_test::LazyYUVImage::Make(yuvaPixmaps,
|
|
|
|
GrMipmapped::kNo,
|
|
|
|
std::move(cs));
|
|
|
|
fImages[opaque][i++] =
|
|
|
|
lazyYUV->refImage(context, sk_gpu_test::LazyYUVImage::Type::kFromTextures);
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-19 16:29:57 +00:00
|
|
|
|
|
|
|
// Some backends (e.g., Vulkan) require all work be completed for backend textures before
|
|
|
|
// they are deleted. Since we don't know when we'll next have access to a direct context,
|
|
|
|
// flush all the work now.
|
2020-06-30 17:42:46 +00:00
|
|
|
context->flush();
|
2020-06-19 16:29:57 +00:00
|
|
|
context->submit(true);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-03 14:14:16 +00:00
|
|
|
DrawResult onGpuSetup(GrDirectContext* dContext, SkString* errorMsg) override {
|
|
|
|
if (!dContext || dContext->abandoned()) {
|
|
|
|
*errorMsg = "DirectContext required to create YUV images";
|
2020-06-19 16:29:57 +00:00
|
|
|
return DrawResult::kSkip;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->createBitmaps();
|
2021-06-03 14:14:16 +00:00
|
|
|
if (!this->createImages(dContext)) {
|
2020-06-19 16:29:57 +00:00
|
|
|
*errorMsg = "Failed to create YUV images";
|
|
|
|
return DrawResult::kFail;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DrawResult::kOk;
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 16:38:53 +00:00
|
|
|
void onGpuTeardown() override {
|
|
|
|
fImages[0][0] = fImages[0][1] = fImages[1][0] = fImages[1][1] = nullptr;
|
|
|
|
}
|
|
|
|
|
2021-06-03 14:14:16 +00:00
|
|
|
DrawResult onDraw(SkCanvas* canvas, SkString* msg) override {
|
2020-06-19 16:29:57 +00:00
|
|
|
SkASSERT(fImages[0][0] && fImages[0][1] && fImages[1][0] && fImages[1][1]);
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
|
2021-06-03 14:14:16 +00:00
|
|
|
auto dContext = GrAsDirectContext(canvas->recordingContext());
|
|
|
|
if (!dContext) {
|
2020-07-15 14:37:50 +00:00
|
|
|
*msg = "YUV ColorSpace image creation requires a direct context.";
|
|
|
|
return DrawResult::kSkip;
|
|
|
|
}
|
|
|
|
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
int x = kPad;
|
|
|
|
for (int tagged : { 0, 1 }) {
|
|
|
|
for (int opaque : { 0, 1 }) {
|
|
|
|
int y = kPad;
|
|
|
|
|
2021-06-03 14:14:16 +00:00
|
|
|
auto raster = fOriginalBMs[opaque].asImage()->makeColorSpace(fTargetColorSpace,
|
|
|
|
nullptr);
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
canvas->drawImage(raster, x, y);
|
|
|
|
y += kTileWidthHeight + kPad;
|
|
|
|
|
2020-03-09 19:18:35 +00:00
|
|
|
if (fImages[opaque][tagged]) {
|
2020-08-27 16:44:07 +00:00
|
|
|
auto yuv = fImages[opaque][tagged]->makeColorSpace(fTargetColorSpace, dContext);
|
2020-07-15 14:37:50 +00:00
|
|
|
SkASSERT(yuv);
|
2020-03-09 19:18:35 +00:00
|
|
|
SkASSERT(SkColorSpace::Equals(yuv->colorSpace(), fTargetColorSpace.get()));
|
|
|
|
canvas->drawImage(yuv, x, y);
|
|
|
|
y += kTileWidthHeight + kPad;
|
|
|
|
|
2020-07-10 18:33:22 +00:00
|
|
|
SkIRect bounds = SkIRect::MakeWH(kTileWidthHeight / 2, kTileWidthHeight / 2);
|
2020-08-27 16:44:07 +00:00
|
|
|
auto subset = yuv->makeSubset(bounds, dContext);
|
2020-07-15 14:37:50 +00:00
|
|
|
SkASSERT(subset);
|
2020-03-09 19:18:35 +00:00
|
|
|
canvas->drawImage(subset, x, y);
|
|
|
|
y += kTileWidthHeight + kPad;
|
|
|
|
|
|
|
|
auto nonTexture = yuv->makeNonTextureImage();
|
2020-07-15 14:37:50 +00:00
|
|
|
SkASSERT(nonTexture);
|
2020-03-09 19:18:35 +00:00
|
|
|
canvas->drawImage(nonTexture, x, y);
|
|
|
|
y += kTileWidthHeight + kPad;
|
|
|
|
|
|
|
|
SkBitmap readBack;
|
|
|
|
readBack.allocPixels(yuv->imageInfo());
|
2020-08-27 16:44:07 +00:00
|
|
|
SkAssertResult(yuv->readPixels(dContext, readBack.pixmap(), 0, 0));
|
2021-01-25 22:49:32 +00:00
|
|
|
canvas->drawImage(readBack.asImage(), x, y);
|
2020-03-09 19:18:35 +00:00
|
|
|
}
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
x += kTileWidthHeight + kPad;
|
|
|
|
}
|
|
|
|
}
|
2020-07-15 14:37:50 +00:00
|
|
|
return DrawResult::kOk;
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkBitmap fOriginalBMs[2];
|
|
|
|
sk_sp<SkImage> fImages[2][2];
|
|
|
|
sk_sp<SkColorSpace> fTargetColorSpace;
|
|
|
|
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = GM;
|
Fix makeColorSpace on YUV images
This is a second attempt at https://skia-review.googlesource.com/c/skia/+/182816
This version ensures that SkImage::colorSpace() returns the target after
makeColorSpace has been called (to match user expectations, and match
behavior with lazy images). Given that, the xform is baked into the FP
within the maker, rather than externally (again, this matches the lazy
image behavior).
Additionally, the target color space needs to be taken into account when
flattening into the RGB proxy, and some base-class methods need to use
this->colorSpace() rather than fColorSpace to tag the output.
Added a GM that tests quite a few different scenarios. All images have
makeColorSpace() applied:
- Raster image (for reference)
- yuvImage
- yuvImage->makeSubset()
- yuvImage->makeNonTextureImage()
- readPixels(yuvImage)
All images should look the same as the top row. Verified that they do
match, in both untagged (gl) and tagged (glsrgb) configs.
I think there may still be some cases where we transform too many or too
few times, or incorrectly tag the result of an image operation, but this
is much more correct than before, and should (I hope) address Chrome's
immediate needs.
Bug: skia:8740
Change-Id: I5d501879866861a5ba91240f688d3f95711f7595
Reviewed-on: https://skia-review.googlesource.com/c/189494
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2019-02-05 22:00:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DEF_GM(return new YUVMakeColorSpaceGM();)
|
|
|
|
|
2020-08-06 18:11:56 +00:00
|
|
|
} // namespace skiagm
|
2019-05-23 19:30:07 +00:00
|
|
|
|
|
|
|
///////////////
|
|
|
|
|
|
|
|
#include "include/effects/SkColorMatrix.h"
|
2019-06-06 16:44:05 +00:00
|
|
|
#include "src/core/SkAutoPixmapStorage.h"
|
|
|
|
#include "tools/Resources.h"
|
2019-05-23 19:30:07 +00:00
|
|
|
|
|
|
|
static void draw_diff(SkCanvas* canvas, SkScalar x, SkScalar y,
|
|
|
|
const SkImage* a, const SkImage* b) {
|
2020-12-10 02:48:52 +00:00
|
|
|
auto sh = SkShaders::Blend(SkBlendMode::kDifference,
|
|
|
|
a->makeShader(SkSamplingOptions()),
|
|
|
|
b->makeShader(SkSamplingOptions()));
|
2019-05-23 19:30:07 +00:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setShader(sh);
|
|
|
|
canvas->save();
|
|
|
|
canvas->translate(x, y);
|
|
|
|
canvas->drawRect(SkRect::MakeWH(a->width(), a->height()), paint);
|
|
|
|
|
|
|
|
SkColorMatrix cm;
|
|
|
|
cm.setScale(64, 64, 64);
|
|
|
|
paint.setShader(sh->makeWithColorFilter(SkColorFilters::Matrix(cm)));
|
|
|
|
canvas->translate(0, a->height());
|
|
|
|
canvas->drawRect(SkRect::MakeWH(a->width(), a->height()), paint);
|
|
|
|
|
|
|
|
canvas->restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exercises SkColorMatrix_RGB2YUV for yuv colorspaces, showing the planes, and the
|
|
|
|
// resulting (recombined) images (gpu only for now).
|
|
|
|
//
|
|
|
|
class YUVSplitterGM : public skiagm::GM {
|
2021-05-21 18:00:44 +00:00
|
|
|
sk_sp<SkImage> fOrig;
|
2019-05-23 19:30:07 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
YUVSplitterGM() {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
SkString onShortName() override {
|
|
|
|
return SkString("yuv_splitter");
|
|
|
|
}
|
|
|
|
|
|
|
|
SkISize onISize() override {
|
2019-11-01 14:02:24 +00:00
|
|
|
return SkISize::Make(1280, 768);
|
2019-05-23 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void onOnceBeforeDraw() override {
|
|
|
|
fOrig = GetResourceAsImage("images/mandrill_256.png");
|
|
|
|
}
|
|
|
|
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
|
|
canvas->translate(fOrig->width(), 0);
|
|
|
|
canvas->save();
|
2021-05-21 18:00:44 +00:00
|
|
|
SkYUVAInfo info;
|
|
|
|
std::array<sk_sp<SkImage>, SkYUVAInfo::kMaxPlanes> planes;
|
|
|
|
for (auto cs : {kRec709_SkYUVColorSpace,
|
|
|
|
kRec601_SkYUVColorSpace,
|
|
|
|
kJPEG_SkYUVColorSpace,
|
2019-11-01 14:02:24 +00:00
|
|
|
kBT2020_SkYUVColorSpace}) {
|
2021-05-21 18:00:44 +00:00
|
|
|
std::tie(planes, info) = sk_gpu_test::MakeYUVAPlanesAsA8(fOrig.get(),
|
|
|
|
cs,
|
|
|
|
SkYUVAInfo::Subsampling::k444,
|
|
|
|
/*recording context*/ nullptr);
|
|
|
|
SkPixmap pixmaps[4];
|
|
|
|
for (int i = 0; i < info.numPlanes(); ++i) {
|
|
|
|
planes[i]->peekPixels(&pixmaps[i]);
|
|
|
|
}
|
|
|
|
auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(info, pixmaps);
|
2020-10-05 17:25:05 +00:00
|
|
|
auto img = SkImage::MakeFromYUVAPixmaps(canvas->recordingContext(),
|
|
|
|
yuvaPixmaps,
|
2022-04-15 13:19:38 +00:00
|
|
|
GrMipmapped::kNo,
|
2020-10-05 17:25:05 +00:00
|
|
|
/* limit to max tex size */ false,
|
|
|
|
/* color space */ nullptr);
|
2019-05-23 19:30:07 +00:00
|
|
|
if (img) {
|
2021-01-24 02:14:47 +00:00
|
|
|
canvas->drawImage(img, 0, 0);
|
2019-05-23 19:30:07 +00:00
|
|
|
draw_diff(canvas, 0, fOrig->height(), fOrig.get(), img.get());
|
|
|
|
}
|
|
|
|
canvas->translate(fOrig->width(), 0);
|
|
|
|
}
|
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(-fOrig->width(), 0);
|
2021-05-21 18:00:44 +00:00
|
|
|
int y = 0;
|
|
|
|
for (int i = 0; i < info.numPlanes(); ++i) {
|
|
|
|
canvas->drawImage(planes[i], 0, y);
|
|
|
|
y += planes[i]->height();
|
|
|
|
}
|
2019-05-23 19:30:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = GM;
|
2019-05-23 19:30:07 +00:00
|
|
|
};
|
|
|
|
DEF_GM( return new YUVSplitterGM; )
|