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) {
SkASSERT(renderTargetContext);
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 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;
}
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];
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], 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()) {
int numTextures;
if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
return nullptr;
}
// DDL TODO: in the promise image version we must not flush here
ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
sk_sp<GrTextureProxy> tempTextureProxies[4];
if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, origin,
tempTextureProxies)) {
return nullptr;
}
const SkRect rect = SkRect::MakeIWH(size.width(), size.height());
if (!RenderYUVAToRGBA(ctx, renderTargetContext, rect, yuvColorSpace,
tempTextureProxies, yuvaIndices)) {
return nullptr;
}
// MDB: this call is okay bc we know 'renderTargetContext' was exact
return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, kOpaque_SkAlphaType,

View File

@ -12,6 +12,7 @@
#include "GrRenderTargetContext.h"
#include "GrTexture.h"
#include "GrTextureAdjuster.h"
#include "effects/GrYUVtoRGBEffect.h"
#include "SkBitmapCache.h"
#include "SkImage_Gpu.h"
#include "SkImage_GpuBase.h"
@ -289,6 +290,59 @@ bool SkImage_GpuBase::onIsValid(GrContext* context) const {
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,
GrPixelConfig config) {

View File

@ -61,12 +61,20 @@ public:
static bool ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
GrPixelConfig* config, SkColorType ct, SkAlphaType at,
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 void(*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
typedef void(*PromiseDoneProc)(TextureContext textureContext);
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;
const SkAlphaType fAlphaType; // alpha type for final image
const SkBudgeted fBudgeted;

View File

@ -25,8 +25,9 @@
SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
const SkYUVAIndex yuvaIndices[4], GrSurfaceOrigin origin,
sk_sp<SkColorSpace> imageColorSpace, SkBudgeted budgeted)
int numProxies, const SkYUVAIndex yuvaIndices[4],
GrSurfaceOrigin origin, sk_sp<SkColorSpace> imageColorSpace,
SkBudgeted budgeted)
: INHERITED(std::move(context), width, height, uniqueID,
// 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
@ -34,15 +35,15 @@ SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height
-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
: kOpaque_SkAlphaType,
budgeted, imageColorSpace)
, fNumProxies(numProxies)
, fYUVColorSpace(colorSpace)
, fOrigin(origin) {
int maxIndex = yuvaIndices[0].fIndex;
for (int i = 1; i < 4; ++i) {
if (yuvaIndices[i].fIndex > maxIndex) {
maxIndex = yuvaIndices[i].fIndex;
}
}
for (int i = 0; i <= maxIndex; ++i) {
// The caller should have done this work, just verifying
SkDEBUGCODE(int textureCount;)
SkASSERT(SkYUVAIndex::AreValidIndices(yuvaIndices, &textureCount));
SkASSERT(textureCount == fNumProxies);
for (int i = 0; i < numProxies; ++i) {
fProxies[i] = std::move(proxies[i]);
}
memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex));
@ -57,12 +58,7 @@ SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
}
bool SkImage_GpuYUVA::setupMipmapsForPlanes() const {
int numTextures;
if (!SkYUVAIndex::AreValidIndices(fYUVAIndices, &numTextures)) {
return false;
}
for (int i = 0; i < numTextures; ++i) {
for (int i = 0; i < fNumProxies; ++i) {
GrTextureProducer::CopyParams copyParams;
int mipCount = SkMipMap::ComputeLevelCount(fProxies[i]->width(), fProxies[i]->height());
if (mipCount && GrGpu::IsACopyNeededForMips(fContext->contextPriv().caps(),
@ -83,24 +79,6 @@ bool SkImage_GpuYUVA::setupMipmapsForPlanes() const {
sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
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.
sk_sp<GrRenderTargetContext> renderTargetContext(
fContext->contextPriv().makeDeferredRenderTargetContext(
@ -109,15 +87,13 @@ sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
if (!renderTargetContext) {
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;
}
// DDL TODO: in the promise image version we must not flush here
fContext->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
fRGBProxy = renderTargetContext->asTextureProxyRef();
}
@ -150,62 +126,24 @@ sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx,
SkISize imageSize,
GrSurfaceOrigin imageOrigin,
sk_sp<SkColorSpace> imageColorSpace) {
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 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;
}
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.
int numTextures;
if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
return nullptr;
}
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;
}
}
sk_sp<GrTextureProxy> tempTextureProxies[4];
if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, imageOrigin,
tempTextureProxies)) {
return nullptr;
}
// TODO: Check that for each plane, the channel actually exist in the image source we are
// reading from.
return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), imageSize.width(), imageSize.height(),
kNeedNewImageUniqueID, colorSpace, tempTextureProxies,
yuvaIndices, imageOrigin, imageColorSpace, SkBudgeted::kYes);
numTextures, yuvaIndices, imageOrigin, imageColorSpace,
SkBudgeted::kYes);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
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,
kNeedNewImageUniqueID, yuvColorSpace, proxies, yuvaIndices,
imageOrigin, std::move(imageColorSpace), SkBudgeted::kNo);
kNeedNewImageUniqueID, yuvColorSpace, proxies, numTextures,
yuvaIndices, imageOrigin, std::move(imageColorSpace),
SkBudgeted::kNo);
}

View File

@ -26,7 +26,7 @@ public:
friend class GrYUVAImageTextureMaker;
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);
~SkImage_GpuYUVA() override;
@ -113,14 +113,15 @@ private:
// 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];
int fNumProxies;
SkYUVAIndex fYUVAIndices[4];
const SkYUVColorSpace fYUVColorSpace;
GrSurfaceOrigin fOrigin;
// 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
// the RGBProxy.
mutable sk_sp<GrTextureProxy> fRGBProxy;
const SkYUVColorSpace fYUVColorSpace;
GrSurfaceOrigin fOrigin;
typedef SkImage_GpuBase INHERITED;
};