Add target SkColorSpace to SkImage_GpuYUVA.

Bug: skia:8868
Change-Id: I91f58bf88aec14c17ea904adca792e20099c36eb
Reviewed-on: https://skia-review.googlesource.com/c/182816
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Jim Van Verth 2019-01-10 17:03:25 -05:00 committed by Skia Commit-Bot
parent e1be373a44
commit 2232b9ed39
11 changed files with 118 additions and 44 deletions

View File

@ -719,14 +719,18 @@ namespace skiagm {
// YV12
class WackyYUVFormatsGM : public GM {
public:
WackyYUVFormatsGM() {
WackyYUVFormatsGM(bool useTargetColorSpace) : fUseTargetColorSpace(useTargetColorSpace) {
this->setBGColor(0xFFCCCCCC);
}
protected:
SkString onShortName() override {
return SkString("wacky_yuv_formats");
SkString name("wacky_yuv_formats");
if (fUseTargetColorSpace) {
name += "_cs";
}
return name;
}
SkISize onISize() override {
@ -754,6 +758,10 @@ protected:
SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 7, &circles);
fOriginalBMs[1] = make_bitmap(path, circles, true);
}
if (fUseTargetColorSpace) {
fTargetColorSpace = SkColorSpace::MakeSRGB()->makeColorSpin();
}
}
void createImages(GrContext* context) {
@ -850,8 +858,13 @@ protected:
for (int format = kAYUV_YUVFormat; format <= kLast_YUVFormat; ++format) {
draw_row_label(canvas, y, format);
canvas->drawImage(fImages[opaque][cs][format], x, y);
if (fUseTargetColorSpace) {
sk_sp<SkImage> csImage =
fImages[opaque][cs][format]->makeColorSpace(fTargetColorSpace);
canvas->drawImage(csImage, x, y);
} else {
canvas->drawImage(fImages[opaque][cs][format], x, y);
}
y += kTileWidthHeight + kPad;
}
@ -863,11 +876,14 @@ protected:
private:
SkBitmap fOriginalBMs[2];
sk_sp<SkImage> fImages[2][kLastEnum_SkYUVColorSpace+1][kLast_YUVFormat+1];
bool fUseTargetColorSpace;
sk_sp<SkColorSpace> fTargetColorSpace;
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM(return new WackyYUVFormatsGM;)
DEF_GM(return new WackyYUVFormatsGM(false);)
DEF_GM(return new WackyYUVFormatsGM(true);)
}

View File

@ -81,6 +81,9 @@ SkAlphaType GrYUVAImageTextureMaker::alphaType() const {
SkColorSpace* GrYUVAImageTextureMaker::colorSpace() const {
return fImage->colorSpace();
}
SkColorSpace* GrYUVAImageTextureMaker::targetColorSpace() const {
return fImage->targetColorSpace();
}
std::unique_ptr<GrFragmentProcessor> GrYUVAImageTextureMaker::createFragmentProcessor(
const SkMatrix& textureMatrix,

View File

@ -65,6 +65,7 @@ protected:
SkAlphaType alphaType() const override;
SkColorSpace* colorSpace() const override;
SkColorSpace* targetColorSpace() const override;
private:
const SkImage_GpuYUVA* fImage;

View File

@ -109,6 +109,7 @@ public:
bool isAlphaOnly() const { return fIsAlphaOnly; }
virtual SkAlphaType alphaType() const = 0;
virtual SkColorSpace* colorSpace() const = 0;
virtual SkColorSpace* targetColorSpace() const { return nullptr; }
protected:
friend class GrTextureProducer_TestAccess;

View File

@ -289,8 +289,11 @@ void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer,
}
auto fp = producer->createFragmentProcessor(*textureMatrix, clippedSrcRect, constraintMode,
coordsAllInsideSrcRect, filterMode);
SkColorSpace* rtColorSpace = fRenderTargetContext->colorSpaceInfo().colorSpace();
SkColorSpace* targetColorSpace = producer->targetColorSpace();
SkColorSpace* dstColorSpace = SkToBool(rtColorSpace) ? rtColorSpace : targetColorSpace;
fp = GrColorSpaceXformEffect::Make(std::move(fp), producer->colorSpace(), producer->alphaType(),
fRenderTargetContext->colorSpaceInfo().colorSpace());
dstColorSpace);
if (!fp) {
return;
}

View File

@ -60,6 +60,42 @@ SkImageInfo SkImage_Gpu::onImageInfo() const {
return SkImageInfo::Make(fProxy->width(), fProxy->height(), colorType, fAlphaType, fColorSpace);
}
sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), fAlphaType,
target.get(), fAlphaType);
SkASSERT(xform);
sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
GrBackendFormat format = proxy->backendFormat().makeTexture2D();
if (!format.isValid()) {
return nullptr;
}
sk_sp<GrRenderTargetContext> renderTargetContext(
fContext->contextPriv().makeDeferredRenderTargetContextWithFallback(
format, SkBackingFit::kExact, this->width(), this->height(),
proxy->config(), nullptr));
if (!renderTargetContext) {
return nullptr;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.addColorTextureProcessor(std::move(proxy), SkMatrix::I());
paint.addColorFragmentProcessor(std::move(xform));
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
SkRect::MakeIWH(this->width(), this->height()));
if (!renderTargetContext->asTextureProxy()) {
return nullptr;
}
// MDB: this call is okay bc we know 'renderTargetContext' was exact
return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fAlphaType,
renderTargetContext->asTextureProxyRef(), std::move(target));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,

