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:
parent
32828eb006
commit
0e67194586
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user