Add a new entry point for making promise images

This paves the way for promise image sharing among direct & recording
contexts, and untethers promise images from DDL recorder.

Followup CLs will migrate us to actually use this entry point,
and then migrate Chrome to do same.

Bug: skia:10286
Change-Id: I0ad46e8e4b91d8bc03cb039b304d2ea6d8a65c35
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/373716
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Adlai Holler 2021-02-22 14:08:07 -05:00 committed by Skia Commit-Bot
parent cc35b06f6d
commit c44e21f37e
12 changed files with 187 additions and 150 deletions

View File

@ -58,6 +58,10 @@ Milestone 90
improves rendering when diffuse and specular constants are greater than 1.
https://review.skia.org/355496
* SkDeferredDisplayListRecorder::makePromiseTexture has moved to SkImage::MakePromiseTexture.
New code should use the new entry point migration CLs will be coming soon.
https://review.skia.org/373716
Milestone 89
------------
* Removed SkYUVAIndex and SkYUVASizeInfo. These were no longer used in any

View File

@ -26,7 +26,7 @@ class SkSurface;
/*
* This class is intended to be used as:
* Get an SkSurfaceCharacterization representing the intended gpu-backed destination SkSurface
* Create one of these (an SkDDLMaker) on the stack
* Create one of these (an SkDeferredDisplayListRecorder) on the stack
* Get the canvas and render into it
* Snap off and hold on to an SkDeferredDisplayList
* Once your app actually needs the pixels, call SkSurface::draw(SkDeferredDisplayList*)
@ -51,43 +51,12 @@ public:
sk_sp<SkDeferredDisplayList> detach();
using PromiseImageTextureContext = void*;
using PromiseImageTextureFulfillProc =
sk_sp<SkPromiseImageTexture> (*)(PromiseImageTextureContext);
using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext);
using PromiseImageTextureContext = SkImage::PromiseImageTextureContext;
using PromiseImageTextureFulfillProc = SkImage::PromiseImageTextureFulfillProc;
using PromiseImageTextureReleaseProc = SkImage::PromiseImageTextureReleaseProc;
/**
Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The
difference is that the caller need not have created the texture nor populated it with the
image pixel data. Moreover, the SkImage may be created on a thread as the creation of the
image does not require access to the backend API or GrContext. Instead of passing a
GrBackendTexture the client supplies a description of the texture consisting of
GrBackendFormat, width, height, and GrMipmapped state. The resulting SkImage can be drawn
to a SkDeferredDisplayListRecorder or directly to a GPU-backed SkSurface.
When the actual texture is required to perform a backend API draw, textureFulfillProc will
be called to receive a GrBackendTexture. The properties of the GrBackendTexture must match
those set during the SkImage creation, and it must refer to a valid existing texture in the
backend API context/device, and be populated with the image pixel data. The texture cannot
be deleted until textureReleaseProc is called.
There is at most one call to each of textureFulfillProc and textureReleaseProc.
textureReleaseProc is always called even if image creation fails or if the
image is never fulfilled (e.g. it is never drawn or all draws are clipped out)
This call is only valid if the SkDeferredDisplayListRecorder is backed by a GPU context.
@param backendFormat format of promised gpu texture
@param width width of promised gpu texture
@param height height of promised gpu texture
@param mipMapped mip mapped state of promised gpu texture
@param colorSpace range of colors; may be nullptr
@param textureFulfillProc function called to get actual gpu texture
@param textureReleaseProc function called when texture can be deleted
@param textureContext state passed to textureFulfillProc and textureReleaseProc
@param version controls when textureReleaseProc is called
@return created SkImage, or nullptr
*/
#ifndef SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API
/** Deprecated: Use SkImage::MakePromiseTexture instead. */
sk_sp<SkImage> makePromiseTexture(const GrBackendFormat& backendFormat,
int width,
int height,
@ -100,26 +69,13 @@ public:
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContext);
/**
This entry point operates like 'makePromiseTexture' but it is used to construct a SkImage
from YUV[A] data. The source data may be planar (i.e. spread across multiple textures). In
the extreme Y, U, V, and A are all in different planes and thus the image is specified by
four textures. 'yuvaBackendTextureInfo' describes the planar arrangement, texture formats,
conversion to RGB, and origin of the textures. Separate 'textureFulfillProc' and
'textureReleaseProc' calls are made for each texture. Each texture has its own
PromiseImageTextureContext. If 'yuvaBackendTextureinfo' is not valid then no release proc
calls are made. Otherwise, the calls will be made even on failure. 'textureContexts' has one
entry for each of the up to four textures, as indicated by 'yuvaBackendTextureinfo'.
Currently the mip mapped property of 'yuvaBackendTextureInfo' is ignored. However, in the
near future it will be required that if it is kYes then textureFulfillProc must return
a mip mapped texture for each plane in order to successfully draw the image.
*/
/** Deprecated: Use SkImage::MakePromiseYUVATexture instead. */
sk_sp<SkImage> makeYUVAPromiseTexture(const GrYUVABackendTextureInfo& yuvaBackendTextureInfo,
sk_sp<SkColorSpace> imageColorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContexts[]);
#endif
private:
SkDeferredDisplayListRecorder(const SkDeferredDisplayListRecorder&) = delete;