View File

@ -37,6 +37,8 @@ public:
virtual bool onIsTextureBacked() const override { return SkToBool(fProxy.get()); }
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const final;
/**
Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The main
difference is that the client doesn't have the backend texture on the gpu yet but they know

View File

@ -256,42 +256,6 @@ GrTexture* SkImage_GpuBase::onGetTexture() const {
return proxy->peekTexture();
}
sk_sp<SkImage> SkImage_GpuBase::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), fAlphaType,
target.get(), fAlphaType);
SkASSERT(xform);
sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
GrBackendFormat format = proxy->backendFormat().makeTexture2D();
if (!format.isValid()) {
return nullptr;
}
sk_sp<GrRenderTargetContext> renderTargetContext(
fContext->contextPriv().makeDeferredRenderTargetContextWithFallback(
format, SkBackingFit::kExact, this->width(), this->height(),
proxy->config(), nullptr));
if (!renderTargetContext) {
return nullptr;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.addColorTextureProcessor(std::move(proxy), SkMatrix::I());
paint.addColorFragmentProcessor(std::move(xform));
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
SkRect::MakeIWH(this->width(), this->height()));
if (!renderTargetContext->asTextureProxy()) {
return nullptr;
}
// MDB: this call is okay bc we know 'renderTargetContext' was exact
return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fAlphaType,
renderTargetContext->asTextureProxyRef(), std::move(target));
}
bool SkImage_GpuBase::onIsValid(GrContext* context) const {
// The base class has already checked that context isn't abandoned (if it's not nullptr)
if (fContext->abandoned()) {

View File

@ -49,8 +49,6 @@ public:
GrTexture* onGetTexture() const final;
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const final;
bool onIsValid(GrContext*) const final;
#if GR_TEST_UTILS

View File

@ -48,6 +48,28 @@ SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height
memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex));
}
// For onMakeColorSpace()
SkImage_GpuYUVA::SkImage_GpuYUVA(const SkImage_GpuYUVA* image, sk_sp<SkColorSpace> targetCS)
: INHERITED(image->fContext, image->width(), image->height(), kNeedNewImageUniqueID,
// 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.
GetAlphaTypeFromYUVAIndices(image->fYUVAIndices), image->fColorSpace)
, fNumProxies(image->fNumProxies)
, fYUVColorSpace(image->fYUVColorSpace)
, fOrigin(image->fOrigin)
, fTargetColorSpace(targetCS) {
// The caller should have done this work, just verifying
SkDEBUGCODE(int textureCount;)
SkASSERT(SkYUVAIndex::AreValidIndices(image->fYUVAIndices, &textureCount));
SkASSERT(textureCount == fNumProxies);
for (int i = 0; i < fNumProxies; ++i) {
fProxies[i] = image->fProxies[i]; // we ref in this case, not move
}
memcpy(fYUVAIndices, image->fYUVAIndices, 4 * sizeof(SkYUVAIndex));
}
SkImage_GpuYUVA::~SkImage_GpuYUVA() {}
SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
@ -121,6 +143,22 @@ sk_sp<GrTextureProxy> SkImage_GpuYUVA::asMippedTextureProxyRef() const {
//////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage_GpuYUVA::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
// we may need a mutex here but for now we expect usage to be in a single thread
if (fOnMakeColorSpaceTarget &&
SkColorSpace::Equals(target.get(), fOnMakeColorSpaceTarget.get())) {
return fOnMakeColorSpaceResult;
}
sk_sp<SkImage> result = sk_sp<SkImage>(new SkImage_GpuYUVA(this, target));
if (result) {
fOnMakeColorSpaceTarget = target;
fOnMakeColorSpaceResult = result;
}
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx,
SkYUVColorSpace colorSpace,
const GrBackendTexture yuvaTextures[],

View File

@ -36,6 +36,8 @@ public:
virtual bool onIsTextureBacked() const override { return SkToBool(fProxies[0].get()); }
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const final;
virtual bool isYUVA() const override { return true; }
virtual bool asYUVATextureProxiesRef(sk_sp<GrTextureProxy> proxies[4],
SkYUVAIndex yuvaIndices[4],
@ -53,6 +55,8 @@ public:
// Returns a ref-ed texture proxy with miplevels
sk_sp<GrTextureProxy> asMippedTextureProxyRef() const;
SkColorSpace* targetColorSpace() const { return fTargetColorSpace.get(); }
/**
Create a new SkImage_GpuYUVA that's very similar to SkImage created by MakeFromYUVATextures.
The main difference is that the client doesn't have the backend textures on the gpu yet but
@ -109,6 +113,8 @@ public:
PromiseImageTextureContext textureContexts[]);
private:
SkImage_GpuYUVA(const SkImage_GpuYUVA* image, sk_sp<SkColorSpace>);
// This array will usually only be sparsely populated.
// The actual non-null fields are dictated by the 'fYUVAIndices' indices
mutable sk_sp<GrTextureProxy> fProxies[4];
@ -116,6 +122,12 @@ private:
SkYUVAIndex fYUVAIndices[4];
const SkYUVColorSpace fYUVColorSpace;
GrSurfaceOrigin fOrigin;
const sk_sp<SkColorSpace> fTargetColorSpace;
// Repeated calls to onMakeColorSpace will result in a proliferation of unique IDs and
// SkImage_GpuYUVA instances. Cache the result of the last successful onMakeColorSpace call.
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