Implement more SkImage_GpuYUVA functionality

Bug: skia:7901
Change-Id: I78a947edb924e0a1240537a83aa0bc111239e567
Reviewed-on: https://skia-review.googlesource.com/c/159320
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Jim Van Verth 2018-10-04 13:10:39 -04:00 committed by Skia Commit-Bot
parent 5959353a31
commit 8026ccc46e
9 changed files with 329 additions and 385 deletions

View File

@ -544,8 +544,8 @@ skia_gpu_sources = [
"$_src/image/SkImage_Gpu.h", "$_src/image/SkImage_Gpu.h",
"$_src/image/SkImage_Gpu.cpp", "$_src/image/SkImage_Gpu.cpp",
"$_src/image/SkImage_GpuShared.h", "$_src/image/SkImage_GpuBase.h",
"$_src/image/SkImage_GpuShared.cpp", "$_src/image/SkImage_GpuBase.cpp",
"$_src/image/SkImage_GpuYUVA.h", "$_src/image/SkImage_GpuYUVA.h",
"$_src/image/SkImage_GpuYUVA.cpp", "$_src/image/SkImage_GpuYUVA.cpp",
"$_src/image/SkSurface_Gpu.h", "$_src/image/SkSurface_Gpu.h",

View File

@ -37,7 +37,6 @@
#include "SkGr.h" #include "SkGr.h"
#include "SkImageInfoPriv.h" #include "SkImageInfoPriv.h"
#include "SkImage_Gpu.h" #include "SkImage_Gpu.h"
#include "SkImage_GpuShared.h"
#include "SkMipMap.h" #include "SkMipMap.h"
#include "SkPixelRef.h" #include "SkPixelRef.h"
#include "SkReadPixelsRec.h" #include "SkReadPixelsRec.h"
@ -46,17 +45,12 @@
#include "effects/GrYUVtoRGBEffect.h" #include "effects/GrYUVtoRGBEffect.h"
#include "gl/GrGLTexture.h" #include "gl/GrGLTexture.h"
using namespace SkImage_GpuShared;
SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at, SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at,
sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace, sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace,
SkBudgeted budgeted) SkBudgeted budgeted)
: INHERITED(proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID) : INHERITED(std::move(context), proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID,
, fContext(std::move(context)) at, budgeted, colorSpace)
, fProxy(std::move(proxy)) , fProxy(std::move(proxy)) {}
, fAlphaType(at)
, fBudgeted(budgeted)
, fColorSpace(std::move(colorSpace)) {}
SkImage_Gpu::~SkImage_Gpu() {} SkImage_Gpu::~SkImage_Gpu() {}
@ -69,66 +63,6 @@ SkImageInfo SkImage_Gpu::onImageInfo() const {
return SkImageInfo::Make(fProxy->width(), fProxy->height(), colorType, fAlphaType, fColorSpace); return SkImageInfo::Make(fProxy->width(), fProxy->height(), colorType, fAlphaType, fColorSpace);
} }
bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
if (!fContext->contextPriv().resourceProvider()) {
// DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
return false;
}
// The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
// will be used. The client doesn't expect that we convert to that color space, it's intended
// for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
// into that color space (to save the client some effort in whatever they're about to do), but
// that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
// rolled the dstColorSpace into the key).
const auto desc = SkBitmapCacheDesc::Make(this);
if (SkBitmapCache::Find(desc, dst)) {
SkASSERT(dst->getGenerationID() == this->uniqueID());
SkASSERT(dst->isImmutable());
SkASSERT(dst->getPixels());
return true;
}
SkBitmapCache::RecPtr rec = nullptr;
SkPixmap pmap;
if (kAllow_CachingHint == chint) {
rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
if (!rec) {
return false;
}
} else {
if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
return false;
}
}
sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
fProxy,
fColorSpace);
if (!sContext) {
return false;
}
if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
return false;
}
if (rec) {
SkBitmapCache::Add(std::move(rec), dst);
this->notifyAddedToRasterCache();
}
return true;
}
sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
const GrSamplerState& params,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* texColorSpace,
SkScalar scaleAdjust[2]) const {
return AsTextureProxyRef(context, params, dstColorSpace, texColorSpace, scaleAdjust,
fContext.get(), this, fAlphaType, fColorSpace.get());
}
static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) { static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
switch (info.colorType()) { switch (info.colorType()) {
case kRGBA_8888_SkColorType: case kRGBA_8888_SkColorType:
@ -151,51 +85,6 @@ static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes)
} }
} }
GrBackendTexture SkImage_Gpu::onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const {
SkASSERT(fProxy);
if (!fContext->contextPriv().resourceProvider() && !fProxy->isInstantiated()) {
// This image was created with a DDL context and cannot be instantiated.
return GrBackendTexture();
}
if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
return GrBackendTexture(); // invalid
}
GrTexture* texture = fProxy->peekTexture();
if (texture) {
if (flushPendingGrContextIO) {
fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
}
if (origin) {
*origin = fProxy->origin();
}
return texture->getBackendTexture();
}
return GrBackendTexture(); // invalid
}
GrTexture* SkImage_Gpu::onGetTexture() const {
GrTextureProxy* proxy = this->peekProxy();
if (!proxy) {
return nullptr;
}
if (!fContext->contextPriv().resourceProvider() && !fProxy->isInstantiated()) {
// This image was created with a DDL context and cannot be instantiated.
return nullptr;
}
if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
return nullptr;
}
return proxy->peekTexture();
}
bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
int srcX, int srcY, CachingHint) const { int srcX, int srcY, CachingHint) const {
if (!fContext->contextPriv().resourceProvider()) { if (!fContext->contextPriv().resourceProvider()) {
@ -275,7 +164,7 @@ sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
return nullptr; return nullptr;
} }
GrBackendTexture texCopy = tex; GrBackendTexture texCopy = tex;
if (!ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
return nullptr; return nullptr;
} }
return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs), return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
@ -291,7 +180,7 @@ sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
return nullptr; return nullptr;
} }
GrBackendTexture texCopy = tex; GrBackendTexture texCopy = tex;
if (!ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
return nullptr; return nullptr;
} }
return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs), return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
@ -1129,57 +1018,3 @@ bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc); return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
} }
///////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
SkAlphaType newAlphaType = fAlphaType;
#if defined(SK_LEGACY_MAKE_COLOR_SPACE_IMPL)
if (kUnpremul_SkAlphaType == fAlphaType) {
newAlphaType = kPremul_SkAlphaType;
}
#endif
auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), this->alphaType(),
target.get(), newAlphaType);
if (!xform) {
return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
}
sk_sp<GrRenderTargetContext> renderTargetContext(
fContext->contextPriv().makeDeferredRenderTargetContext(
SkBackingFit::kExact, this->width(), this->height(),
kRGBA_8888_GrPixelConfig, nullptr));
if (!renderTargetContext) {
return nullptr;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.addColorTextureProcessor(fProxy, SkMatrix::I());
paint.addColorFragmentProcessor(std::move(xform));
const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
if (!renderTargetContext->asTextureProxy()) {
return nullptr;
}
// MDB: this call is okay bc we know 'renderTargetContext' was exact
return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
newAlphaType, renderTargetContext->asTextureProxyRef(),
std::move(target), fBudgeted);
}
bool SkImage_Gpu::onIsValid(GrContext* context) const {
// The base class has already checked that context isn't abandoned (if it's not nullptr)
if (fContext->abandoned()) {
return false;
}
if (context && context != fContext.get()) {
return false;
}
return true;
}