View File

@ -31,12 +31,15 @@ class SkImageGenerator;
class SkMipmap;
class SkPaint;
class SkPicture;
class SkPromiseImageTexture;
class SkSurface;
class SkYUVAPixmaps;
class GrBackendFormat;
class GrBackendTexture;
class GrDirectContext;
class GrRecordingContext;
class GrContextThreadSafeProxy;
class GrYUVABackendTextureInfo;
class GrYUVABackendTextures;
/** \class SkImage
@ -474,6 +477,83 @@ public:
GrSurfaceOrigin surfaceOrigin = kTopLeft_GrSurfaceOrigin);
#endif
using PromiseImageTextureContext = void*;
using PromiseImageTextureFulfillProc =
sk_sp<SkPromiseImageTexture> (*)(PromiseImageTextureContext);
using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext);
/** Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The
difference is that the caller need not have created the texture nor populated it with the
image pixel data. Moreover, the SkImage may be created on a thread as the creation of the
image does not require access to the backend API or GrDirectContext. Instead of passing a
GrBackendTexture the client supplies a description of the texture consisting of
GrBackendFormat, width, height, and GrMipmapped state. The resulting SkImage can be drawn
to a SkDeferredDisplayListRecorder or directly to a GPU-backed SkSurface.
When the actual texture is required to perform a backend API draw, textureFulfillProc will
be called to receive a GrBackendTexture. The properties of the GrBackendTexture must match
those set during the SkImage creation, and it must refer to a valid existing texture in the
backend API context/device, and be populated with the image pixel data. The texture cannot
be deleted until textureReleaseProc is called.
There is at most one call to each of textureFulfillProc and textureReleaseProc.
textureReleaseProc is always called even if image creation fails or if the
image is never fulfilled (e.g. it is never drawn or all draws are clipped out)
@param gpuContextProxy the thread-safe proxy of the gpu context. required.
@param backendFormat format of promised gpu texture
@param dimensions width & height of promised gpu texture
@param mipMapped mip mapped state of promised gpu texture
@param origin surface origin of promised gpu texture
@param colorType color type of promised gpu texture
@param alphaType alpha type of promised gpu texture
@param colorSpace range of colors; may be nullptr
@param textureFulfillProc function called to get actual gpu texture
@param textureReleaseProc function called when texture can be deleted
@param textureContext state passed to textureFulfillProc and textureReleaseProc
@return created SkImage, or nullptr
*/
static sk_sp<SkImage> MakePromiseTexture(sk_sp<GrContextThreadSafeProxy> gpuContextProxy,
const GrBackendFormat& backendFormat,
SkISize dimensions,
GrMipmapped mipMapped,
GrSurfaceOrigin origin,
SkColorType colorType,
SkAlphaType alphaType,
sk_sp<SkColorSpace> colorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContext);
/** This entry point operates like 'MakePromiseTexture' but it is used to construct a SkImage
from YUV[A] data. The source data may be planar (i.e. spread across multiple textures). In
the extreme Y, U, V, and A are all in different planes and thus the image is specified by
four textures. 'backendTextureInfo' describes the planar arrangement, texture formats,
conversion to RGB, and origin of the textures. Separate 'textureFulfillProc' and
'textureReleaseProc' calls are made for each texture. Each texture has its own
PromiseImageTextureContext. If 'backendTextureInfo' is not valid then no release proc
calls are made. Otherwise, the calls will be made even on failure. 'textureContexts' has one
entry for each of the up to four textures, as indicated by 'backendTextureInfo'.
Currently the mip mapped property of 'backendTextureInfo' is ignored. However, in the
near future it will be required that if it is kYes then textureFulfillProc must return
a mip mapped texture for each plane in order to successfully draw the image.
@param gpuContextProxy the thread-safe proxy of the gpu context. required.
@param backendTextureInfo info about the promised yuva gpu texture
@param imageColorSpace range of colors; may be nullptr
@param textureFulfillProc function called to get actual gpu texture
@param textureReleaseProc function called when texture can be deleted
@param textureContexts state passed to textureFulfillProc and textureReleaseProc
@return created SkImage, or nullptr
*/
static sk_sp<SkImage> MakePromiseYUVATexture(sk_sp<GrContextThreadSafeProxy> gpuContextProxy,
const GrYUVABackendTextureInfo& backendTextureInfo,
sk_sp<SkColorSpace> imageColorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContexts[]);
/** Returns a SkImageInfo describing the width, height, color type, alpha type, and color space
of the SkImage.

View File

@ -8,8 +8,11 @@
#ifndef GrContextThreadSafeProxy_DEFINED
#define GrContextThreadSafeProxy_DEFINED
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#if SK_SUPPORT_GPU
#include "include/core/SkImageInfo.h"
#include "include/gpu/GrContextOptions.h"
#include "include/gpu/GrTypes.h"
@ -138,4 +141,8 @@ private:
std::atomic<bool> fAbandoned{false};
};
#else // !SK_SUPPORT_GPU
class SK_API GrContextThreadSafeProxy final : public SkNVRefCnt<GrContextThreadSafeProxy> {};
#endif
#endif

View File

@ -234,6 +234,7 @@ sk_sp<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
return ddl;
}
#ifndef SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API
sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
const GrBackendFormat& backendFormat,
int width,
@ -249,21 +250,21 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
if (!fContext) {
return nullptr;
}
return SkImage_Gpu::MakePromiseTexture(fContext->threadSafeProxy(),
backendFormat,
{width, height},
mipMapped,
origin,
colorType,
alphaType,
std::move(colorSpace),
textureFulfillProc,
textureReleaseProc,
textureContext);
return SkImage::MakePromiseTexture(fContext->threadSafeProxy(),
backendFormat,
{width, height},
mipMapped,
origin,
colorType,
alphaType,
std::move(colorSpace),
textureFulfillProc,
textureReleaseProc,
textureContext);
}
sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
const GrYUVABackendTextureInfo& yuvaBackendTextureInfo,
const GrYUVABackendTextureInfo& backendTextureInfo,
sk_sp<SkColorSpace> imageColorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
@ -271,12 +272,13 @@ sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
if (!fContext) {
return nullptr;
}
return SkImage_GpuYUVA::MakePromiseYUVATexture(fContext->threadSafeProxy(),
yuvaBackendTextureInfo,
std::move(imageColorSpace),
textureFulfillProc,
textureReleaseProc,
textureContexts);
return SkImage::MakePromiseYUVATexture(fContext->threadSafeProxy(),
backendTextureInfo,
std::move(imageColorSpace),
textureFulfillProc,
textureReleaseProc,
textureContexts);
}
#endif // !SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API
#endif

View File

@ -609,7 +609,7 @@ void GrDrawingManager::createDDLTask(sk_sp<const SkDeferredDisplayList> ddl,
SkDEBUGCODE(this->validate());
if (fActiveOpsTask) {
// This is a temporary fix for the partial-MDB world. In that world we're not
// This is a temporary fix for the partial-MDB world. In that world we're not
// reordering so ops that (in the single opsTask world) would've just glommed onto the
// end of the single opsTask but referred to a far earlier RT need to appear in their
// own opsTask.

View File

@ -37,6 +37,7 @@
#include "src/image/SkImage_Gpu.h"
#endif
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContextThreadSafeProxy.h"
SkImage::SkImage(const SkImageInfo& info, uint32_t uniqueID)
: fInfo(info)
@ -590,6 +591,29 @@ sk_sp<SkImage> SkImage::makeTextureImage(GrDirectContext*, GrMipmapped, SkBudget
return nullptr;
}
sk_sp<SkImage> SkImage::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy>,
const GrBackendFormat&,
SkISize,
GrMipmapped,
GrSurfaceOrigin,
SkColorType,
SkAlphaType,
sk_sp<SkColorSpace>,
PromiseImageTextureFulfillProc,
PromiseImageTextureReleaseProc,
PromiseImageTextureContext) {
return nullptr;
}
sk_sp<SkImage> SkImage::MakePromiseYUVATexture(sk_sp<GrContextThreadSafeProxy>,
const GrYUVABackendTextureInfo&,
sk_sp<SkColorSpace>,
PromiseImageTextureFulfillProc,
PromiseImageTextureReleaseProc,
PromiseImageTextureContext[]) {
return nullptr;
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -374,17 +374,17 @@ sk_sp<SkImage> SkImage::makeTextureImage(GrDirectContext* dContext,
///////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
const GrBackendFormat& backendFormat,
SkISize dimensions,
GrMipmapped mipMapped,
GrSurfaceOrigin origin,
SkColorType colorType,
SkAlphaType alphaType,
sk_sp<SkColorSpace> colorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContext) {
sk_sp<SkImage> SkImage::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
const GrBackendFormat& backendFormat,
SkISize dimensions,
GrMipmapped mipMapped,
GrSurfaceOrigin origin,
SkColorType colorType,
SkAlphaType alphaType,
sk_sp<SkColorSpace> colorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContext) {
// Our contract is that we will always call the release proc even on failure.
// We use the helper to convey the context, so we need to ensure make doesn't fail.
textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
@ -414,12 +414,12 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy> t
return nullptr;
}
auto proxy = MakePromiseImageLazyProxy(threadSafeProxy.get(),
dimensions,
backendFormat,
mipMapped,
textureFulfillProc,
std::move(releaseHelper));
auto proxy = SkImage_GpuBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
dimensions,
backendFormat,
mipMapped,
textureFulfillProc,
std::move(releaseHelper));
if (!proxy) {
return nullptr;
}

View File

@ -76,22 +76,6 @@ public:
ReadPixelsCallback,
ReadPixelsContext) override;
/**
* This is the implementation of SkDeferredDisplayListRecorder::makePromiseImage.
* TODO: Make this public, and remove the SkDDLRecorder entry point.
*/
static sk_sp<SkImage> MakePromiseTexture(sk_sp<GrContextThreadSafeProxy>,
const GrBackendFormat& backendFormat,
SkISize dimensions,
GrMipmapped mipMapped,
GrSurfaceOrigin origin,
SkColorType colorType,
SkAlphaType alphaType,
sk_sp<SkColorSpace> colorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContext);
private:
std::tuple<GrSurfaceProxyView, GrColorType> onAsView(GrRecordingContext*,
GrMipmapped,

View File

@ -47,20 +47,8 @@ public:
static bool ValidateCompressedBackendTexture(const GrCaps*, const GrBackendTexture& tex,
SkAlphaType);
using PromiseImageTextureContext = SkDeferredDisplayListRecorder::PromiseImageTextureContext;
using PromiseImageTextureFulfillProc =
SkDeferredDisplayListRecorder::PromiseImageTextureFulfillProc;
using PromiseImageTextureReleaseProc =
SkDeferredDisplayListRecorder::PromiseImageTextureReleaseProc;
protected:
SkImage_GpuBase(sk_sp<GrImageContext>, SkISize size, uint32_t uniqueID, SkColorType,
SkAlphaType, sk_sp<SkColorSpace>);
// Helper for making a lazy proxy for a promise image. The PromiseDoneProc we be called,
// if not null, immediately if this function fails. Othwerwise, it is installed in the
// proxy along with the TextureFulfillProc and TextureReleaseProc. PromiseDoneProc must not
// be null.
// Helper for making a lazy proxy for a promise image.
// PromiseImageTextureFulfillProc must not be null.
static sk_sp<GrTextureProxy> MakePromiseImageLazyProxy(GrContextThreadSafeProxy*,
SkISize dimensions,
GrBackendFormat,
@ -68,6 +56,10 @@ protected:
PromiseImageTextureFulfillProc,
sk_sp<GrRefCntedCallback> releaseHelper);
protected:
SkImage_GpuBase(sk_sp<GrImageContext>, SkISize size, uint32_t uniqueID, SkColorType,
SkAlphaType, sk_sp<SkColorSpace>);
sk_sp<GrImageContext> fContext;
private:

View File

@ -379,19 +379,18 @@ sk_sp<SkImage> SkImage::MakeFromYUVAPixmaps(GrRecordingContext* context,
/////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
const GrYUVABackendTextureInfo& yuvaBackendTextureInfo,
sk_sp<SkColorSpace> imageColorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContexts[]) {
if (!yuvaBackendTextureInfo.isValid()) {
sk_sp<SkImage> SkImage::MakePromiseYUVATexture(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
const GrYUVABackendTextureInfo& backendTextureInfo,
sk_sp<SkColorSpace> imageColorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContexts[]) {
if (!backendTextureInfo.isValid()) {
return nullptr;
}
SkISize planeDimensions[SkYUVAInfo::kMaxPlanes];
int n = yuvaBackendTextureInfo.yuvaInfo().planeDimensions(planeDimensions);
int n = backendTextureInfo.yuvaInfo().planeDimensions(planeDimensions);
// Our contract is that we will always call the release proc even on failure.
// We use the helper to convey the context, so we need to ensure make doesn't fail.
@ -405,9 +404,9 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
return nullptr;
}
SkAlphaType at = yuvaBackendTextureInfo.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType
: kOpaque_SkAlphaType;
SkImageInfo info = SkImageInfo::Make(yuvaBackendTextureInfo.yuvaInfo().dimensions(),
SkAlphaType at = backendTextureInfo.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType
: kOpaque_SkAlphaType;
SkImageInfo info = SkImageInfo::Make(backendTextureInfo.yuvaInfo().dimensions(),
kAssumedColorType, at, imageColorSpace);
if (!SkImageInfoIsValid(info)) {
return nullptr;
@ -416,19 +415,19 @@ sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(
// Make a lazy proxy for each plane and wrap in a view.
sk_sp<GrSurfaceProxy> proxies[4];
for (int i = 0; i < n; ++i) {
proxies[i] = MakePromiseImageLazyProxy(threadSafeProxy.get(),
planeDimensions[i],
yuvaBackendTextureInfo.planeFormat(i),
GrMipmapped::kNo,
textureFulfillProc,
std::move(releaseHelpers[i]));
proxies[i] = SkImage_GpuBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
planeDimensions[i],
backendTextureInfo.planeFormat(i),
GrMipmapped::kNo,
textureFulfillProc,
std::move(releaseHelpers[i]));
if (!proxies[i]) {
return nullptr;
}
}
GrYUVATextureProxies yuvaTextureProxies(yuvaBackendTextureInfo.yuvaInfo(),
GrYUVATextureProxies yuvaTextureProxies(backendTextureInfo.yuvaInfo(),
proxies,
yuvaBackendTextureInfo.textureOrigin());
backendTextureInfo.textureOrigin());
SkASSERT(yuvaTextureProxies.isValid());
sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
return sk_make_sp<SkImage_GpuYUVA>(std::move(ctx),

View File

@ -63,17 +63,6 @@ public:
}
#endif
/**
* This is the implementation of SkDeferredDisplayListRecorder::makeYUVAPromiseTexture.
* TODO: Make this public, and remove the SkDDLRecorder entry point.
*/
static sk_sp<SkImage> MakePromiseYUVATexture(sk_sp<GrContextThreadSafeProxy>,
const GrYUVABackendTextureInfo&,
sk_sp<SkColorSpace> imageColorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureContext textureContexts[]);
private:
SkImage_GpuYUVA(sk_sp<GrImageContext>, const SkImage_GpuYUVA* image, sk_sp<SkColorSpace>);