Fix up SkImage_GpuYUVA MakePromiseYUVATexture

Bug: skia:7901
Change-Id: I8722373148f99cb16e2aa9c825832bb83fa4e979
Reviewed-on: https://skia-review.googlesource.com/c/161043
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2018-10-10 13:03:23 -04:00 committed by Skia Commit-Bot
parent 6ba8c83234
commit f00b16233d
3 changed files with 95 additions and 82 deletions

View File

@ -52,6 +52,37 @@ struct SK_API SkYUVAIndex {
/** The channel describes from which channel to read the info from. Currently we only deal with
* YUV and NV12 and channel info is ignored. */
SkColorChannel fChannel;
static bool AreValidIndices(const SkYUVAIndex yuvaIndices[4], int* numPlanes) {
// Note that 'numPlanes' is always filled in even if the indices are not valid.
// This means it can always be used to process the backing resources (but be careful
// of empty intervening slots).
int maxSlotUsed = -1;
bool used[4] = { false, false, false, false };
bool valid = true;
for (int i = 0; i < 4; ++i) {
if (yuvaIndices[i].fIndex < 0) {
if (SkYUVAIndex::kA_Index != i) {
valid = false; // only the 'A' plane can be omitted
}
} else if (yuvaIndices[i].fIndex > 3) {
valid = false; // A maximum of four input textures is allowed
} else {
maxSlotUsed = SkTMax(yuvaIndices[i].fIndex, maxSlotUsed);
used[i] = true;
}
}
// All the used slots should be packed starting at 0 with no gaps
for (int i = 0; i <= maxSlotUsed; ++i) {
if (!used[i]) {
valid = false;
}
}
*numPlanes = maxSlotUsed + 1;
return valid;
}
};
#endif

View File