View File

@ -13,15 +13,14 @@
#include "GrSurfaceProxyPriv.h" #include "GrSurfaceProxyPriv.h"
#include "SkGr.h" #include "SkGr.h"
#include "SkImagePriv.h" #include "SkImagePriv.h"
#include "SkImage_Base.h" #include "SkImage_GpuBase.h"
#include "SkImage_GpuShared.h"
class GrTexture; class GrTexture;
class SkBitmap; class SkBitmap;
struct SkYUVAIndex; struct SkYUVAIndex;
class SkImage_Gpu : public SkImage_Base { class SkImage_Gpu : public SkImage_GpuBase {
public: public:
SkImage_Gpu(sk_sp<GrContext>, uint32_t uniqueID, SkAlphaType, sk_sp<GrTextureProxy>, SkImage_Gpu(sk_sp<GrContext>, uint32_t uniqueID, SkAlphaType, sk_sp<GrTextureProxy>,
sk_sp<SkColorSpace>, SkBudgeted); sk_sp<SkColorSpace>, SkBudgeted);
@ -29,40 +28,18 @@ public:
SkImageInfo onImageInfo() const override; SkImageInfo onImageInfo() const override;
bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override;
sk_sp<SkImage> onMakeSubset(const SkIRect& subset) const override {
return SkImage_GpuShared::OnMakeSubset(subset, fContext, this, fAlphaType, fColorSpace,
fBudgeted);
}
GrContext* context() const override { return fContext.get(); }
GrTextureProxy* peekProxy() const override { GrTextureProxy* peekProxy() const override {
return fProxy.get(); return fProxy.get();
} }
sk_sp<GrTextureProxy> asTextureProxyRef() const override { sk_sp<GrTextureProxy> asTextureProxyRef() const override {
return fProxy; return fProxy;
} }
sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&, SkColorSpace*,
sk_sp<SkColorSpace>*,
SkScalar scaleAdjust[2]) const override;
sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const override {
*uniqueID = this->uniqueID();
return fProxy;
}
GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const override;
GrTexture* onGetTexture() const override;
bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes, bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes,
int srcX, int srcY, CachingHint) const override; int srcX, int srcY, CachingHint) const override;
sk_sp<SkColorSpace> refColorSpace() { return fColorSpace; } sk_sp<SkColorSpace> refColorSpace() { return fColorSpace; }
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const override;
typedef ReleaseContext TextureContext; typedef ReleaseContext TextureContext;
typedef void (*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture); typedef void (*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
typedef void (*PromiseDoneProc)(TextureContext textureContext); typedef void (*PromiseDoneProc)(TextureContext textureContext);
@ -158,8 +135,6 @@ public:
const GrBackendTexture backendTexture, const GrBackendTexture backendTexture,
sk_sp<SkColorSpace> imageColorSpace); sk_sp<SkColorSpace> imageColorSpace);
bool onIsValid(GrContext*) const override;
void resetContext(sk_sp<GrContext> newContext) { void resetContext(sk_sp<GrContext> newContext) {
SkASSERT(fContext->uniqueID() == newContext->uniqueID()); SkASSERT(fContext->uniqueID() == newContext->uniqueID());
fContext = newContext; fContext = newContext;
@ -171,13 +146,9 @@ private:
const SkYUVAIndex yuvaIndices[4], SkISize size, GrSurfaceOrigin origin, const SkYUVAIndex yuvaIndices[4], SkISize size, GrSurfaceOrigin origin,
SkBudgeted isBudgeted, GrRenderTargetContext* renderTargetContext); SkBudgeted isBudgeted, GrRenderTargetContext* renderTargetContext);
sk_sp<GrContext> fContext;
sk_sp<GrTextureProxy> fProxy; sk_sp<GrTextureProxy> fProxy;
const SkAlphaType fAlphaType;
const SkBudgeted fBudgeted;
sk_sp<SkColorSpace> fColorSpace;
typedef SkImage_Base INHERITED; typedef SkImage_GpuBase INHERITED;
}; };
#endif #endif

