Merge common code for SkImage_Gpu and SkImage_GpuYUVA.

Bug: skia:7903
Change-Id: I29957babe65e9e1c505166d01490233fe542a559
Reviewed-on: https://skia-review.googlesource.com/c/169824
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Jim Van Verth 2018-11-09 12:03:57 -05:00 committed by Skia Commit-Bot
parent 32828eb006
commit 0e67194586
5 changed files with 109 additions and 166 deletions

View File

@ -121,81 +121,22 @@ sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(
SkBudgeted isBudgeted, GrRenderTargetContext* renderTargetContext) { SkBudgeted isBudgeted, GrRenderTargetContext* renderTargetContext) {
SkASSERT(renderTargetContext); SkASSERT(renderTargetContext);
GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); int numTextures;
if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
// We need to make a copy of the input backend textures because we need to preserve the result
// of validate_backend_texture.
GrBackendTexture yuvaTexturesCopy[4];
for (int i = 0; i < 4; ++i) {
// Validate that the yuvaIndices refer to valid backend textures.
const SkYUVAIndex& yuvaIndex = yuvaIndices[i];
if (i == 3 && yuvaIndex.fIndex == -1) {
// Meaning the A plane isn't passed in.
continue;
}
if (yuvaIndex.fIndex == -1 || yuvaIndex.fIndex > 3) {
// Y plane, U plane, and V plane must refer to image sources being passed in. There are
// at most 4 images sources being passed in, could not have a index more than 3.
return nullptr; return nullptr;
} }
if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) {
yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex];
if (!ctx->contextPriv().caps()->getYUVAConfigFromBackendTexture(
yuvaTexturesCopy[yuvaIndex.fIndex],
&yuvaTexturesCopy[yuvaIndex.fIndex].fConfig)) {
return nullptr;
}
}
// TODO: Check that for each plane, the channel actually exist in the image source we are
// reading from.
}
sk_sp<GrTextureProxy> tempTextureProxies[4]; sk_sp<GrTextureProxy> tempTextureProxies[4];
for (int i = 0; i < 4; ++i) { if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, origin,
// Fill in tempTextureProxies to avoid duplicate texture proxies. tempTextureProxies)) {
int textureIndex = yuvaIndices[i].fIndex;
// Safely ignore since this means we are missing the A plane.
if (textureIndex == -1) {
SkASSERT(SkYUVAIndex::kA_Index == i);
continue;
}
if (!tempTextureProxies[textureIndex]) {
SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
tempTextureProxies[textureIndex] =
proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], origin);
if (!tempTextureProxies[textureIndex]) {
return nullptr;
}
}
}
const int width = size.width();
const int height = size.height();
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
// TODO: Modify the fragment processor to sample from different channel instead of taking nv12
// bool.
paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(tempTextureProxies, yuvaIndices,
yuvColorSpace,
GrSamplerState::Filter::kNearest));
const SkRect rect = SkRect::MakeIWH(width, height);
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
if (!renderTargetContext->asSurfaceProxy()) {
return nullptr; return nullptr;
} }
// DDL TODO: in the promise image version we must not flush here const SkRect rect = SkRect::MakeIWH(size.width(), size.height());
ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy()); if (!RenderYUVAToRGBA(ctx, renderTargetContext, rect, yuvColorSpace,
tempTextureProxies, yuvaIndices)) {
return nullptr;
}
// MDB: this call is okay bc we know 'renderTargetContext' was exact // MDB: this call is okay bc we know 'renderTargetContext' was exact
return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, kOpaque_SkAlphaType, return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, kOpaque_SkAlphaType,

View File