@ -28,40 +28,11 @@ static const float kRec709ConversionMatrix[16] = {
0.0f, 0.0f, 0.0f, 1.0f
};
static bool is_valid_yuv(const SkYUVAIndex yuvaIndices[4], int* numPlanes) {
int maxSlotUsed = -1;
bool used[4] = { false, false, false, false };
for (int i = 0; i < 4; ++i) {
if (yuvaIndices[i].fIndex < 0) {
if (SkYUVAIndex::kA_Index != i) {
return false; // only the 'A' plane can be omitted
}
} else if (yuvaIndices[i].fIndex > 3) {
return false; // A maximum of four input textures is allowed
} else {
maxSlotUsed = SkTMax(yuvaIndices[i].fIndex, maxSlotUsed);
used[i] = true;
}
}
// All the used slots should be packed starting at 0 with no gaps
for (int i = 0; i <= maxSlotUsed; ++i) {
if (!used[i]) {
return false;
}
}
*numPlanes = maxSlotUsed+1;
return true;
}
std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextureProxy> proxies[],
const SkYUVAIndex yuvaIndices[4],
SkYUVColorSpace yuvColorSpace) {
int numPlanes;
SkAssertResult(is_valid_yuv(yuvaIndices, &numPlanes));
SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
const SkISize YSize = proxies[yuvaIndices[SkYUVAIndex::kY_Index].fIndex]->isize();

View File

@ -168,13 +168,11 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakeFromYUVATextures(GrContext* ctx,
SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
tempTextureProxies[textureIndex] =
proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], origin);
}
}
if (!tempTextureProxies[yuvaIndices[SkYUVAIndex::kY_Index].fIndex] ||
!tempTextureProxies[yuvaIndices[SkYUVAIndex::kU_Index].fIndex] ||
!tempTextureProxies[yuvaIndices[SkYUVAIndex::kV_Index].fIndex]) {
if (!tempTextureProxies[textureIndex]) {
return nullptr;
}
}
}
return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), kNeedNewImageUniqueID, colorSpace,
tempTextureProxies, yuvaIndices, size, origin,
@ -193,11 +191,25 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
TextureReleaseProc textureReleaseProc,
PromiseDoneProc promiseDoneProc,
TextureContext textureContexts[]) {
// The contract here is that if 'promiseDoneProc' is passed in it should always be called,
// even if creation of the SkImage fails.
if (!promiseDoneProc) {
return nullptr;
}
// TODO: fill in the promise image helpers here so promiseDoneProc will always be called
int numTextures;
bool valid = SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures);
// Set up promise helpers
SkPromiseImageHelper promiseHelpers[4];
for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
promiseHelpers[texIdx].set(textureFulfillProc, textureReleaseProc, promiseDoneProc,
textureContexts[texIdx]);
}
if (!valid) {
return nullptr;
}
if (!context) {
return nullptr;
@ -219,29 +231,48 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
return nullptr;
}
GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
SkColorType colorTypes[4] = { kUnknown_SkColorType, kUnknown_SkColorType,
// Set up color types
SkColorType texColorTypes[4] = { kUnknown_SkColorType, kUnknown_SkColorType,
kUnknown_SkColorType, kUnknown_SkColorType };
for (int i = 0; i < 4; ++i) {
if (yuvaIndices[i].fIndex < 0) {
SkASSERT(SkYUVAIndex::kA_Index == i); // We had better have YUV channels
for (int yuvIndex = 0; yuvIndex < 4; ++yuvIndex) {
int texIdx = yuvaIndices[yuvIndex].fIndex;
if (texIdx < 0) {
SkASSERT(SkYUVAIndex::kA_Index);
continue;
}
SkASSERT(yuvaIndices[i].fIndex < 4);
if (kUnknown_SkColorType == colorTypes[i]) {
colorTypes[i] = kAlpha_8_SkColorType;
if (kUnknown_SkColorType == texColorTypes[texIdx]) {
texColorTypes[texIdx] = kAlpha_8_SkColorType;
} else {
colorTypes[i] = kRGBA_8888_SkColorType;
texColorTypes[texIdx] = kRGBA_8888_SkColorType;
}
}
// If UV is interleaved, then Y will have RGBA color type
if (kRGBA_8888_SkColorType == texColorTypes[yuvaIndices[SkYUVAIndex::kU_Index].fIndex]) {
texColorTypes[yuvaIndices[SkYUVAIndex::kY_Index].fIndex] = kRGBA_8888_SkColorType;
}
// Get lazy proxies
GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
GrSurfaceDesc desc;
desc.fFlags = kNone_GrSurfaceFlags;
desc.fWidth = size.width();
desc.fHeight = size.height();
desc.fConfig = kUnknown_GrPixelConfig; // We'll replace this for each proxy.
desc.fSampleCnt = 1;
sk_sp<GrTextureProxy> proxies[4];
for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
// for each proxy we need to fill in
struct {
GrPixelConfig fConfig;
SkPromiseImageHelper fPromiseHelper;
} params;
if (!context->contextPriv().caps()->getConfigFromBackendFormat(yuvaFormats[texIdx],
texColorTypes[texIdx],
&params.fConfig)) {
return nullptr;
}
params.fPromiseHelper = promiseHelpers[texIdx];
GrProxyProvider::LazyInstantiateCallback lazyInstCallback =
[params](GrResourceProvider* resourceProvider) mutable {
if (!resourceProvider || !params.fPromiseHelper.isValid()) {
@ -253,36 +284,16 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
return params.fPromiseHelper.getTexture(resourceProvider, params.fConfig);
};
GrSurfaceDesc desc;
desc.fFlags = kNone_GrSurfaceFlags;
desc.fWidth = size.width();
desc.fHeight = size.height();
// For now, we'll replace this for each proxy
desc.fConfig = kUnknown_GrPixelConfig;
desc.fSampleCnt = 1;
sk_sp<GrTextureProxy> proxies[4];
for (int i = 0; i < 4; ++i) {
// for each proxy we need to fill in
if (kUnknown_SkColorType != colorTypes[i]) {
GrPixelConfig pixelConfig;
if (!context->contextPriv().caps()->getConfigFromBackendFormat(yuvaFormats[i],
colorTypes[i],
&pixelConfig)) {
return nullptr;
}
desc.fConfig = pixelConfig;
proxies[i] = proxyProvider->createLazyProxy(
desc.fConfig = params.fConfig;
proxies[texIdx] = proxyProvider->createLazyProxy(
std::move(lazyInstCallback), desc, imageOrigin, GrMipMapped::kNo,
GrTextureType::k2D, GrInternalSurfaceFlags::kNone,
SkBackingFit::kExact, SkBudgeted::kNo,
GrSurfaceProxy::LazyInstantiationType::kUninstantiate);
if (!proxies[i]) {
if (!proxies[texIdx]) {
return nullptr;
}
}
}
return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), kNeedNewImageUniqueID, yuvColorSpace,
proxies, yuvaIndices, size, imageOrigin,