View File

@ -0,0 +1,237 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrBackendSurface.h"
#include "GrClip.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrRenderTargetContext.h"
#include "GrTexture.h"
#include "GrTextureAdjuster.h"
#include "SkBitmapCache.h"
#include "SkImage_Gpu.h"
#include "SkImage_GpuBase.h"
SkImage_GpuBase::SkImage_GpuBase(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
SkAlphaType at, SkBudgeted budgeted, sk_sp<SkColorSpace> cs)
: INHERITED(width, height, uniqueID)
, fContext(std::move(context))
, fAlphaType(at)
, fBudgeted(budgeted)
, fColorSpace(std::move(cs)) {}
SkImage_GpuBase::~SkImage_GpuBase() {}
//////////////////////////////////////////////////////////////////////////////////////////////////
bool SkImage_GpuBase::ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
GrPixelConfig* config, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs) {
if (!tex.isValid()) {
return false;
}
// TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
// create a fake image info here.
SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
if (!SkImageInfoIsValid(info)) {
return false;
}
return ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
bool SkImage_GpuBase::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
if (!fContext->contextPriv().resourceProvider()) {
// DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
return false;
}
// The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
// will be used. The client doesn't expect that we convert to that color space, it's intended
// for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
// into that color space (to save the client some effort in whatever they're about to do), but
// that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
// rolled the dstColorSpace into the key).
const auto desc = SkBitmapCacheDesc::Make(this);
if (SkBitmapCache::Find(desc, dst)) {
SkASSERT(dst->getGenerationID() == this->uniqueID());
SkASSERT(dst->isImmutable());
SkASSERT(dst->getPixels());
return true;
}
SkBitmapCache::RecPtr rec = nullptr;
SkPixmap pmap;
if (kAllow_CachingHint == chint) {
rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
if (!rec) {
return false;
}
} else {
if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
return false;
}
}
sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
this->asTextureProxyRef(),
fColorSpace);
if (!sContext) {
return false;
}
if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
return false;
}
if (rec) {
SkBitmapCache::Add(std::move(rec), dst);
this->notifyAddedToRasterCache();
}
return true;
}
sk_sp<SkImage> SkImage_GpuBase::onMakeSubset(const SkIRect& subset) const {
sk_sp<GrSurfaceProxy> proxy = this->asTextureProxyRef();
GrSurfaceDesc desc;
desc.fWidth = subset.width();
desc.fHeight = subset.height();
desc.fConfig = proxy->config();
sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
desc, proxy->origin(), GrMipMapped::kNo, SkBackingFit::kExact, fBudgeted));
if (!sContext) {
return nullptr;
}
if (!sContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) {
return nullptr;
}
// MDB: this call is okay bc we know 'sContext' was kExact
return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
fAlphaType, sContext->asTextureProxyRef(),
fColorSpace, fBudgeted);
}
sk_sp<GrTextureProxy> SkImage_GpuBase::asTextureProxyRef(GrContext* context,
const GrSamplerState& params,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* texColorSpace,
SkScalar scaleAdjust[2]) const {
if (context->uniqueID() != fContext->uniqueID()) {
SkASSERT(0);
return nullptr;
}
GrTextureAdjuster adjuster(fContext.get(), this->asTextureProxyRef(), fAlphaType,
this->uniqueID(), fColorSpace.get());
return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
}
GrBackendTexture SkImage_GpuBase::onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const {
sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
SkASSERT(proxy);
if (!fContext->contextPriv().resourceProvider() && !proxy->isInstantiated()) {
// This image was created with a DDL context and cannot be instantiated.
return GrBackendTexture();
}
if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
return GrBackendTexture(); // invalid
}
GrTexture* texture = proxy->peekTexture();
if (texture) {
if (flushPendingGrContextIO) {
fContext->contextPriv().prepareSurfaceForExternalIO(proxy.get());
}
if (origin) {
*origin = proxy->origin();
}
return texture->getBackendTexture();
}
return GrBackendTexture(); // invalid
}
GrTexture* SkImage_GpuBase::onGetTexture() const {
GrTextureProxy* proxy = this->peekProxy();
if (!proxy) {
return nullptr;
}
sk_sp<GrTextureProxy> proxyRef = this->asTextureProxyRef();
if (!fContext->contextPriv().resourceProvider() && !proxyRef->isInstantiated()) {
// This image was created with a DDL context and cannot be instantiated.
return nullptr;
}
if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
return nullptr;
}
return proxy->peekTexture();
}
sk_sp<SkImage> SkImage_GpuBase::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
SkAlphaType newAlphaType = fAlphaType;
#if defined(SK_LEGACY_MAKE_COLOR_SPACE_IMPL)
if (kUnpremul_SkAlphaType == fAlphaType) {
newAlphaType = kPremul_SkAlphaType;
}
#endif
auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), this->alphaType(),
target.get(), newAlphaType);
if (!xform) {
return sk_ref_sp(const_cast<SkImage_GpuBase*>(this));
}
sk_sp<GrRenderTargetContext> renderTargetContext(
fContext->contextPriv().makeDeferredRenderTargetContext(
SkBackingFit::kExact, this->width(), this->height(),
kRGBA_8888_GrPixelConfig, nullptr));
if (!renderTargetContext) {
return nullptr;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.addColorTextureProcessor(this->asTextureProxyRef(), SkMatrix::I());
paint.addColorFragmentProcessor(std::move(xform));
const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
if (!renderTargetContext->asTextureProxy()) {
return nullptr;
}
// MDB: this call is okay bc we know 'renderTargetContext' was exact
return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
newAlphaType, renderTargetContext->asTextureProxyRef(),
std::move(target), fBudgeted);
}
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()) {
return false;
}
if (context && context != fContext.get()) {
return false;
}
return true;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImage_GpuBase_DEFINED
#define SkImage_GpuBase_DEFINED
#include "SkImage_Base.h"
class GrContext;
class SkColorSpace;
class SkImage_GpuBase : public SkImage_Base {
public:
SkImage_GpuBase(sk_sp<GrContext>, int width, int height, uint32_t uniqueID,
SkAlphaType, SkBudgeted, sk_sp<SkColorSpace>);
~SkImage_GpuBase() override;
GrContext* context() const final { return fContext.get(); }
bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const final;
sk_sp<SkImage> onMakeSubset(const SkIRect& subset) const final;
sk_sp<GrTextureProxy> asTextureProxyRef() const override {
// we shouldn't end up calling this
SkASSERT(false);
return this->INHERITED::asTextureProxyRef();
}
sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&, SkColorSpace*,
sk_sp<SkColorSpace>*,
SkScalar scaleAdjust[2]) const final;
sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const final {
*uniqueID = this->uniqueID();
return this->asTextureProxyRef();
}
GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const final;
GrTexture* onGetTexture() const final;
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const final;
bool onIsValid(GrContext*) const final;
static bool ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
GrPixelConfig* config, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs);
protected:
sk_sp<GrContext> fContext;
const SkAlphaType fAlphaType; // alpha type for final image
const SkBudgeted fBudgeted;
sk_sp<SkColorSpace> fColorSpace; // color space for final image
private:
typedef SkImage_Base INHERITED;
};
#endif