@ -12,6 +12,7 @@
#include "GrRenderTargetContext.h" #include "GrRenderTargetContext.h"
#include "GrTexture.h" #include "GrTexture.h"
#include "GrTextureAdjuster.h" #include "GrTextureAdjuster.h"
#include "effects/GrYUVtoRGBEffect.h"
#include "SkBitmapCache.h" #include "SkBitmapCache.h"
#include "SkImage_Gpu.h" #include "SkImage_Gpu.h"
#include "SkImage_GpuBase.h" #include "SkImage_GpuBase.h"
@ -289,6 +290,59 @@ bool SkImage_GpuBase::onIsValid(GrContext* context) const {
return true; return true;
} }
bool SkImage_GpuBase::MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[],
int numTextures, GrSurfaceOrigin imageOrigin,
sk_sp<GrTextureProxy> tempTextureProxies[4]) {
GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
// We need to make a copy of the input backend textures because we need to preserve the result
// of validate_backend_texture.
GrBackendTexture yuvaTexturesCopy[4];
for (int textureIndex = 0; textureIndex < numTextures; ++textureIndex) {
yuvaTexturesCopy[textureIndex] = yuvaTextures[textureIndex];
if (!ctx->contextPriv().caps()->getYUVAConfigFromBackendTexture(
yuvaTexturesCopy[textureIndex],
&yuvaTexturesCopy[textureIndex].fConfig)) {
return false;
}
SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
tempTextureProxies[textureIndex] =
proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], imageOrigin);
if (!tempTextureProxies[textureIndex]) {
return false;
}
}
return true;
}
bool SkImage_GpuBase::RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* renderTargetContext,
const SkRect& rect, SkYUVColorSpace yuvColorSpace,
const sk_sp<GrTextureProxy> proxies[4],
const SkYUVAIndex yuvaIndices[4]) {
SkASSERT(renderTargetContext);
if (!renderTargetContext->asSurfaceProxy()) {
return false;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
// TODO: modify the YUVtoRGBEffect to do premul if needed
// (e.g., if SkImage_GpuYUVA::fImageAlphaType is kPremul_AlphaType)
paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(proxies, yuvaIndices,
yuvColorSpace,
GrSamplerState::Filter::kNearest));
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
// DDL TODO: in the promise image version we must not flush here
ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<GrTexture> SkPromiseImageHelper::getTexture(GrResourceProvider* resourceProvider, sk_sp<GrTexture> SkPromiseImageHelper::getTexture(GrResourceProvider* resourceProvider,
GrPixelConfig config) { GrPixelConfig config) {

View File

@ -61,12 +61,20 @@ public:
static bool ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex, static bool ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
GrPixelConfig* config, SkColorType ct, SkAlphaType at, GrPixelConfig* config, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs); sk_sp<SkColorSpace> cs);
static bool MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[],
int numTextures, GrSurfaceOrigin imageOrigin,
sk_sp<GrTextureProxy> tempTextureProxies[4]);
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);
protected: protected:
static bool RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* renderTargetContext,
const SkRect& rect, SkYUVColorSpace yuvColorSpace,
const sk_sp<GrTextureProxy> proxies[4],
const SkYUVAIndex yuvaIndices[4]);
sk_sp<GrContext> fContext; sk_sp<GrContext> fContext;
const SkAlphaType fAlphaType; // alpha type for final image const SkAlphaType fAlphaType; // alpha type for final image
const SkBudgeted fBudgeted; const SkBudgeted fBudgeted;

View File

