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:
parent
e1be373a44
commit
2232b9ed39
@ -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);)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -65,6 +65,7 @@ protected:
|
||||
|
||||
SkAlphaType alphaType() const override;
|
||||
SkColorSpace* colorSpace() const override;
|
||||
SkColorSpace* targetColorSpace() const override;
|
||||
|
||||
private:
|
||||
const SkImage_GpuYUVA* fImage;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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[],
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user