View File

@ -1,79 +0,0 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrBackendSurface.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrTextureAdjuster.h"
#include "SkImage_Gpu.h"
#include "SkImage_GpuShared.h"
namespace SkImage_GpuShared {
bool ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
GrPixelConfig* config, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs) {
if (!tex.isValid()) {
return false;
}
// TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
// create a fake image info here.
SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
if (!SkImageInfoIsValid(info)) {
return false;
}
return ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config);
}
sk_sp<GrTextureProxy> AsTextureProxyRef(GrContext* context,
const GrSamplerState& params,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* texColorSpace,
SkScalar scaleAdjust[2],
GrContext* imageContext,
const SkImage_Base* image,
const SkAlphaType imageAlphaType,
SkColorSpace* imageColorSpace) {
if (context->uniqueID() != imageContext->uniqueID()) {
SkASSERT(0);
return nullptr;
}
GrTextureAdjuster adjuster(imageContext, image->asTextureProxyRef(), imageAlphaType,
image->uniqueID(), imageColorSpace);
return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
}
sk_sp<SkImage> OnMakeSubset(const SkIRect& subset, sk_sp<GrContext> imageContext,
const SkImage_Base* image, const SkAlphaType imageAlphaType,
sk_sp<SkColorSpace> imageColorSpace, const SkBudgeted budgeted){
sk_sp<GrSurfaceProxy> proxy = image->asTextureProxyRef();
GrSurfaceDesc desc;
desc.fWidth = subset.width();
desc.fHeight = subset.height();
desc.fConfig = proxy->config();
sk_sp<GrSurfaceContext> sContext(imageContext->contextPriv().makeDeferredSurfaceContext(
desc, proxy->origin(), GrMipMapped::kNo, SkBackingFit::kExact, budgeted));
if (!sContext) {
return nullptr;
}
if (!sContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) {
return nullptr;
}
// MDB: this call is okay bc we know 'sContext' was kExact
return sk_make_sp<SkImage_Gpu>(imageContext, kNeedNewImageUniqueID,
imageAlphaType, sContext->asTextureProxyRef(),
imageColorSpace, budgeted);
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImage_GpuShared_DEFINED
#define SkImage_GpuShared_DEFINED
#include "SkImageInfo.h"
#include "SkTypes.h"
class GrContext;
class SkImage_Base;
namespace SkImage_GpuShared {
bool ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
GrPixelConfig* config, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs);
sk_sp<GrTextureProxy> AsTextureProxyRef(GrContext* context,
const GrSamplerState& params,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* texColorSpace,
SkScalar scaleAdjust[2],
GrContext* imageContext,
const SkImage_Base* image,
const SkAlphaType imageAlphaType,
SkColorSpace* imageColorSpace);
sk_sp<SkImage> OnMakeSubset(const SkIRect& subset, sk_sp<GrContext> imageContext,
const SkImage_Base* image, const SkAlphaType imageAlphaType,
sk_sp<SkColorSpace> imageColorSpace, const SkBudgeted budgeted);
}
#endif