@ -25,8 +25,9 @@
SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID, SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[], SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
const SkYUVAIndex yuvaIndices[4], GrSurfaceOrigin origin, int numProxies, const SkYUVAIndex yuvaIndices[4],
sk_sp<SkColorSpace> imageColorSpace, SkBudgeted budgeted) GrSurfaceOrigin origin, sk_sp<SkColorSpace> imageColorSpace,
SkBudgeted budgeted)
: INHERITED(std::move(context), width, height, uniqueID, : INHERITED(std::move(context), width, height, uniqueID,
// If an alpha channel is present we always switch to kPremul. This is because, // 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 // although the planar data is always un-premul, the final interleaved RGB image
@ -34,15 +35,15 @@ SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height
-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
: kOpaque_SkAlphaType, : kOpaque_SkAlphaType,
budgeted, imageColorSpace) budgeted, imageColorSpace)
, fNumProxies(numProxies)
, fYUVColorSpace(colorSpace) , fYUVColorSpace(colorSpace)
, fOrigin(origin) { , fOrigin(origin) {
int maxIndex = yuvaIndices[0].fIndex; // The caller should have done this work, just verifying
for (int i = 1; i < 4; ++i) { SkDEBUGCODE(int textureCount;)
if (yuvaIndices[i].fIndex > maxIndex) { SkASSERT(SkYUVAIndex::AreValidIndices(yuvaIndices, &textureCount));
maxIndex = yuvaIndices[i].fIndex; SkASSERT(textureCount == fNumProxies);
}
} for (int i = 0; i < numProxies; ++i) {
for (int i = 0; i <= maxIndex; ++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));
@ -57,12 +58,7 @@ SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
} }
bool SkImage_GpuYUVA::setupMipmapsForPlanes() const { bool SkImage_GpuYUVA::setupMipmapsForPlanes() const {
int numTextures; for (int i = 0; i < fNumProxies; ++i) {
if (!SkYUVAIndex::AreValidIndices(fYUVAIndices, &numTextures)) {
return false;
}
for (int i = 0; i < numTextures; ++i) {
GrTextureProducer::CopyParams copyParams; GrTextureProducer::CopyParams copyParams;
int mipCount = SkMipMap::ComputeLevelCount(fProxies[i]->width(), fProxies[i]->height()); int mipCount = SkMipMap::ComputeLevelCount(fProxies[i]->width(), fProxies[i]->height());
if (mipCount && GrGpu::IsACopyNeededForMips(fContext->contextPriv().caps(), if (mipCount && GrGpu::IsACopyNeededForMips(fContext->contextPriv().caps(),
@ -83,24 +79,6 @@ bool SkImage_GpuYUVA::setupMipmapsForPlanes() const {
sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const { sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
if (!fRGBProxy) { if (!fRGBProxy) {
sk_sp<GrTextureProxy> yProxy = fProxies[fYUVAIndices[SkYUVAIndex::kY_Index].fIndex];
sk_sp<GrTextureProxy> uProxy = fProxies[fYUVAIndices[SkYUVAIndex::kU_Index].fIndex];
sk_sp<GrTextureProxy> vProxy = fProxies[fYUVAIndices[SkYUVAIndex::kV_Index].fIndex];
if (!yProxy || !uProxy || !vProxy) {
return nullptr;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
// TODO: modify the YUVtoRGBEffect to do premul if fImageAlphaType is kPremul_AlphaType
paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(fProxies, fYUVAIndices,
fYUVColorSpace,
GrSamplerState::Filter::kNearest));
const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
// Needs to create a render target in order to draw to it for the yuv->rgb conversion. // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
sk_sp<GrRenderTargetContext> renderTargetContext( sk_sp<GrRenderTargetContext> renderTargetContext(
fContext->contextPriv().makeDeferredRenderTargetContext( fContext->contextPriv().makeDeferredRenderTargetContext(
@ -109,15 +87,13 @@ sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
if (!renderTargetContext) { if (!renderTargetContext) {
return nullptr; return nullptr;
} }
renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
if (!renderTargetContext->asSurfaceProxy()) { const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
if (!RenderYUVAToRGBA(fContext.get(), renderTargetContext.get(), rect, fYUVColorSpace,
fProxies, fYUVAIndices)) {
return nullptr; return nullptr;
} }
// DDL TODO: in the promise image version we must not flush here
fContext->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
fRGBProxy = renderTargetContext->asTextureProxyRef(); fRGBProxy = renderTargetContext->asTextureProxyRef();
} }
@ -150,62 +126,24 @@ sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx,
SkISize imageSize, SkISize imageSize,
GrSurfaceOrigin imageOrigin, GrSurfaceOrigin imageOrigin,
sk_sp<SkColorSpace> imageColorSpace) { sk_sp<SkColorSpace> imageColorSpace) {
GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); int numTextures;
if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
// We need to make a copy of the input backend textures because we need to preserve the result
// of validate_backend_texture.
GrBackendTexture yuvaTexturesCopy[4];
for (int i = 0; i < 4; ++i) {
// Validate that the yuvaIndices refer to valid backend textures.
const SkYUVAIndex& yuvaIndex = yuvaIndices[i];
if (SkYUVAIndex::kA_Index == i && yuvaIndex.fIndex == -1) {
// Meaning the A plane isn't passed in.
continue;
}
if (yuvaIndex.fIndex == -1 || yuvaIndex.fIndex > 3) {
// Y plane, U plane, and V plane must refer to image sources being passed in. There are
// at most 4 image sources being passed in, could not have a index more than 3.
return nullptr; return nullptr;
} }
if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) { sk_sp<GrTextureProxy> tempTextureProxies[4];
yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex]; if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, imageOrigin,
tempTextureProxies)) {
if (!ctx->contextPriv().caps()->getYUVAConfigFromBackendTexture(
yuvaTexturesCopy[yuvaIndex.fIndex],
&yuvaTexturesCopy[yuvaIndex.fIndex].fConfig)) {
return nullptr; return nullptr;
} }
}
// TODO: Check that for each plane, the channel actually exist in the image source we are // TODO: Check that for each plane, the channel actually exist in the image source we are
// reading from. // reading from.
}
sk_sp<GrTextureProxy> tempTextureProxies[4]; // build from yuvaTextures
for (int i = 0; i < 4; ++i) {
// Fill in tempTextureProxies to avoid duplicate texture proxies.
int textureIndex = yuvaIndices[i].fIndex;
// Safely ignore since this means we are missing the A plane.
if (textureIndex == -1) {
SkASSERT(SkYUVAIndex::kA_Index == i);
continue;
}
if (!tempTextureProxies[textureIndex]) {
SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
tempTextureProxies[textureIndex] =
proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], imageOrigin);
if (!tempTextureProxies[textureIndex]) {
return nullptr;
}
}
}
return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), imageSize.width(), imageSize.height(), return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), imageSize.width(), imageSize.height(),
kNeedNewImageUniqueID, colorSpace, tempTextureProxies, kNeedNewImageUniqueID, colorSpace, tempTextureProxies,
yuvaIndices, imageOrigin, imageColorSpace, SkBudgeted::kYes); numTextures, yuvaIndices, imageOrigin, imageColorSpace,
SkBudgeted::kYes);
} }
///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context, sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
@ -318,7 +256,8 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
} }
return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageWidth, imageHeight, return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageWidth, imageHeight,
kNeedNewImageUniqueID, yuvColorSpace, proxies, yuvaIndices, kNeedNewImageUniqueID, yuvColorSpace, proxies, numTextures,
imageOrigin, std::move(imageColorSpace), SkBudgeted::kNo); yuvaIndices, imageOrigin, std::move(imageColorSpace),
SkBudgeted::kNo);
} }

