blob: 6fc49fe3fbbe8f6ba3c2d4e10e08782e55ebb19a [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkDeferredDisplayListRecorder_DEFINED
#define SkDeferredDisplayListRecorder_DEFINED
#include "include/core/SkDeferredDisplayList.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurfaceCharacterization.h"
#include "include/core/SkTypes.h"
class GrBackendFormat;
class GrBackendTexture;
class GrRecordingContext;
class SkCanvas;
class SkImage;
class SkPromiseImageTexture;
class SkSurface;
struct SkYUVAIndex;
struct SkYUVASizeInfo;
/*
* 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
* 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*)
*
* This class never accesses the GPU but performs all the cpu work it can. It
* is thread-safe (i.e., one can break a scene into tiles and perform their cpu-side
* work in parallel ahead of time).
*/
class SK_API SkDeferredDisplayListRecorder {
public:
SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&);
~SkDeferredDisplayListRecorder();
const SkSurfaceCharacterization& characterization() const {
return fCharacterization;
}
// The backing canvas will become invalid (and this entry point will return
// null) once 'detach' is called.
// Note: ownership of the SkCanvas is not transferred via this call.
SkCanvas* getCanvas();
sk_sp<SkDeferredDisplayList> detach();
using PromiseImageTextureContext = void*;
using PromiseImageTextureFulfillProc =
sk_sp<SkPromiseImageTexture> (*)(PromiseImageTextureContext);
using PromiseImageTextureReleaseProc = void (*)(PromiseImageTextureContext);
using PromiseImageTextureDoneProc = void (*)(PromiseImageTextureContext);
enum class PromiseImageApiVersion { kLegacy, kNew };
/**
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 contents
cannot be modified until textureReleaseProc is called. The texture cannot be deleted until
textureDoneProc is called.
When all the following are true:
* the promise SkImage is deleted,
* any SkDeferredDisplayLists that recorded draws referencing the image are deleted,
* and all draws referencing the texture have been flushed (via GrContext::flush or
SkSurface::flush)
the textureReleaseProc is called. When the following additional constraint is met
* the texture is safe to delete in the underlying API
the textureDoneProc is called. For some APIs (e.g. GL) the two states are equivalent.
However, for others (e.g. Vulkan) they are not as it is not legal to delete a texture until
the GPU work referencing it has completed.
There is at most one call to each of textureFulfillProc, textureReleaseProc, and
textureDoneProc. textureDoneProc 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). If
textureFulfillProc is called then textureReleaseProc will always be called even if
textureFulfillProc failed.
If 'version' is set to kLegacy then the textureReleaseProc call is delayed until the
conditions for textureDoneProc are met and then they are both called.
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 released
@param textureDoneProc function called when we will no longer call textureFulfillProc
@param textureContext state passed to textureFulfillProc and textureReleaseProc
@param version controls when textureReleaseProc is called
@return created SkImage, or nullptr
*/
sk_sp<SkImage> makePromiseTexture(
const GrBackendFormat& backendFormat,
int width,
int height,
GrMipmapped mipMapped,
GrSurfaceOrigin origin,
SkColorType colorType,
SkAlphaType alphaType,
sk_sp<SkColorSpace> colorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureDoneProc textureDoneProc,
PromiseImageTextureContext textureContext,
PromiseImageApiVersion version = PromiseImageApiVersion::kLegacy);
/**
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. 'yuvaIndices' specifies the mapping from texture color channels to Y, U, V,
and possibly A components. It therefore indicates how many unique textures compose the full
image. Separate textureFulfillProc, textureReleaseProc, and textureDoneProc calls are made
for each texture and each texture has its own PromiseImageTextureContext. 'yuvFormats',
'yuvaSizes', and 'textureContexts' have one entry for each of the up to four textures, as
indicated by 'yuvaIndices'.
*/
sk_sp<SkImage> makeYUVAPromiseTexture(
SkYUVColorSpace yuvColorSpace,
const GrBackendFormat yuvaFormats[],
const SkISize yuvaSizes[],
const SkYUVAIndex yuvaIndices[4],
int imageWidth,
int imageHeight,
GrSurfaceOrigin imageOrigin,
sk_sp<SkColorSpace> imageColorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureDoneProc textureDoneProc,
PromiseImageTextureContext textureContexts[],
PromiseImageApiVersion version = PromiseImageApiVersion::kLegacy);
private:
bool init();
const SkSurfaceCharacterization fCharacterization;
#if SK_SUPPORT_GPU
sk_sp<GrRecordingContext> fContext;
sk_sp<GrRenderTargetProxy> fTargetProxy;
sk_sp<SkDeferredDisplayList::LazyProxyData> fLazyProxyData;
sk_sp<SkSurface> fSurface;
#endif
};
#endif