View File

@ -16,33 +16,27 @@
#include "GrTexture.h" #include "GrTexture.h"
#include "GrTextureAdjuster.h" #include "GrTextureAdjuster.h"
#include "SkImage_Gpu.h" #include "SkImage_Gpu.h"
#include "SkImage_GpuShared.h"
#include "SkImage_GpuYUVA.h" #include "SkImage_GpuYUVA.h"
#include "SkReadPixelsRec.h" #include "SkReadPixelsRec.h"
#include "effects/GrYUVtoRGBEffect.h" #include "effects/GrYUVtoRGBEffect.h"
using namespace SkImage_GpuShared;
SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, uint32_t uniqueID, SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, uint32_t uniqueID,
SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[], SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
SkYUVAIndex yuvaIndices[4], SkISize size, GrSurfaceOrigin origin, SkYUVAIndex yuvaIndices[4], SkISize size, GrSurfaceOrigin origin,
sk_sp<SkColorSpace> imageColorSpace, SkBudgeted budgeted) sk_sp<SkColorSpace> imageColorSpace, SkBudgeted budgeted)
: INHERITED(size.width(), size.height(), uniqueID) : INHERITED(std::move(context), size.width(), size.height(), uniqueID,
, fContext(std::move(context)) // If an alpha channel is present we always switch to kPremul. This is because,
, fBudgeted(budgeted) // although the planar data is always un-premul, the final interleaved RGB image
, fColorSpace(colorSpace) // is/would-be premul.
, fOrigin(origin) -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
, fImageAlphaType(kOpaque_SkAlphaType) : kOpaque_SkAlphaType,
, fImageColorSpace(std::move(imageColorSpace)) { budgeted, imageColorSpace)
, fYUVColorSpace(colorSpace)
, fOrigin(origin) {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
fProxies[i] = std::move(proxies[i]); fProxies[i] = std::move(proxies[i]);
} }
memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex)); memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex));
// 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.
if (-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex) {
fImageAlphaType = kPremul_SkAlphaType;
}
} }
SkImage_GpuYUVA::~SkImage_GpuYUVA() {} SkImage_GpuYUVA::~SkImage_GpuYUVA() {}
@ -50,7 +44,7 @@ SkImage_GpuYUVA::~SkImage_GpuYUVA() {}
SkImageInfo SkImage_GpuYUVA::onImageInfo() const { SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
// Note: this is the imageInfo for the flattened image, not the YUV planes // Note: this is the imageInfo for the flattened image, not the YUV planes
return SkImageInfo::Make(this->width(), this->height(), kRGBA_8888_SkColorType, return SkImageInfo::Make(this->width(), this->height(), kRGBA_8888_SkColorType,
fImageAlphaType, fImageColorSpace); fAlphaType, fColorSpace);
} }
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
@ -73,7 +67,7 @@ sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
fYUVAIndices[SkYUVAIndex::kV_Index].fIndex); fYUVAIndices[SkYUVAIndex::kV_Index].fIndex);
// TODO: modify the YUVtoRGBEffect to do premul if fImageAlphaType is kPremul_AlphaType // TODO: modify the YUVtoRGBEffect to do premul if fImageAlphaType is kPremul_AlphaType
paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(std::move(yProxy), std::move(uProxy), paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(std::move(yProxy), std::move(uProxy),
std::move(vProxy), fColorSpace, std::move(vProxy), fYUVColorSpace,
nv12)); nv12));
const SkRect rect = SkRect::MakeIWH(this->width(), this->height()); const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
@ -82,7 +76,7 @@ sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
sk_sp<GrRenderTargetContext> renderTargetContext( sk_sp<GrRenderTargetContext> renderTargetContext(
fContext->contextPriv().makeDeferredRenderTargetContext( fContext->contextPriv().makeDeferredRenderTargetContext(
SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig,
std::move(fImageColorSpace), 1, GrMipMapped::kNo, fOrigin)); std::move(fColorSpace), 1, GrMipMapped::kNo, fOrigin));
if (!renderTargetContext) { if (!renderTargetContext) {
return nullptr; return nullptr;
} }
@ -102,15 +96,6 @@ sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
return fRGBProxy; return fRGBProxy;
} }
sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef(GrContext* context,
const GrSamplerState& params,
SkColorSpace* dstColorSpace,
sk_sp<SkColorSpace>* texColorSpace,
SkScalar scaleAdjust[2]) const {
return AsTextureProxyRef(context, params, dstColorSpace, texColorSpace, scaleAdjust,
fContext.get(), this, fImageAlphaType, fImageColorSpace.get());
}
bool SkImage_GpuYUVA::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, bool SkImage_GpuYUVA::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
int srcX, int srcY, CachingHint) const { int srcX, int srcY, CachingHint) const {
if (!fContext->contextPriv().resourceProvider()) { if (!fContext->contextPriv().resourceProvider()) {
@ -133,13 +118,13 @@ bool SkImage_GpuYUVA::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels,
// TODO: this seems to duplicate code in GrTextureContext::onReadPixels and // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
// GrRenderTargetContext::onReadPixels // GrRenderTargetContext::onReadPixels
uint32_t flags = 0; uint32_t flags = 0;
if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fImageAlphaType) { if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
// let the GPU perform this transformation for us // let the GPU perform this transformation for us
flags = GrContextPriv::kUnpremul_PixelOpsFlag; flags = GrContextPriv::kUnpremul_PixelOpsFlag;
} }
sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext( sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
proxy, fImageColorSpace); proxy, fColorSpace);
if (!sContext) { if (!sContext) {
return false; return false;
} }