View File

@ -26,7 +26,7 @@ public:
friend class GrYUVAImageTextureMaker; friend class GrYUVAImageTextureMaker;
SkImage_GpuYUVA(sk_sp<GrContext>, int width, int height, uint32_t uniqueID, SkYUVColorSpace, SkImage_GpuYUVA(sk_sp<GrContext>, int width, int height, uint32_t uniqueID, SkYUVColorSpace,
sk_sp<GrTextureProxy> proxies[], const SkYUVAIndex yuvaIndices[4], sk_sp<GrTextureProxy> proxies[], int numProxies, const SkYUVAIndex [4],
GrSurfaceOrigin, sk_sp<SkColorSpace>, SkBudgeted); GrSurfaceOrigin, sk_sp<SkColorSpace>, SkBudgeted);
~SkImage_GpuYUVA() override; ~SkImage_GpuYUVA() override;
@ -113,14 +113,15 @@ private:
// 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
mutable sk_sp<GrTextureProxy> fProxies[4]; mutable sk_sp<GrTextureProxy> fProxies[4];
int fNumProxies;
SkYUVAIndex fYUVAIndices[4]; SkYUVAIndex fYUVAIndices[4];
const SkYUVColorSpace fYUVColorSpace;
GrSurfaceOrigin fOrigin;
// This is only allocated when the image needs to be flattened rather than // 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 // using the separate YUVA planes. From thence forth we will only use the
// the RGBProxy. // the RGBProxy.
mutable sk_sp<GrTextureProxy> fRGBProxy; mutable sk_sp<GrTextureProxy> fRGBProxy;
const SkYUVColorSpace fYUVColorSpace;
GrSurfaceOrigin fOrigin;
typedef SkImage_GpuBase INHERITED; typedef SkImage_GpuBase INHERITED;
}; };