skia2/include/core/SkImageGenerator.h
Brian Salomon 87d42e5d12 A new way to specify YUVA planar data from SkCodec to SkImage_Lazy
Tunnels through SkImageGenerator as well.

The new SkCodec interface doesn't assume three 8 bit planes.

New SkYUVASpec more clearly defines chroma subsampling and siting of
the planes.

The intent is to use this for other YUVA APIs as well, in particular
SkImage factories in the future.

In this change we convert to the SkYUVASpec to SkYUVASizeInfo
and SkYUVAIndex[4] representation. But the intent is to use
the SkYUVASpec representation throughout the pipeline once
legacy APIs are removed.

orientation GM is replicated to test a variety of chroma
subsampling configs.

Bug: skia:10632

Change-Id: I3fad35752b87cac16c51b24824331f2ae7d458d3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/309658
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
2020-08-24 14:25:32 +00:00

246 lines
10 KiB
C++

/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageGenerator_DEFINED
#define SkImageGenerator_DEFINED
#include "include/core/SkBitmap.h"
#include "include/core/SkColor.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkYUVAIndex.h"
#include "include/core/SkYUVAInfo.h"
#include "include/core/SkYUVASizeInfo.h"
class GrRecordingContext;
class GrSurfaceProxyView;
class GrSamplerState;
class SkBitmap;
class SkData;
class SkMatrix;
class SkPaint;
class SkPicture;
enum class GrImageTexGenPolicy : int;
class SK_API SkImageGenerator {
public:
/**
* The PixelRef which takes ownership of this SkImageGenerator
* will call the image generator's destructor.
*/
virtual ~SkImageGenerator() { }
uint32_t uniqueID() const { return fUniqueID; }
/**
* Return a ref to the encoded (i.e. compressed) representation
* of this data.
*
* If non-NULL is returned, the caller is responsible for calling
* unref() on the data when it is finished.
*/
sk_sp<SkData> refEncodedData() {
return this->onRefEncodedData();
}
/**
* Return the ImageInfo associated with this generator.
*/
const SkImageInfo& getInfo() const { return fInfo; }
/**
* Can this generator be used to produce images that will be drawable to the specified context
* (or to CPU, if context is nullptr)?
*/
bool isValid(GrRecordingContext* context) const {
return this->onIsValid(context);
}
/**
* Decode into the given pixels, a block of memory of size at
* least (info.fHeight - 1) * rowBytes + (info.fWidth *
* bytesPerPixel)
*
* Repeated calls to this function should give the same results,
* allowing the PixelRef to be immutable.
*
* @param info A description of the format
* expected by the caller. This can simply be identical
* to the info returned by getInfo().
*
* This contract also allows the caller to specify
* different output-configs, which the implementation can
* decide to support or not.
*
* A size that does not match getInfo() implies a request
* to scale. If the generator cannot perform this scale,
* it will return false.
*
* @return true on success.
*/
bool getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
bool getPixels(const SkPixmap& pm) {
return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes());
}
/**
* If decoding to YUV is supported, this returns true. Otherwise, this
* returns false and does not modify any of the parameters.
*
* @param yuvaInfo Specifies the planar configuration, subsampling, orientation, and chroma
* siting.
* @param colorTypes Output parameter. Color types for the planar data.
* @param rowBytes Output parameter. Row bytes for planar data.
*/
bool queryYUVAInfo(SkYUVAInfo* yuvaInfo,
SkColorType colorTypes[SkYUVAInfo::kMaxPlanes],
size_t rowBytes[SkYUVAInfo::kMaxPlanes]) const;
/**
* Returns true on success and false on failure.
* This always attempts to perform a full decode. If the client only wants planar information
* it should call queryYUVAInfo().
*
* @param planes Memory allocated by caller for the planes. Number of allocated planes,
* sizes, color types, and row bytes are initialized using the result of a
* successful call to queryYUVAInfo().
*/
bool getYUVAPlanes(const SkPixmap planes[SkYUVAInfo::kMaxPlanes]);
/**
* Deprecated. Use queryYUVAInfo instead for more structured YUVA plane specification.
*
* If decoding to YUV is supported, this returns true. Otherwise, this
* returns false and does not modify any of the parameters.
*
* @param sizeInfo Output parameter indicating the sizes and required
* allocation widths of the Y, U, V, and A planes.
* @param yuvaIndices How the YUVA planes are organized/used
* @param colorSpace Output parameter.
*/
bool queryYUVA8(SkYUVASizeInfo* sizeInfo,
SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
SkYUVColorSpace* colorSpace) const;
/**
* Deprecated. Use getYUVAPlanes instead for more structured YUVA plane retrieval.
*
* Returns true on success and false on failure.
* This always attempts to perform a full decode. If the client only
* wants size, it should call queryYUVA8().
*
* @param sizeInfo Needs to exactly match the values returned by the
* query, except the WidthBytes may be larger than the
* recommendation (but not smaller).
* @param yuvaIndices Needs to exactly match the values returned by the query.
* @param planes Memory for the Y, U, V, and A planes. Note that, depending on the
* settings in yuvaIndices, anywhere from 1..4 planes could be returned.
*/
bool getYUVA8Planes(const SkYUVASizeInfo& sizeInfo,
const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
void* planes[]);
#if SK_SUPPORT_GPU
/**
* If the generator can natively/efficiently return its pixels as a GPU image (backed by a
* texture) this will return that image. If not, this will return NULL.
*
* This routine also supports retrieving only a subset of the pixels. That subset is specified
* by the following rectangle:
*
* subset = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height())
*
* If subset is not contained inside the generator's bounds, this returns false.
*
* whole = SkIRect::MakeWH(getInfo().width(), getInfo().height())
* if (!whole.contains(subset)) {
* return false;
* }
*
* Regarding the GrRecordingContext parameter:
*
* It must be non-NULL. The generator should only succeed if:
* - its internal context is the same
* - it can somehow convert its texture into one that is valid for the provided context.
*
* If the willNeedMipMaps flag is true, the generator should try to create a TextureProxy that
* at least has the mip levels allocated and the base layer filled in. If this is not possible,
* the generator is allowed to return a non mipped proxy, but this will have some additional
* overhead in later allocating mips and copying of the base layer.
*
* GrImageTexGenPolicy determines whether or not a new texture must be created (and its budget
* status) or whether this may (but is not required to) return a pre-existing texture that is
* retained by the generator (kDraw).
*/
GrSurfaceProxyView generateTexture(GrRecordingContext*, const SkImageInfo& info,
const SkIPoint& origin, GrMipmapped, GrImageTexGenPolicy);
#endif
/**
* If the default image decoder system can interpret the specified (encoded) data, then
* this returns a new ImageGenerator for it. Otherwise this returns NULL. Either way
* the caller is still responsible for managing their ownership of the data.
*/
static std::unique_ptr<SkImageGenerator> MakeFromEncoded(sk_sp<SkData>);
/** Return a new image generator backed by the specified picture. If the size is empty or
* the picture is NULL, this returns NULL.
* The optional matrix and paint arguments are passed to drawPicture() at rasterization
* time.
*/
static std::unique_ptr<SkImageGenerator> MakeFromPicture(const SkISize&, sk_sp<SkPicture>,
const SkMatrix*, const SkPaint*,
SkImage::BitDepth,
sk_sp<SkColorSpace>);
protected:
static constexpr int kNeedNewImageUniqueID = 0;
SkImageGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID);
virtual sk_sp<SkData> onRefEncodedData() { return nullptr; }
struct Options {};
virtual bool onGetPixels(const SkImageInfo&, void*, size_t, const Options&) { return false; }
virtual bool onIsValid(GrRecordingContext*) const { return true; }
virtual bool onQueryYUVAInfo(SkYUVAInfo*,
SkColorType[SkYUVAInfo::kMaxPlanes],
size_t[SkYUVAInfo::kMaxPlanes]) const {
return false;
}
virtual bool onGetYUVAPlanes(const SkPixmap[SkYUVAInfo::kMaxPlanes]) { return false; }
virtual bool onQueryYUVA8(SkYUVASizeInfo*, SkYUVAIndex[SkYUVAIndex::kIndexCount],
SkYUVColorSpace*) const { return false; }
virtual bool onGetYUVA8Planes(const SkYUVASizeInfo&, const SkYUVAIndex[SkYUVAIndex::kIndexCount],
void*[4] /*planes*/) { return false; }
#if SK_SUPPORT_GPU
// returns nullptr
virtual GrSurfaceProxyView onGenerateTexture(GrRecordingContext*, const SkImageInfo&,
const SkIPoint&, GrMipmapped, GrImageTexGenPolicy);
#endif
private:
const SkImageInfo fInfo;
const uint32_t fUniqueID;
friend class SkImage_Lazy;
// This is our default impl, which may be different on different platforms.
// It is called from NewFromEncoded() after it has checked for any runtime factory.
// The SkData will never be NULL, as that will have been checked by NewFromEncoded.
static std::unique_ptr<SkImageGenerator> MakeFromEncodedImpl(sk_sp<SkData>);
SkImageGenerator(SkImageGenerator&&) = delete;
SkImageGenerator(const SkImageGenerator&) = delete;
SkImageGenerator& operator=(SkImageGenerator&&) = delete;
SkImageGenerator& operator=(const SkImageGenerator&) = delete;
};
#endif // SkImageGenerator_DEFINED