View File

@ -11,7 +11,7 @@
#include "GrBackendSurface.h" #include "GrBackendSurface.h"
#include "GrContext.h" #include "GrContext.h"
#include "SkCachedData.h" #include "SkCachedData.h"
#include "SkImage_Base.h" #include "SkImage_GpuBase.h"
#include "SkYUVAIndex.h" #include "SkYUVAIndex.h"
class GrTexture; class GrTexture;
@ -20,7 +20,7 @@ class GrTexture;
// Initially any direct rendering will be done by passing the individual planes to a shader. // Initially any direct rendering will be done by passing the individual planes to a shader.
// Once any method requests a flattened image (e.g., onReadPixels), the flattened RGB // Once any method requests a flattened image (e.g., onReadPixels), the flattened RGB
// proxy will be stored and used for any future rendering. // proxy will be stored and used for any future rendering.
class SkImage_GpuYUVA : public SkImage_Base { class SkImage_GpuYUVA : public SkImage_GpuBase {
public: public:
SkImage_GpuYUVA(sk_sp<GrContext>, uint32_t uniqueID, SkYUVColorSpace, SkImage_GpuYUVA(sk_sp<GrContext>, uint32_t uniqueID, SkYUVColorSpace,
sk_sp<GrTextureProxy> proxies[], SkYUVAIndex yuvaIndices[4], SkISize size, sk_sp<GrTextureProxy> proxies[], SkYUVAIndex yuvaIndices[4], SkISize size,
@ -29,31 +29,8 @@ public:
SkImageInfo onImageInfo() const override; SkImageInfo onImageInfo() const override;
bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override { GrTextureProxy* peekProxy() const override { return this->asTextureProxyRef().get(); }
return false;
}
sk_sp<SkImage> onMakeSubset(const SkIRect& subset) const override {
return SkImage_GpuShared::OnMakeSubset(subset, fContext, this, fImageAlphaType,
fImageColorSpace, fBudgeted);
}
GrContext* context() const override { return fContext.get(); }
GrTextureProxy* peekProxy() const override { return nullptr; }
sk_sp<GrTextureProxy> asTextureProxyRef() const override; sk_sp<GrTextureProxy> asTextureProxyRef() const override;
sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&, SkColorSpace*,
sk_sp<SkColorSpace>*,
SkScalar scaleAdjust[2]) const override;
sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const override {
return nullptr;
}
GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const override {
return GrBackendTexture(); // invalid
}
GrTexture* onGetTexture() const override { return nullptr; }
bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes, bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes,
int srcX, int srcY, CachingHint) const override; int srcX, int srcY, CachingHint) const override;
@ -61,8 +38,6 @@ public:
sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVColorSpace*, sk_sp<SkCachedData> getPlanes(SkYUVSizeInfo*, SkYUVColorSpace*,
const void* planes[3]) override { return nullptr; } const void* planes[3]) override { return nullptr; }
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const override { return nullptr; }
// These need to match the ones defined elsewhere // These need to match the ones defined elsewhere
typedef ReleaseContext TextureContext; typedef ReleaseContext TextureContext;
typedef void (*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture); typedef void (*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
@ -128,10 +103,7 @@ public:
GrSurfaceOrigin imageOrigin, GrSurfaceOrigin imageOrigin,
sk_sp<SkColorSpace> imageColorSpace); sk_sp<SkColorSpace> imageColorSpace);
bool onIsValid(GrContext*) const override { return false; }
private: private:
sk_sp<GrContext> fContext;
// This array will usually only be sparsely populated. // This array will usually only be sparsely populated.
// The actual non-null fields are dictated by the 'fYUVAIndices' indices // The actual non-null fields are dictated by the 'fYUVAIndices' indices
sk_sp<GrTextureProxy> fProxies[4]; sk_sp<GrTextureProxy> fProxies[4];
@ -140,13 +112,10 @@ private:
// using the separate YUVA planes. From thence forth we will only use the // using the separate YUVA planes. From thence forth we will only use the
// the RGBProxy. // the RGBProxy.
sk_sp<GrTextureProxy> fRGBProxy; sk_sp<GrTextureProxy> fRGBProxy;
const SkBudgeted fBudgeted; const SkYUVColorSpace fYUVColorSpace;
const SkYUVColorSpace fColorSpace;
GrSurfaceOrigin fOrigin; GrSurfaceOrigin fOrigin;
SkAlphaType fImageAlphaType;
sk_sp<SkColorSpace> fImageColorSpace;
typedef SkImage_Base INHERITED; typedef SkImage_GpuBase INHERITED;
}; };
#endif #endif