Bug 1958191 - Update Skia to m136. r=aosmond
This looks like a fairly mild update with some of our local patches being upstreamed and otherwise reasonably small amounts of code churn. Differential Revision: https://phabricator.services.mozilla.com/D244290
This commit is contained in:
@@ -219,6 +219,12 @@ def generate_separated_sources(platform_sources):
|
|||||||
|
|
||||||
separated = defaultdict(set, {
|
separated = defaultdict(set, {
|
||||||
'common': {
|
'common': {
|
||||||
|
'skia/src/codec/SkCodec.cpp',
|
||||||
|
'skia/src/codec/SkCodecImageGenerator.cpp',
|
||||||
|
'skia/src/codec/SkColorPalette.cpp',
|
||||||
|
'skia/src/codec/SkImageGenerator_FromEncoded.cpp',
|
||||||
|
'skia/src/codec/SkPixmapUtils.cpp',
|
||||||
|
'skia/src/codec/SkSampler.cpp',
|
||||||
'skia/src/effects/imagefilters/SkBlendImageFilter.cpp',
|
'skia/src/effects/imagefilters/SkBlendImageFilter.cpp',
|
||||||
'skia/src/effects/imagefilters/SkBlurImageFilter.cpp',
|
'skia/src/effects/imagefilters/SkBlurImageFilter.cpp',
|
||||||
'skia/src/effects/imagefilters/SkComposeImageFilter.cpp',
|
'skia/src/effects/imagefilters/SkComposeImageFilter.cpp',
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ UNIFIED_SOURCES += [
|
|||||||
'skia/src/base/SkTSearch.cpp',
|
'skia/src/base/SkTSearch.cpp',
|
||||||
'skia/src/base/SkUTF.cpp',
|
'skia/src/base/SkUTF.cpp',
|
||||||
'skia/src/base/SkUtils.cpp',
|
'skia/src/base/SkUtils.cpp',
|
||||||
|
'skia/src/codec/SkCodec.cpp',
|
||||||
|
'skia/src/codec/SkCodecImageGenerator.cpp',
|
||||||
|
'skia/src/codec/SkColorPalette.cpp',
|
||||||
|
'skia/src/codec/SkImageGenerator_FromEncoded.cpp',
|
||||||
|
'skia/src/codec/SkPixmapUtils.cpp',
|
||||||
|
'skia/src/codec/SkSampler.cpp',
|
||||||
'skia/src/core/SkAAClip.cpp',
|
'skia/src/core/SkAAClip.cpp',
|
||||||
'skia/src/core/SkAlphaRuns.cpp',
|
'skia/src/core/SkAlphaRuns.cpp',
|
||||||
'skia/src/core/SkAnalyticEdge.cpp',
|
'skia/src/core/SkAnalyticEdge.cpp',
|
||||||
@@ -127,6 +133,7 @@ UNIFIED_SOURCES += [
|
|||||||
'skia/src/core/SkMaskBlurFilter.cpp',
|
'skia/src/core/SkMaskBlurFilter.cpp',
|
||||||
'skia/src/core/SkMaskCache.cpp',
|
'skia/src/core/SkMaskCache.cpp',
|
||||||
'skia/src/core/SkMaskFilter.cpp',
|
'skia/src/core/SkMaskFilter.cpp',
|
||||||
|
'skia/src/core/SkMaskFilterBase.cpp',
|
||||||
'skia/src/core/SkMaskGamma.cpp',
|
'skia/src/core/SkMaskGamma.cpp',
|
||||||
'skia/src/core/SkMasks.cpp',
|
'skia/src/core/SkMasks.cpp',
|
||||||
'skia/src/core/SkMatrixInvert.cpp',
|
'skia/src/core/SkMatrixInvert.cpp',
|
||||||
|
|||||||
@@ -412,6 +412,9 @@ public:
|
|||||||
* If a scanline decode is in progress, scanline mode will end, requiring the client to call
|
* If a scanline decode is in progress, scanline mode will end, requiring the client to call
|
||||||
* startScanlineDecode() in order to return to decoding scanlines.
|
* startScanlineDecode() in order to return to decoding scanlines.
|
||||||
*
|
*
|
||||||
|
* For certain codecs, reading into a smaller bitmap than the original dimensions may not
|
||||||
|
* produce correct results (e.g. animated webp).
|
||||||
|
*
|
||||||
* @return Result kSuccess, or another value explaining the type of failure.
|
* @return Result kSuccess, or another value explaining the type of failure.
|
||||||
*/
|
*/
|
||||||
Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*);
|
Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*);
|
||||||
@@ -781,12 +784,46 @@ public:
|
|||||||
*
|
*
|
||||||
* As such, future decoding calls may require a rewind.
|
* As such, future decoding calls may require a rewind.
|
||||||
*
|
*
|
||||||
* For still (non-animated) image codecs, this will return 0.
|
* `getRepetitionCount` will return `0` in two cases:
|
||||||
|
* 1. Still (non-animated) images.
|
||||||
|
* 2. Animated images that only play the animation once (i.e. that don't
|
||||||
|
* repeat the animation)
|
||||||
|
* `isAnimated` can be used to disambiguate between these two cases.
|
||||||
*/
|
*/
|
||||||
int getRepetitionCount() {
|
int getRepetitionCount() {
|
||||||
return this->onGetRepetitionCount();
|
return this->onGetRepetitionCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `isAnimated` returns whether the full input is expected to contain an
|
||||||
|
* animated image (i.e. more than 1 image frame). This can be used to
|
||||||
|
* disambiguate the meaning of `getRepetitionCount` returning `0` (see
|
||||||
|
* `getRepetitionCount`'s doc comment for more details).
|
||||||
|
*
|
||||||
|
* Note that in some codecs `getFrameCount()` only returns the number of
|
||||||
|
* frames for which all the metadata has been already successfully decoded.
|
||||||
|
* Therefore for a partial input `isAnimated()` may return "yes", even
|
||||||
|
* though `getFrameCount()` may temporarily return `1` until more of the
|
||||||
|
* input is available.
|
||||||
|
*
|
||||||
|
* When handling partial input, some codecs may not know until later (e.g.
|
||||||
|
* until encountering additional image frames) whether the given image has
|
||||||
|
* more than one frame. Such codecs may initially return
|
||||||
|
* `IsAnimated::kUnknown` and only later give a definitive "yes" or "no"
|
||||||
|
* answer. GIF format is one example where this may happen.
|
||||||
|
*
|
||||||
|
* Other codecs may be able to decode the information from the metadata
|
||||||
|
* present before the first image frame. Such codecs should be able to give
|
||||||
|
* a definitive "yes" or "no" answer as soon as they are constructed. PNG
|
||||||
|
* format is one example where this happens.
|
||||||
|
*/
|
||||||
|
enum class IsAnimated {
|
||||||
|
kYes,
|
||||||
|
kNo,
|
||||||
|
kUnknown,
|
||||||
|
};
|
||||||
|
IsAnimated isAnimated() { return this->onIsAnimated(); }
|
||||||
|
|
||||||
// Register a decoder at runtime by passing two function pointers:
|
// Register a decoder at runtime by passing two function pointers:
|
||||||
// - peek() to return true if the span of bytes appears to be your encoded format;
|
// - peek() to return true if the span of bytes appears to be your encoded format;
|
||||||
// - make() to attempt to create an SkCodec from the given stream.
|
// - make() to attempt to create an SkCodec from the given stream.
|
||||||
@@ -812,6 +849,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual bool onGetGainmapCodec(SkGainmapInfo*, std::unique_ptr<SkCodec>*) { return false; }
|
virtual bool onGetGainmapCodec(SkGainmapInfo*, std::unique_ptr<SkCodec>*) { return false; }
|
||||||
|
virtual bool onGetGainmapInfo(SkGainmapInfo*) { return false; }
|
||||||
|
|
||||||
// TODO(issues.skia.org/363544350): This API only works for JPEG images. Remove this API once
|
// TODO(issues.skia.org/363544350): This API only works for JPEG images. Remove this API once
|
||||||
// it is no longer used.
|
// it is no longer used.
|
||||||
@@ -933,6 +971,10 @@ protected:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual IsAnimated onIsAnimated() {
|
||||||
|
return IsAnimated::kNo;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SkEncodedInfo fEncodedInfo;
|
const SkEncodedInfo fEncodedInfo;
|
||||||
XformFormat fSrcXformFormat;
|
XformFormat fSrcXformFormat;
|
||||||
@@ -1053,8 +1095,9 @@ private:
|
|||||||
friend class PNGCodecGM; // for fillIncompleteImage
|
friend class PNGCodecGM; // for fillIncompleteImage
|
||||||
friend class SkSampledCodec;
|
friend class SkSampledCodec;
|
||||||
friend class SkIcoCodec;
|
friend class SkIcoCodec;
|
||||||
friend class SkAndroidCodec; // for fEncodedInfo
|
friend class SkPngCodec; // for onGetGainmapCodec
|
||||||
friend class SkPDFBitmap; // for fEncodedInfo
|
friend class SkAndroidCodec; // for handleFrameIndex
|
||||||
|
friend class SkCodecPriv; // for fEncodedInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace SkCodecs {
|
namespace SkCodecs {
|
||||||
|
|||||||
@@ -74,15 +74,11 @@
|
|||||||
*/
|
*/
|
||||||
//#define SK_R32_SHIFT 16
|
//#define SK_R32_SHIFT 16
|
||||||
|
|
||||||
/* Determines whether to build code that supports the Ganesh GPU backend. Some classes
|
/* This controls how much space should be pre-allocated in an SkCanvas object
|
||||||
that are not GPU-specific, such as SkShader subclasses, have optional code
|
to store the SkMatrix and clip via calls to SkCanvas::save() (and balanced with
|
||||||
that is used allows them to interact with this GPU backend. If you'd like to
|
SkCanvas::restore()).
|
||||||
include this code, include -DSK_GANESH in your cflags or uncomment below.
|
|
||||||
Defaults to not set (No Ganesh GPU backend).
|
|
||||||
This define affects the ABI of Skia, so make sure it matches the client which uses
|
|
||||||
the compiled version of Skia.
|
|
||||||
*/
|
*/
|
||||||
//#define SK_GANESH
|
//#define SK_CANVAS_SAVE_RESTORE_PREALLOC_COUNT 32
|
||||||
|
|
||||||
/* Skia makes use of histogram logging macros to trace the frequency of
|
/* Skia makes use of histogram logging macros to trace the frequency of
|
||||||
events. By default, Skia provides no-op versions of these macros.
|
events. By default, Skia provides no-op versions of these macros.
|
||||||
@@ -93,8 +89,14 @@
|
|||||||
//#define SK_HISTOGRAM_ENUMERATION(name, sampleEnum, enumSize)
|
//#define SK_HISTOGRAM_ENUMERATION(name, sampleEnum, enumSize)
|
||||||
//#define SK_HISTOGRAM_EXACT_LINEAR(name, sample, valueMax)
|
//#define SK_HISTOGRAM_EXACT_LINEAR(name, sample, valueMax)
|
||||||
//#define SK_HISTOGRAM_MEMORY_KB(name, sample)
|
//#define SK_HISTOGRAM_MEMORY_KB(name, sample)
|
||||||
|
//#define SK_HISTOGRAM_CUSTOM_COUNTS(name, sample, countMin, countMax, bucketCount)
|
||||||
//#define SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sampleUSec, minUSec, maxUSec, bucketCount)
|
//#define SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sampleUSec, minUSec, maxUSec, bucketCount)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skia can provide extensive logging of Graphite Pipeline lifetimes.
|
||||||
|
*/
|
||||||
|
//#define SK_PIPELINE_LIFETIME_LOGGING
|
||||||
|
|
||||||
// To use smaller but slower mipmap builder
|
// To use smaller but slower mipmap builder
|
||||||
//#define SK_USE_DRAWING_MIPMAP_DOWNSAMPLER
|
//#define SK_USE_DRAWING_MIPMAP_DOWNSAMPLER
|
||||||
|
|
||||||
@@ -141,6 +143,8 @@
|
|||||||
|
|
||||||
#define SK_USE_FREETYPE_EMBOLDEN
|
#define SK_USE_FREETYPE_EMBOLDEN
|
||||||
|
|
||||||
|
#define SK_DISABLE_DIRECTWRITE_COLRv1 1
|
||||||
|
|
||||||
#ifndef MOZ_IMPLICIT
|
#ifndef MOZ_IMPLICIT
|
||||||
# ifdef MOZ_CLANG_PLUGIN
|
# ifdef MOZ_CLANG_PLUGIN
|
||||||
# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
|
# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
|
||||||
@@ -151,6 +155,4 @@
|
|||||||
|
|
||||||
#define SK_DISABLE_LEGACY_IMAGE_READBUFFER
|
#define SK_DISABLE_LEGACY_IMAGE_READBUFFER
|
||||||
|
|
||||||
#define SK_DISABLE_DIRECTWRITE_COLRv1 1
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "include/private/base/SkDeque.h"
|
#include "include/private/base/SkDeque.h"
|
||||||
#include "include/private/base/SkTArray.h"
|
#include "include/private/base/SkTArray.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -53,6 +54,7 @@ class GrRecordingContext;
|
|||||||
|
|
||||||
class SkBitmap;
|
class SkBitmap;
|
||||||
class SkBlender;
|
class SkBlender;
|
||||||
|
class SkBlurMaskFilterImpl;
|
||||||
class SkColorSpace;
|
class SkColorSpace;
|
||||||
class SkData;
|
class SkData;
|
||||||
class SkDevice;
|
class SkDevice;
|
||||||
@@ -2502,15 +2504,18 @@ private:
|
|||||||
void reset(SkDevice* device);
|
void reset(SkDevice* device);
|
||||||
};
|
};
|
||||||
|
|
||||||
// the first N recs that can fit here mean we won't call malloc
|
#if defined(SK_CANVAS_SAVE_RESTORE_PREALLOC_COUNT)
|
||||||
static constexpr int kMCRecSize = 96; // most recent measurement
|
static constexpr int kMCRecCount = SK_CANVAS_SAVE_RESTORE_PREALLOC_COUNT;
|
||||||
|
#else
|
||||||
static constexpr int kMCRecCount = 32; // common depth for save/restores
|
static constexpr int kMCRecCount = 32; // common depth for save/restores
|
||||||
|
#endif
|
||||||
|
|
||||||
intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)];
|
// This stack allocation of memory will be used to house the first kMCRecCount
|
||||||
|
// layers without need to call malloc.
|
||||||
|
alignas(MCRec) std::byte fMCRecStorage[sizeof(MCRec) * kMCRecCount];
|
||||||
|
|
||||||
SkDeque fMCStack;
|
SkDeque fMCStack; // uses the stack memory
|
||||||
// points to top of stack
|
MCRec* fMCRec; // points to top of stack for convenience
|
||||||
MCRec* fMCRec;
|
|
||||||
|
|
||||||
// Installed via init()
|
// Installed via init()
|
||||||
sk_sp<SkDevice> fRootDevice;
|
sk_sp<SkDevice> fRootDevice;
|
||||||
@@ -2675,11 +2680,14 @@ private:
|
|||||||
// into the canvas' global space.
|
// into the canvas' global space.
|
||||||
SkRect computeDeviceClipBounds(bool outsetForAA=true) const;
|
SkRect computeDeviceClipBounds(bool outsetForAA=true) const;
|
||||||
|
|
||||||
// Attempt to draw a rrect with an analytic blur. If the paint does not contain a blur, or the
|
// Returns the paint's mask filter if it can be used to draw an rrect with an analytic blur, and
|
||||||
// geometry can't be drawn with an analytic blur by the device, a layer is returned for a
|
// returns null otherwise.
|
||||||
// regular draw. If the draw succeeds or predrawNotify fails, nullopt is returned indicating
|
const SkBlurMaskFilterImpl* canAttemptBlurredRRectDraw(const SkPaint&) const;
|
||||||
// that nothing further should be drawn.
|
|
||||||
|
// Attempt to draw a rrect with an analytic blur. If the draw succeeds or predrawNotify fails,
|
||||||
|
// nullopt is returned indicating that nothing further should be drawn.
|
||||||
std::optional<AutoLayerForImageFilter> attemptBlurredRRectDraw(const SkRRect&,
|
std::optional<AutoLayerForImageFilter> attemptBlurredRRectDraw(const SkRRect&,
|
||||||
|
const SkBlurMaskFilterImpl*,
|
||||||
const SkPaint&,
|
const SkPaint&,
|
||||||
SkEnumBitMask<PredrawFlags>);
|
SkEnumBitMask<PredrawFlags>);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "include/core/SkScalar.h"
|
#include "include/core/SkScalar.h"
|
||||||
#include "include/core/SkTypes.h"
|
#include "include/core/SkTypes.h"
|
||||||
#include "include/private/base/SkCPUTypes.h"
|
#include "include/private/base/SkCPUTypes.h"
|
||||||
|
#include "include/private/base/SkTPin.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -415,6 +416,15 @@ struct SkRGBA4f {
|
|||||||
SkRGBA4f makeOpaque() const {
|
SkRGBA4f makeOpaque() const {
|
||||||
return { fR, fG, fB, 1.0f };
|
return { fR, fG, fB, 1.0f };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a copy of the SkRGBA4f but with the alpha component pinned to [0, 1].
|
||||||
|
|
||||||
|
@return color with pinned alpha
|
||||||
|
*/
|
||||||
|
SkRGBA4f pinAlpha() const {
|
||||||
|
return { fR, fG, fB, SkTPin(fA, 0.f, 1.f) };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \struct SkColor4f
|
/** \struct SkColor4f
|
||||||
|
|||||||
@@ -39,6 +39,85 @@ struct SK_API SkColorSpacePrimaries {
|
|||||||
bool toXYZD50(skcms_Matrix3x3* toXYZD50) const;
|
bool toXYZD50(skcms_Matrix3x3* toXYZD50) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace SkNamedPrimaries {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Color primaries defined by ITU-T H.273, table 2. Names are given by the first
|
||||||
|
// specification referenced in the value's row.
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.709-6, value 1.
|
||||||
|
static constexpr SkColorSpacePrimaries kRec709 = {
|
||||||
|
0.64f, 0.33f, 0.3f, 0.6f, 0.15f, 0.06f, 0.3127f, 0.329f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.470-6 System M (historical), value 4.
|
||||||
|
static constexpr SkColorSpacePrimaries kRec470SystemM = {
|
||||||
|
0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f, 0.31f, 0.316f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.470-6 System B, G (historical), value 5.
|
||||||
|
static constexpr SkColorSpacePrimaries kRec470SystemBG = {
|
||||||
|
0.64f, 0.33f, 0.29f, 0.60f, 0.15f, 0.06f, 0.3127f, 0.3290f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.601-7 525, value 6.
|
||||||
|
static constexpr SkColorSpacePrimaries kRec601 = {
|
||||||
|
0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f, 0.3127f, 0.3290f};
|
||||||
|
|
||||||
|
// SMPTE ST 240, value 7 (functionally the same as value 6).
|
||||||
|
static constexpr SkColorSpacePrimaries kSMPTE_ST_240 = kRec601;
|
||||||
|
|
||||||
|
// Generic film (colour filters using Illuminant C), value 8.
|
||||||
|
static constexpr SkColorSpacePrimaries kGenericFilm = {
|
||||||
|
0.681f, 0.319f, 0.243f, 0.692f, 0.145f, 0.049f, 0.310f, 0.316f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.2020-2, value 9.
|
||||||
|
static constexpr SkColorSpacePrimaries kRec2020{
|
||||||
|
0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f, 0.3127f, 0.3290f};
|
||||||
|
|
||||||
|
// SMPTE ST 428-1, value 10.
|
||||||
|
static constexpr SkColorSpacePrimaries kSMPTE_ST_428_1 = {
|
||||||
|
1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f / 3.f, 1.f / 3.f};
|
||||||
|
|
||||||
|
// SMPTE RP 431-2, value 11.
|
||||||
|
static constexpr SkColorSpacePrimaries kSMPTE_RP_431_2 = {
|
||||||
|
0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, 0.314f, 0.351f};
|
||||||
|
|
||||||
|
// SMPTE EG 432-1, value 12.
|
||||||
|
static constexpr SkColorSpacePrimaries kSMPTE_EG_432_1 = {
|
||||||
|
0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, 0.3127f, 0.3290f};
|
||||||
|
|
||||||
|
// No corresponding industry specification identified, value 22.
|
||||||
|
// This is sometimes referred to as EBU 3213-E, but that document doesn't
|
||||||
|
// specify these values.
|
||||||
|
static constexpr SkColorSpacePrimaries kITU_T_H273_Value22 = {
|
||||||
|
0.630f, 0.340f, 0.295f, 0.605f, 0.155f, 0.077f, 0.3127f, 0.3290f};
|
||||||
|
|
||||||
|
// Mapping between names of color primaries and the number of the corresponding
|
||||||
|
// row in ITU-T H.273, table 2. As above, the constants are named based on the
|
||||||
|
// first specification referenced in the value's row.
|
||||||
|
enum class CicpId : uint8_t {
|
||||||
|
// Value 0 is reserved.
|
||||||
|
kRec709 = 1,
|
||||||
|
// Value 2 is unspecified.
|
||||||
|
// Value 3 is reserved.
|
||||||
|
kRec470SystemM = 4,
|
||||||
|
kRec470SystemBG = 5,
|
||||||
|
kRec601 = 6,
|
||||||
|
kSMPTE_ST_240 = 7,
|
||||||
|
kGenericFilm = 8,
|
||||||
|
kRec2020 = 9,
|
||||||
|
kSMPTE_ST_428_1 = 10,
|
||||||
|
kSMPTE_RP_431_2 = 11,
|
||||||
|
kSMPTE_EG_432_1 = 12,
|
||||||
|
// Values 13-21 are reserved.
|
||||||
|
kITU_T_H273_Value22 = 22,
|
||||||
|
// Values 23-255 are reserved.
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/css-color-4/#predefined-prophoto-rgb
|
||||||
|
static constexpr SkColorSpacePrimaries kProPhotoRGB = {
|
||||||
|
0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f, 0.34567f, 0.35850f};
|
||||||
|
|
||||||
|
} // namespace SkNamedPrimaries
|
||||||
|
|
||||||
namespace SkNamedTransferFn {
|
namespace SkNamedTransferFn {
|
||||||
|
|
||||||
// Like SkNamedGamut::kSRGB, keeping this bitwise exactly the same as skcms makes things fastest.
|
// Like SkNamedGamut::kSRGB, keeping this bitwise exactly the same as skcms makes things fastest.
|
||||||
@@ -48,18 +127,98 @@ static constexpr skcms_TransferFunction kSRGB =
|
|||||||
static constexpr skcms_TransferFunction k2Dot2 =
|
static constexpr skcms_TransferFunction k2Dot2 =
|
||||||
{ 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
{ 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
static constexpr skcms_TransferFunction kRec2020 = {
|
||||||
|
2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Color primaries defined by ITU-T H.273, table 3. Names are given by the first
|
||||||
|
// specification referenced in the value's row.
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.709-6, value 1.
|
||||||
|
static constexpr skcms_TransferFunction kRec709 = {2.222222222222f,
|
||||||
|
0.909672415686f,
|
||||||
|
0.090327584314f,
|
||||||
|
0.222222222222f,
|
||||||
|
0.081242858299f,
|
||||||
|
0.f,
|
||||||
|
0.f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.470-6 System M (historical) assumed display gamma 2.2, value 4.
|
||||||
|
static constexpr skcms_TransferFunction kRec470SystemM = {2.2f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.470-6 System B, G (historical) assumed display gamma 2.8,
|
||||||
|
// value 5.
|
||||||
|
static constexpr skcms_TransferFunction kRec470SystemBG = {2.8f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.601-7, same as kRec709, value 6.
|
||||||
|
static constexpr skcms_TransferFunction kRec601 = kRec709;
|
||||||
|
|
||||||
|
// SMPTE ST 240, value 7.
|
||||||
|
static constexpr skcms_TransferFunction kSMPTE_ST_240 = {
|
||||||
|
2.222222222222f, 0.899626676224f, 0.100373323776f, 0.25f, 0.091286342118f, 0.f, 0.f};
|
||||||
|
|
||||||
|
// Linear, value 8
|
||||||
static constexpr skcms_TransferFunction kLinear =
|
static constexpr skcms_TransferFunction kLinear =
|
||||||
{ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
{ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
static constexpr skcms_TransferFunction kRec2020 =
|
// IEC 61966-2-4, value 11, same as kRec709 (but is explicitly extended).
|
||||||
{2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0};
|
static constexpr skcms_TransferFunction kIEC61966_2_4 = kRec709;
|
||||||
|
|
||||||
|
// IEC 61966-2-1 sRGB, value 13.
|
||||||
|
static constexpr skcms_TransferFunction kIEC61966_2_1 = kSRGB;
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.2020-2 (10-bit system), value 14.
|
||||||
|
static constexpr skcms_TransferFunction kRec2020_10bit = kRec709;
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.2020-2 (12-bit system), value 15.
|
||||||
|
static constexpr skcms_TransferFunction kRec2020_12bit = kRec709;
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system, value 16.
|
||||||
static constexpr skcms_TransferFunction kPQ =
|
static constexpr skcms_TransferFunction kPQ =
|
||||||
{-2.0f, -107/128.0f, 1.0f, 32/2523.0f, 2413/128.0f, -2392/128.0f, 8192/1305.0f };
|
{-2.0f, -107/128.0f, 1.0f, 32/2523.0f, 2413/128.0f, -2392/128.0f, 8192/1305.0f };
|
||||||
|
|
||||||
|
// SMPTE ST 428-1, value 17.
|
||||||
|
static constexpr skcms_TransferFunction kSMPTE_ST_428_1 = {
|
||||||
|
2.6f, 1.034080527699f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
||||||
|
|
||||||
|
// Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system, value 18.
|
||||||
static constexpr skcms_TransferFunction kHLG =
|
static constexpr skcms_TransferFunction kHLG =
|
||||||
{-3.0f, 2.0f, 2.0f, 1/0.17883277f, 0.28466892f, 0.55991073f, 0.0f };
|
{-3.0f, 2.0f, 2.0f, 1/0.17883277f, 0.28466892f, 0.55991073f, 0.0f };
|
||||||
|
|
||||||
|
// Mapping between transfer function names and the number of the corresponding
|
||||||
|
// row in ITU-T H.273, table 3. As above, the constants are named based on the
|
||||||
|
// first specification referenced in the value's row.
|
||||||
|
enum class CicpId : uint8_t {
|
||||||
|
// Value 0 is reserved.
|
||||||
|
kRec709 = 1,
|
||||||
|
// Value 2 is unspecified.
|
||||||
|
// Value 3 is reserved.
|
||||||
|
kRec470SystemM = 4,
|
||||||
|
kRec470SystemBG = 5,
|
||||||
|
kRec601 = 6,
|
||||||
|
kSMPTE_ST_240 = 7,
|
||||||
|
kLinear = 8,
|
||||||
|
// Value 9 is not supported by `SkColorSpace::MakeCICP`.
|
||||||
|
// Value 10 is not supported by `SkColorSpace::MakeCICP`.
|
||||||
|
kIEC61966_2_4 = 11,
|
||||||
|
// Value 12 is not supported by `SkColorSpace::MakeCICP`.
|
||||||
|
kIEC61966_2_1 = 13,
|
||||||
|
kSRGB = kIEC61966_2_1,
|
||||||
|
kRec2020_10bit = 14,
|
||||||
|
kRec2020_12bit = 15,
|
||||||
|
kPQ = 16,
|
||||||
|
kSMPTE_ST_428_1 = 17,
|
||||||
|
kHLG = 18,
|
||||||
|
// Values 19-255 are reserved.
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3.org/TR/css-color-4/#valdef-color-prophoto-rgb
|
||||||
|
// "The transfer curve is a gamma function with a value of 1/1.8"
|
||||||
|
static constexpr skcms_TransferFunction kProPhotoRGB = {1.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/css-color-4/#predefined-a98-rgb
|
||||||
|
static constexpr skcms_TransferFunction kA98RGB = k2Dot2;
|
||||||
|
|
||||||
} // namespace SkNamedTransferFn
|
} // namespace SkNamedTransferFn
|
||||||
|
|
||||||
namespace SkNamedGamut {
|
namespace SkNamedGamut {
|
||||||
@@ -122,6 +281,29 @@ public:
|
|||||||
static sk_sp<SkColorSpace> MakeRGB(const skcms_TransferFunction& transferFn,
|
static sk_sp<SkColorSpace> MakeRGB(const skcms_TransferFunction& transferFn,
|
||||||
const skcms_Matrix3x3& toXYZ);
|
const skcms_Matrix3x3& toXYZ);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an SkColorSpace from code points specified in Rec. ITU-T H.273.
|
||||||
|
* Null will be returned for invalid or unsupported combination of code
|
||||||
|
* points.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
*
|
||||||
|
* - `color_primaries` identifies an entry in Rec. ITU-T H.273, Table 2.
|
||||||
|
* - `transfer_characteristics` identifies an entry in Rec. ITU-T H.273, Table 3.
|
||||||
|
*
|
||||||
|
* `SkColorSpace` (and the underlying `skcms_ICCProfile`) only supports RGB
|
||||||
|
* color spaces and therefore this function does not take a
|
||||||
|
* `matrix_coefficients` parameter - the caller is expected to verify that
|
||||||
|
* `matrix_coefficients` is `0`.
|
||||||
|
*
|
||||||
|
* Narrow range images are extremely rare - see
|
||||||
|
* https://github.com/w3c/png/issues/312#issuecomment-2327349614. Therefore
|
||||||
|
* this function doesn't take a `video_full_range_flag` - the caller is
|
||||||
|
* expected to verify that it is `1` (indicating a full range image).
|
||||||
|
*/
|
||||||
|
static sk_sp<SkColorSpace> MakeCICP(SkNamedPrimaries::CicpId color_primaries,
|
||||||
|
SkNamedTransferFn::CicpId transfer_characteristics);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an SkColorSpace from a parsed (skcms) ICC profile.
|
* Create an SkColorSpace from a parsed (skcms) ICC profile.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,43 +15,125 @@
|
|||||||
|
|
||||||
kN32_SkColorType selects the native 32-bit ARGB format for the current configuration. This can
|
kN32_SkColorType selects the native 32-bit ARGB format for the current configuration. This can
|
||||||
lead to inconsistent results across platforms, so use with caution.
|
lead to inconsistent results across platforms, so use with caution.
|
||||||
|
|
||||||
|
By default, Skia operates with the assumption of a little-Endian system. The names of each
|
||||||
|
SkColorType implicitly define the channel ordering and size in memory. Due to historical reasons
|
||||||
|
the names do not follow 100% identical convention, but are typically labeled from least
|
||||||
|
significant to most significant. To help clarify when the actual data layout differs from the
|
||||||
|
default convention, every SkColorType's comment includes a bit-labeled description of a pixel
|
||||||
|
in that color type on a LE system.
|
||||||
|
|
||||||
|
Unless specified otherwise, a channel's value is treated as an unsigned integer with a range of
|
||||||
|
of [0, 2^N-1] and this is mapped uniformly to a floating point value of [0.0, 1.0]. Some color
|
||||||
|
types instead store data directly in 32-bit floating point (assumed to be IEEE), or in 16-bit
|
||||||
|
"half" floating point values. A half float, or F16/float16, is interpreted as FP 1-5-10 or
|
||||||
|
Bits: [sign:15 exp:14..10 man:9..0]
|
||||||
*/
|
*/
|
||||||
enum SkColorType : int {
|
enum SkColorType : int {
|
||||||
kUnknown_SkColorType, //!< uninitialized
|
// Unknown or unrepresentable as an SkColorType.
|
||||||
kAlpha_8_SkColorType, //!< pixel with alpha in 8-bit byte
|
kUnknown_SkColorType,
|
||||||
kRGB_565_SkColorType, //!< pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
|
// Single channel data (8-bit) interpreted as an alpha value. RGB are 0.
|
||||||
kARGB_4444_SkColorType, //!< pixel with 4 bits for alpha, red, green, blue; in 16-bit word
|
// Bits: [A:7..0]
|
||||||
kRGBA_8888_SkColorType, //!< pixel with 8 bits for red, green, blue, alpha; in 32-bit word
|
kAlpha_8_SkColorType,
|
||||||
kRGB_888x_SkColorType, //!< pixel with 8 bits each for red, green, blue; in 32-bit word
|
// Three channel BGR data (5 bits red, 6 bits green, 5 bits blue) packed into a LE 16-bit word.
|
||||||
kBGRA_8888_SkColorType, //!< pixel with 8 bits for blue, green, red, alpha; in 32-bit word
|
// NOTE: The name of this enum value does not match the standard convention for SkColorType.
|
||||||
kRGBA_1010102_SkColorType, //!< 10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
|
// Bits: [R:15..11 G:10..5 B:4..0]
|
||||||
kBGRA_1010102_SkColorType, //!< 10 bits for blue, green, red; 2 bits for alpha; in 32-bit word
|
kRGB_565_SkColorType,
|
||||||
kRGB_101010x_SkColorType, //!< pixel with 10 bits each for red, green, blue; in 32-bit word
|
// Four channel ABGR data (4 bits per channel) packed into a LE 16-bit word.
|
||||||
kBGR_101010x_SkColorType, //!< pixel with 10 bits each for blue, green, red; in 32-bit word
|
// NOTE: The name of this enum value does not match the standard convention for SkColorType.
|
||||||
kBGR_101010x_XR_SkColorType, //!< pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
|
// Bits: [R:15..12 G:11..8 B:7..4 A:3..0]
|
||||||
kBGRA_10101010_XR_SkColorType, //!< pixel with 10 bits each for blue, green, red, alpha; in 64-bit word, extended range
|
kARGB_4444_SkColorType,
|
||||||
kRGBA_10x6_SkColorType, //!< pixel with 10 used bits (most significant) followed by 6 unused
|
// Four channel RGBA data (8 bits per channel) packed into a LE 32-bit word.
|
||||||
// bits for red, green, blue, alpha; in 64-bit word
|
// Bits: [A:31..24 B:23..16 G:15..8 R:7..0]
|
||||||
kGray_8_SkColorType, //!< pixel with grayscale level in 8-bit byte
|
kRGBA_8888_SkColorType,
|
||||||
kRGBA_F16Norm_SkColorType, //!< pixel with half floats in [0,1] for red, green, blue, alpha;
|
// Three channel RGB data (8 bits per channel) packed into a LE 32-bit word. The remaining bits
|
||||||
// in 64-bit word
|
// are ignored and alpha is forced to opaque.
|
||||||
kRGBA_F16_SkColorType, //!< pixel with half floats for red, green, blue, alpha;
|
// Bits: [x:31..24 B:23..16 G:15..8 R:7..0]
|
||||||
// in 64-bit word
|
kRGB_888x_SkColorType,
|
||||||
kRGB_F16F16F16x_SkColorType, //!< pixel with half floats for red, green, blue; in 64-bit word
|
// Four channel BGRA data (8 bits per channel) packed into a LE 32-bit word. R and B are swapped
|
||||||
kRGBA_F32_SkColorType, //!< pixel using C float for red, green, blue, alpha; in 128-bit word
|
// relative to kRGBA_8888.
|
||||||
|
// Bits: [A:31..24 R:23..16 G:15..8 B:7..0]
|
||||||
|
kBGRA_8888_SkColorType,
|
||||||
|
// Four channel RGBA data (10 bits per color, 2 bits for alpha) packed into a LE 32-bit word.
|
||||||
|
// Bits: [A:31..30 B:29..20 G:19..10 R:9..0]
|
||||||
|
kRGBA_1010102_SkColorType,
|
||||||
|
// Four channel BGRA data (10 bits per color, 2 bits for alpha) packed into a LE 32-bit word.
|
||||||
|
// R and B are swapped relative to kRGBA_1010102.
|
||||||
|
// Bits: [A:31..30 R:29..20 G:19..10 B:9..0]
|
||||||
|
kBGRA_1010102_SkColorType,
|
||||||
|
// Three channel RGB data (10 bits per channel) packed into a LE 32-bit word. The remaining bits
|
||||||
|
// are ignored and alpha is forced to opaque.
|
||||||
|
// Bits: [x:31..30 B:29..20 G:19..10 R:9..0]
|
||||||
|
kRGB_101010x_SkColorType,
|
||||||
|
// Three channel BGR data (10 bits per channel) packed into a LE 32-bit word. The remaining bits
|
||||||
|
// are ignored and alpha is forced to opaque. R and B are swapped relative to kRGB_101010x.
|
||||||
|
// Bits: [x:31..30 R:29..20 G:19..10 B:9..0]
|
||||||
|
kBGR_101010x_SkColorType,
|
||||||
|
// Three channel BGR data (10 bits per channel) packed into a LE 32-bit word. The remaining bits
|
||||||
|
// are ignored and alpha is forced to opaque. Instead of normalizing [0, 1023] to [0.0, 1.0] the
|
||||||
|
// color channels map to an extended range of [-0.752941, 1.25098], compatible with
|
||||||
|
// MTLPixelFormatBGR10_XR.
|
||||||
|
// Bits: [x:31..30 R:29..20 G:19..10 B:9..0]
|
||||||
|
kBGR_101010x_XR_SkColorType,
|
||||||
|
// Four channel BGRA data (10 bits per channel) packed into a LE 64-bit word. Each channel is
|
||||||
|
// preceded by 6 bits of padding. Instead of normalizing [0, 1023] to [0.0, 1.0] the color and
|
||||||
|
// alpha channels map to an extended range of [-0.752941, 1.25098], compatible with
|
||||||
|
// MTLPixelFormatBGRA10_XR.
|
||||||
|
// Bits: [A:63..54 x:53..48 R:47..38 x:37..32 G:31..22 x:21..16 B:15..6 x:5..0]
|
||||||
|
kBGRA_10101010_XR_SkColorType,
|
||||||
|
// Four channel RGBA data (10 bits per channel) packed into a LE 64-bit word. Each channel is
|
||||||
|
// preceded by 6 bits of padding.
|
||||||
|
// Bits: [A:63..54 x:53..48 B:47..38 x:37..32 G:31..22 x:21..16 R:15..6 x:5..0]
|
||||||
|
kRGBA_10x6_SkColorType,
|
||||||
|
// Single channel data (8-bit) interpreted as a grayscale value (e.g. replicated to RGB).
|
||||||
|
// Bits: [G:7..0]
|
||||||
|
kGray_8_SkColorType,
|
||||||
|
// Four channel RGBA data (16-bit half-float per channel) packed into a LE 64-bit word. Values
|
||||||
|
// are assumed to be in [0.0,1.0] range, unlike kRGBA_F16.
|
||||||
|
// Bits: [A:63..48 B:47..32 G:31..16 R:15..0]
|
||||||
|
kRGBA_F16Norm_SkColorType,
|
||||||
|
// Four channel RGBA data (16-bit half-float per channel) packed into a LE 64-bit word.
|
||||||
|
// This has extended range compared to kRGBA_F16Norm.
|
||||||
|
// Bits: [A:63..48 B:47..32 G:31..16 R:15..0]
|
||||||
|
kRGBA_F16_SkColorType,
|
||||||
|
// Three channel RGB data (16-bit half-float per channel) packed into a LE 64-bit word. The last
|
||||||
|
// 16 bits are ignored and alpha is forced to opaque.
|
||||||
|
// Bits: [x:63..48 B:47..32 G:31..16 R:15..0]
|
||||||
|
kRGB_F16F16F16x_SkColorType,
|
||||||
|
// Four channel RGBA data (32-bit float per channel) packed into a LE 128-bit word.
|
||||||
|
// Bits: [A:127..96 B:95..64 G:63..32 R:31..0]
|
||||||
|
kRGBA_F32_SkColorType,
|
||||||
|
|
||||||
// The following 6 colortypes are just for reading from - not for rendering to
|
// The following 8 colortypes are just for reading from - not for rendering to
|
||||||
kR8G8_unorm_SkColorType, //!< pixel with a uint8_t for red and green
|
|
||||||
|
|
||||||
kA16_float_SkColorType, //!< pixel with a half float for alpha
|
|
||||||
kR16G16_float_SkColorType, //!< pixel with a half float for red and green
|
|
||||||
|
|
||||||
kA16_unorm_SkColorType, //!< pixel with a little endian uint16_t for alpha
|
|
||||||
kR16G16_unorm_SkColorType, //!< pixel with a little endian uint16_t for red and green
|
|
||||||
kR16G16B16A16_unorm_SkColorType, //!< pixel with a little endian uint16_t for red, green, blue
|
|
||||||
// and alpha
|
|
||||||
|
|
||||||
|
// Two channel RG data (8 bits per channel). Blue is forced to 0, alpha is forced to opaque.
|
||||||
|
// Bits: [G:15..8 R:7..0]
|
||||||
|
kR8G8_unorm_SkColorType,
|
||||||
|
// Single channel data (16-bit half-float) interpreted as alpha. RGB are 0.
|
||||||
|
// Bits: [A:15..0]
|
||||||
|
kA16_float_SkColorType,
|
||||||
|
// Two channel RG data (16-bit half-float per channel) packed into a LE 32-bit word.
|
||||||
|
// Blue is forced to 0, alpha is forced to opaque.
|
||||||
|
// Bits: [G:31..16 R:15..0]
|
||||||
|
kR16G16_float_SkColorType,
|
||||||
|
// Single channel data (16 bits) interpreted as alpha. RGB are 0.
|
||||||
|
// Bits: [A:15..0]
|
||||||
|
kA16_unorm_SkColorType,
|
||||||
|
// Two channel RG data (16 bits per channel) packed into a LE 32-bit word. B is forced to 0,
|
||||||
|
// alpha is forced to opaque.
|
||||||
|
// Bits: [G:31..16 R:15..0]
|
||||||
|
kR16G16_unorm_SkColorType,
|
||||||
|
// Four channel RGBA data (16 bits per channel) packed into a LE 64-bit word.
|
||||||
|
// Bits: [A:63..48 B:47..32 G:31..16 R:15..0]
|
||||||
|
kR16G16B16A16_unorm_SkColorType,
|
||||||
|
// Four channel RGBA data (8 bits per channel) packed into a LE 32-bit word. The RGB values are
|
||||||
|
// assumed to be encoded with the sRGB transfer function, which can be decoded automatically
|
||||||
|
// by GPU hardware with certain texture formats.
|
||||||
|
// Bits: [A:31..24 B:23..16 G:15..8 R:7..0]
|
||||||
kSRGBA_8888_SkColorType,
|
kSRGBA_8888_SkColorType,
|
||||||
|
// Single channel data (8 bits) interpreted as red. G and B are forced to 0, alpha is forced to
|
||||||
|
// opaque.
|
||||||
|
// Bits: [R:7..0]
|
||||||
kR8_unorm_SkColorType,
|
kR8_unorm_SkColorType,
|
||||||
|
|
||||||
kLastEnum_SkColorType = kR8_unorm_SkColorType, //!< last valid value
|
kLastEnum_SkColorType = kR8_unorm_SkColorType, //!< last valid value
|
||||||
|
|||||||
@@ -91,13 +91,13 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const ForwardVerbIterator& other) {
|
bool operator==(const ForwardVerbIterator& other) const {
|
||||||
SkASSERT(fSegments.data() != other.fSegments.data() ||
|
SkASSERT(fSegments.data() != other.fSegments.data() ||
|
||||||
fSegments.size() == other.fSegments.size());
|
fSegments.size() == other.fSegments.size());
|
||||||
return fSegments.data() == other.fSegments.data();
|
return fSegments.data() == other.fSegments.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const ForwardVerbIterator& other) {
|
bool operator!=(const ForwardVerbIterator& other) const {
|
||||||
return !((*this) == other);
|
return !((*this) == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define SKFONTSCANNER_H_
|
#define SKFONTSCANNER_H_
|
||||||
|
|
||||||
#include "include/core/SkFontArguments.h"
|
#include "include/core/SkFontArguments.h"
|
||||||
|
#include "include/core/SkFontParameters.h"
|
||||||
#include "include/core/SkRefCnt.h"
|
#include "include/core/SkRefCnt.h"
|
||||||
#include "include/core/SkTypes.h"
|
#include "include/core/SkTypes.h"
|
||||||
#include "include/private/base/SkFixed.h"
|
#include "include/private/base/SkFixed.h"
|
||||||
@@ -22,13 +23,8 @@ class SkTypeface;
|
|||||||
class SkFontScanner : public SkNoncopyable {
|
class SkFontScanner : public SkNoncopyable {
|
||||||
public:
|
public:
|
||||||
virtual ~SkFontScanner() = default;
|
virtual ~SkFontScanner() = default;
|
||||||
struct AxisDefinition {
|
using AxisDefinitions = skia_private::STArray<4, SkFontParameters::Variation::Axis, true>;
|
||||||
SkFourByteTag fTag;
|
using VariationPosition = skia_private::STArray<4, SkFontArguments::VariationPosition::Coordinate, true>;
|
||||||
SkScalar fMinimum;
|
|
||||||
SkScalar fDefault;
|
|
||||||
SkScalar fMaximum;
|
|
||||||
};
|
|
||||||
typedef skia_private::STArray<4, AxisDefinition, true> AxisDefinitions;
|
|
||||||
|
|
||||||
virtual bool scanFile(SkStreamAsset* stream, int* numFaces) const = 0;
|
virtual bool scanFile(SkStreamAsset* stream, int* numFaces) const = 0;
|
||||||
virtual bool scanFace(SkStreamAsset* stream, int faceIndex, int* numInstances) const = 0;
|
virtual bool scanFace(SkStreamAsset* stream, int faceIndex, int* numInstances) const = 0;
|
||||||
@@ -39,7 +35,8 @@ public:
|
|||||||
SkString* name,
|
SkString* name,
|
||||||
SkFontStyle* style,
|
SkFontStyle* style,
|
||||||
bool* isFixedPitch,
|
bool* isFixedPitch,
|
||||||
AxisDefinitions* axes) const = 0;
|
AxisDefinitions* axes,
|
||||||
|
VariationPosition* position) const = 0;
|
||||||
virtual sk_sp<SkTypeface> MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
|
virtual sk_sp<SkTypeface> MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
|
||||||
const SkFontArguments& args) const = 0;
|
const SkFontArguments& args) const = 0;
|
||||||
virtual SkFourByteTag getFactoryId() const = 0;
|
virtual SkFourByteTag getFactoryId() const = 0;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public:
|
|||||||
kUltraExpanded_Width = 9,
|
kUltraExpanded_Width = 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Slant {
|
enum Slant : uint8_t {
|
||||||
kUpright_Slant,
|
kUpright_Slant,
|
||||||
kItalic_Slant,
|
kItalic_Slant,
|
||||||
kOblique_Slant,
|
kOblique_Slant,
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
enum SkBlurStyle : int;
|
enum SkBlurStyle : int;
|
||||||
struct SkDeserialProcs;
|
struct SkDeserialProcs;
|
||||||
struct SkRect;
|
|
||||||
|
|
||||||
/** \class SkMaskFilter
|
/** \class SkMaskFilter
|
||||||
|
|
||||||
@@ -35,13 +34,6 @@ public:
|
|||||||
static sk_sp<SkMaskFilter> MakeBlur(SkBlurStyle style, SkScalar sigma,
|
static sk_sp<SkMaskFilter> MakeBlur(SkBlurStyle style, SkScalar sigma,
|
||||||
bool respectCTM = true);
|
bool respectCTM = true);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the approximate bounds that would result from filtering the src rect.
|
|
||||||
* The actual result may be different, but it should be contained within the
|
|
||||||
* returned bounds.
|
|
||||||
*/
|
|
||||||
SkRect approximateFilteredBounds(const SkRect& src) const;
|
|
||||||
|
|
||||||
static sk_sp<SkMaskFilter> Deserialize(const void* data, size_t size,
|
static sk_sp<SkMaskFilter> Deserialize(const void* data, size_t size,
|
||||||
const SkDeserialProcs* procs = nullptr);
|
const SkDeserialProcs* procs = nullptr);
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
#ifndef SK_MILESTONE
|
#ifndef SK_MILESTONE
|
||||||
#define SK_MILESTONE 132
|
#define SK_MILESTONE 136
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -317,15 +317,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
SkScalar getStrokeMiter() const { return fMiterLimit; }
|
SkScalar getStrokeMiter() const { return fMiterLimit; }
|
||||||
|
|
||||||
/** Sets the limit at which a sharp corner is drawn beveled.
|
/** When stroking a small joinAngle with miter, the miterLength may be very long.
|
||||||
Valid values are zero and greater.
|
When miterLength > maxMiterLength (or joinAngle < minJoinAngle) the join will become bevel.
|
||||||
Has no effect if miter is less than zero.
|
miterLimit = maxMiterLength / strokeWidth or miterLimit = 1 / sin(minJoinAngle / 2).
|
||||||
|
|
||||||
@param miter zero and greater miter limit
|
This call has no effect if the miterLimit passed is less than zero.
|
||||||
|
Values less than one will be treated as bevel.
|
||||||
|
|
||||||
|
@param miterLimit zero and greater miter limit
|
||||||
|
|
||||||
example: https://fiddle.skia.org/c/@Paint_setStrokeMiter
|
example: https://fiddle.skia.org/c/@Paint_setStrokeMiter
|
||||||
*/
|
*/
|
||||||
void setStrokeMiter(SkScalar miter);
|
void setStrokeMiter(SkScalar miterLimit);
|
||||||
|
|
||||||
/** \enum SkPaint::Cap
|
/** \enum SkPaint::Cap
|
||||||
Cap draws at the beginning and end of an open path contour.
|
Cap draws at the beginning and end of an open path contour.
|
||||||
|
|||||||
@@ -1909,7 +1909,7 @@ private:
|
|||||||
void shrinkToFit();
|
void shrinkToFit();
|
||||||
|
|
||||||
// Creates a new Path after the supplied arguments have been validated by
|
// Creates a new Path after the supplied arguments have been validated by
|
||||||
// sk_path_analyze_verbs().
|
// SkPathPriv::AnalyzeVerbs().
|
||||||
static SkPath MakeInternal(const SkPathVerbAnalysis& analsis,
|
static SkPath MakeInternal(const SkPathVerbAnalysis& analsis,
|
||||||
const SkPoint points[],
|
const SkPoint points[],
|
||||||
const uint8_t verbs[],
|
const uint8_t verbs[],
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "include/core/SkScalar.h"
|
#include "include/core/SkScalar.h"
|
||||||
#include "include/core/SkSpan.h"
|
#include "include/core/SkSpan.h"
|
||||||
#include "include/core/SkTypes.h"
|
#include "include/core/SkTypes.h"
|
||||||
|
#include "include/private/base/SkMacros.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -33,6 +34,7 @@ class SkString;
|
|||||||
If either axis radii is zero or less: radii are stored as zero; corner is square.
|
If either axis radii is zero or less: radii are stored as zero; corner is square.
|
||||||
If corner curves overlap, radii are proportionally reduced to fit within bounds.
|
If corner curves overlap, radii are proportionally reduced to fit within bounds.
|
||||||
*/
|
*/
|
||||||
|
SK_BEGIN_REQUIRE_DENSE
|
||||||
class SK_API SkRRect {
|
class SK_API SkRRect {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -511,11 +513,11 @@ private:
|
|||||||
SkVector fRadii[4] = {{0, 0}, {0, 0}, {0,0}, {0,0}};
|
SkVector fRadii[4] = {{0, 0}, {0, 0}, {0,0}, {0,0}};
|
||||||
// use an explicitly sized type so we're sure the class is dense (no uninitialized bytes)
|
// use an explicitly sized type so we're sure the class is dense (no uninitialized bytes)
|
||||||
int32_t fType = kEmpty_Type;
|
int32_t fType = kEmpty_Type;
|
||||||
// TODO: add padding so we can use memcpy for flattening and not copy uninitialized data
|
|
||||||
|
|
||||||
// to access fRadii directly
|
// to access fRadii directly
|
||||||
friend class SkPath;
|
friend class SkPath;
|
||||||
friend class SkRRectPriv;
|
friend class SkRRectPriv;
|
||||||
};
|
};
|
||||||
|
SK_END_REQUIRE_DENSE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ struct SkSamplingOptions;
|
|||||||
|
|
||||||
/** \class SkShader
|
/** \class SkShader
|
||||||
*
|
*
|
||||||
* Shaders specify the source color(s) for what is being drawn. If a paint
|
* Shaders specify the premultiplied source color(s) for what is being drawn.
|
||||||
* has no shader, then the paint's color is used. If the paint has a
|
* If a paint has no shader, then the paint's color is used. If the paint has a
|
||||||
* shader, then the shader's color(s) are use instead, but they are
|
* shader, then the shader's color(s) are used instead, but they are
|
||||||
* modulated by the paint's alpha. This makes it easy to create a shader
|
* modulated by the paint's alpha. This makes it easy to create a shader
|
||||||
* once (e.g. bitmap tiling or gradient) and then change its transparency
|
* once (e.g. bitmap tiling or gradient) and then change its transparency
|
||||||
* w/o having to modify the original shader... only the paint's alpha needs
|
* w/o having to modify the original shader... only the paint's alpha needs
|
||||||
|
|||||||
@@ -79,10 +79,12 @@ public:
|
|||||||
[[nodiscard]] bool readS8(int8_t*);
|
[[nodiscard]] bool readS8(int8_t*);
|
||||||
[[nodiscard]] bool readS16(int16_t*);
|
[[nodiscard]] bool readS16(int16_t*);
|
||||||
[[nodiscard]] bool readS32(int32_t*);
|
[[nodiscard]] bool readS32(int32_t*);
|
||||||
|
[[nodiscard]] bool readS64(int64_t*);
|
||||||
|
|
||||||
[[nodiscard]] bool readU8(uint8_t* i) { return this->readS8((int8_t*)i); }
|
[[nodiscard]] bool readU8(uint8_t* i) { return this->readS8((int8_t*)i); }
|
||||||
[[nodiscard]] bool readU16(uint16_t* i) { return this->readS16((int16_t*)i); }
|
[[nodiscard]] bool readU16(uint16_t* i) { return this->readS16((int16_t*)i); }
|
||||||
[[nodiscard]] bool readU32(uint32_t* i) { return this->readS32((int32_t*)i); }
|
[[nodiscard]] bool readU32(uint32_t* i) { return this->readS32((int32_t*)i); }
|
||||||
|
[[nodiscard]] bool readU64(uint64_t* i) { return this->readS64((int64_t*)i); }
|
||||||
|
|
||||||
[[nodiscard]] bool readBool(bool* b) {
|
[[nodiscard]] bool readBool(bool* b) {
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
@@ -240,8 +242,11 @@ public:
|
|||||||
uint16_t v = SkToU16(value);
|
uint16_t v = SkToU16(value);
|
||||||
return this->write(&v, 2);
|
return this->write(&v, 2);
|
||||||
}
|
}
|
||||||
bool write32(uint32_t v) {
|
bool write32(uint32_t value) {
|
||||||
return this->write(&v, 4);
|
return this->write(&value, 4);
|
||||||
|
}
|
||||||
|
bool write64(uint64_t value) {
|
||||||
|
return this->write(&value, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeText(const char text[]) {
|
bool writeText(const char text[]) {
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ static inline bool SkStrStartsWith(const char string[], const char prefixStr[])
|
|||||||
SkASSERT(prefixStr);
|
SkASSERT(prefixStr);
|
||||||
return !strncmp(string, prefixStr, strlen(prefixStr));
|
return !strncmp(string, prefixStr, strlen(prefixStr));
|
||||||
}
|
}
|
||||||
static inline bool SkStrStartsWith(const char string[], const char prefixChar) {
|
static inline bool SkStrStartsWith(const char string[], char prefixChar) {
|
||||||
SkASSERT(string);
|
SkASSERT(string);
|
||||||
return (prefixChar == *string);
|
return (prefixChar == *string);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkStrEndsWith(const char string[], const char suffixStr[]);
|
bool SkStrEndsWith(const char string[], const char suffixStr[]);
|
||||||
bool SkStrEndsWith(const char string[], const char suffixChar);
|
bool SkStrEndsWith(const char string[], char suffixChar);
|
||||||
|
|
||||||
int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
|
int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ static inline int SkStrFind(const char string[], const char substring[]) {
|
|||||||
return SkToInt(first - &string[0]);
|
return SkToInt(first - &string[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int SkStrFindLastOf(const char string[], const char subchar) {
|
static inline int SkStrFindLastOf(const char string[], char subchar) {
|
||||||
const char* last = strrchr(string, subchar);
|
const char* last = strrchr(string, subchar);
|
||||||
if (nullptr == last) return -1;
|
if (nullptr == last) return -1;
|
||||||
return SkToInt(last - &string[0]);
|
return SkToInt(last - &string[0]);
|
||||||
@@ -55,7 +55,7 @@ static inline bool SkStrContains(const char string[], const char substring[]) {
|
|||||||
SkASSERT(substring);
|
SkASSERT(substring);
|
||||||
return (-1 != SkStrFind(string, substring));
|
return (-1 != SkStrFind(string, substring));
|
||||||
}
|
}
|
||||||
static inline bool SkStrContains(const char string[], const char subchar) {
|
static inline bool SkStrContains(const char string[], char subchar) {
|
||||||
SkASSERT(string);
|
SkASSERT(string);
|
||||||
char tmp[2];
|
char tmp[2];
|
||||||
tmp[0] = subchar;
|
tmp[0] = subchar;
|
||||||
@@ -142,25 +142,25 @@ public:
|
|||||||
bool startsWith(const char prefixStr[]) const {
|
bool startsWith(const char prefixStr[]) const {
|
||||||
return SkStrStartsWith(fRec->data(), prefixStr);
|
return SkStrStartsWith(fRec->data(), prefixStr);
|
||||||
}
|
}
|
||||||
bool startsWith(const char prefixChar) const {
|
bool startsWith(char prefixChar) const {
|
||||||
return SkStrStartsWith(fRec->data(), prefixChar);
|
return SkStrStartsWith(fRec->data(), prefixChar);
|
||||||
}
|
}
|
||||||
bool endsWith(const char suffixStr[]) const {
|
bool endsWith(const char suffixStr[]) const {
|
||||||
return SkStrEndsWith(fRec->data(), suffixStr);
|
return SkStrEndsWith(fRec->data(), suffixStr);
|
||||||
}
|
}
|
||||||
bool endsWith(const char suffixChar) const {
|
bool endsWith(char suffixChar) const {
|
||||||
return SkStrEndsWith(fRec->data(), suffixChar);
|
return SkStrEndsWith(fRec->data(), suffixChar);
|
||||||
}
|
}
|
||||||
bool contains(const char substring[]) const {
|
bool contains(const char substring[]) const {
|
||||||
return SkStrContains(fRec->data(), substring);
|
return SkStrContains(fRec->data(), substring);
|
||||||
}
|
}
|
||||||
bool contains(const char subchar) const {
|
bool contains(char subchar) const {
|
||||||
return SkStrContains(fRec->data(), subchar);
|
return SkStrContains(fRec->data(), subchar);
|
||||||
}
|
}
|
||||||
int find(const char substring[]) const {
|
int find(const char substring[]) const {
|
||||||
return SkStrFind(fRec->data(), substring);
|
return SkStrFind(fRec->data(), substring);
|
||||||
}
|
}
|
||||||
int findLastOf(const char subchar) const {
|
int findLastOf(char subchar) const {
|
||||||
return SkStrFindLastOf(fRec->data(), subchar);
|
return SkStrFindLastOf(fRec->data(), subchar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -330,6 +330,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
sk_sp<SkImage> makeImageSnapshot(const SkIRect& bounds);
|
sk_sp<SkImage> makeImageSnapshot(const SkIRect& bounds);
|
||||||
|
|
||||||
|
/** Returns an SkImage capturing the current SkSurface contents. However, the contents of the
|
||||||
|
SkImage are only valid as long as no other writes to the SkSurface occur. If writes to the
|
||||||
|
original SkSurface happen then contents of the SkImage are undefined. However, continued use
|
||||||
|
of the SkImage should not cause crashes or similar fatal behavior.
|
||||||
|
|
||||||
|
This API is useful for cases where the client either immediately destroys the SkSurface
|
||||||
|
after the SkImage is created or knows they will destroy the SkImage before writing to the
|
||||||
|
SkSurface again.
|
||||||
|
|
||||||
|
This API can be more performant than makeImageSnapshot as it never does an internal copy
|
||||||
|
of the data assuming the user frees either the SkImage or SkSurface as described above.
|
||||||
|
*/
|
||||||
|
sk_sp<SkImage> makeTemporaryImage();
|
||||||
|
|
||||||
/** Draws SkSurface contents to canvas, with its top-left corner at (x, y).
|
/** Draws SkSurface contents to canvas, with its top-left corner at (x, y).
|
||||||
|
|
||||||
If SkPaint paint is not nullptr, apply SkColorFilter, alpha, SkImageFilter, and SkBlendMode.
|
If SkPaint paint is not nullptr, apply SkColorFilter, alpha, SkImageFilter, and SkBlendMode.
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ public:
|
|||||||
struct Run {
|
struct Run {
|
||||||
SkTypeface* fTypeface;
|
SkTypeface* fTypeface;
|
||||||
int fGlyphCount;
|
int fGlyphCount;
|
||||||
const uint16_t* fGlyphIndices;
|
const SkGlyphID* fGlyphIndices;
|
||||||
#ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED
|
#ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED
|
||||||
const uint32_t* fClusterIndex_forTest;
|
const uint32_t* fClusterIndex_forTest;
|
||||||
int fUtf8Size_forTest;
|
int fUtf8Size_forTest;
|
||||||
@@ -231,7 +231,7 @@ public:
|
|||||||
struct ExperimentalRun {
|
struct ExperimentalRun {
|
||||||
SkFont font;
|
SkFont font;
|
||||||
int count;
|
int count;
|
||||||
const uint16_t* glyphs;
|
const SkGlyphID* glyphs;
|
||||||
const SkPoint* positions;
|
const SkPoint* positions;
|
||||||
};
|
};
|
||||||
bool experimentalNext(ExperimentalRun*);
|
bool experimentalNext(ExperimentalRun*);
|
||||||
|
|||||||
@@ -53,20 +53,18 @@ typedef uint32_t SkFontTableTag;
|
|||||||
class SK_API SkTypeface : public SkWeakRefCnt {
|
class SK_API SkTypeface : public SkWeakRefCnt {
|
||||||
public:
|
public:
|
||||||
/** Returns the typeface's intrinsic style attributes. */
|
/** Returns the typeface's intrinsic style attributes. */
|
||||||
SkFontStyle fontStyle() const {
|
SkFontStyle fontStyle() const;
|
||||||
return fStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns true if style() has the kBold bit set. */
|
/** Returns true if style() has the kBold bit set. */
|
||||||
bool isBold() const { return fStyle.weight() >= SkFontStyle::kSemiBold_Weight; }
|
bool isBold() const;
|
||||||
|
|
||||||
/** Returns true if style() has the kItalic bit set. */
|
/** Returns true if style() has the kItalic bit set. */
|
||||||
bool isItalic() const { return fStyle.slant() != SkFontStyle::kUpright_Slant; }
|
bool isItalic() const;
|
||||||
|
|
||||||
/** Returns true if the typeface claims to be fixed-pitch.
|
/** Returns true if the typeface claims to be fixed-pitch.
|
||||||
* This is a style bit, advance widths may vary even if this returns true.
|
* This is a style bit, advance widths may vary even if this returns true.
|
||||||
*/
|
*/
|
||||||
bool isFixedPitch() const { return fIsFixedPitch; }
|
bool isFixedPitch() const;
|
||||||
|
|
||||||
/** Copy into 'coordinates' (allocated by the caller) the design variation coordinates.
|
/** Copy into 'coordinates' (allocated by the caller) the design variation coordinates.
|
||||||
*
|
*
|
||||||
@@ -287,6 +285,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool getPostScriptName(SkString* name) const;
|
bool getPostScriptName(SkString* name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the primary resource backing this typeface has a name (like a file
|
||||||
|
* path or URL) representable by unicode code points, the `resourceName`
|
||||||
|
* will be set. The primary purpose is as a user facing indication about
|
||||||
|
* where the data was obtained (which font file was used).
|
||||||
|
*
|
||||||
|
* Returns the number of resources backing this typeface.
|
||||||
|
*
|
||||||
|
* For local font collections resource name will often be a file path. The
|
||||||
|
* file path may or may not exist. If it does exist, using it to create an
|
||||||
|
* SkTypeface may or may not create a similar SkTypeface to this one.
|
||||||
|
*/
|
||||||
|
int getResourceName(SkString* resourceName) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a stream for the contents of the font data, or NULL on failure.
|
* Return a stream for the contents of the font data, or NULL on failure.
|
||||||
* If ttcIndex is not null, it is set to the TrueTypeCollection index
|
* If ttcIndex is not null, it is set to the TrueTypeCollection index
|
||||||
@@ -355,13 +367,15 @@ protected:
|
|||||||
/** Sets the font style. If used, must be called in the constructor. */
|
/** Sets the font style. If used, must be called in the constructor. */
|
||||||
void setFontStyle(SkFontStyle style) { fStyle = style; }
|
void setFontStyle(SkFontStyle style) { fStyle = style; }
|
||||||
|
|
||||||
|
virtual SkFontStyle onGetFontStyle() const; // TODO: = 0;
|
||||||
|
|
||||||
|
virtual bool onGetFixedPitch() const; // TODO: = 0;
|
||||||
|
|
||||||
// Must return a valid scaler context. It can not return nullptr.
|
// Must return a valid scaler context. It can not return nullptr.
|
||||||
virtual std::unique_ptr<SkScalerContext> onCreateScalerContext(const SkScalerContextEffects&,
|
virtual std::unique_ptr<SkScalerContext> onCreateScalerContext(
|
||||||
const SkDescriptor*) const = 0;
|
const SkScalerContextEffects&, const SkDescriptor*) const = 0;
|
||||||
virtual std::unique_ptr<SkScalerContext> onCreateScalerContextAsProxyTypeface
|
virtual std::unique_ptr<SkScalerContext> onCreateScalerContextAsProxyTypeface
|
||||||
(const SkScalerContextEffects&,
|
(const SkScalerContextEffects&, const SkDescriptor*, SkTypeface* proxyTypeface) const;
|
||||||
const SkDescriptor*,
|
|
||||||
sk_sp<SkTypeface>) const;
|
|
||||||
virtual void onFilterRec(SkScalerContextRec*) const = 0;
|
virtual void onFilterRec(SkScalerContextRec*) const = 0;
|
||||||
friend class SkScalerContext; // onFilterRec
|
friend class SkScalerContext; // onFilterRec
|
||||||
|
|
||||||
@@ -404,6 +418,7 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void onGetFamilyName(SkString* familyName) const = 0;
|
virtual void onGetFamilyName(SkString* familyName) const = 0;
|
||||||
virtual bool onGetPostScriptName(SkString*) const = 0;
|
virtual bool onGetPostScriptName(SkString*) const = 0;
|
||||||
|
virtual int onGetResourceName(SkString* resourceName) const; // TODO: = 0;
|
||||||
|
|
||||||
/** Returns an iterator over the family names in the font. */
|
/** Returns an iterator over the family names in the font. */
|
||||||
virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0;
|
virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0;
|
||||||
@@ -430,9 +445,9 @@ private:
|
|||||||
std::unique_ptr<SkAdvancedTypefaceMetrics> getAdvancedMetrics() const;
|
std::unique_ptr<SkAdvancedTypefaceMetrics> getAdvancedMetrics() const;
|
||||||
friend class SkRandomTypeface; // getAdvancedMetrics
|
friend class SkRandomTypeface; // getAdvancedMetrics
|
||||||
friend class SkPDFFont; // getAdvancedMetrics
|
friend class SkPDFFont; // getAdvancedMetrics
|
||||||
friend class SkTypeface_fontconfig;
|
friend class SkTypeface_proxy;
|
||||||
|
|
||||||
friend class SkFontPriv; // getGlyphToUnicodeMap
|
friend class SkFontPriv; // getGlyphToUnicodeMap
|
||||||
|
friend void TestSkTypefaceGlyphToUnicodeMap(SkTypeface&, SkUnichar*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkTypefaceID fUniqueID;
|
SkTypefaceID fUniqueID;
|
||||||
|
|||||||
@@ -97,6 +97,7 @@
|
|||||||
defined(SK_HISTOGRAM_BOOLEAN) || \
|
defined(SK_HISTOGRAM_BOOLEAN) || \
|
||||||
defined(SK_HISTOGRAM_EXACT_LINEAR) || \
|
defined(SK_HISTOGRAM_EXACT_LINEAR) || \
|
||||||
defined(SK_HISTOGRAM_MEMORY_KB) || \
|
defined(SK_HISTOGRAM_MEMORY_KB) || \
|
||||||
|
defined(SK_HISTOGRAM_CUSTOM_COUNTS)|| \
|
||||||
defined(SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES)
|
defined(SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES)
|
||||||
# define SK_HISTOGRAMS_ENABLED 1
|
# define SK_HISTOGRAMS_ENABLED 1
|
||||||
#else
|
#else
|
||||||
@@ -119,6 +120,10 @@
|
|||||||
# define SK_HISTOGRAM_MEMORY_KB(name, sample)
|
# define SK_HISTOGRAM_MEMORY_KB(name, sample)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SK_HISTOGRAM_CUSTOM_COUNTS
|
||||||
|
# define SK_HISTOGRAM_CUSTOM_COUNTS(name, sample, countMin, countMax, bucketCount)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES
|
#ifndef SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES
|
||||||
# define SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sampleUSec, minUSec, maxUSec, bucketCount)
|
# define SK_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(name, sampleUSec, minUSec, maxUSec, bucketCount)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,9 +16,12 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class SkCanvas;
|
class SkCanvas;
|
||||||
|
class SkCodec;
|
||||||
|
class SkData;
|
||||||
class SkExecutor;
|
class SkExecutor;
|
||||||
class SkPDFArray;
|
class SkPDFArray;
|
||||||
class SkPDFStructTree;
|
class SkPDFStructTree;
|
||||||
|
class SkPixmap;
|
||||||
class SkWStream;
|
class SkWStream;
|
||||||
|
|
||||||
#define SKPDF_STRING(X) SKPDF_STRING_IMPL(X)
|
#define SKPDF_STRING(X) SKPDF_STRING_IMPL(X)
|
||||||
@@ -80,6 +83,9 @@ struct DateTime {
|
|||||||
void toISO8601(SkString* dst) const;
|
void toISO8601(SkString* dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using DecodeJpegCallback = std::unique_ptr<SkCodec> (*)(sk_sp<SkData>);
|
||||||
|
using EncodeJpegCallback = bool (*)(SkWStream* dst, const SkPixmap& src, int quality);
|
||||||
|
|
||||||
/** Optional metadata to be passed into the PDF factory function.
|
/** Optional metadata to be passed into the PDF factory function.
|
||||||
*/
|
*/
|
||||||
struct Metadata {
|
struct Metadata {
|
||||||
@@ -157,6 +163,7 @@ struct Metadata {
|
|||||||
enum class Outline : int {
|
enum class Outline : int {
|
||||||
None = 0,
|
None = 0,
|
||||||
StructureElementHeaders = 1,
|
StructureElementHeaders = 1,
|
||||||
|
StructureElements = 2,
|
||||||
} fOutline = Outline::None;
|
} fOutline = Outline::None;
|
||||||
|
|
||||||
/** Executor to handle threaded work within PDF Backend. If this is nullptr,
|
/** Executor to handle threaded work within PDF Backend. If this is nullptr,
|
||||||
@@ -186,14 +193,50 @@ struct Metadata {
|
|||||||
enum Subsetter {
|
enum Subsetter {
|
||||||
kHarfbuzz_Subsetter,
|
kHarfbuzz_Subsetter,
|
||||||
} fSubsetter = kHarfbuzz_Subsetter;
|
} fSubsetter = kHarfbuzz_Subsetter;
|
||||||
|
|
||||||
|
/** Clients can provide a way to decode jpeg. To use Skia's JPEG decoder, pass in
|
||||||
|
SkJpegDecoder::Decode. If not supplied, all images will need to be re-encoded
|
||||||
|
as jpegs or deflated images before embedding. If supplied, Skia may be able to
|
||||||
|
skip the re-encoding step.
|
||||||
|
Skia's JPEG decoder can be used here.
|
||||||
|
*/
|
||||||
|
SkPDF::DecodeJpegCallback jpegDecoder = nullptr;
|
||||||
|
|
||||||
|
/** Clients can provide a way to encode jpeg. If not supplied, images will be embedded
|
||||||
|
as a deflated image, potentially making them much larger. If clients provide
|
||||||
|
their own implementation, JPEGs should be encoded to RGB (not YUV) otherwise they
|
||||||
|
will have the wrong surrounding metadata provided by Skia.
|
||||||
|
Skia's JPEG encoder can be used here.
|
||||||
|
*/
|
||||||
|
SkPDF::EncodeJpegCallback jpegEncoder = nullptr;
|
||||||
|
|
||||||
|
// Skia's PDF support depends on having both a jpeg encoder and decoder for writing
|
||||||
|
// compact PDFs. It will technically work, but produce larger than optimal PDFs
|
||||||
|
// if either the decoder or encoder are left as nullptr. If clients will be creating
|
||||||
|
// PDFs that don't use images or otherwise want to incur this cost (with the upside
|
||||||
|
// of not having a jpeg library), they should set this to true to avoid an internal
|
||||||
|
// assert from firing.
|
||||||
|
bool allowNoJpegs = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace NodeID {
|
||||||
|
static const constexpr int Nothing = 0;
|
||||||
|
static const constexpr int OtherArtifact = -1;
|
||||||
|
static const constexpr int PaginationArtifact = -2;
|
||||||
|
static const constexpr int PaginationHeaderArtifact = -3;
|
||||||
|
static const constexpr int PaginationFooterArtifact = -4;
|
||||||
|
static const constexpr int PaginationWatermarkArtifact = -5;
|
||||||
|
static const constexpr int LayoutArtifact = -6;
|
||||||
|
static const constexpr int PageArtifact = -7;
|
||||||
|
static const constexpr int BackgroundArtifact = -8;
|
||||||
|
} // namespace NodeID
|
||||||
|
|
||||||
/** Associate a node ID with subsequent drawing commands in an
|
/** Associate a node ID with subsequent drawing commands in an
|
||||||
SkCanvas. The same node ID can appear in a StructureElementNode
|
SkCanvas. The same node ID can appear in a StructureElementNode
|
||||||
in order to associate a document's structure element tree with
|
in order to associate a document's structure element tree with
|
||||||
its content.
|
its content.
|
||||||
|
|
||||||
A node ID of zero indicates no node ID.
|
A node ID of zero indicates no node ID. Negative node IDs are reserved.
|
||||||
|
|
||||||
@param canvas The canvas used to draw to the PDF.
|
@param canvas The canvas used to draw to the PDF.
|
||||||
@param nodeId The node ID for subsequent drawing commands.
|
@param nodeId The node ID for subsequent drawing commands.
|
||||||
@@ -207,15 +250,17 @@ SK_API void SetNodeId(SkCanvas* dst, int nodeID);
|
|||||||
@param stream A PDF document will be written to this stream. The document may write
|
@param stream A PDF document will be written to this stream. The document may write
|
||||||
to the stream at anytime during its lifetime, until either close() is
|
to the stream at anytime during its lifetime, until either close() is
|
||||||
called or the document is deleted.
|
called or the document is deleted.
|
||||||
@param metadata a PDFmetadata object. Any fields may be left empty.
|
@param metadata a PDFmetadata object. Some fields may be left empty.
|
||||||
|
|
||||||
@returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument.
|
@returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument.
|
||||||
*/
|
*/
|
||||||
SK_API sk_sp<SkDocument> MakeDocument(SkWStream* stream, const Metadata& metadata);
|
SK_API sk_sp<SkDocument> MakeDocument(SkWStream* stream, const Metadata& metadata);
|
||||||
|
|
||||||
|
#if !defined(SK_DISABLE_LEGACY_PDF_JPEG)
|
||||||
static inline sk_sp<SkDocument> MakeDocument(SkWStream* stream) {
|
static inline sk_sp<SkDocument> MakeDocument(SkWStream* stream) {
|
||||||
return MakeDocument(stream, Metadata());
|
return MakeDocument(stream, Metadata());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace SkPDF
|
} // namespace SkPDF
|
||||||
|
|
||||||
|
|||||||
41
gfx/skia/skia/include/docs/SkPDFJpegHelpers.h
Normal file
41
gfx/skia/skia/include/docs/SkPDFJpegHelpers.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
#ifndef SkPDFJPEGHelpers_DEFINED
|
||||||
|
#define SkPDFJPEGHelpers_DEFINED
|
||||||
|
|
||||||
|
#include "include/codec/SkJpegDecoder.h"
|
||||||
|
#include "include/core/SkData.h"
|
||||||
|
#include "include/core/SkRefCnt.h"
|
||||||
|
#include "include/docs/SkPDFDocument.h"
|
||||||
|
#include "include/encode/SkJpegEncoder.h"
|
||||||
|
|
||||||
|
class SkPixmap;
|
||||||
|
class SkWStream;
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace SkPDF::JPEG {
|
||||||
|
inline std::unique_ptr<SkCodec> Decode(sk_sp<SkData> data) {
|
||||||
|
return SkJpegDecoder::Decode(data, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Encode(SkWStream* dst, const SkPixmap& src, int quality) {
|
||||||
|
SkJpegEncoder::Options jOpts;
|
||||||
|
jOpts.fQuality = quality;
|
||||||
|
return SkJpegEncoder::Encode(dst, src, jOpts);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SkPDF::Metadata MetadataWithCallbacks() {
|
||||||
|
SkPDF::Metadata m;
|
||||||
|
m.jpegDecoder = SkPDF::JPEG::Decode;
|
||||||
|
m.jpegEncoder = SkPDF::JPEG::Encode;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SkPDF::JPEG
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -94,7 +94,12 @@ public:
|
|||||||
kHSL,
|
kHSL,
|
||||||
kHWB,
|
kHWB,
|
||||||
|
|
||||||
kLastColorSpace = kHWB,
|
kDisplayP3,
|
||||||
|
kRec2020,
|
||||||
|
kProphotoRGB,
|
||||||
|
kA98RGB,
|
||||||
|
|
||||||
|
kLastColorSpace = kA98RGB,
|
||||||
};
|
};
|
||||||
static constexpr int kColorSpaceCount = static_cast<int>(ColorSpace::kLastColorSpace) + 1;
|
static constexpr int kColorSpaceCount = static_cast<int>(ColorSpace::kLastColorSpace) + 1;
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ public:
|
|||||||
// don't run the inliner directly, but they still get an inlining pass once they are
|
// don't run the inliner directly, but they still get an inlining pass once they are
|
||||||
// painted.)
|
// painted.)
|
||||||
bool forceUnoptimized = false;
|
bool forceUnoptimized = false;
|
||||||
|
// When possible this name will be used to identify the created runtime effect.
|
||||||
|
std::string_view fName;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SkRuntimeEffect;
|
friend class SkRuntimeEffect;
|
||||||
@@ -170,6 +172,7 @@ public:
|
|||||||
|
|
||||||
// Shader SkSL requires an entry point that looks like:
|
// Shader SkSL requires an entry point that looks like:
|
||||||
// vec4 main(vec2 inCoords) { ... }
|
// vec4 main(vec2 inCoords) { ... }
|
||||||
|
// The color that is returned should be premultiplied.
|
||||||
static Result MakeForShader(SkString sksl, const Options&);
|
static Result MakeForShader(SkString sksl, const Options&);
|
||||||
static Result MakeForShader(SkString sksl) {
|
static Result MakeForShader(SkString sksl) {
|
||||||
return MakeForShader(std::move(sksl), Options{});
|
return MakeForShader(std::move(sksl), Options{});
|
||||||
@@ -316,7 +319,9 @@ private:
|
|||||||
friend class SkRuntimeEffectPriv;
|
friend class SkRuntimeEffectPriv;
|
||||||
|
|
||||||
uint32_t fHash;
|
uint32_t fHash;
|
||||||
uint32_t fStableKey;
|
// When not 0, this field holds a StableKey value or a user-defined stable key
|
||||||
|
uint32_t fStableKey = 0;
|
||||||
|
SkString fName;
|
||||||
|
|
||||||
std::unique_ptr<SkSL::Program> fBaseProgram;
|
std::unique_ptr<SkSL::Program> fBaseProgram;
|
||||||
std::unique_ptr<SkSL::RP::Program> fRPProgram;
|
std::unique_ptr<SkSL::RP::Program> fRPProgram;
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ public:
|
|||||||
static SkMaskFilter* CreateClip(uint8_t min, uint8_t max);
|
static SkMaskFilter* CreateClip(uint8_t min, uint8_t max);
|
||||||
|
|
||||||
SkTableMaskFilter() = delete;
|
SkTableMaskFilter() = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void RegisterFlattenables();
|
||||||
|
friend class SkFlattenable;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class SkImage;
|
|||||||
class SkPixmap;
|
class SkPixmap;
|
||||||
class SkWStream;
|
class SkWStream;
|
||||||
struct skcms_ICCProfile;
|
struct skcms_ICCProfile;
|
||||||
|
struct SkGainmapInfo;
|
||||||
|
|
||||||
namespace SkPngEncoder {
|
namespace SkPngEncoder {
|
||||||
|
|
||||||
@@ -80,6 +81,19 @@ struct Options {
|
|||||||
*/
|
*/
|
||||||
const skcms_ICCProfile* fICCProfile = nullptr;
|
const skcms_ICCProfile* fICCProfile = nullptr;
|
||||||
const char* fICCProfileDescription = nullptr;
|
const char* fICCProfileDescription = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If non-null, then a gainmap and its metadata will be encoded as png chunks.
|
||||||
|
* The gainmap will be encoded in a gmAP chunk as a full PNG container. The
|
||||||
|
* gainmap info will be encoded in a gdAT chunk inside of the gmAP chunk.
|
||||||
|
* This effectively is Option B proposed in this discussion for adding gainmaps
|
||||||
|
* into PNG: https://github.com/w3c/png/issues/380#issuecomment-2325163149.
|
||||||
|
*
|
||||||
|
* Note that if fGainmapInfo is null, then fGainmap will fail to encode, as the
|
||||||
|
* gainmap metadata is required to correctly interpret the encoded gainmap.
|
||||||
|
*/
|
||||||
|
const SkPixmap* fGainmap = nullptr;
|
||||||
|
const SkGainmapInfo* fGainmapInfo = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ enum class Origin : unsigned {
|
|||||||
kBottomLeft,
|
kBottomLeft,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GpuStatsFlags : uint32_t {
|
||||||
|
kNone = 0b00,
|
||||||
|
kElapsedTime = 0b01,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GpuStats {
|
||||||
|
uint64_t elapsedTime = 0;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace skgpu
|
} // namespace skgpu
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,55 @@ struct SK_API GrContextOptions {
|
|||||||
|
|
||||||
GrContextOptions() {}
|
GrContextOptions() {}
|
||||||
|
|
||||||
// Suppress prints for the GrContext.
|
/**
|
||||||
bool fSuppressPrints = false;
|
* If Skia is creating a default VMA allocator for the Vulkan backend this value will be used
|
||||||
|
* for the preferredLargeHeapBlockSize. If the value is not set, then Skia will use an
|
||||||
|
* inernally defined default size.
|
||||||
|
*
|
||||||
|
* However, it is highly discouraged to have Skia make a default allocator (and support for
|
||||||
|
* doing so will be removed soon, b/321962001). Instead clients should create their own
|
||||||
|
* allocator to pass into Skia where they can fine tune this value themeselves.
|
||||||
|
*/
|
||||||
|
std::optional<uint64_t> fVulkanVMALargeHeapBlockSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional callback that can be passed into the GrDirectContext which will be called when the
|
||||||
|
* GrDirectContext is about to be destroyed. When this call is made, it will be safe for the
|
||||||
|
* client to delete the GPU backend context that is backing the GrDirectContext. The
|
||||||
|
* GrDirectContextDestroyedContext will be passed back to the client in the callback.
|
||||||
|
*/
|
||||||
|
GrDirectContextDestroyedContext fContextDeleteContext = nullptr;
|
||||||
|
GrDirectContextDestroyedProc fContextDeleteProc = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executor to handle threaded work within Ganesh. If this is nullptr, then all work will be
|
||||||
|
* done serially on the main thread. To have worker threads assist with various tasks, set this
|
||||||
|
* to a valid SkExecutor instance. Currently, used for software path rendering, but may be used
|
||||||
|
* for other tasks.
|
||||||
|
*/
|
||||||
|
SkExecutor* fExecutor = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache in which to store compiled shader binaries between runs.
|
||||||
|
*/
|
||||||
|
PersistentCache* fPersistentCache = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If present, use this object to report shader compilation failures. If not, report failures
|
||||||
|
* via SkDebugf and assert.
|
||||||
|
*/
|
||||||
|
ShaderErrorHandler* fShaderErrorHandler = nullptr;
|
||||||
|
|
||||||
|
/** Default minimum size to use when allocating buffers for uploading data to textures. The
|
||||||
|
larger the value the more uploads can be packed into one buffer, but at the cost of
|
||||||
|
more gpu memory allocated that may not be used. Uploads larger than the minimum will still
|
||||||
|
work by allocating a dedicated buffer. */
|
||||||
|
size_t fMinimumStagingBufferSize = 64 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum size of cache textures used for Skia's Glyph cache.
|
||||||
|
*/
|
||||||
|
size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls whether we check for GL errors after functions that allocate resources (e.g.
|
* Controls whether we check for GL errors after functions that allocate resources (e.g.
|
||||||
@@ -86,6 +133,33 @@ struct SK_API GrContextOptions {
|
|||||||
*/
|
*/
|
||||||
Enable fSkipGLErrorChecks = Enable::kDefault;
|
Enable fSkipGLErrorChecks = Enable::kDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can the glyph atlas use multiple textures. If allowed, the each texture's size is bound by
|
||||||
|
* fGlypheCacheTextureMaximumBytes.
|
||||||
|
*/
|
||||||
|
Enable fAllowMultipleGlyphCacheTextures = Enable::kDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables driver workaround to use draws instead of HW clears, e.g. glClear on the GL backend.
|
||||||
|
*/
|
||||||
|
Enable fUseDrawInsteadOfClear = Enable::kDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow Ganesh to more aggressively reorder operations to reduce the number of render passes.
|
||||||
|
* Offscreen draws will be done upfront instead of interrupting the main render pass when
|
||||||
|
* possible. May increase VRAM usage, but still observes the resource cache limit.
|
||||||
|
* Enabled by default.
|
||||||
|
*/
|
||||||
|
Enable fReduceOpsTaskSplitting = Enable::kDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This affects the usage of the PersistentCache. We can cache SkSL, backend source (GLSL), or
|
||||||
|
* backend binaries (GL program binaries). By default we cache binaries, but if the driver's
|
||||||
|
* binary loading/storing is believed to have bugs, this can be limited to caching GLSL.
|
||||||
|
* Caching GLSL strings still saves CPU work when a GL program is created.
|
||||||
|
*/
|
||||||
|
ShaderCacheStrategy fShaderCacheStrategy = ShaderCacheStrategy::kBackendBinary;
|
||||||
|
|
||||||
/** Overrides: These options override feature detection using backend API queries. These
|
/** Overrides: These options override feature detection using backend API queries. These
|
||||||
overrides can only reduce the feature set or limits, never increase them beyond the
|
overrides can only reduce the feature set or limits, never increase them beyond the
|
||||||
detected values. */
|
detected values. */
|
||||||
@@ -97,19 +171,48 @@ struct SK_API GrContextOptions {
|
|||||||
deduce the optimal value for this platform. */
|
deduce the optimal value for this platform. */
|
||||||
int fBufferMapThreshold = -1;
|
int fBufferMapThreshold = -1;
|
||||||
|
|
||||||
/** Default minimum size to use when allocating buffers for uploading data to textures. The
|
/**
|
||||||
larger the value the more uploads can be packed into one buffer, but at the cost of
|
* Maximum number of GPU programs or pipelines to keep active in the runtime cache.
|
||||||
more gpu memory allocated that may not be used. Uploads larger than the minimum will still
|
*/
|
||||||
work by allocating a dedicated buffer. */
|
int fRuntimeProgramCacheSize = 256;
|
||||||
size_t fMinimumStagingBufferSize = 64 * 1024;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executor to handle threaded work within Ganesh. If this is nullptr, then all work will be
|
* Specifies the number of samples Ganesh should use when performing internal draws with MSAA
|
||||||
* done serially on the main thread. To have worker threads assist with various tasks, set this
|
* (hardware capabilities permitting).
|
||||||
* to a valid SkExecutor instance. Currently, used for software path rendering, but may be used
|
*
|
||||||
* for other tasks.
|
* If 0, Ganesh will disable internal code paths that use multisampling.
|
||||||
*/
|
*/
|
||||||
SkExecutor* fExecutor = nullptr;
|
int fInternalMultisampleCount = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In Skia's vulkan backend a single GrContext submit equates to the submission of a single
|
||||||
|
* primary command buffer to the VkQueue. This value specifies how many vulkan secondary command
|
||||||
|
* buffers we will cache for reuse on a given primary command buffer. A single submit may use
|
||||||
|
* more than this many secondary command buffers, but after the primary command buffer is
|
||||||
|
* finished on the GPU it will only hold on to this many secondary command buffers for reuse.
|
||||||
|
*
|
||||||
|
* A value of -1 means we will pick a limit value internally.
|
||||||
|
*/
|
||||||
|
int fMaxCachedVulkanSecondaryCommandBuffers = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Below this threshold size in device space distance field fonts won't be used. Distance field
|
||||||
|
* fonts don't support hinting which is more important at smaller sizes.
|
||||||
|
*/
|
||||||
|
float fMinDistanceFieldFontSize = 18;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Above this threshold size in device space glyphs are drawn as individual paths.
|
||||||
|
*/
|
||||||
|
#if defined(SK_BUILD_FOR_ANDROID)
|
||||||
|
float fGlyphsAsPathsFontSize = 384;
|
||||||
|
#elif defined(SK_BUILD_FOR_MAC)
|
||||||
|
float fGlyphsAsPathsFontSize = 256;
|
||||||
|
#else
|
||||||
|
float fGlyphsAsPathsFontSize = 324;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GrDriverBugWorkarounds fDriverBugWorkarounds;
|
||||||
|
|
||||||
/** Construct mipmaps manually, via repeated downsampling draw-calls. This is used when
|
/** Construct mipmaps manually, via repeated downsampling draw-calls. This is used when
|
||||||
the driver's implementation (glGenerateMipmap) contains bugs. This requires mipmap
|
the driver's implementation (glGenerateMipmap) contains bugs. This requires mipmap
|
||||||
@@ -142,34 +245,6 @@ struct SK_API GrContextOptions {
|
|||||||
*/
|
*/
|
||||||
bool fDisableGpuYUVConversion = false;
|
bool fDisableGpuYUVConversion = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum size of cache textures used for Skia's Glyph cache.
|
|
||||||
*/
|
|
||||||
size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Below this threshold size in device space distance field fonts won't be used. Distance field
|
|
||||||
* fonts don't support hinting which is more important at smaller sizes.
|
|
||||||
*/
|
|
||||||
float fMinDistanceFieldFontSize = 18;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Above this threshold size in device space glyphs are drawn as individual paths.
|
|
||||||
*/
|
|
||||||
#if defined(SK_BUILD_FOR_ANDROID)
|
|
||||||
float fGlyphsAsPathsFontSize = 384;
|
|
||||||
#elif defined(SK_BUILD_FOR_MAC)
|
|
||||||
float fGlyphsAsPathsFontSize = 256;
|
|
||||||
#else
|
|
||||||
float fGlyphsAsPathsFontSize = 324;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can the glyph atlas use multiple textures. If allowed, the each texture's size is bound by
|
|
||||||
* fGlypheCacheTextureMaximumBytes.
|
|
||||||
*/
|
|
||||||
Enable fAllowMultipleGlyphCacheTextures = Enable::kDefault;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bugs on certain drivers cause stencil buffers to leak. This flag causes Skia to avoid
|
* Bugs on certain drivers cause stencil buffers to leak. This flag causes Skia to avoid
|
||||||
* allocating stencil buffers and use alternate rasterization paths, avoiding the leak.
|
* allocating stencil buffers and use alternate rasterization paths, avoiding the leak.
|
||||||
@@ -183,19 +258,6 @@ struct SK_API GrContextOptions {
|
|||||||
*/
|
*/
|
||||||
bool fSharpenMipmappedTextures = true;
|
bool fSharpenMipmappedTextures = true;
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables driver workaround to use draws instead of HW clears, e.g. glClear on the GL backend.
|
|
||||||
*/
|
|
||||||
Enable fUseDrawInsteadOfClear = Enable::kDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow Ganesh to more aggressively reorder operations to reduce the number of render passes.
|
|
||||||
* Offscreen draws will be done upfront instead of interrupting the main render pass when
|
|
||||||
* possible. May increase VRAM usage, but still observes the resource cache limit.
|
|
||||||
* Enabled by default.
|
|
||||||
*/
|
|
||||||
Enable fReduceOpsTaskSplitting = Enable::kDefault;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some ES3 contexts report the ES2 external image extension, but not the ES3 version.
|
* Some ES3 contexts report the ES2 external image extension, but not the ES3 version.
|
||||||
* If support for external images is critical, enabling this option will cause Ganesh to limit
|
* If support for external images is critical, enabling this option will cause Ganesh to limit
|
||||||
@@ -210,60 +272,6 @@ struct SK_API GrContextOptions {
|
|||||||
*/
|
*/
|
||||||
bool fDisableDriverCorrectnessWorkarounds = false;
|
bool fDisableDriverCorrectnessWorkarounds = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of GPU programs or pipelines to keep active in the runtime cache.
|
|
||||||
*/
|
|
||||||
int fRuntimeProgramCacheSize = 256;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache in which to store compiled shader binaries between runs.
|
|
||||||
*/
|
|
||||||
PersistentCache* fPersistentCache = nullptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This affects the usage of the PersistentCache. We can cache SkSL, backend source (GLSL), or
|
|
||||||
* backend binaries (GL program binaries). By default we cache binaries, but if the driver's
|
|
||||||
* binary loading/storing is believed to have bugs, this can be limited to caching GLSL.
|
|
||||||
* Caching GLSL strings still saves CPU work when a GL program is created.
|
|
||||||
*/
|
|
||||||
ShaderCacheStrategy fShaderCacheStrategy = ShaderCacheStrategy::kBackendBinary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If present, use this object to report shader compilation failures. If not, report failures
|
|
||||||
* via SkDebugf and assert.
|
|
||||||
*/
|
|
||||||
ShaderErrorHandler* fShaderErrorHandler = nullptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the number of samples Ganesh should use when performing internal draws with MSAA
|
|
||||||
* (hardware capabilities permitting).
|
|
||||||
*
|
|
||||||
* If 0, Ganesh will disable internal code paths that use multisampling.
|
|
||||||
*/
|
|
||||||
int fInternalMultisampleCount = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In Skia's vulkan backend a single GrContext submit equates to the submission of a single
|
|
||||||
* primary command buffer to the VkQueue. This value specifies how many vulkan secondary command
|
|
||||||
* buffers we will cache for reuse on a given primary command buffer. A single submit may use
|
|
||||||
* more than this many secondary command buffers, but after the primary command buffer is
|
|
||||||
* finished on the GPU it will only hold on to this many secondary command buffers for reuse.
|
|
||||||
*
|
|
||||||
* A value of -1 means we will pick a limit value internally.
|
|
||||||
*/
|
|
||||||
int fMaxCachedVulkanSecondaryCommandBuffers = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If Skia is creating a default VMA allocator for the Vulkan backend this value will be used
|
|
||||||
* for the preferredLargeHeapBlockSize. If the value is not set, then Skia will use an
|
|
||||||
* inernally defined default size.
|
|
||||||
*
|
|
||||||
* However, it is highly discouraged to have Skia make a default allocator (and support for
|
|
||||||
* doing so will be removed soon, b/321962001). Instead clients should create their own
|
|
||||||
* allocator to pass into Skia where they can fine tune this value themeselves.
|
|
||||||
*/
|
|
||||||
std::optional<uint64_t> fVulkanVMALargeHeapBlockSize;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the caps will never support mipmaps.
|
* If true, the caps will never support mipmaps.
|
||||||
*/
|
*/
|
||||||
@@ -307,20 +315,32 @@ struct SK_API GrContextOptions {
|
|||||||
*/
|
*/
|
||||||
bool fAlwaysUseTexStorageWhenAvailable = false;
|
bool fAlwaysUseTexStorageWhenAvailable = false;
|
||||||
|
|
||||||
/**
|
// Suppress prints for the GrContext.
|
||||||
* Optional callback that can be passed into the GrDirectContext which will be called when the
|
bool fSuppressPrints = false;
|
||||||
* GrDirectContext is about to be destroyed. When this call is made, it will be safe for the
|
|
||||||
* client to delete the GPU backend context that is backing the GrDirectContext. The
|
|
||||||
* GrDirectContextDestroyedContext will be passed back to the client in the callback.
|
|
||||||
*/
|
|
||||||
GrDirectContextDestroyedContext fContextDeleteContext = nullptr;
|
|
||||||
GrDirectContextDestroyedProc fContextDeleteProc = nullptr;
|
|
||||||
|
|
||||||
#if defined(GPU_TEST_UTILS)
|
#if defined(GPU_TEST_UTILS)
|
||||||
/**
|
/**
|
||||||
* Private options that are only meant for testing within Skia's tools.
|
* Private options that are only meant for testing within Skia's tools.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include or exclude specific GPU path renderers.
|
||||||
|
*/
|
||||||
|
GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the GPU resource cache limit. Equivalent to calling `setResourceCacheLimit` on the
|
||||||
|
* context at construction time.
|
||||||
|
*
|
||||||
|
* A value of -1 means use the default limit value.
|
||||||
|
*/
|
||||||
|
int fResourceCacheLimitOverride = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum width and height of internal texture atlases.
|
||||||
|
*/
|
||||||
|
int fMaxTextureAtlasSize = 2048;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Testing-only mode to exercise allocation failures in the flush-time callback objects.
|
* Testing-only mode to exercise allocation failures in the flush-time callback objects.
|
||||||
* For now it only simulates allocation failure during the preFlush callback.
|
* For now it only simulates allocation failure during the preFlush callback.
|
||||||
@@ -368,26 +388,8 @@ struct SK_API GrContextOptions {
|
|||||||
*/
|
*/
|
||||||
bool fDisallowWriteAndTransferPixelRowBytes = false;
|
bool fDisallowWriteAndTransferPixelRowBytes = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Include or exclude specific GPU path renderers.
|
|
||||||
*/
|
|
||||||
GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the GPU resource cache limit. Equivalent to calling `setResourceCacheLimit` on the
|
|
||||||
* context at construction time.
|
|
||||||
*
|
|
||||||
* A value of -1 means use the default limit value.
|
|
||||||
*/
|
|
||||||
int fResourceCacheLimitOverride = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum width and height of internal texture atlases.
|
|
||||||
*/
|
|
||||||
int fMaxTextureAtlasSize = 2048;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GrDriverBugWorkarounds fDriverBugWorkarounds;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -271,6 +271,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
void purgeUnlockedResources(GrPurgeResourceOptions opts);
|
void purgeUnlockedResources(GrPurgeResourceOptions opts);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the types of GPU stats supported by this Context.
|
||||||
|
*/
|
||||||
|
skgpu::GpuStatsFlags supportedGpuStats() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum supported texture size.
|
* Gets the maximum supported texture size.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -34,8 +34,10 @@ enum GrDriverBugWorkaroundType {
|
|||||||
|
|
||||||
class SK_API GrDriverBugWorkarounds {
|
class SK_API GrDriverBugWorkarounds {
|
||||||
public:
|
public:
|
||||||
GrDriverBugWorkarounds();
|
GrDriverBugWorkarounds() = default;
|
||||||
GrDriverBugWorkarounds(const GrDriverBugWorkarounds&) = default;
|
GrDriverBugWorkarounds(const GrDriverBugWorkarounds&) = default;
|
||||||
|
~GrDriverBugWorkarounds() = default;
|
||||||
|
|
||||||
explicit GrDriverBugWorkarounds(const std::vector<int32_t>& workarounds);
|
explicit GrDriverBugWorkarounds(const std::vector<int32_t>& workarounds);
|
||||||
|
|
||||||
GrDriverBugWorkarounds& operator=(const GrDriverBugWorkarounds&) = default;
|
GrDriverBugWorkarounds& operator=(const GrDriverBugWorkarounds&) = default;
|
||||||
@@ -43,8 +45,6 @@ class SK_API GrDriverBugWorkarounds {
|
|||||||
// Turn on any workarounds listed in |workarounds| (but don't turn any off).
|
// Turn on any workarounds listed in |workarounds| (but don't turn any off).
|
||||||
void applyOverrides(const GrDriverBugWorkarounds& workarounds);
|
void applyOverrides(const GrDriverBugWorkarounds& workarounds);
|
||||||
|
|
||||||
~GrDriverBugWorkarounds();
|
|
||||||
|
|
||||||
#define GPU_OP(type, name) bool name = false;
|
#define GPU_OP(type, name) bool name = false;
|
||||||
GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
|
GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
|
||||||
#undef GPU_OP
|
#undef GPU_OP
|
||||||
|
|||||||
@@ -9,17 +9,13 @@
|
|||||||
#define GrTypes_DEFINED
|
#define GrTypes_DEFINED
|
||||||
|
|
||||||
#include "include/core/SkTypes.h"
|
#include "include/core/SkTypes.h"
|
||||||
|
#include "include/gpu/GpuTypes.h"
|
||||||
#include "include/private/base/SkTo.h" // IWYU pragma: keep
|
#include "include/private/base/SkTo.h" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
class GrBackendSemaphore;
|
class GrBackendSemaphore;
|
||||||
|
|
||||||
namespace skgpu {
|
|
||||||
enum class Protected : bool;
|
|
||||||
enum class Renderable : bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,6 +106,8 @@ static const uint32_t kAll_GrBackendState = 0xffffffff;
|
|||||||
|
|
||||||
typedef void* GrGpuFinishedContext;
|
typedef void* GrGpuFinishedContext;
|
||||||
typedef void (*GrGpuFinishedProc)(GrGpuFinishedContext finishedContext);
|
typedef void (*GrGpuFinishedProc)(GrGpuFinishedContext finishedContext);
|
||||||
|
typedef void (*GrGpuFinishedWithStatsProc)(GrGpuFinishedContext finishedContext,
|
||||||
|
const skgpu::GpuStats&);
|
||||||
|
|
||||||
typedef void* GrGpuSubmittedContext;
|
typedef void* GrGpuSubmittedContext;
|
||||||
typedef void (*GrGpuSubmittedProc)(GrGpuSubmittedContext submittedContext, bool success);
|
typedef void (*GrGpuSubmittedProc)(GrGpuSubmittedContext submittedContext, bool success);
|
||||||
@@ -131,10 +129,15 @@ typedef void (*GrDirectContextDestroyedProc)(GrDirectContextDestroyedContext des
|
|||||||
* and returned in initialized GrBackendSemaphore objects. The GrBackendSemaphore objects
|
* and returned in initialized GrBackendSemaphore objects. The GrBackendSemaphore objects
|
||||||
* themselves can be deleted as soon as this function returns.
|
* themselves can be deleted as soon as this function returns.
|
||||||
*
|
*
|
||||||
* If a finishedProc is provided, the finishedProc will be called when all work submitted to the gpu
|
* If a finishedProc or finishedWithStatsProc is provided, the proc will be called when all work
|
||||||
* from this flush call and all previous flush calls has finished on the GPU. If the flush call
|
* submitted to the gpu from this flush call and all previous flush calls has finished on the GPU.
|
||||||
* fails due to an error and nothing ends up getting sent to the GPU, the finished proc is called
|
* If the flush call fails due to an error and nothing ends up getting sent to the GPU, the finished
|
||||||
* immediately.
|
* proc is called immediately. If both types of proc are provided then finishedWithStatsProc is
|
||||||
|
* preferred.
|
||||||
|
*
|
||||||
|
* When finishedWithStatsProc is called the GpuStats passed will contain valid values for stats
|
||||||
|
* by requested by gpuStatsFlags, assuming the stats are supported by the underlying backend GPU
|
||||||
|
* context and the GPU work completed successfully.
|
||||||
*
|
*
|
||||||
* If a submittedProc is provided, the submittedProc will be called when all work from this flush
|
* If a submittedProc is provided, the submittedProc will be called when all work from this flush
|
||||||
* call is submitted to the GPU. If the flush call fails due to an error and nothing will get sent
|
* call is submitted to the GPU. If the flush call fails due to an error and nothing will get sent
|
||||||
@@ -148,8 +151,10 @@ typedef void (*GrDirectContextDestroyedProc)(GrDirectContextDestroyedContext des
|
|||||||
*/
|
*/
|
||||||
struct GrFlushInfo {
|
struct GrFlushInfo {
|
||||||
size_t fNumSemaphores = 0;
|
size_t fNumSemaphores = 0;
|
||||||
|
skgpu::GpuStatsFlags fGpuStatsFlags = skgpu::GpuStatsFlags::kNone;
|
||||||
GrBackendSemaphore* fSignalSemaphores = nullptr;
|
GrBackendSemaphore* fSignalSemaphores = nullptr;
|
||||||
GrGpuFinishedProc fFinishedProc = nullptr;
|
GrGpuFinishedProc fFinishedProc = nullptr;
|
||||||
|
GrGpuFinishedWithStatsProc fFinishedWithStatsProc = nullptr;
|
||||||
GrGpuFinishedContext fFinishedContext = nullptr;
|
GrGpuFinishedContext fFinishedContext = nullptr;
|
||||||
GrGpuSubmittedProc fSubmittedProc = nullptr;
|
GrGpuSubmittedProc fSubmittedProc = nullptr;
|
||||||
GrGpuSubmittedContext fSubmittedContext = nullptr;
|
GrGpuSubmittedContext fSubmittedContext = nullptr;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
class BackendTextureData;
|
class BackendTextureData;
|
||||||
struct VulkanTextureInfo;
|
|
||||||
|
|
||||||
class SK_API BackendTexture {
|
class SK_API BackendTexture {
|
||||||
public:
|
public:
|
||||||
@@ -61,4 +60,3 @@ private:
|
|||||||
} // namespace skgpu::graphite
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
#endif // skgpu_graphite_BackendTexture_DEFINED
|
#endif // skgpu_graphite_BackendTexture_DEFINED
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
#include "include/gpu/graphite/Recorder.h"
|
#include "include/gpu/graphite/Recorder.h"
|
||||||
#include "include/private/base/SingleOwner.h"
|
#include "include/private/base/SingleOwner.h"
|
||||||
|
|
||||||
|
#if defined(GPU_TEST_UTILS)
|
||||||
|
#include "include/private/base/SkMutex.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -33,7 +37,7 @@ class Context;
|
|||||||
class ContextPriv;
|
class ContextPriv;
|
||||||
class GlobalCache;
|
class GlobalCache;
|
||||||
class PaintOptions;
|
class PaintOptions;
|
||||||
class PlotUploadTracker;
|
class PrecompileContext;
|
||||||
class QueueManager;
|
class QueueManager;
|
||||||
class Recording;
|
class Recording;
|
||||||
class ResourceProvider;
|
class ResourceProvider;
|
||||||
@@ -53,6 +57,11 @@ public:
|
|||||||
|
|
||||||
std::unique_ptr<Recorder> makeRecorder(const RecorderOptions& = {});
|
std::unique_ptr<Recorder> makeRecorder(const RecorderOptions& = {});
|
||||||
|
|
||||||
|
/** Creates a helper object that can be moved to a different thread and used
|
||||||
|
* for precompilation.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<PrecompileContext> makePrecompileContext();
|
||||||
|
|
||||||
bool insertRecording(const InsertRecordingInfo&);
|
bool insertRecording(const InsertRecordingInfo&);
|
||||||
bool submit(SyncToCpu = SyncToCpu::kNo);
|
bool submit(SyncToCpu = SyncToCpu::kNo);
|
||||||
|
|
||||||
@@ -218,6 +227,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
size_t maxBudgetedBytes() const;
|
size_t maxBudgetedBytes() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the size of Context's gpu memory cache budget in bytes. If the new budget is lower than
|
||||||
|
* the current budget, the cache will try to free resources to get under the new budget.
|
||||||
|
*/
|
||||||
|
void setMaxBudgetedBytes(size_t bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerates all cached GPU resources owned by the Context and dumps their memory to
|
* Enumerates all cached GPU resources owned by the Context and dumps their memory to
|
||||||
* traceMemoryDump.
|
* traceMemoryDump.
|
||||||
@@ -240,6 +255,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool supportsProtectedContent() const;
|
bool supportsProtectedContent() const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the types of GPU stats supported by this Context.
|
||||||
|
*/
|
||||||
|
GpuStatsFlags supportedGpuStats() const;
|
||||||
|
|
||||||
// Provides access to functions that aren't part of the public API.
|
// Provides access to functions that aren't part of the public API.
|
||||||
ContextPriv priv();
|
ContextPriv priv();
|
||||||
const ContextPriv priv() const; // NOLINT(readability-const-return-type)
|
const ContextPriv priv() const; // NOLINT(readability-const-return-type)
|
||||||
@@ -343,11 +363,14 @@ private:
|
|||||||
mutable SingleOwner fSingleOwner;
|
mutable SingleOwner fSingleOwner;
|
||||||
|
|
||||||
#if defined(GPU_TEST_UTILS)
|
#if defined(GPU_TEST_UTILS)
|
||||||
|
void deregisterRecorder(const Recorder*) SK_EXCLUDES(fTestingLock);
|
||||||
|
|
||||||
// In test builds a Recorder may track the Context that was used to create it.
|
// In test builds a Recorder may track the Context that was used to create it.
|
||||||
bool fStoreContextRefInRecorder = false;
|
bool fStoreContextRefInRecorder = false;
|
||||||
// If this tracking is on, to allow the client to safely delete this Context or its Recorders
|
// If this tracking is on, to allow the client to safely delete this Context or its Recorders
|
||||||
// in any order we must also track the Recorders created here.
|
// in any order we must also track the Recorders created here.
|
||||||
std::vector<Recorder*> fTrackedRecorders;
|
SkMutex fTestingLock;
|
||||||
|
std::vector<Recorder*> fTrackedRecorders SK_GUARDED_BY(fTestingLock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Needed for MessageBox handling
|
// Needed for MessageBox handling
|
||||||
|
|||||||
@@ -8,11 +8,15 @@
|
|||||||
#ifndef skgpu_graphite_ContextOptions_DEFINED
|
#ifndef skgpu_graphite_ContextOptions_DEFINED
|
||||||
#define skgpu_graphite_ContextOptions_DEFINED
|
#define skgpu_graphite_ContextOptions_DEFINED
|
||||||
|
|
||||||
|
#include "include/core/SkRefCnt.h"
|
||||||
|
#include "include/core/SkSpan.h"
|
||||||
#include "include/private/base/SkAPI.h"
|
#include "include/private/base/SkAPI.h"
|
||||||
#include "include/private/base/SkMath.h"
|
#include "include/private/base/SkMath.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
class SkData;
|
||||||
|
class SkRuntimeEffect;
|
||||||
namespace skgpu { class ShaderErrorHandler; }
|
namespace skgpu { class ShaderErrorHandler; }
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
@@ -85,12 +89,12 @@ struct SK_API ContextOptions {
|
|||||||
bool fSupportBilerpFromGlyphAtlas = false;
|
bool fSupportBilerpFromGlyphAtlas = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable caching of glyph uploads at the start of each Recording. These can add additional
|
* For the moment, if Recordings are replayed in the order they are recorded, then
|
||||||
* overhead and are only necessary if Recordings are replayed or played out of order.
|
* Graphite can make certain assumptions that allow for better performance. Otherwise
|
||||||
*
|
* we have to flush some caches at the start of each Recording to ensure that they can
|
||||||
* Deprecated, now only used to set requireOrderedRecordings Caps.
|
* be played back properly.
|
||||||
*/
|
*/
|
||||||
bool fDisableCachedGlyphUploads = false;
|
bool fRequireOrderedRecordings = false;
|
||||||
|
|
||||||
static constexpr size_t kDefaultContextBudget = 256 * (1 << 20);
|
static constexpr size_t kDefaultContextBudget = 256 * (1 << 20);
|
||||||
/**
|
/**
|
||||||
@@ -118,6 +122,37 @@ struct SK_API ContextOptions {
|
|||||||
*/
|
*/
|
||||||
std::optional<uint64_t> fVulkanVMALargeHeapBlockSize;
|
std::optional<uint64_t> fVulkanVMALargeHeapBlockSize;
|
||||||
|
|
||||||
|
/** Client-provided context that is passed to client-provided PipelineCallback. */
|
||||||
|
using PipelineCallbackContext = void*;
|
||||||
|
/** Client-provided callback that is called whenever Graphite encounters a new Pipeline. */
|
||||||
|
using PipelineCallback = void (*)(PipelineCallbackContext context, sk_sp<SkData> pipelineData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These two members allow a client to register a callback that will be invoked
|
||||||
|
* whenever Graphite encounters a new Pipeline. The callback will be passed an
|
||||||
|
* sk_sp<SkData> that a client can take ownership of and serialize. The SkData
|
||||||
|
* contains all the information Graphite requires to recreate the Pipeline at
|
||||||
|
* a later date. The SkData is versioned however, so must be regenerated and
|
||||||
|
* re-serialized when it becomes out of date.
|
||||||
|
*/
|
||||||
|
PipelineCallbackContext fPipelineCallbackContext = nullptr;
|
||||||
|
PipelineCallback fPipelineCallback = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The runtime effects provided here will be registered as user-defined *known* runtime
|
||||||
|
* effects and will be given a stable key. Such runtime effects can then be used in
|
||||||
|
* serialized pipeline keys (c.f. PrecompileContext::precompile).
|
||||||
|
*
|
||||||
|
* Graphite will take a ref on the provided runtime effects and they will persist for as long
|
||||||
|
* as the Context exists. Rather than recreating new SkRuntimeEffects using the same SkSL,
|
||||||
|
* clients should use the existing SkRuntimeEffects provided here.
|
||||||
|
*
|
||||||
|
* Warning: Registering runtime effects here does obligate users to clear out their caches
|
||||||
|
* of serialized pipeline keys if the provided runtime effects ever change in a meaningful way.
|
||||||
|
* This includes adding, removing or reordering the effects provided here.
|
||||||
|
*/
|
||||||
|
SkSpan<sk_sp<SkRuntimeEffect>> fUserDefinedKnownRuntimeEffects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private options that are only meant for testing within Skia's tools.
|
* Private options that are only meant for testing within Skia's tools.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -30,13 +30,23 @@ class Task;
|
|||||||
using GpuFinishedContext = void*;
|
using GpuFinishedContext = void*;
|
||||||
using GpuFinishedProc = void (*)(GpuFinishedContext finishedContext, CallbackResult);
|
using GpuFinishedProc = void (*)(GpuFinishedContext finishedContext, CallbackResult);
|
||||||
|
|
||||||
|
using GpuFinishedWithStatsProc = void (*)(GpuFinishedContext finishedContext,
|
||||||
|
CallbackResult,
|
||||||
|
const GpuStats&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The fFinishedProc is called when the Recording has been submitted and finished on the GPU, or
|
* The fFinishedProc is called when the Recording has been submitted and finished on the GPU, or
|
||||||
* when there is a failure that caused it not to be submitted. The callback will always be called
|
* when there is a failure that caused it not to be submitted. The callback will always be called
|
||||||
* and the caller can use the callback to know it is safe to free any resources associated with
|
* and the caller can use the callback to know it is safe to free any resources associated with
|
||||||
* the Recording that they may be holding onto. If the Recording is successfully submitted to the
|
* the Recording that they may be holding onto. If the Recording is successfully submitted to the
|
||||||
* GPU the callback will be called with CallbackResult::kSuccess once the GPU has finished. All
|
* GPU the callback will be called with CallbackResult::kSuccess once the GPU has finished. All
|
||||||
* other cases where some failure occured it will be called with CallbackResult::kFailed.
|
* other cases where some failure occurred it will be called with CallbackResult::kFailed.
|
||||||
|
*
|
||||||
|
* Alternatively, the client can provide fFinishedProcWithStats. This provides additional
|
||||||
|
* information about execution of the recording on the GPU. Only the stats requested using
|
||||||
|
* fStatsFlags will be valid and only if CallbackResult is kSuccess. If both fFinishedProc
|
||||||
|
* and fFinishedProcWithStats are provided the latter is preferred and the former won't be
|
||||||
|
* called.
|
||||||
*
|
*
|
||||||
* The fTargetSurface, if provided, is used as a target for any draws recorded onto a deferred
|
* The fTargetSurface, if provided, is used as a target for any draws recorded onto a deferred
|
||||||
* canvas returned from Recorder::makeDeferredCanvas. This target surface must be provided iff
|
* canvas returned from Recorder::makeDeferredCanvas. This target surface must be provided iff
|
||||||
@@ -74,8 +84,10 @@ struct InsertRecordingInfo {
|
|||||||
size_t fNumSignalSemaphores = 0;
|
size_t fNumSignalSemaphores = 0;
|
||||||
BackendSemaphore* fSignalSemaphores = nullptr;
|
BackendSemaphore* fSignalSemaphores = nullptr;
|
||||||
|
|
||||||
|
GpuStatsFlags fGpuStatsFlags = GpuStatsFlags::kNone;
|
||||||
GpuFinishedContext fFinishedContext = nullptr;
|
GpuFinishedContext fFinishedContext = nullptr;
|
||||||
GpuFinishedProc fFinishedProc = nullptr;
|
GpuFinishedProc fFinishedProc = nullptr;
|
||||||
|
GpuFinishedWithStatsProc fFinishedWithStatsProc = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,8 +99,15 @@ struct InsertRecordingInfo {
|
|||||||
* other cases where some failure occured it will be called with CallbackResult::kFailed.
|
* other cases where some failure occured it will be called with CallbackResult::kFailed.
|
||||||
*/
|
*/
|
||||||
struct InsertFinishInfo {
|
struct InsertFinishInfo {
|
||||||
|
InsertFinishInfo() = default;
|
||||||
|
InsertFinishInfo(GpuFinishedContext context, GpuFinishedProc proc)
|
||||||
|
: fFinishedContext{context}, fFinishedProc{proc} {}
|
||||||
|
InsertFinishInfo(GpuFinishedContext context, GpuFinishedWithStatsProc proc)
|
||||||
|
: fFinishedContext{context}, fFinishedWithStatsProc{proc} {}
|
||||||
GpuFinishedContext fFinishedContext = nullptr;
|
GpuFinishedContext fFinishedContext = nullptr;
|
||||||
GpuFinishedProc fFinishedProc = nullptr;
|
GpuFinishedProc fFinishedProc = nullptr;
|
||||||
|
GpuFinishedWithStatsProc fFinishedWithStatsProc = nullptr;
|
||||||
|
GpuStatsFlags fGpuStatsFlags = GpuStatsFlags::kNone;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,44 +140,47 @@ enum class DepthStencilFlags : int {
|
|||||||
*/
|
*/
|
||||||
enum DrawTypeFlags : uint16_t {
|
enum DrawTypeFlags : uint16_t {
|
||||||
|
|
||||||
kNone = 0b000000000,
|
kNone = 0,
|
||||||
|
|
||||||
// kBitmapText_Mask should be used for the BitmapTextRenderStep[mask] RenderStep
|
// kBitmapText_Mask should be used for the BitmapTextRenderStep[mask] RenderStep
|
||||||
kBitmapText_Mask = 0b00000001,
|
kBitmapText_Mask = 1 << 0,
|
||||||
// kBitmapText_LCD should be used for the BitmapTextRenderStep[LCD] RenderStep
|
// kBitmapText_LCD should be used for the BitmapTextRenderStep[LCD] RenderStep
|
||||||
kBitmapText_LCD = 0b00000010,
|
kBitmapText_LCD = 1 << 1,
|
||||||
// kBitmapText_Color should be used for the BitmapTextRenderStep[color] RenderStep
|
// kBitmapText_Color should be used for the BitmapTextRenderStep[color] RenderStep
|
||||||
kBitmapText_Color = 0b00000100,
|
kBitmapText_Color = 1 << 2,
|
||||||
// kSDFText should be used for the SDFTextRenderStep RenderStep
|
// kSDFText should be used for the SDFTextRenderStep RenderStep
|
||||||
kSDFText = 0b00001000,
|
kSDFText = 1 << 3,
|
||||||
// kSDFText_LCD should be used for the SDFTextLCDRenderStep RenderStep
|
// kSDFText_LCD should be used for the SDFTextLCDRenderStep RenderStep
|
||||||
kSDFText_LCD = 0b00010000,
|
kSDFText_LCD = 1 << 4,
|
||||||
|
|
||||||
// kDrawVertices should be used to generate Pipelines that use the following RenderSteps:
|
// kDrawVertices should be used to generate Pipelines that use the following RenderSteps:
|
||||||
// VerticesRenderStep[*] for:
|
// VerticesRenderStep[*] for:
|
||||||
// [tris], [tris-texCoords], [tris-color], [tris-color-texCoords],
|
// [Tris], [TrisTexCoords], [TrisColor], [TrisColorTexCoords],
|
||||||
// [tristrips], [tristrips-texCoords], [tristrips-color], [tristrips-color-texCoords]
|
// [Tristrips], [TristripsTexCoords], [TristripsColor], [TristripsColorTexCoords]
|
||||||
kDrawVertices = 0b00100000,
|
kDrawVertices = 1 << 5,
|
||||||
|
|
||||||
|
// kCircularArc renders filled circular arcs, with or without the center included, and
|
||||||
|
// stroked circular arcs with butt or round caps that don't include the center point.
|
||||||
|
// It corresponds to the CircularArcRenderStep.
|
||||||
|
kCircularArc = 1 << 6,
|
||||||
|
|
||||||
// kSimpleShape should be used to generate Pipelines that use the following RenderSteps:
|
// kSimpleShape should be used to generate Pipelines that use the following RenderSteps:
|
||||||
// AnalyticBlurRenderStep
|
|
||||||
// AnalyticRRectRenderStep
|
// AnalyticRRectRenderStep
|
||||||
// PerEdgeAAQuadRenderStep
|
// PerEdgeAAQuadRenderStep
|
||||||
// CoverBoundsRenderStep[non-aa-fill]
|
// CoverBoundsRenderStep[NonAAFill]
|
||||||
kSimpleShape = 0b01000000,
|
kSimpleShape = 1 << 7,
|
||||||
|
|
||||||
// kNonSimpleShape should be used to generate Pipelines that use the following RenderSteps:
|
// kNonSimpleShape should be used to generate Pipelines that use the following RenderSteps:
|
||||||
// CoverageMaskRenderStep
|
// CoverageMaskRenderStep
|
||||||
// CoverBoundsRenderStep[*] for [inverse-cover], [regular-cover]
|
// CoverBoundsRenderStep[*] for [InverseCover], [RegularCover]
|
||||||
// TessellateStrokeRenderStep
|
// TessellateStrokeRenderStep
|
||||||
// TessellateWedgesRenderStep[*] for [convex], [evenodd], [winding]
|
// TessellateWedgesRenderStep[*] for [Convex], [EvenOdd], [Winding]
|
||||||
// TessellateCurvesRenderStep[*] for [even-odd], [winding]
|
// TessellateCurvesRenderStep[*] for [EvenOdd], [Winding]
|
||||||
// MiddleOutFanRenderStep[*] for [even-odd], [winding]
|
// MiddleOutFanRenderStep[*] for [EvenOdd], [Winding]
|
||||||
kNonSimpleShape = 0b10000000,
|
kNonSimpleShape = 1 << 8,
|
||||||
|
|
||||||
kLast = kNonSimpleShape,
|
kLast = kNonSimpleShape,
|
||||||
};
|
};
|
||||||
static constexpr int kDrawTypeFlagsCnt = static_cast<int>(DrawTypeFlags::kLast) + 1;
|
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "include/gpu/GpuTypes.h"
|
#include "include/gpu/GpuTypes.h"
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
class SkYUVAInfo;
|
class SkYUVAInfo;
|
||||||
class SkYUVAPixmaps;
|
class SkYUVAPixmaps;
|
||||||
|
|||||||
36
gfx/skia/skia/include/gpu/graphite/LogPriority.h
Normal file
36
gfx/skia/skia/include/gpu/graphite/LogPriority.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef skgpu_graphite_LogPriority_DEFINED
|
||||||
|
#define skgpu_graphite_LogPriority_DEFINED
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: this file may be included in clients' SkUserConfig.h files, so including any other headers
|
||||||
|
* in this file should be avoided.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace skgpu::graphite {
|
||||||
|
/**
|
||||||
|
* SKGPU_GRAPHITE_LOWEST_ACTIVE_LOG_PRIORITY can be defined to one of these values (in
|
||||||
|
* SkUserConfig.h) to control Graphite's logging behavior.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* ```
|
||||||
|
* #define SKGPU_GRAPHITE_LOWEST_ACTIVE_LOG_PRIORITY skgpu::graphite::LogPriority::kWarning
|
||||||
|
* ```
|
||||||
|
* Would cause Graphite to log warnings, non-fatal errors, and fatal errors.
|
||||||
|
* However, debug logs would be omitted.
|
||||||
|
*/
|
||||||
|
enum class LogPriority : int {
|
||||||
|
kFatal = 0,
|
||||||
|
kError = 1,
|
||||||
|
kWarning = 2,
|
||||||
|
kDebug = 3,
|
||||||
|
};
|
||||||
|
}; // namespace skgpu::graphite
|
||||||
|
|
||||||
|
#endif // skgpu_graphite_LogPriority_DEFINED
|
||||||
76
gfx/skia/skia/include/gpu/graphite/PrecompileContext.h
Normal file
76
gfx/skia/skia/include/gpu/graphite/PrecompileContext.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef skgpu_graphite_PrecompileContext_DEFINED
|
||||||
|
#define skgpu_graphite_PrecompileContext_DEFINED
|
||||||
|
|
||||||
|
#include "include/core/SkRefCnt.h"
|
||||||
|
#include "include/private/base/SingleOwner.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class SkData;
|
||||||
|
|
||||||
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
|
class SharedContext;
|
||||||
|
class PrecompileContextPriv;
|
||||||
|
class ResourceProvider;
|
||||||
|
|
||||||
|
class SK_API PrecompileContext {
|
||||||
|
public:
|
||||||
|
~PrecompileContext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge Pipelines that haven't been used in the past 'msNotUsed' milliseconds
|
||||||
|
* regardless of whether the pipeline cache is under budget.
|
||||||
|
*
|
||||||
|
* @param msNotUsed Pipelines not used in these last milliseconds will be cleaned up.
|
||||||
|
*/
|
||||||
|
void purgePipelinesNotUsedInMs(std::chrono::milliseconds msNotUsed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit histograms (using the SK_HISTOGRAM* macros) for Skia's Pipeline usage.
|
||||||
|
*/
|
||||||
|
void reportPipelineStats();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Precompile one specific Pipeline that has been previously serialized. Serialized pipeline
|
||||||
|
* keys can be acquired via the ContextOptions::PipelineCallback.
|
||||||
|
*
|
||||||
|
* @param serializedPipelineKey serialized Pipeline key.
|
||||||
|
* @return true if a Pipeline was created from the key; false otherwise
|
||||||
|
*/
|
||||||
|
bool precompile(sk_sp<SkData> serializedPipelineKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a human-readable version of a serialized pipeline key.
|
||||||
|
*
|
||||||
|
* @param serializedPipelineKey serialized Pipeline key.
|
||||||
|
* @return A human-readable version of the provided key; "" on failure.
|
||||||
|
*/
|
||||||
|
std::string getPipelineLabel(sk_sp<SkData> serializedPipelineKey);
|
||||||
|
|
||||||
|
// Provides access to functions that aren't part of the public API.
|
||||||
|
PrecompileContextPriv priv();
|
||||||
|
const PrecompileContextPriv priv() const; // NOLINT(readability-const-return-type)
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class PrecompileContextPriv;
|
||||||
|
friend class Context; // for ctor
|
||||||
|
|
||||||
|
PrecompileContext(sk_sp<SharedContext>);
|
||||||
|
|
||||||
|
mutable SingleOwner fSingleOwner;
|
||||||
|
sk_sp<SharedContext> fSharedContext;
|
||||||
|
std::unique_ptr<ResourceProvider> fResourceProvider;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
|
#endif // skgpu_graphite_PrecompileContext_DEFINED
|
||||||
@@ -209,6 +209,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
size_t maxBudgetedBytes() const;
|
size_t maxBudgetedBytes() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the size of Recorders's gpu memory cache budget in bytes. If the new budget is lower
|
||||||
|
* than the current budget, the cache will try to free resources to get under the new budget.
|
||||||
|
*/
|
||||||
|
void setMaxBudgetedBytes(size_t bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerates all cached GPU resources owned by the Recorder and dumps their memory to
|
* Enumerates all cached GPU resources owned by the Recorder and dumps their memory to
|
||||||
* traceMemoryDump.
|
* traceMemoryDump.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define skgpu_graphite_Recording_DEFINED
|
#define skgpu_graphite_Recording_DEFINED
|
||||||
|
|
||||||
#include "include/core/SkRefCnt.h"
|
#include "include/core/SkRefCnt.h"
|
||||||
|
#include "include/core/SkSize.h"
|
||||||
#include "include/private/base/SkTArray.h"
|
#include "include/private/base/SkTArray.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -21,6 +22,7 @@ class RefCntedCallback;
|
|||||||
|
|
||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
|
class Caps;
|
||||||
class CommandBuffer;
|
class CommandBuffer;
|
||||||
class RecordingPriv;
|
class RecordingPriv;
|
||||||
class Resource;
|
class Resource;
|
||||||
@@ -44,7 +46,7 @@ private:
|
|||||||
// replay, and it handles the target proxy's instantiation with the provided target.
|
// replay, and it handles the target proxy's instantiation with the provided target.
|
||||||
class LazyProxyData {
|
class LazyProxyData {
|
||||||
public:
|
public:
|
||||||
LazyProxyData(const TextureInfo&);
|
LazyProxyData(const Caps*, SkISize dimensions, const TextureInfo&);
|
||||||
|
|
||||||
TextureProxy* lazyProxy();
|
TextureProxy* lazyProxy();
|
||||||
sk_sp<TextureProxy> refLazyProxy();
|
sk_sp<TextureProxy> refLazyProxy();
|
||||||
|
|||||||
@@ -18,70 +18,115 @@ struct SkISize;
|
|||||||
|
|
||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
class TextureInfoData;
|
enum class TextureFormat : uint8_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TextureInfo is a backend-agnostic wrapper around the properties of a texture, sans dimensions.
|
||||||
|
* It is designed this way to be compilable w/o bringing in a specific backend's build files, and
|
||||||
|
* without requiring heap allocations of virtual types.
|
||||||
|
*/
|
||||||
class SK_API TextureInfo {
|
class SK_API TextureInfo {
|
||||||
|
private:
|
||||||
|
class Data;
|
||||||
|
friend class MtlTextureInfo;
|
||||||
|
friend class DawnTextureInfo;
|
||||||
|
friend class VulkanTextureInfo;
|
||||||
|
|
||||||
|
// Size is the largest of the Data subclasses assuming a 64-bit compiler.
|
||||||
|
inline constexpr static size_t kMaxSubclassSize = 112;
|
||||||
|
using AnyTextureInfoData = SkAnySubclass<Data, kMaxSubclassSize>;
|
||||||
|
|
||||||
|
// Base properties for all backend-specific properties. Clients managing textures directly
|
||||||
|
// should use the public subclasses of Data directly, e.g. MtlTextureInfo/DawnTextureInfo.
|
||||||
|
//
|
||||||
|
// Each backend subclass must expose to TextureInfo[Priv]:
|
||||||
|
// static constexpr BackendApi kBackend;
|
||||||
|
// Protected isProtected() const;
|
||||||
|
// TextureFormat viewFormat() const;
|
||||||
|
// bool serialize(SkWStream*) const;
|
||||||
|
// bool deserialize(SkStream*);
|
||||||
|
class Data {
|
||||||
|
public:
|
||||||
|
virtual ~Data() = default;
|
||||||
|
|
||||||
|
Data(uint32_t sampleCount, skgpu::Mipmapped mipmapped)
|
||||||
|
: fSampleCount(sampleCount)
|
||||||
|
, fMipmapped(mipmapped) {}
|
||||||
|
|
||||||
|
Data() = default;
|
||||||
|
Data(const Data&) = default;
|
||||||
|
|
||||||
|
Data& operator=(const Data&) = default;
|
||||||
|
|
||||||
|
// NOTE: These fields are accessible via the backend-specific subclasses.
|
||||||
|
uint32_t fSampleCount = 1;
|
||||||
|
Mipmapped fMipmapped = Mipmapped::kNo;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class TextureInfo;
|
||||||
|
friend class TextureInfoPriv;
|
||||||
|
|
||||||
|
virtual SkString toBackendString() const = 0;
|
||||||
|
|
||||||
|
virtual void copyTo(AnyTextureInfoData&) const = 0;
|
||||||
|
// Passed in TextureInfo will have data of the same backend type and subclass, and
|
||||||
|
// base properties of Data have already been checked for equality/compatibility.
|
||||||
|
virtual bool isCompatible(const TextureInfo& that, bool requireExact) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TextureInfo();
|
TextureInfo() = default;
|
||||||
~TextureInfo();
|
~TextureInfo() = default;
|
||||||
|
|
||||||
TextureInfo(const TextureInfo&);
|
TextureInfo(const TextureInfo&);
|
||||||
TextureInfo& operator=(const TextureInfo&);
|
TextureInfo& operator=(const TextureInfo&);
|
||||||
|
|
||||||
bool operator==(const TextureInfo&) const;
|
bool operator==(const TextureInfo& that) const {
|
||||||
|
return this->isCompatible(that, /*requireExact=*/true);
|
||||||
|
}
|
||||||
bool operator!=(const TextureInfo& that) const { return !(*this == that); }
|
bool operator!=(const TextureInfo& that) const { return !(*this == that); }
|
||||||
|
|
||||||
bool isValid() const { return fValid; }
|
bool isValid() const { return fData.has_value(); }
|
||||||
BackendApi backend() const { return fBackend; }
|
BackendApi backend() const {
|
||||||
|
SkASSERT(fData.has_value() || fBackend == BackendApi::kUnsupported);
|
||||||
uint32_t numSamples() const { return fSampleCount; }
|
return fBackend;
|
||||||
Mipmapped mipmapped() const { return fMipmapped; }
|
|
||||||
Protected isProtected() const { return fProtected; }
|
|
||||||
SkTextureCompressionType compressionType() const;
|
|
||||||
bool isMemoryless() const;
|
|
||||||
|
|
||||||
bool isCompatible(const TextureInfo& that) const;
|
|
||||||
// Return a string containing the full description of this TextureInfo.
|
|
||||||
SkString toString() const;
|
|
||||||
// Return a string containing only the info relevant for its use as a RenderPass attachment.
|
|
||||||
SkString toRPAttachmentString() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class TextureInfoData;
|
|
||||||
friend class TextureInfoPriv;
|
|
||||||
|
|
||||||
// Size determined by looking at the TextureInfoData subclasses, then guessing-and-checking.
|
|
||||||
// Compiler will complain if this is too small - in that case, just increase the number.
|
|
||||||
inline constexpr static size_t kMaxSubclassSize = 112;
|
|
||||||
using AnyTextureInfoData = SkAnySubclass<TextureInfoData, kMaxSubclassSize>;
|
|
||||||
|
|
||||||
template <typename SomeTextureInfoData>
|
|
||||||
TextureInfo(BackendApi backend,
|
|
||||||
uint32_t sampleCount,
|
|
||||||
skgpu::Mipmapped mipped,
|
|
||||||
skgpu::Protected isProtected,
|
|
||||||
const SomeTextureInfoData& textureInfoData)
|
|
||||||
: fBackend(backend)
|
|
||||||
, fValid(true)
|
|
||||||
, fSampleCount(sampleCount)
|
|
||||||
, fMipmapped(mipped)
|
|
||||||
, fProtected(isProtected) {
|
|
||||||
fTextureInfoData.emplace<SomeTextureInfoData>(textureInfoData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
friend size_t ComputeSize(SkISize dimensions, const TextureInfo&); // for bytesPerPixel
|
uint32_t numSamples() const { return fData.has_value() ? fData->fSampleCount : 1; }
|
||||||
|
Mipmapped mipmapped() const { return fData.has_value() ? fData->fMipmapped : Mipmapped::kNo; }
|
||||||
|
Protected isProtected() const { return fProtected; }
|
||||||
|
|
||||||
size_t bytesPerPixel() const;
|
// Return true if `that` describes a texture that is compatible with this info and can validly
|
||||||
|
// be used to fulfill a promise image that was created with this TextureInfo.
|
||||||
|
bool canBeFulfilledBy(const TextureInfo& that) const {
|
||||||
|
return this->isCompatible(that, /*requireExact=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
BackendApi fBackend = BackendApi::kMock;
|
// Return a string containing the full description of this TextureInfo.
|
||||||
bool fValid = false;
|
SkString toString() const;
|
||||||
|
|
||||||
uint32_t fSampleCount = 1;
|
private:
|
||||||
Mipmapped fMipmapped = Mipmapped::kNo;
|
friend class TextureInfoPriv;
|
||||||
|
|
||||||
|
template <typename BackendTextureData,
|
||||||
|
std::enable_if_t<std::is_base_of_v<Data, BackendTextureData>, bool> = true>
|
||||||
|
explicit TextureInfo(const BackendTextureData& data)
|
||||||
|
: fBackend(BackendTextureData::kBackend)
|
||||||
|
, fViewFormat(data.viewFormat())
|
||||||
|
, fProtected(data.isProtected()) {
|
||||||
|
fData.emplace<BackendTextureData>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCompatible(const TextureInfo& that, bool requireExact) const;
|
||||||
|
|
||||||
|
skgpu::BackendApi fBackend = BackendApi::kUnsupported;
|
||||||
|
AnyTextureInfoData fData;
|
||||||
|
|
||||||
|
// Derived properties from the backend data, cached to avoid a virtual function call
|
||||||
|
TextureFormat fViewFormat;
|
||||||
Protected fProtected = Protected::kNo;
|
Protected fProtected = Protected::kNo;
|
||||||
|
|
||||||
AnyTextureInfoData fTextureInfoData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
#endif //skgpu_graphite_TextureInfo_DEFINED
|
#endif // skgpu_graphite_TextureInfo_DEFINED
|
||||||
|
|||||||
@@ -37,10 +37,15 @@ public:
|
|||||||
* by Mipmapped. This will produce an invalid result (return false from isValid()) if the
|
* by Mipmapped. This will produce an invalid result (return false from isValid()) if the
|
||||||
* passed formats' channels don't agree with SkYUVAInfo.
|
* passed formats' channels don't agree with SkYUVAInfo.
|
||||||
*/
|
*/
|
||||||
YUVABackendTextureInfo(const Recorder*,
|
YUVABackendTextureInfo(const SkYUVAInfo&,
|
||||||
const SkYUVAInfo&,
|
|
||||||
SkSpan<const TextureInfo>,
|
SkSpan<const TextureInfo>,
|
||||||
Mipmapped);
|
Mipmapped);
|
||||||
|
// DEPRECATED: No more need for a Recorder to construct YUVABackendTextureInfo
|
||||||
|
YUVABackendTextureInfo(Recorder*,
|
||||||
|
const SkYUVAInfo& yuvaInfo,
|
||||||
|
SkSpan<const TextureInfo> textures,
|
||||||
|
Mipmapped mipmapped)
|
||||||
|
: YUVABackendTextureInfo(yuvaInfo, textures, mipmapped) {}
|
||||||
|
|
||||||
bool operator==(const YUVABackendTextureInfo&) const;
|
bool operator==(const YUVABackendTextureInfo&) const;
|
||||||
bool operator!=(const YUVABackendTextureInfo& that) const { return !(*this == that); }
|
bool operator!=(const YUVABackendTextureInfo& that) const { return !(*this == that); }
|
||||||
@@ -95,9 +100,13 @@ public:
|
|||||||
* indicated by the SkYUVAInfo. This will produce an invalid result (return false from
|
* indicated by the SkYUVAInfo. This will produce an invalid result (return false from
|
||||||
* isValid()) if the passed texture formats' channels don't agree with SkYUVAInfo.
|
* isValid()) if the passed texture formats' channels don't agree with SkYUVAInfo.
|
||||||
*/
|
*/
|
||||||
YUVABackendTextures(const Recorder*,
|
YUVABackendTextures(const SkYUVAInfo&,
|
||||||
const SkYUVAInfo&,
|
|
||||||
SkSpan<const BackendTexture>);
|
SkSpan<const BackendTexture>);
|
||||||
|
// DEPRECATED: No more need for a Recorder to construct YUVABackendTextureInfo
|
||||||
|
YUVABackendTextures(Recorder*,
|
||||||
|
const SkYUVAInfo& yuvaInfo,
|
||||||
|
SkSpan<const BackendTexture> textures)
|
||||||
|
: YUVABackendTextures(yuvaInfo, textures) {}
|
||||||
|
|
||||||
SkSpan<const BackendTexture> planeTextures() const {
|
SkSpan<const BackendTexture> planeTextures() const {
|
||||||
return SkSpan<const BackendTexture>(fPlaneTextures);
|
return SkSpan<const BackendTexture>(fPlaneTextures);
|
||||||
|
|||||||
@@ -11,8 +11,13 @@
|
|||||||
#include "include/core/SkTypes.h"
|
#include "include/core/SkTypes.h"
|
||||||
#include "webgpu/webgpu_cpp.h" // NO_G3_REWRITE
|
#include "webgpu/webgpu_cpp.h" // NO_G3_REWRITE
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
|
class Context;
|
||||||
|
struct ContextOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebGPU needs to allow the main thread loop to run to detect GPU progress. Dawn native has a
|
* WebGPU needs to allow the main thread loop to run to detect GPU progress. Dawn native has a
|
||||||
* function wgpu::Instance::ProcessEvents, not (currently) present in WebGPU, that can be used to
|
* function wgpu::Instance::ProcessEvents, not (currently) present in WebGPU, that can be used to
|
||||||
@@ -63,6 +68,10 @@ struct SK_API DawnBackendContext {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace ContextFactory {
|
||||||
|
SK_API std::unique_ptr<Context> MakeDawn(const DawnBackendContext&, const ContextOptions&);
|
||||||
|
} // namespace ContextFactory
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
#endif // skgpu_graphite_DawnBackendContext_DEFINED
|
#endif // skgpu_graphite_DawnBackendContext_DEFINED
|
||||||
|
|||||||
166
gfx/skia/skia/include/gpu/graphite/dawn/DawnGraphiteTypes.h
Normal file
166
gfx/skia/skia/include/gpu/graphite/dawn/DawnGraphiteTypes.h
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef skgpu_graphite_DawnTypes_DEFINED
|
||||||
|
#define skgpu_graphite_DawnTypes_DEFINED
|
||||||
|
|
||||||
|
#include "include/core/SkSize.h"
|
||||||
|
#include "include/gpu/graphite/GraphiteTypes.h"
|
||||||
|
#include "include/gpu/graphite/TextureInfo.h"
|
||||||
|
#include "include/private/base/SkAPI.h"
|
||||||
|
|
||||||
|
#include "webgpu/webgpu_cpp.h" // NO_G3_REWRITE
|
||||||
|
|
||||||
|
class SkStream;
|
||||||
|
class SkWStream;
|
||||||
|
|
||||||
|
namespace skgpu::graphite {
|
||||||
|
class BackendTexture;
|
||||||
|
|
||||||
|
class SK_API DawnTextureInfo final : public TextureInfo::Data {
|
||||||
|
public:
|
||||||
|
// wgpu::TextureDescriptor properties
|
||||||
|
wgpu::TextureFormat fFormat = wgpu::TextureFormat::Undefined;
|
||||||
|
// `fViewFormat` for multiplanar formats corresponds to the plane TextureView's format.
|
||||||
|
wgpu::TextureFormat fViewFormat = wgpu::TextureFormat::Undefined;
|
||||||
|
wgpu::TextureUsage fUsage = wgpu::TextureUsage::None;
|
||||||
|
// TODO(b/308944094): Migrate aspect information to BackendTextureViews.
|
||||||
|
wgpu::TextureAspect fAspect = wgpu::TextureAspect::All;
|
||||||
|
uint32_t fSlice = 0;
|
||||||
|
|
||||||
|
#if !defined(__EMSCRIPTEN__)
|
||||||
|
// The descriptor of the YCbCr info (if any) for this texture. Dawn's YCbCr
|
||||||
|
// sampling will be used for this texture if this info is set. Setting the
|
||||||
|
// info is supported only on Android and only if using Vulkan as the
|
||||||
|
// underlying GPU driver.
|
||||||
|
wgpu::YCbCrVkDescriptor fYcbcrVkDescriptor = {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
wgpu::TextureFormat getViewFormat() const {
|
||||||
|
return fViewFormat != wgpu::TextureFormat::Undefined ? fViewFormat : fFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
DawnTextureInfo() = default;
|
||||||
|
|
||||||
|
DawnTextureInfo(WGPUTexture texture);
|
||||||
|
|
||||||
|
DawnTextureInfo(uint32_t sampleCount,
|
||||||
|
Mipmapped mipmapped,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
wgpu::TextureUsage usage,
|
||||||
|
wgpu::TextureAspect aspect)
|
||||||
|
: DawnTextureInfo(sampleCount,
|
||||||
|
mipmapped,
|
||||||
|
/*format=*/format,
|
||||||
|
/*viewFormat=*/format,
|
||||||
|
usage,
|
||||||
|
aspect,
|
||||||
|
/*slice=*/0) {}
|
||||||
|
|
||||||
|
DawnTextureInfo(uint32_t sampleCount,
|
||||||
|
Mipmapped mipmapped,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
wgpu::TextureFormat viewFormat,
|
||||||
|
wgpu::TextureUsage usage,
|
||||||
|
wgpu::TextureAspect aspect,
|
||||||
|
uint32_t slice)
|
||||||
|
: Data(sampleCount, mipmapped)
|
||||||
|
, fFormat(format)
|
||||||
|
, fViewFormat(viewFormat)
|
||||||
|
, fUsage(usage)
|
||||||
|
, fAspect(aspect)
|
||||||
|
, fSlice(slice) {}
|
||||||
|
|
||||||
|
#if !defined(__EMSCRIPTEN__)
|
||||||
|
DawnTextureInfo(uint32_t sampleCount,
|
||||||
|
Mipmapped mipmapped,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
wgpu::TextureFormat viewFormat,
|
||||||
|
wgpu::TextureUsage usage,
|
||||||
|
wgpu::TextureAspect aspect,
|
||||||
|
uint32_t slice,
|
||||||
|
wgpu::YCbCrVkDescriptor ycbcrVkDescriptor)
|
||||||
|
: Data(sampleCount, mipmapped)
|
||||||
|
, fFormat(format)
|
||||||
|
, fViewFormat(viewFormat)
|
||||||
|
, fUsage(usage)
|
||||||
|
, fAspect(aspect)
|
||||||
|
, fSlice(slice)
|
||||||
|
, fYcbcrVkDescriptor(ycbcrVkDescriptor) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class TextureInfo;
|
||||||
|
friend class TextureInfoPriv;
|
||||||
|
|
||||||
|
// Non-virtual template API for TextureInfo::Data accessed directly when backend type is known.
|
||||||
|
static constexpr skgpu::BackendApi kBackend = skgpu::BackendApi::kDawn;
|
||||||
|
|
||||||
|
Protected isProtected() const { return Protected::kNo; }
|
||||||
|
TextureFormat viewFormat() const;
|
||||||
|
|
||||||
|
bool serialize(SkWStream*) const;
|
||||||
|
bool deserialize(SkStream*);
|
||||||
|
|
||||||
|
// Virtual API when the specific backend type is not available.
|
||||||
|
SkString toBackendString() const override;
|
||||||
|
|
||||||
|
void copyTo(TextureInfo::AnyTextureInfoData& dstData) const override {
|
||||||
|
dstData.emplace<DawnTextureInfo>(*this);
|
||||||
|
}
|
||||||
|
bool isCompatible(const TextureInfo& that, bool requireExact) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace TextureInfos {
|
||||||
|
SK_API TextureInfo MakeDawn(const DawnTextureInfo& dawnInfo);
|
||||||
|
|
||||||
|
SK_API bool GetDawnTextureInfo(const TextureInfo&, DawnTextureInfo*);
|
||||||
|
} // namespace TextureInfos
|
||||||
|
|
||||||
|
namespace BackendTextures {
|
||||||
|
// Create a BackendTexture from a WGPUTexture. Texture info will be queried from the texture.
|
||||||
|
//
|
||||||
|
// This is the recommended way of specifying a BackendTexture for Dawn. See the note below on
|
||||||
|
// the constructor that takes a WGPUTextureView for a fuller explanation.
|
||||||
|
//
|
||||||
|
// The BackendTexture will not call retain or release on the passed in WGPUTexture. Thus, the
|
||||||
|
// client must keep the WGPUTexture valid until they are no longer using the BackendTexture.
|
||||||
|
// However, any SkImage or SkSurface that wraps the BackendTexture *will* retain and release
|
||||||
|
// the WGPUTexture.
|
||||||
|
SK_API BackendTexture MakeDawn(WGPUTexture);
|
||||||
|
|
||||||
|
// Create a BackendTexture from a WGPUTexture. Texture planeDimensions, plane aspect and
|
||||||
|
// info have to be provided. This is intended to be used only when accessing a plane
|
||||||
|
// of a WGPUTexture.
|
||||||
|
//
|
||||||
|
// The BackendTexture will not call retain or release on the passed in WGPUTexture. Thus, the
|
||||||
|
// client must keep the WGPUTexture valid until they are no longer using the BackendTexture.
|
||||||
|
// However, any SkImage or SkSurface that wraps the BackendTexture *will* retain and release
|
||||||
|
// the WGPUTexture.
|
||||||
|
SK_API BackendTexture MakeDawn(SkISize planeDimensions, const DawnTextureInfo&, WGPUTexture);
|
||||||
|
|
||||||
|
// Create a BackendTexture from a WGPUTextureView. Texture dimensions and
|
||||||
|
// info have to be provided.
|
||||||
|
//
|
||||||
|
// Using a WGPUTextureView rather than a WGPUTexture is less effecient for operations that
|
||||||
|
// require buffer transfers to or from the texture (e.g. methods on graphite::Context that read
|
||||||
|
// pixels or SkSurface::writePixels). In such cases an intermediate copy to or from a
|
||||||
|
// WGPUTexture is required. Thus, it is recommended to use this functionality only for cases
|
||||||
|
// where a WGPUTexture is unavailable, in particular when using wgpu::SwapChain.
|
||||||
|
//
|
||||||
|
// The BackendTexture will not call retain or release on the passed in WGPUTextureView. Thus,
|
||||||
|
// the client must keep the WGPUTextureView valid until they are no longer using the
|
||||||
|
// BackendTexture. However, any SkImage or SkSurface that wraps the BackendTexture *will* retain
|
||||||
|
// and release the WGPUTextureView.
|
||||||
|
SK_API BackendTexture MakeDawn(SkISize dimensions,
|
||||||
|
const DawnTextureInfo& info,
|
||||||
|
WGPUTextureView textureView);
|
||||||
|
} // namespace BackendTextures
|
||||||
|
|
||||||
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
|
#endif // skgpu_graphite_DawnTypes_DEFINED
|
||||||
@@ -1,147 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 Google LLC.
|
* Copyright 2022 Google LLC
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef skgpu_graphite_DawnTypes_DEFINED
|
// DEPRECRATED: DawnTypes.h will be removed in the future, please include DawnGraphiteTypes.h
|
||||||
#define skgpu_graphite_DawnTypes_DEFINED
|
#include "include/gpu/graphite/dawn/DawnGraphiteTypes.h"
|
||||||
|
|
||||||
#include "include/core/SkSize.h"
|
|
||||||
#include "include/gpu/graphite/GraphiteTypes.h"
|
|
||||||
#include "include/private/base/SkAPI.h"
|
|
||||||
|
|
||||||
#include "webgpu/webgpu_cpp.h" // NO_G3_REWRITE
|
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
|
||||||
class BackendTexture;
|
|
||||||
class TextureInfo;
|
|
||||||
|
|
||||||
struct DawnTextureInfo {
|
|
||||||
uint32_t fSampleCount = 1;
|
|
||||||
Mipmapped fMipmapped = Mipmapped::kNo;
|
|
||||||
|
|
||||||
// wgpu::TextureDescriptor properties
|
|
||||||
wgpu::TextureFormat fFormat = wgpu::TextureFormat::Undefined;
|
|
||||||
// `fViewFormat` for multiplanar formats corresponds to the plane TextureView's format.
|
|
||||||
wgpu::TextureFormat fViewFormat = wgpu::TextureFormat::Undefined;
|
|
||||||
wgpu::TextureUsage fUsage = wgpu::TextureUsage::None;
|
|
||||||
// TODO(b/308944094): Migrate aspect information to BackendTextureViews.
|
|
||||||
wgpu::TextureAspect fAspect = wgpu::TextureAspect::All;
|
|
||||||
uint32_t fSlice = 0;
|
|
||||||
|
|
||||||
#if !defined(__EMSCRIPTEN__)
|
|
||||||
// The descriptor of the YCbCr info (if any) for this texture. Dawn's YCbCr
|
|
||||||
// sampling will be used for this texture if this info is set. Setting the
|
|
||||||
// info is supported only on Android and only if using Vulkan as the
|
|
||||||
// underlying GPU driver.
|
|
||||||
wgpu::YCbCrVkDescriptor fYcbcrVkDescriptor = {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wgpu::TextureFormat getViewFormat() const {
|
|
||||||
return fViewFormat != wgpu::TextureFormat::Undefined ? fViewFormat : fFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
DawnTextureInfo() = default;
|
|
||||||
|
|
||||||
DawnTextureInfo(uint32_t sampleCount,
|
|
||||||
Mipmapped mipmapped,
|
|
||||||
wgpu::TextureFormat format,
|
|
||||||
wgpu::TextureUsage usage,
|
|
||||||
wgpu::TextureAspect aspect)
|
|
||||||
: DawnTextureInfo(sampleCount,
|
|
||||||
mipmapped,
|
|
||||||
/*format=*/format,
|
|
||||||
/*viewFormat=*/format,
|
|
||||||
usage,
|
|
||||||
aspect,
|
|
||||||
/*slice=*/0) {}
|
|
||||||
|
|
||||||
DawnTextureInfo(uint32_t sampleCount,
|
|
||||||
Mipmapped mipmapped,
|
|
||||||
wgpu::TextureFormat format,
|
|
||||||
wgpu::TextureFormat viewFormat,
|
|
||||||
wgpu::TextureUsage usage,
|
|
||||||
wgpu::TextureAspect aspect,
|
|
||||||
uint32_t slice)
|
|
||||||
: fSampleCount(sampleCount)
|
|
||||||
, fMipmapped(mipmapped)
|
|
||||||
, fFormat(format)
|
|
||||||
, fViewFormat(viewFormat)
|
|
||||||
, fUsage(usage)
|
|
||||||
, fAspect(aspect)
|
|
||||||
, fSlice(slice) {}
|
|
||||||
|
|
||||||
#if !defined(__EMSCRIPTEN__)
|
|
||||||
DawnTextureInfo(uint32_t sampleCount,
|
|
||||||
Mipmapped mipmapped,
|
|
||||||
wgpu::TextureFormat format,
|
|
||||||
wgpu::TextureFormat viewFormat,
|
|
||||||
wgpu::TextureUsage usage,
|
|
||||||
wgpu::TextureAspect aspect,
|
|
||||||
uint32_t slice,
|
|
||||||
wgpu::YCbCrVkDescriptor ycbcrVkDescriptor)
|
|
||||||
: fSampleCount(sampleCount)
|
|
||||||
, fMipmapped(mipmapped)
|
|
||||||
, fFormat(format)
|
|
||||||
, fViewFormat(viewFormat)
|
|
||||||
, fUsage(usage)
|
|
||||||
, fAspect(aspect)
|
|
||||||
, fSlice(slice)
|
|
||||||
, fYcbcrVkDescriptor(ycbcrVkDescriptor) {}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace TextureInfos {
|
|
||||||
SK_API TextureInfo MakeDawn(const DawnTextureInfo& dawnInfo);
|
|
||||||
|
|
||||||
SK_API bool GetDawnTextureInfo(const TextureInfo&, DawnTextureInfo*);
|
|
||||||
} // namespace TextureInfos
|
|
||||||
|
|
||||||
namespace BackendTextures {
|
|
||||||
// Create a BackendTexture from a WGPUTexture. Texture info will be queried from the texture.
|
|
||||||
//
|
|
||||||
// This is the recommended way of specifying a BackendTexture for Dawn. See the note below on
|
|
||||||
// the constructor that takes a WGPUTextureView for a fuller explanation.
|
|
||||||
//
|
|
||||||
// The BackendTexture will not call retain or release on the passed in WGPUTexture. Thus, the
|
|
||||||
// client must keep the WGPUTexture valid until they are no longer using the BackendTexture.
|
|
||||||
// However, any SkImage or SkSurface that wraps the BackendTexture *will* retain and release
|
|
||||||
// the WGPUTexture.
|
|
||||||
SK_API BackendTexture MakeDawn(WGPUTexture);
|
|
||||||
|
|
||||||
// Create a BackendTexture from a WGPUTexture. Texture planeDimensions, plane aspect and
|
|
||||||
// info have to be provided. This is intended to be used only when accessing a plane
|
|
||||||
// of a WGPUTexture.
|
|
||||||
//
|
|
||||||
// The BackendTexture will not call retain or release on the passed in WGPUTexture. Thus, the
|
|
||||||
// client must keep the WGPUTexture valid until they are no longer using the BackendTexture.
|
|
||||||
// However, any SkImage or SkSurface that wraps the BackendTexture *will* retain and release
|
|
||||||
// the WGPUTexture.
|
|
||||||
SK_API BackendTexture MakeDawn(SkISize planeDimensions, const DawnTextureInfo&, WGPUTexture);
|
|
||||||
|
|
||||||
// Create a BackendTexture from a WGPUTextureView. Texture dimensions and
|
|
||||||
// info have to be provided.
|
|
||||||
//
|
|
||||||
// Using a WGPUTextureView rather than a WGPUTexture is less effecient for operations that
|
|
||||||
// require buffer transfers to or from the texture (e.g. methods on graphite::Context that read
|
|
||||||
// pixels or SkSurface::writePixels). In such cases an intermediate copy to or from a
|
|
||||||
// WGPUTexture is required. Thus, it is recommended to use this functionality only for cases
|
|
||||||
// where a WGPUTexture is unavailable, in particular when using wgpu::SwapChain.
|
|
||||||
//
|
|
||||||
// The BackendTexture will not call retain or release on the passed in WGPUTextureView. Thus,
|
|
||||||
// the client must keep the WGPUTextureView valid until they are no longer using the
|
|
||||||
// BackendTexture. However, any SkImage or SkSurface that wraps the BackendTexture *will* retain
|
|
||||||
// and release the WGPUTextureView.
|
|
||||||
SK_API BackendTexture MakeDawn(SkISize dimensions,
|
|
||||||
const DawnTextureInfo& info,
|
|
||||||
WGPUTextureView textureView);
|
|
||||||
|
|
||||||
} // namespace BackendTextures
|
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
|
||||||
|
|
||||||
#endif // skgpu_graphite_DawnTypes_DEFINED
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,24 +5,5 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef skgpu_graphite_DawnUtils_DEFINED
|
// DEPRECRATED: DawnUtils.h will be removed in the future, please include DawnBackendContext.h
|
||||||
#define skgpu_graphite_DawnUtils_DEFINED
|
#include "include/gpu/graphite/dawn/DawnBackendContext.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "include/private/base/SkAPI.h"
|
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
|
||||||
|
|
||||||
class Context;
|
|
||||||
struct ContextOptions;
|
|
||||||
struct DawnBackendContext;
|
|
||||||
|
|
||||||
namespace ContextFactory {
|
|
||||||
SK_API std::unique_ptr<Context> MakeDawn(const DawnBackendContext&, const ContextOptions&);
|
|
||||||
} // namespace ContextFactory
|
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
|
||||||
|
|
||||||
|
|
||||||
#endif // skgpu_graphite_DawnUtils_DEFINED
|
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ struct SK_API MtlBackendContext {
|
|||||||
sk_cfp<CFTypeRef> fQueue;
|
sk_cfp<CFTypeRef> fQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace ContextFactory {
|
||||||
|
SK_API std::unique_ptr<Context> MakeMetal(const MtlBackendContext&, const ContextOptions&);
|
||||||
|
} // namespace ContextFactory
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
#endif // skgpu_graphite_MtlBackendContext_DEFINED
|
#endif // skgpu_graphite_MtlBackendContext_DEFINED
|
||||||
|
|||||||
@@ -8,31 +8,26 @@
|
|||||||
#ifndef skgpu_graphite_MtlGraphiteTypes_DEFINED
|
#ifndef skgpu_graphite_MtlGraphiteTypes_DEFINED
|
||||||
#define skgpu_graphite_MtlGraphiteTypes_DEFINED
|
#define skgpu_graphite_MtlGraphiteTypes_DEFINED
|
||||||
|
|
||||||
|
#if __OBJC__ // <Metal/Metal.h> only works when compiled for Objective C
|
||||||
|
|
||||||
#include "include/core/SkTypes.h"
|
#include "include/core/SkTypes.h"
|
||||||
|
|
||||||
#if __OBJC__ // <Metal/Metal.h> only works when compiled for Objective C
|
|
||||||
#include "include/gpu/graphite/BackendTexture.h"
|
|
||||||
#include "include/gpu/graphite/GraphiteTypes.h"
|
#include "include/gpu/graphite/GraphiteTypes.h"
|
||||||
#include "include/gpu/graphite/TextureInfo.h"
|
#include "include/gpu/graphite/TextureInfo.h"
|
||||||
#include "include/ports/SkCFObject.h"
|
#include "include/gpu/graphite/mtl/MtlGraphiteTypes_cpp.h"
|
||||||
#include "include/private/base/SkAPI.h"
|
#include "include/private/base/SkAPI.h"
|
||||||
|
|
||||||
#import <CoreFoundation/CoreFoundation.h>
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
#import <Metal/Metal.h>
|
#import <Metal/Metal.h>
|
||||||
#import <TargetConditionals.h>
|
#import <TargetConditionals.h>
|
||||||
|
|
||||||
#if TARGET_OS_SIMULATOR
|
class SkStream;
|
||||||
#define SK_API_AVAILABLE_CA_METAL_LAYER SK_API_AVAILABLE(macos(10.11), ios(13.0), tvos(13.0))
|
class SkWStream;
|
||||||
#else // TARGET_OS_SIMULATOR
|
|
||||||
#define SK_API_AVAILABLE_CA_METAL_LAYER SK_API_AVAILABLE(macos(10.11), ios(8.0), tvos(9.0))
|
|
||||||
#endif // TARGET_OS_SIMULATOR
|
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
struct SK_API MtlTextureInfo {
|
class SK_API MtlTextureInfo final : public TextureInfo::Data {
|
||||||
uint32_t fSampleCount = 1;
|
public:
|
||||||
skgpu::Mipmapped fMipmapped = skgpu::Mipmapped::kNo;
|
|
||||||
|
|
||||||
MTLPixelFormat fFormat = MTLPixelFormatInvalid;
|
MTLPixelFormat fFormat = MTLPixelFormatInvalid;
|
||||||
MTLTextureUsage fUsage = MTLTextureUsageUnknown;
|
MTLTextureUsage fUsage = MTLTextureUsageUnknown;
|
||||||
MTLStorageMode fStorageMode = MTLStorageModeShared;
|
MTLStorageMode fStorageMode = MTLStorageModeShared;
|
||||||
@@ -46,37 +41,34 @@ struct SK_API MtlTextureInfo {
|
|||||||
MTLTextureUsage usage,
|
MTLTextureUsage usage,
|
||||||
MTLStorageMode storageMode,
|
MTLStorageMode storageMode,
|
||||||
bool framebufferOnly)
|
bool framebufferOnly)
|
||||||
: fSampleCount(sampleCount)
|
: Data(sampleCount, mipmapped)
|
||||||
, fMipmapped(mipmapped)
|
|
||||||
, fFormat(format)
|
, fFormat(format)
|
||||||
, fUsage(usage)
|
, fUsage(usage)
|
||||||
, fStorageMode(storageMode)
|
, fStorageMode(storageMode)
|
||||||
, fFramebufferOnly(framebufferOnly) {}
|
, fFramebufferOnly(framebufferOnly) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class TextureInfo;
|
||||||
|
friend class TextureInfoPriv;
|
||||||
|
|
||||||
|
// Non-virtual template API for TextureInfo::Data accessed directly when backend type is known.
|
||||||
|
static constexpr skgpu::BackendApi kBackend = skgpu::BackendApi::kMetal;
|
||||||
|
|
||||||
|
Protected isProtected() const { return Protected::kNo; }
|
||||||
|
TextureFormat viewFormat() const;
|
||||||
|
|
||||||
|
bool serialize(SkWStream*) const;
|
||||||
|
bool deserialize(SkStream*);
|
||||||
|
|
||||||
|
// Virtual API when the specific backend type is not available.
|
||||||
|
SkString toBackendString() const override;
|
||||||
|
|
||||||
|
void copyTo(TextureInfo::AnyTextureInfoData& dstData) const override {
|
||||||
|
dstData.emplace<MtlTextureInfo>(*this);
|
||||||
|
}
|
||||||
|
bool isCompatible(const TextureInfo& that, bool requireExact) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace TextureInfos {
|
|
||||||
SK_API TextureInfo MakeMetal(const MtlTextureInfo&);
|
|
||||||
SK_API TextureInfo MakeMetal(CFTypeRef mtlTexture);
|
|
||||||
|
|
||||||
SK_API bool GetMtlTextureInfo(const TextureInfo&, MtlTextureInfo*);
|
|
||||||
} // namespace TextureInfos
|
|
||||||
|
|
||||||
namespace BackendTextures {
|
|
||||||
// The BackendTexture will not call retain or release on the passed in CFTypeRef. Thus the
|
|
||||||
// client must keep the CFTypeRef valid until they are no longer using the BackendTexture.
|
|
||||||
SK_API BackendTexture MakeMetal(SkISize dimensions, CFTypeRef mtlTexture);
|
|
||||||
|
|
||||||
SK_API CFTypeRef GetMtlTexture(const BackendTexture&);
|
|
||||||
} // namespace BackendTextures
|
|
||||||
|
|
||||||
namespace BackendSemaphores {
|
|
||||||
// TODO(b/286088355) Determine creator's responsibility for setting refcnt.
|
|
||||||
SK_API BackendSemaphore MakeMetal(CFTypeRef mtlEvent, uint64_t value);
|
|
||||||
|
|
||||||
SK_API CFTypeRef GetMtlEvent(const BackendSemaphore&);
|
|
||||||
SK_API uint64_t GetMtlValue(const BackendSemaphore&);
|
|
||||||
} // namespace BackendSemaphores
|
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
#endif // __OBJC__
|
#endif // __OBJC__
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DEPRECRATED: MtlGraphiteTypesUtils.h will be removed in the future, please include
|
||||||
|
// MtlGraphiteTypes_cpp.h
|
||||||
|
#include "include/gpu/graphite/mtl/MtlGraphiteTypes_cpp.h"
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef skgpu_graphite_MtlGraphiteTypesUtils_DEFINED
|
||||||
|
#define skgpu_graphite_MtlGraphiteTypesUtils_DEFINED
|
||||||
|
|
||||||
|
#include "include/core/SkTypes.h"
|
||||||
|
|
||||||
|
#include "include/gpu/graphite/BackendTexture.h"
|
||||||
|
#include "include/gpu/graphite/TextureInfo.h"
|
||||||
|
#include "include/private/base/SkAPI.h"
|
||||||
|
|
||||||
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
|
// MtlTextureInfo requires compiling with Objective-C, so this header is split to allow invoking
|
||||||
|
// the various backend wrapping APIs from a C++-only compilation unit.
|
||||||
|
class SK_API MtlTextureInfo;
|
||||||
|
|
||||||
|
namespace TextureInfos {
|
||||||
|
SK_API TextureInfo MakeMetal(const MtlTextureInfo&);
|
||||||
|
SK_API TextureInfo MakeMetal(CFTypeRef mtlTexture);
|
||||||
|
|
||||||
|
SK_API bool GetMtlTextureInfo(const TextureInfo&, MtlTextureInfo*);
|
||||||
|
} // namespace TextureInfos
|
||||||
|
|
||||||
|
namespace BackendTextures {
|
||||||
|
// The BackendTexture will not call retain or release on the passed in CFTypeRef. Thus the
|
||||||
|
// client must keep the CFTypeRef valid until they are no longer using the BackendTexture.
|
||||||
|
SK_API BackendTexture MakeMetal(SkISize dimensions, CFTypeRef mtlTexture);
|
||||||
|
|
||||||
|
SK_API CFTypeRef GetMtlTexture(const BackendTexture&);
|
||||||
|
} // namespace BackendTextures
|
||||||
|
|
||||||
|
namespace BackendSemaphores {
|
||||||
|
// TODO(b/286088355) Determine creator's responsibility for setting refcnt.
|
||||||
|
SK_API BackendSemaphore MakeMetal(CFTypeRef mtlEvent, uint64_t value);
|
||||||
|
|
||||||
|
SK_API CFTypeRef GetMtlEvent(const BackendSemaphore&);
|
||||||
|
SK_API uint64_t GetMtlValue(const BackendSemaphore&);
|
||||||
|
} // namespace BackendSemaphores
|
||||||
|
|
||||||
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
|
#endif // skgpu_graphite_MtlGraphiteTypesUtils_DEFINED
|
||||||
@@ -5,23 +5,5 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef skgpu_graphite_MtlGraphiteUtils_DEFINED
|
// DEPRECRATED: MtlGraphiteUtils.h will be removed in the future, please include MtlBackendContext.h
|
||||||
#define skgpu_graphite_MtlGraphiteUtils_DEFINED
|
#include "include/gpu/graphite/mtl/MtlBackendContext.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "include/private/base/SkAPI.h"
|
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
|
||||||
|
|
||||||
class Context;
|
|
||||||
struct ContextOptions;
|
|
||||||
struct MtlBackendContext;
|
|
||||||
|
|
||||||
namespace ContextFactory {
|
|
||||||
SK_API std::unique_ptr<Context> MakeMetal(const MtlBackendContext&, const ContextOptions&);
|
|
||||||
} // namespace ContextFactory
|
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
|
||||||
|
|
||||||
#endif // skgpu_graphite_MtlGraphiteUtils_DEFINED
|
|
||||||
|
|||||||
@@ -8,13 +8,15 @@
|
|||||||
#ifndef skgpu_graphite_precompile_Precompile_DEFINED
|
#ifndef skgpu_graphite_precompile_Precompile_DEFINED
|
||||||
#define skgpu_graphite_precompile_Precompile_DEFINED
|
#define skgpu_graphite_precompile_Precompile_DEFINED
|
||||||
|
|
||||||
|
#include "include/core/SkColorSpace.h"
|
||||||
|
#include "include/core/SkColorType.h"
|
||||||
#include "include/core/SkSpan.h"
|
#include "include/core/SkSpan.h"
|
||||||
#include "include/gpu/graphite/GraphiteTypes.h"
|
#include "include/gpu/graphite/GraphiteTypes.h"
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
class Context;
|
|
||||||
class PaintOptions;
|
class PaintOptions;
|
||||||
|
class PrecompileContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the required properties of a RenderPass that will be combined with the
|
* Describes the required properties of a RenderPass that will be combined with the
|
||||||
@@ -22,8 +24,17 @@ class PaintOptions;
|
|||||||
* a pipeline.
|
* a pipeline.
|
||||||
*/
|
*/
|
||||||
struct SK_API RenderPassProperties {
|
struct SK_API RenderPassProperties {
|
||||||
|
bool operator==(const RenderPassProperties& other) const {
|
||||||
|
return fDSFlags == other.fDSFlags &&
|
||||||
|
fDstCT == other.fDstCT &&
|
||||||
|
fRequiresMSAA == other.fRequiresMSAA &&
|
||||||
|
SkColorSpace::Equals(fDstCS.get(), other.fDstCS.get());
|
||||||
|
}
|
||||||
|
bool operator!= (const RenderPassProperties& other) const { return !(*this == other); }
|
||||||
|
|
||||||
DepthStencilFlags fDSFlags = DepthStencilFlags::kNone;
|
DepthStencilFlags fDSFlags = DepthStencilFlags::kNone;
|
||||||
SkColorType fDstCT = kRGBA_8888_SkColorType;
|
SkColorType fDstCT = kRGBA_8888_SkColorType;
|
||||||
|
sk_sp<SkColorSpace> fDstCS = nullptr;
|
||||||
bool fRequiresMSAA = false;
|
bool fRequiresMSAA = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,12 +44,12 @@ struct SK_API RenderPassProperties {
|
|||||||
* drawing. Graphite will always be able to perform an inline compilation if some SkPaint
|
* drawing. Graphite will always be able to perform an inline compilation if some SkPaint
|
||||||
* combination was omitted from precompilation.
|
* combination was omitted from precompilation.
|
||||||
*
|
*
|
||||||
* @param context the Context to which the actual draws will be submitted
|
* @param precompileContext thread-safe helper holding required portions of the Context
|
||||||
* @param paintOptions captures a set of SkPaints that will be drawn
|
* @param paintOptions captures a set of SkPaints that will be drawn
|
||||||
* @param drawTypes communicates which primitives those paints will be drawn with
|
* @param drawTypes communicates which primitives those paints will be drawn with
|
||||||
* @param renderPassProperties describes the RenderPasses needed for the desired Pipelines
|
* @param renderPassProperties describes the RenderPasses needed for the desired Pipelines
|
||||||
*/
|
*/
|
||||||
void SK_API Precompile(Context* context,
|
void SK_API Precompile(PrecompileContext* precompileContext,
|
||||||
const PaintOptions& paintOptions,
|
const PaintOptions& paintOptions,
|
||||||
DrawTypeFlags drawTypes,
|
DrawTypeFlags drawTypes,
|
||||||
SkSpan<const RenderPassProperties> renderPassProperties);
|
SkSpan<const RenderPassProperties> renderPassProperties);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
#include "include/gpu/graphite/precompile/PrecompileBase.h"
|
#include "include/gpu/graphite/precompile/PrecompileBase.h"
|
||||||
|
|
||||||
#include "include/core/SkBlendMode.h"
|
#include "include/core/SkBlendMode.h"
|
||||||
|
#include "include/core/SkImageInfo.h"
|
||||||
|
#include "include/effects/SkGradientShader.h"
|
||||||
|
|
||||||
class SkColorSpace;
|
class SkColorSpace;
|
||||||
|
|
||||||
@@ -109,11 +111,13 @@ namespace PrecompileShaders {
|
|||||||
// time this entry point allows the equivalent precompilation program structure to be created.
|
// time this entry point allows the equivalent precompilation program structure to be created.
|
||||||
// Note that this factory is for non-YUV SkImages, the YUVImage factory (below) should be used
|
// Note that this factory is for non-YUV SkImages, the YUVImage factory (below) should be used
|
||||||
// to represent the shading and sampling required for YUV images.
|
// to represent the shading and sampling required for YUV images.
|
||||||
SK_API sk_sp<PrecompileShader> Image();
|
SK_API sk_sp<PrecompileShader> Image(SkSpan<const SkColorInfo> = {},
|
||||||
|
SkSpan<const SkTileMode> = {});
|
||||||
// As with the above Image call, raw ImageShaders are usually created via an
|
// As with the above Image call, raw ImageShaders are usually created via an
|
||||||
// SkImage::makeRawShader call. The RawImage call allows the equivalent precompilation
|
// SkImage::makeRawShader call. The RawImage call allows the equivalent precompilation
|
||||||
// program structure to be created without needing the SkImage.
|
// program structure to be created without needing the SkImage.
|
||||||
SK_API sk_sp<PrecompileShader> RawImage();
|
SK_API sk_sp<PrecompileShader> RawImage(SkSpan<const SkColorInfo> = {},
|
||||||
|
SkSpan<const SkTileMode> = {});
|
||||||
|
|
||||||
// In the main Skia API, the specifics of the SkImage used for the SkImage::makeShader call
|
// In the main Skia API, the specifics of the SkImage used for the SkImage::makeShader call
|
||||||
// can determine whether normal or YUV sampling is required. This entry point allows clients
|
// can determine whether normal or YUV sampling is required. This entry point allows clients
|
||||||
@@ -126,10 +130,14 @@ namespace PrecompileShaders {
|
|||||||
SK_API sk_sp<PrecompileShader> MakeTurbulence();
|
SK_API sk_sp<PrecompileShader> MakeTurbulence();
|
||||||
|
|
||||||
// --- This block of four matches all the factories in SkGradientShader (SkGradientShader.h)
|
// --- This block of four matches all the factories in SkGradientShader (SkGradientShader.h)
|
||||||
SK_API sk_sp<PrecompileShader> LinearGradient();
|
SK_API sk_sp<PrecompileShader> LinearGradient(
|
||||||
SK_API sk_sp<PrecompileShader> RadialGradient();
|
SkGradientShader::Interpolation = SkGradientShader::Interpolation());
|
||||||
SK_API sk_sp<PrecompileShader> TwoPointConicalGradient();
|
SK_API sk_sp<PrecompileShader> RadialGradient(
|
||||||
SK_API sk_sp<PrecompileShader> SweepGradient();
|
SkGradientShader::Interpolation = SkGradientShader::Interpolation());
|
||||||
|
SK_API sk_sp<PrecompileShader> TwoPointConicalGradient(
|
||||||
|
SkGradientShader::Interpolation = SkGradientShader::Interpolation());
|
||||||
|
SK_API sk_sp<PrecompileShader> SweepGradient(
|
||||||
|
SkGradientShader::Interpolation = SkGradientShader::Interpolation());
|
||||||
|
|
||||||
// Normally, SkPicture shaders are only created via SkPicture::makeShader. Since the
|
// Normally, SkPicture shaders are only created via SkPicture::makeShader. Since the
|
||||||
// SkPicture to be drawn, most likely, won't be available at precompilation time, this
|
// SkPicture to be drawn, most likely, won't be available at precompilation time, this
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef skgpu_graphite_VulkanGraphiteUtils_DEFINED
|
||||||
|
#define skgpu_graphite_VulkanGraphiteUtils_DEFINED
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "include/private/base/SkAPI.h"
|
||||||
|
|
||||||
|
// NOTE: Because there is already a VulkanBackendContext header shared between Ganesh and Graphite,
|
||||||
|
// this is named VulkanGraphiteContext.h to supply just the factory function (differing from the
|
||||||
|
// public headers exposed by other backends).
|
||||||
|
namespace skgpu { struct VulkanBackendContext; }
|
||||||
|
|
||||||
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
|
class Context;
|
||||||
|
struct ContextOptions;
|
||||||
|
|
||||||
|
namespace ContextFactory {
|
||||||
|
SK_API std::unique_ptr<Context> MakeVulkan(const VulkanBackendContext&, const ContextOptions&);
|
||||||
|
} // namespace ContextFactory
|
||||||
|
|
||||||
|
} // namespace skgpu::graphite
|
||||||
|
|
||||||
|
#endif // skgpu_graphite_VulkanGraphiteUtils_DEFINED
|
||||||
@@ -13,12 +13,13 @@
|
|||||||
#include "include/gpu/graphite/TextureInfo.h"
|
#include "include/gpu/graphite/TextureInfo.h"
|
||||||
#include "include/gpu/vk/VulkanTypes.h"
|
#include "include/gpu/vk/VulkanTypes.h"
|
||||||
|
|
||||||
|
class SkStream;
|
||||||
|
class SkWStream;
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
namespace skgpu::graphite {
|
||||||
|
|
||||||
struct VulkanTextureInfo {
|
class SK_API VulkanTextureInfo final : public TextureInfo::Data {
|
||||||
uint32_t fSampleCount = 1;
|
public:
|
||||||
Mipmapped fMipmapped = Mipmapped::kNo;
|
|
||||||
|
|
||||||
// VkImageCreateInfo properties
|
// VkImageCreateInfo properties
|
||||||
// Currently the only supported flag is VK_IMAGE_CREATE_PROTECTED_BIT. Any other flag will not
|
// Currently the only supported flag is VK_IMAGE_CREATE_PROTECTED_BIT. Any other flag will not
|
||||||
// be accepted
|
// be accepted
|
||||||
@@ -48,8 +49,7 @@ struct VulkanTextureInfo {
|
|||||||
VkSharingMode sharingMode,
|
VkSharingMode sharingMode,
|
||||||
VkImageAspectFlags aspectMask,
|
VkImageAspectFlags aspectMask,
|
||||||
VulkanYcbcrConversionInfo ycbcrConversionInfo)
|
VulkanYcbcrConversionInfo ycbcrConversionInfo)
|
||||||
: fSampleCount(sampleCount)
|
: Data(sampleCount, mipmapped)
|
||||||
, fMipmapped(mipmapped)
|
|
||||||
, fFlags(flags)
|
, fFlags(flags)
|
||||||
, fFormat(format)
|
, fFormat(format)
|
||||||
, fImageTiling(imageTiling)
|
, fImageTiling(imageTiling)
|
||||||
@@ -57,6 +57,29 @@ struct VulkanTextureInfo {
|
|||||||
, fSharingMode(sharingMode)
|
, fSharingMode(sharingMode)
|
||||||
, fAspectMask(aspectMask)
|
, fAspectMask(aspectMask)
|
||||||
, fYcbcrConversionInfo(ycbcrConversionInfo) {}
|
, fYcbcrConversionInfo(ycbcrConversionInfo) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class TextureInfo;
|
||||||
|
friend class TextureInfoPriv;
|
||||||
|
|
||||||
|
// Non-virtual template API for TextureInfo::Data accessed directly when backend type is known.
|
||||||
|
static constexpr skgpu::BackendApi kBackend = skgpu::BackendApi::kVulkan;
|
||||||
|
|
||||||
|
Protected isProtected() const {
|
||||||
|
return fFlags & VK_IMAGE_CREATE_PROTECTED_BIT ? Protected::kYes : Protected::kNo;
|
||||||
|
}
|
||||||
|
TextureFormat viewFormat() const;
|
||||||
|
|
||||||
|
bool serialize(SkWStream*) const;
|
||||||
|
bool deserialize(SkStream*);
|
||||||
|
|
||||||
|
// Virtual API when the specific backend type is not available.
|
||||||
|
SkString toBackendString() const override;
|
||||||
|
|
||||||
|
void copyTo(TextureInfo::AnyTextureInfoData& dstData) const override {
|
||||||
|
dstData.emplace<VulkanTextureInfo>(*this);
|
||||||
|
}
|
||||||
|
bool isCompatible(const TextureInfo& that, bool requireExact) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace TextureInfos {
|
namespace TextureInfos {
|
||||||
@@ -78,7 +101,6 @@ namespace BackendSemaphores {
|
|||||||
SK_API BackendSemaphore MakeVulkan(VkSemaphore);
|
SK_API BackendSemaphore MakeVulkan(VkSemaphore);
|
||||||
|
|
||||||
SK_API VkSemaphore GetVkSemaphore(const BackendSemaphore&);
|
SK_API VkSemaphore GetVkSemaphore(const BackendSemaphore&);
|
||||||
|
|
||||||
} // namespace BackendSemaphores
|
} // namespace BackendSemaphores
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
} // namespace skgpu::graphite
|
||||||
|
|||||||
@@ -5,24 +5,6 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef skgpu_graphite_VulkanGraphiteUtils_DEFINED
|
// DEPRECRATED: VulkanGraphiteUtils.h will be removed in the future, please include
|
||||||
#define skgpu_graphite_VulkanGraphiteUtils_DEFINED
|
// VulkanGraphiteContext.h
|
||||||
|
#include "include/gpu/graphite/vk/VulkanGraphiteContext.h"
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "include/private/base/SkAPI.h"
|
|
||||||
|
|
||||||
namespace skgpu { struct VulkanBackendContext; }
|
|
||||||
|
|
||||||
namespace skgpu::graphite {
|
|
||||||
|
|
||||||
class Context;
|
|
||||||
struct ContextOptions;
|
|
||||||
|
|
||||||
namespace ContextFactory {
|
|
||||||
SK_API std::unique_ptr<Context> MakeVulkan(const VulkanBackendContext&, const ContextOptions&);
|
|
||||||
} // namespace ContextFactory
|
|
||||||
|
|
||||||
} // namespace skgpu::graphite
|
|
||||||
|
|
||||||
#endif // skgpu_graphite_VulkanGraphiteUtils_DEFINED
|
|
||||||
|
|||||||
@@ -65,7 +65,15 @@ bool SK_API Simplify(const SkPath& path, SkPath* result);
|
|||||||
@param result The tight bounds of the path.
|
@param result The tight bounds of the path.
|
||||||
@return True if the bounds could be computed.
|
@return True if the bounds could be computed.
|
||||||
*/
|
*/
|
||||||
bool SK_API TightBounds(const SkPath& path, SkRect* result);
|
[[deprecated]]
|
||||||
|
static inline bool TightBounds(const SkPath& path, SkRect* result) {
|
||||||
|
auto rect = path.computeTightBounds();
|
||||||
|
if (rect.isFinite()) {
|
||||||
|
*result = rect;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** Set the result with fill type winding to area equivalent to path.
|
/** Set the result with fill type winding to area equivalent to path.
|
||||||
Returns true if successful. Does not detect if path contains contours which
|
Returns true if successful. Does not detect if path contains contours which
|
||||||
|
|||||||
@@ -13,8 +13,11 @@
|
|||||||
|
|
||||||
class SkFontMgr;
|
class SkFontMgr;
|
||||||
class SkFontConfigInterface;
|
class SkFontConfigInterface;
|
||||||
|
class SkFontScanner;
|
||||||
|
|
||||||
/** Creates a SkFontMgr which wraps a SkFontConfigInterface. */
|
/** Creates a SkFontMgr which wraps a SkFontConfigInterface. */
|
||||||
SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci);
|
SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci);
|
||||||
|
SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci,
|
||||||
|
std::unique_ptr<SkFontScanner> scanner);
|
||||||
|
|
||||||
#endif // #ifndef SkFontMgr_FontConfigInterface_DEFINED
|
#endif // #ifndef SkFontMgr_FontConfigInterface_DEFINED
|
||||||
|
|||||||
@@ -18,4 +18,7 @@
|
|||||||
SK_API sk_sp<SkTypeface> SkTypeface_Make_Fontations(std::unique_ptr<SkStreamAsset> fontData,
|
SK_API sk_sp<SkTypeface> SkTypeface_Make_Fontations(std::unique_ptr<SkStreamAsset> fontData,
|
||||||
const SkFontArguments& args);
|
const SkFontArguments& args);
|
||||||
|
|
||||||
|
SK_API sk_sp<SkTypeface> SkTypeface_Make_Fontations(sk_sp<SkData> fontData,
|
||||||
|
const SkFontArguments& args);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -86,6 +86,13 @@ public:
|
|||||||
virtual bool findGainmapImage(sk_sp<SkData> baseImageData,
|
virtual bool findGainmapImage(sk_sp<SkData> baseImageData,
|
||||||
sk_sp<SkData>& outGainmapImagedata,
|
sk_sp<SkData>& outGainmapImagedata,
|
||||||
SkGainmapInfo& outGainmapInfo) = 0;
|
SkGainmapInfo& outGainmapInfo) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the first JUMBF superbox, if any, and nullptr otherwise. If |copyData| is false,
|
||||||
|
* then the returned SkData may directly reference the data provided when this object was
|
||||||
|
* created.
|
||||||
|
*/
|
||||||
|
virtual sk_sp<SkData> getJUMBFMetadata(bool copyData) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,15 +28,6 @@
|
|||||||
class SkMatrix;
|
class SkMatrix;
|
||||||
class SkRRect;
|
class SkRRect;
|
||||||
|
|
||||||
// These are computed from a stream of verbs
|
|
||||||
struct SkPathVerbAnalysis {
|
|
||||||
bool valid;
|
|
||||||
int points, weights;
|
|
||||||
unsigned segmentMask;
|
|
||||||
};
|
|
||||||
SkPathVerbAnalysis sk_path_analyze_verbs(const uint8_t verbs[], int count);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the path verbs and points. It is versioned by a generation ID. None of its public methods
|
* Holds the path verbs and points. It is versioned by a generation ID. None of its public methods
|
||||||
* modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an
|
* modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an
|
||||||
@@ -541,7 +532,12 @@ private:
|
|||||||
|
|
||||||
void callGenIDChangeListeners();
|
void callGenIDChangeListeners();
|
||||||
|
|
||||||
|
PointsArray fPoints;
|
||||||
|
VerbsArray fVerbs;
|
||||||
|
ConicWeightsArray fConicWeights;
|
||||||
|
|
||||||
mutable SkRect fBounds;
|
mutable SkRect fBounds;
|
||||||
|
SkRect fArcOval;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs.
|
kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs.
|
||||||
@@ -549,27 +545,25 @@ private:
|
|||||||
mutable uint32_t fGenerationID;
|
mutable uint32_t fGenerationID;
|
||||||
SkIDChangeListener::List fGenIDChangeListeners;
|
SkIDChangeListener::List fGenIDChangeListeners;
|
||||||
|
|
||||||
PointsArray fPoints;
|
|
||||||
VerbsArray fVerbs;
|
|
||||||
ConicWeightsArray fConicWeights;
|
|
||||||
|
|
||||||
SkDEBUGCODE(std::atomic<int> fEditorsAttached;) // assert only one editor in use at any time.
|
SkDEBUGCODE(std::atomic<int> fEditorsAttached;) // assert only one editor in use at any time.
|
||||||
|
|
||||||
mutable uint8_t fBoundsIsDirty;
|
SkScalar fArcStartAngle;
|
||||||
mutable bool fIsFinite; // only meaningful if bounds are valid
|
SkScalar fArcSweepAngle;
|
||||||
|
|
||||||
PathType fType;
|
PathType fType;
|
||||||
// Both the circle and rrect special cases have a notion of direction and starting point
|
|
||||||
// The next two variables store that information for either.
|
mutable uint8_t fBoundsIsDirty;
|
||||||
bool fRRectOrOvalIsCCW;
|
|
||||||
uint8_t fRRectOrOvalStartIdx;
|
uint8_t fRRectOrOvalStartIdx;
|
||||||
uint8_t fSegmentMask;
|
uint8_t fSegmentMask;
|
||||||
// If the path is an arc, these four variables store that information.
|
// If the path is an arc, these four variables store that information.
|
||||||
// We should just store an SkArc, but alignment would cost us 8 more bytes.
|
// We should just store an SkArc, but alignment would cost us 8 more bytes.
|
||||||
SkArc::Type fArcType;
|
SkArc::Type fArcType;
|
||||||
SkRect fArcOval;
|
|
||||||
SkScalar fArcStartAngle;
|
mutable bool fIsFinite; // only meaningful if bounds are valid
|
||||||
SkScalar fArcSweepAngle;
|
// Both the circle and rrect special cases have a notion of direction and starting point
|
||||||
|
// The next two variables store that information for either.
|
||||||
|
bool fRRectOrOvalIsCCW;
|
||||||
|
|
||||||
friend class PathRefTest_Private;
|
friend class PathRefTest_Private;
|
||||||
friend class ForceIsRRect_Private; // unit test isRRect
|
friend class ForceIsRRect_Private; // unit test isRRect
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ public:
|
|||||||
fValid = false;
|
fValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_value() const { return fValid; }
|
||||||
|
explicit operator bool() const { return this->has_value(); }
|
||||||
|
|
||||||
const Base* get() const {
|
const Base* get() const {
|
||||||
SkASSERT(fValid);
|
SkASSERT(fValid);
|
||||||
return std::launder(reinterpret_cast<const Base*>(fData));
|
return std::launder(reinterpret_cast<const Base*>(fData));
|
||||||
@@ -65,6 +68,9 @@ public:
|
|||||||
Base* operator->() { return this->get(); }
|
Base* operator->() { return this->get(); }
|
||||||
const Base* operator->() const { return this->get(); }
|
const Base* operator->() const { return this->get(); }
|
||||||
|
|
||||||
|
Base& operator*() { return *this->get(); }
|
||||||
|
const Base& operator*() const { return *this->get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
alignas(8) std::byte fData[Size];
|
alignas(8) std::byte fData[Size];
|
||||||
bool fValid = false;
|
bool fValid = false;
|
||||||
|
|||||||
@@ -56,20 +56,26 @@
|
|||||||
* Used to ignore sanitizer warnings.
|
* Used to ignore sanitizer warnings.
|
||||||
*/
|
*/
|
||||||
#if !defined(SK_NO_SANITIZE)
|
#if !defined(SK_NO_SANITIZE)
|
||||||
# define SK_NO_SANITIZE(A) SK_ATTRIBUTE(no_sanitize(A))
|
#if defined(__has_attribute)
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper macro to define no_sanitize attributes only with clang.
|
|
||||||
*/
|
|
||||||
#if defined(__clang__) && defined(__has_attribute)
|
|
||||||
#if __has_attribute(no_sanitize)
|
#if __has_attribute(no_sanitize)
|
||||||
#define SK_CLANG_NO_SANITIZE(A) SK_NO_SANITIZE(A)
|
// This should be for clang and versions of gcc >= 8.0
|
||||||
|
#define SK_NO_SANITIZE(A) SK_ATTRIBUTE(no_sanitize(A))
|
||||||
|
#else
|
||||||
|
// For compilers that don't support sanitization, just do nothing.
|
||||||
|
#define SK_NO_SANITIZE(A)
|
||||||
|
#endif
|
||||||
|
#else // no __has_attribute, e.g. MSVC
|
||||||
|
#define SK_NO_SANITIZE(A)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(SK_CLANG_NO_SANITIZE)
|
/**
|
||||||
#define SK_CLANG_NO_SANITIZE(A)
|
* Used to ignore CFI sanitizer warnings, supported only by Clang at the moment.
|
||||||
|
*/
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define SK_NO_SANITIZE_CFI SK_NO_SANITIZE("cfi")
|
||||||
|
#else
|
||||||
|
#define SK_NO_SANITIZE_CFI
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -131,11 +131,7 @@ static constexpr int64_t sk_float_saturate2int64(float x) {
|
|||||||
// Cast double to float, ignoring any warning about too-large finite values being cast to float.
|
// Cast double to float, ignoring any warning about too-large finite values being cast to float.
|
||||||
// Clang thinks this is undefined, but it's actually implementation defined to return either
|
// Clang thinks this is undefined, but it's actually implementation defined to return either
|
||||||
// the largest float or infinity (one of the two bracketing representable floats). Good enough!
|
// the largest float or infinity (one of the two bracketing representable floats). Good enough!
|
||||||
#ifdef __clang__
|
|
||||||
SK_NO_SANITIZE("float-cast-overflow")
|
SK_NO_SANITIZE("float-cast-overflow")
|
||||||
#elif defined(__GNUC__)
|
|
||||||
SK_ATTRIBUTE(no_sanitize_undefined)
|
|
||||||
#endif
|
|
||||||
static constexpr float sk_double_to_float(double x) {
|
static constexpr float sk_double_to_float(double x) {
|
||||||
return static_cast<float>(x);
|
return static_cast<float>(x);
|
||||||
}
|
}
|
||||||
@@ -161,20 +157,12 @@ static inline float sk_float_rsqrt (float x) { return 1.0f / std::sqrt(x
|
|||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4723)
|
#pragma warning(disable : 4723)
|
||||||
#endif
|
#endif
|
||||||
#ifdef __clang__
|
|
||||||
SK_NO_SANITIZE("float-divide-by-zero")
|
SK_NO_SANITIZE("float-divide-by-zero")
|
||||||
#elif defined(__GNUC__)
|
|
||||||
SK_ATTRIBUTE(no_sanitize_undefined)
|
|
||||||
#endif
|
|
||||||
static constexpr float sk_ieee_float_divide(float numer, float denom) {
|
static constexpr float sk_ieee_float_divide(float numer, float denom) {
|
||||||
return numer / denom;
|
return numer / denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __clang__
|
|
||||||
SK_NO_SANITIZE("float-divide-by-zero")
|
SK_NO_SANITIZE("float-divide-by-zero")
|
||||||
#elif defined(__GNUC__)
|
|
||||||
SK_ATTRIBUTE(no_sanitize_undefined)
|
|
||||||
#endif
|
|
||||||
static constexpr double sk_ieee_double_divide(double numer, double denom) {
|
static constexpr double sk_ieee_double_divide(double numer, double denom) {
|
||||||
return numer / denom;
|
return numer / denom;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,14 @@
|
|||||||
#include "include/private/base/SkThreadAnnotations.h"
|
#include "include/private/base/SkThreadAnnotations.h"
|
||||||
#include "include/private/base/SkThreadID.h"
|
#include "include/private/base/SkThreadID.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class SkMutex
|
||||||
|
*
|
||||||
|
* This allows us to have a mutex without needing the one in
|
||||||
|
* the C++ std library which does not work with all clients.
|
||||||
|
* go/cstyle#Disallowed_Stdlib
|
||||||
|
*/
|
||||||
|
|
||||||
class SK_CAPABILITY("mutex") SkMutex {
|
class SK_CAPABILITY("mutex") SkMutex {
|
||||||
public:
|
public:
|
||||||
constexpr SkMutex() = default;
|
constexpr SkMutex() = default;
|
||||||
|
|||||||
@@ -617,11 +617,7 @@ private:
|
|||||||
// unpredictable location in memory. Of course, TArray won't actually use fItemArray in this
|
// unpredictable location in memory. Of course, TArray won't actually use fItemArray in this
|
||||||
// way, and we don't want to construct a T before the user requests one. There's no real risk
|
// way, and we don't want to construct a T before the user requests one. There's no real risk
|
||||||
// here, so disable CFI when doing these casts.
|
// here, so disable CFI when doing these casts.
|
||||||
#ifdef __clang__
|
SK_NO_SANITIZE_CFI
|
||||||
SK_NO_SANITIZE("cfi")
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
SK_ATTRIBUTE(no_sanitize_undefined)
|
|
||||||
#endif
|
|
||||||
static T* TCast(void* buffer) {
|
static T* TCast(void* buffer) {
|
||||||
return (T*)buffer;
|
return (T*)buffer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
#include "include/private/base/SkDebug.h"
|
#include "include/private/base/SkDebug.h"
|
||||||
#include "include/private/base/SkTo.h"
|
#include "include/private/base/SkTo.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class SK_SPI SkTDStorage {
|
class SK_SPI SkTDStorage {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "include/private/base/SkTLogic.h"
|
#include "include/private/base/SkTLogic.h"
|
||||||
#include "include/private/base/SkTo.h"
|
#include "include/private/base/SkTo.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -94,7 +95,8 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
namespace skia_private {
|
namespace skia_private {
|
||||||
/** Allocate an array of T elements, and free the array in the destructor
|
/** Allocate an array of T elements on the heap. Once this goes out of scope, the
|
||||||
|
* elements will be cleaned up "auto"matically.
|
||||||
*/
|
*/
|
||||||
template <typename T> class AutoTArray {
|
template <typename T> class AutoTArray {
|
||||||
public:
|
public:
|
||||||
@@ -164,7 +166,10 @@ private:
|
|||||||
size_t fSize = 0;
|
size_t fSize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Wraps AutoTArray, with room for kCountRequested elements preallocated.
|
/** Like AutoTArray with room for kCountRequested elements preallocated on
|
||||||
|
* the Stack. If count exceeds the space of the preallocation, the elements
|
||||||
|
* will live on the heap. Once this goes out of scope, the elements will be
|
||||||
|
* cleaned up "auto"matically.
|
||||||
*/
|
*/
|
||||||
template <int kCountRequested, typename T> class AutoSTArray {
|
template <int kCountRequested, typename T> class AutoSTArray {
|
||||||
public:
|
public:
|
||||||
@@ -256,17 +261,25 @@ private:
|
|||||||
#if defined(SK_BUILD_FOR_GOOGLE3)
|
#if defined(SK_BUILD_FOR_GOOGLE3)
|
||||||
// Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max,
|
// Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max,
|
||||||
// but some functions have multiple large stack allocations.
|
// but some functions have multiple large stack allocations.
|
||||||
static const int kMaxBytes = 4 * 1024;
|
static constexpr int kMaxBytes = 4 * 1024;
|
||||||
static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
|
static constexpr int kMinCount = kCountRequested * sizeof(T) > kMaxBytes
|
||||||
? kMaxBytes / sizeof(T)
|
? kMaxBytes / sizeof(T)
|
||||||
: kCountRequested;
|
: kCountRequested;
|
||||||
#else
|
#else
|
||||||
static const int kCount = kCountRequested;
|
static constexpr int kMinCount = kCountRequested;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int fCount;
|
// Because we are also storing an int, there is a tiny bit of padding that
|
||||||
|
// the C++ compiler adds after fStorage if sizeof(T) <= alignof(T*).
|
||||||
|
// Thus, we can expand how many elements are stored on the stack to make use of this
|
||||||
|
// (e.g. 1 extra element for 4 byte T if kCountRequested was even).
|
||||||
|
static_assert(alignof(int) <= alignof(T*) || alignof(int) <= alignof(T));
|
||||||
|
static constexpr int kCount =
|
||||||
|
SkAlignTo(kMinCount*sizeof(T) + sizeof(int), std::max(alignof(T*), alignof(T))) / sizeof(T);
|
||||||
|
|
||||||
T* fArray;
|
T* fArray;
|
||||||
alignas(T) char fStorage[kCount * sizeof(T)];
|
alignas(T) std::byte fStorage[kCount * sizeof(T)];
|
||||||
|
int fCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Manages an array of T elements, freeing the array in the destructor.
|
/** Manages an array of T elements, freeing the array in the destructor.
|
||||||
@@ -409,16 +422,16 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Since we use uint32_t storage, we might be able to get more elements for free.
|
// Since we use uint32_t storage, we might be able to get more elements for free.
|
||||||
static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
|
static constexpr size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
|
||||||
#if defined(SK_BUILD_FOR_GOOGLE3)
|
#if defined(SK_BUILD_FOR_GOOGLE3)
|
||||||
// Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions
|
// Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions
|
||||||
// have multiple large stack allocations.
|
// have multiple large stack allocations.
|
||||||
static const size_t kMaxBytes = 4 * 1024;
|
static constexpr size_t kMaxBytes = 4 * 1024;
|
||||||
static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
|
static constexpr size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
|
||||||
? kMaxBytes / sizeof(T)
|
? kMaxBytes / sizeof(T)
|
||||||
: kCountWithPadding;
|
: kCountWithPadding;
|
||||||
#else
|
#else
|
||||||
static const size_t kCount = kCountWithPadding;
|
static constexpr size_t kCount = kCountWithPadding;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
T* fPtr;
|
T* fPtr;
|
||||||
|
|||||||
38
gfx/skia/skia/include/private/chromium/SkPMColor.h
Normal file
38
gfx/skia/skia/include/private/chromium/SkPMColor.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SkPMColor_DEFINED
|
||||||
|
#define SkPMColor_DEFINED
|
||||||
|
|
||||||
|
#include "include/core/SkColor.h"
|
||||||
|
#include "include/private/base/SkAPI.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/** Returns a SkPMColor value from already premultiplied 8-bit component values.
|
||||||
|
|
||||||
|
@param a amount of alpha, from fully transparent (0) to fully opaque (255)
|
||||||
|
@param r amount of red, from no red (0) to full red (255)
|
||||||
|
@param g amount of green, from no green (0) to full green (255)
|
||||||
|
@param b amount of blue, from no blue (0) to full blue (255)
|
||||||
|
@return premultiplied color
|
||||||
|
*/
|
||||||
|
SK_API SkPMColor SkPMColorSetARGB(SkAlpha a, uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
|
||||||
|
/** Returns alpha component of premultiplied color. */
|
||||||
|
SK_API SkAlpha SkPMColorGetA(SkPMColor);
|
||||||
|
|
||||||
|
/** Returns red component of premultiplied color. */
|
||||||
|
SK_API uint8_t SkPMColorGetR(SkPMColor);
|
||||||
|
|
||||||
|
/** Returns green component of premultiplied color. */
|
||||||
|
SK_API uint8_t SkPMColorGetG(SkPMColor);
|
||||||
|
|
||||||
|
/** Returns blue component of premultiplied color. */
|
||||||
|
SK_API uint8_t SkPMColorGetB(SkPMColor);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -539,7 +539,7 @@ SK_MAKE_BITFIELD_CLASS_OPS(GpuPathRenderers)
|
|||||||
enum class GrColorType {
|
enum class GrColorType {
|
||||||
kUnknown,
|
kUnknown,
|
||||||
kAlpha_8,
|
kAlpha_8,
|
||||||
kBGR_565,
|
kBGR_565, // This corresponds to kRGB_565_SkColorType, which is misnamed.
|
||||||
kRGB_565,
|
kRGB_565,
|
||||||
kABGR_4444, // This name differs from SkColorType. kARGB_4444_SkColorType is misnamed.
|
kABGR_4444, // This name differs from SkColorType. kARGB_4444_SkColorType is misnamed.
|
||||||
kRGBA_8888,
|
kRGBA_8888,
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ namespace SkSL {
|
|||||||
|
|
||||||
class DebugTrace : public SkRefCnt {
|
class DebugTrace : public SkRefCnt {
|
||||||
public:
|
public:
|
||||||
/** Serializes a debug trace to JSON which can be parsed by our debugger. */
|
|
||||||
virtual void writeTrace(SkWStream* w) const = 0;
|
|
||||||
|
|
||||||
/** Generates a human-readable dump of the debug trace. */
|
/** Generates a human-readable dump of the debug trace. */
|
||||||
virtual void dump(SkWStream* o) const = 0;
|
virtual void dump(SkWStream* o) const = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
6
gfx/skia/skia/modules/skcms/README.chromium
Normal file
6
gfx/skia/skia/modules/skcms/README.chromium
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Name: skcms
|
||||||
|
URL: https://skia.org/
|
||||||
|
Version: unknown
|
||||||
|
Security Critical: yes
|
||||||
|
Shipped: yes
|
||||||
|
License: BSD
|
||||||
@@ -1464,88 +1464,89 @@ const skcms_ICCProfile* skcms_sRGB_profile() {
|
|||||||
|
|
||||||
// We choose to represent sRGB with its canonical transfer function,
|
// We choose to represent sRGB with its canonical transfer function,
|
||||||
// and with its canonical XYZD50 gamut matrix.
|
// and with its canonical XYZD50 gamut matrix.
|
||||||
true, // has_trc, followed by the 3 trc curves
|
{ // the 3 trc curves
|
||||||
{
|
|
||||||
{{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}},
|
{{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}},
|
||||||
{{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}},
|
{{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}},
|
||||||
{{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}},
|
{{0, {2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0, 0}}},
|
||||||
},
|
},
|
||||||
|
|
||||||
true, // has_toXYZD50, followed by 3x3 toXYZD50 matrix
|
{{ // 3x3 toXYZD50 matrix
|
||||||
{{
|
|
||||||
{ 0.436065674f, 0.385147095f, 0.143066406f },
|
{ 0.436065674f, 0.385147095f, 0.143066406f },
|
||||||
{ 0.222488403f, 0.716873169f, 0.060607910f },
|
{ 0.222488403f, 0.716873169f, 0.060607910f },
|
||||||
{ 0.013916016f, 0.097076416f, 0.714096069f },
|
{ 0.013916016f, 0.097076416f, 0.714096069f },
|
||||||
}},
|
}},
|
||||||
|
|
||||||
false, // has_A2B, followed by A2B itself, which we don't care about.
|
{ // an empty A2B
|
||||||
{
|
{ // input_curves
|
||||||
0,
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
},
|
},
|
||||||
{0,0,0,0},
|
nullptr, // grid_8
|
||||||
nullptr,
|
nullptr, // grid_16
|
||||||
nullptr,
|
0, // input_channels
|
||||||
|
{0,0,0,0}, // grid_points
|
||||||
|
|
||||||
0,
|
{ // matrix_curves
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
},
|
},
|
||||||
{{
|
{{ // matrix (3x4)
|
||||||
|
{ 0,0,0,0 },
|
||||||
|
{ 0,0,0,0 },
|
||||||
|
{ 0,0,0,0 },
|
||||||
|
}},
|
||||||
|
0, // matrix_channels
|
||||||
|
|
||||||
|
0, // output_channels
|
||||||
|
{ // output_curves
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{ // an empty B2A
|
||||||
|
{ // input_curves
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
},
|
||||||
|
0, // input_channels
|
||||||
|
|
||||||
|
0, // matrix_channels
|
||||||
|
{ // matrix_curves
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
},
|
||||||
|
{{ // matrix (3x4)
|
||||||
{ 0,0,0,0 },
|
{ 0,0,0,0 },
|
||||||
{ 0,0,0,0 },
|
{ 0,0,0,0 },
|
||||||
{ 0,0,0,0 },
|
{ 0,0,0,0 },
|
||||||
}},
|
}},
|
||||||
|
|
||||||
0,
|
{ // output_curves
|
||||||
{
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
},
|
},
|
||||||
|
nullptr, // grid_8
|
||||||
|
nullptr, // grid_16
|
||||||
|
{0,0,0,0}, // grid_points
|
||||||
|
0, // output_channels
|
||||||
},
|
},
|
||||||
|
|
||||||
false, // has_B2A, followed by B2A itself, which we also don't care about.
|
{ 0, 0, 0, 0 }, // an empty CICP
|
||||||
{
|
|
||||||
0,
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
},
|
|
||||||
|
|
||||||
0,
|
true, // has_trc
|
||||||
{{
|
true, // has_toXYZD50
|
||||||
{ 0,0,0,0 },
|
false, // has_A2B
|
||||||
{ 0,0,0,0 },
|
false, // has B2A
|
||||||
{ 0,0,0,0 },
|
false, // has_CICP
|
||||||
}},
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
},
|
|
||||||
|
|
||||||
0,
|
|
||||||
{0,0,0,0},
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
false, // has_CICP, followed by cicp itself which we don't care about.
|
|
||||||
{ 0, 0, 0, 0 },
|
|
||||||
};
|
};
|
||||||
return &sRGB_profile;
|
return &sRGB_profile;
|
||||||
}
|
}
|
||||||
@@ -1560,88 +1561,89 @@ const skcms_ICCProfile* skcms_XYZD50_profile() {
|
|||||||
skcms_Signature_XYZ, // pcs
|
skcms_Signature_XYZ, // pcs
|
||||||
0, // tag count, moot here
|
0, // tag count, moot here
|
||||||
|
|
||||||
true, // has_trc, followed by the 3 trc curves
|
{ // the 3 trc curves
|
||||||
{
|
|
||||||
{{0, {1,1, 0,0,0,0,0}}},
|
{{0, {1,1, 0,0,0,0,0}}},
|
||||||
{{0, {1,1, 0,0,0,0,0}}},
|
{{0, {1,1, 0,0,0,0,0}}},
|
||||||
{{0, {1,1, 0,0,0,0,0}}},
|
{{0, {1,1, 0,0,0,0,0}}},
|
||||||
},
|
},
|
||||||
|
|
||||||
true, // has_toXYZD50, followed by 3x3 toXYZD50 matrix
|
{{ // 3x3 toXYZD50 matrix
|
||||||
{{
|
|
||||||
{ 1,0,0 },
|
{ 1,0,0 },
|
||||||
{ 0,1,0 },
|
{ 0,1,0 },
|
||||||
{ 0,0,1 },
|
{ 0,0,1 },
|
||||||
}},
|
}},
|
||||||
|
|
||||||
false, // has_A2B, followed by A2B itself, which we don't care about.
|
{ // an empty A2B
|
||||||
{
|
{ // input_curves
|
||||||
0,
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
},
|
},
|
||||||
{0,0,0,0},
|
nullptr, // grid_8
|
||||||
nullptr,
|
nullptr, // grid_16
|
||||||
nullptr,
|
0, // input_channels
|
||||||
|
{0,0,0,0}, // grid_points
|
||||||
|
|
||||||
0,
|
{ // matrix_curves
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
},
|
},
|
||||||
{{
|
{{ // matrix (3x4)
|
||||||
|
{ 0,0,0,0 },
|
||||||
|
{ 0,0,0,0 },
|
||||||
|
{ 0,0,0,0 },
|
||||||
|
}},
|
||||||
|
0, // matrix_channels
|
||||||
|
|
||||||
|
0, // output_channels
|
||||||
|
{ // output_curves
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{ // an empty B2A
|
||||||
|
{ // input_curves
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
},
|
||||||
|
0, // input_channels
|
||||||
|
|
||||||
|
0, // matrix_channels
|
||||||
|
{ // matrix_curves
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
|
},
|
||||||
|
{{ // matrix (3x4)
|
||||||
{ 0,0,0,0 },
|
{ 0,0,0,0 },
|
||||||
{ 0,0,0,0 },
|
{ 0,0,0,0 },
|
||||||
{ 0,0,0,0 },
|
{ 0,0,0,0 },
|
||||||
}},
|
}},
|
||||||
|
|
||||||
0,
|
{ // output_curves
|
||||||
{
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
{{0, {0,0, 0,0,0,0,0}}},
|
||||||
},
|
},
|
||||||
|
nullptr, // grid_8
|
||||||
|
nullptr, // grid_16
|
||||||
|
{0,0,0,0}, // grid_points
|
||||||
|
0, // output_channels
|
||||||
},
|
},
|
||||||
|
|
||||||
false, // has_B2A, followed by B2A itself, which we also don't care about.
|
{ 0, 0, 0, 0 }, // an empty CICP
|
||||||
{
|
|
||||||
0,
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
},
|
|
||||||
|
|
||||||
0,
|
true, // has_trc
|
||||||
{{
|
true, // has_toXYZD50
|
||||||
{ 0,0,0,0 },
|
false, // has_A2B
|
||||||
{ 0,0,0,0 },
|
false, // has B2A
|
||||||
{ 0,0,0,0 },
|
false, // has_CICP
|
||||||
}},
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
},
|
|
||||||
|
|
||||||
0,
|
|
||||||
{0,0,0,0},
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
{
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
{{0, {0,0, 0,0,0,0,0}}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
false, // has_CICP, followed by cicp itself which we don't care about.
|
|
||||||
{ 0, 0, 0, 0 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return &XYZD50_profile;
|
return &XYZD50_profile;
|
||||||
@@ -2843,6 +2845,7 @@ bool skcms_Transform(const void* src,
|
|||||||
case skcms_PixelFormat_RGB_hhh_Norm >> 1: add_op(Op::store_hhh); break;
|
case skcms_PixelFormat_RGB_hhh_Norm >> 1: add_op(Op::store_hhh); break;
|
||||||
case skcms_PixelFormat_RGBA_hhhh_Norm >> 1: add_op(Op::store_hhhh); break;
|
case skcms_PixelFormat_RGBA_hhhh_Norm >> 1: add_op(Op::store_hhhh); break;
|
||||||
case skcms_PixelFormat_RGB_101010x_XR >> 1: add_op(Op::store_101010x_XR); break;
|
case skcms_PixelFormat_RGB_101010x_XR >> 1: add_op(Op::store_101010x_XR); break;
|
||||||
|
case skcms_PixelFormat_RGBA_10101010_XR >> 1: add_op(Op::store_10101010_XR); break;
|
||||||
case skcms_PixelFormat_RGB_hhh >> 1: add_op(Op::store_hhh); break;
|
case skcms_PixelFormat_RGB_hhh >> 1: add_op(Op::store_hhh); break;
|
||||||
case skcms_PixelFormat_RGBA_hhhh >> 1: add_op(Op::store_hhhh); break;
|
case skcms_PixelFormat_RGBA_hhhh >> 1: add_op(Op::store_hhhh); break;
|
||||||
case skcms_PixelFormat_RGB_fff >> 1: add_op(Op::store_fff); break;
|
case skcms_PixelFormat_RGB_fff >> 1: add_op(Op::store_fff); break;
|
||||||
|
|||||||
@@ -904,24 +904,19 @@ STAGE(load_1010102, NoCtx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
STAGE(load_101010x_XR, NoCtx) {
|
STAGE(load_101010x_XR, NoCtx) {
|
||||||
static constexpr float min = -0.752941f;
|
|
||||||
static constexpr float max = 1.25098f;
|
|
||||||
static constexpr float range = max - min;
|
|
||||||
U32 rgba = load<U32>(src + 4*i);
|
U32 rgba = load<U32>(src + 4*i);
|
||||||
r = cast<F>((rgba >> 0) & 0x3ff) * (1/1023.0f) * range + min;
|
r = cast<F>(((rgba >> 0) & 0x3ff) - 384) / 510.0f;
|
||||||
g = cast<F>((rgba >> 10) & 0x3ff) * (1/1023.0f) * range + min;
|
g = cast<F>(((rgba >> 10) & 0x3ff) - 384) / 510.0f;
|
||||||
b = cast<F>((rgba >> 20) & 0x3ff) * (1/1023.0f) * range + min;
|
b = cast<F>(((rgba >> 20) & 0x3ff) - 384) / 510.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
STAGE(load_10101010_XR, NoCtx) {
|
STAGE(load_10101010_XR, NoCtx) {
|
||||||
static constexpr float min = -0.752941f;
|
|
||||||
static constexpr float max = 1.25098f;
|
|
||||||
static constexpr float range = max - min;
|
|
||||||
U64 rgba = load<U64>(src + 8 * i);
|
U64 rgba = load<U64>(src + 8 * i);
|
||||||
r = cast<F>((rgba >> (0+6)) & 0x3ff) * (1/1023.0f) * range + min;
|
// Each channel is 16 bits, where the 6 low bits are padding.
|
||||||
g = cast<F>((rgba >> (16+6)) & 0x3ff) * (1/1023.0f) * range + min;
|
r = cast<F>(((rgba >> ( 0+6)) & 0x3ff) - 384) / 510.0f;
|
||||||
b = cast<F>((rgba >> (32+6)) & 0x3ff) * (1/1023.0f) * range + min;
|
g = cast<F>(((rgba >> (16+6)) & 0x3ff) - 384) / 510.0f;
|
||||||
a = cast<F>((rgba >> (48+6)) & 0x3ff) * (1/1023.0f) * range + min;
|
b = cast<F>(((rgba >> (32+6)) & 0x3ff) - 384) / 510.0f;
|
||||||
|
a = cast<F>(((rgba >> (48+6)) & 0x3ff) - 384) / 510.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
STAGE(load_161616LE, NoCtx) {
|
STAGE(load_161616LE, NoCtx) {
|
||||||
@@ -1310,12 +1305,17 @@ FINAL_STAGE(store_8888, NoCtx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FINAL_STAGE(store_101010x_XR, NoCtx) {
|
FINAL_STAGE(store_101010x_XR, NoCtx) {
|
||||||
static constexpr float min = -0.752941f;
|
store(dst + 4*i, cast<U32>(to_fixed((r * 510) + 384)) << 0
|
||||||
static constexpr float max = 1.25098f;
|
| cast<U32>(to_fixed((g * 510) + 384)) << 10
|
||||||
static constexpr float range = max - min;
|
| cast<U32>(to_fixed((b * 510) + 384)) << 20);
|
||||||
store(dst + 4*i, cast<U32>(to_fixed(((r - min) / range) * 1023)) << 0
|
}
|
||||||
| cast<U32>(to_fixed(((g - min) / range) * 1023)) << 10
|
|
||||||
| cast<U32>(to_fixed(((b - min) / range) * 1023)) << 20);
|
FINAL_STAGE(store_10101010_XR, NoCtx) {
|
||||||
|
// Each channel is 16 bits, where the 6 low bits are padding.
|
||||||
|
store(dst + 8*i, cast<U64>(to_fixed((r * 510) + 384)) << ( 0+6)
|
||||||
|
| cast<U64>(to_fixed((g * 510) + 384)) << (16+6)
|
||||||
|
| cast<U64>(to_fixed((b * 510) + 384)) << (32+6)
|
||||||
|
| cast<U64>(to_fixed((a * 510) + 384)) << (48+6));
|
||||||
}
|
}
|
||||||
|
|
||||||
FINAL_STAGE(store_1010102, NoCtx) {
|
FINAL_STAGE(store_1010102, NoCtx) {
|
||||||
@@ -1521,7 +1521,7 @@ FINAL_STAGE(store_ffff, NoCtx) {
|
|||||||
// NOLINTNEXTLINE(misc-definitions-in-headers)
|
// NOLINTNEXTLINE(misc-definitions-in-headers)
|
||||||
void run_program(const Op* program, const void** contexts, SKCMS_MAYBE_UNUSED ptrdiff_t programSize,
|
void run_program(const Op* program, const void** contexts, SKCMS_MAYBE_UNUSED ptrdiff_t programSize,
|
||||||
const char* src, char* dst, int n,
|
const char* src, char* dst, int n,
|
||||||
const size_t src_bpp, const size_t dst_bpp) {
|
size_t src_bpp, size_t dst_bpp) {
|
||||||
#if SKCMS_HAS_MUSTTAIL
|
#if SKCMS_HAS_MUSTTAIL
|
||||||
// Convert the program into an array of tailcall stages.
|
// Convert the program into an array of tailcall stages.
|
||||||
StageFn stages[32];
|
StageFn stages[32];
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ namespace skcms_private {
|
|||||||
M(store_161616BE) \
|
M(store_161616BE) \
|
||||||
M(store_16161616BE) \
|
M(store_16161616BE) \
|
||||||
M(store_101010x_XR) \
|
M(store_101010x_XR) \
|
||||||
|
M(store_10101010_XR) \
|
||||||
M(store_hhh) \
|
M(store_hhh) \
|
||||||
M(store_hhhh) \
|
M(store_hhhh) \
|
||||||
M(store_fff) \
|
M(store_fff) \
|
||||||
@@ -144,21 +145,21 @@ namespace baseline {
|
|||||||
|
|
||||||
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
||||||
const char* src, char* dst, int n,
|
const char* src, char* dst, int n,
|
||||||
const size_t src_bpp, const size_t dst_bpp);
|
size_t src_bpp, size_t dst_bpp);
|
||||||
|
|
||||||
}
|
}
|
||||||
namespace hsw {
|
namespace hsw {
|
||||||
|
|
||||||
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
||||||
const char* src, char* dst, int n,
|
const char* src, char* dst, int n,
|
||||||
const size_t src_bpp, const size_t dst_bpp);
|
size_t src_bpp, size_t dst_bpp);
|
||||||
|
|
||||||
}
|
}
|
||||||
namespace skx {
|
namespace skx {
|
||||||
|
|
||||||
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
||||||
const char* src, char* dst, int n,
|
const char* src, char* dst, int n,
|
||||||
const size_t src_bpp, const size_t dst_bpp);
|
size_t src_bpp, size_t dst_bpp);
|
||||||
|
|
||||||
}
|
}
|
||||||
} // namespace skcms_private
|
} // namespace skcms_private
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace hsw {
|
|||||||
|
|
||||||
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
||||||
const char* src, char* dst, int n,
|
const char* src, char* dst, int n,
|
||||||
const size_t src_bpp, const size_t dst_bpp) {
|
size_t src_bpp, size_t dst_bpp) {
|
||||||
skcms_private::baseline::run_program(program, contexts, programSize,
|
skcms_private::baseline::run_program(program, contexts, programSize,
|
||||||
src, dst, n, src_bpp, dst_bpp);
|
src, dst, n, src_bpp, dst_bpp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace skx {
|
|||||||
|
|
||||||
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
void run_program(const Op* program, const void** contexts, ptrdiff_t programSize,
|
||||||
const char* src, char* dst, int n,
|
const char* src, char* dst, int n,
|
||||||
const size_t src_bpp, const size_t dst_bpp) {
|
size_t src_bpp, size_t dst_bpp) {
|
||||||
skcms_private::baseline::run_program(program, contexts, programSize,
|
skcms_private::baseline::run_program(program, contexts, programSize,
|
||||||
src, dst, n, src_bpp, dst_bpp);
|
src, dst, n, src_bpp, dst_bpp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ SKCMS_API bool skcms_TransferFunction_isHLGish (const skcms_TransferFunction*);
|
|||||||
// Unified representation of 'curv' or 'para' tag data, or a 1D table from 'mft1' or 'mft2'
|
// Unified representation of 'curv' or 'para' tag data, or a 1D table from 'mft1' or 'mft2'
|
||||||
typedef union skcms_Curve {
|
typedef union skcms_Curve {
|
||||||
struct {
|
struct {
|
||||||
|
// this needs to line up with alias_of_table_entries so we can tell if there are or
|
||||||
|
// are not table entries. If this is 0, this struct is a parametric function,
|
||||||
|
// otherwise it's a table entry.
|
||||||
uint32_t alias_of_table_entries;
|
uint32_t alias_of_table_entries;
|
||||||
skcms_TransferFunction parametric;
|
skcms_TransferFunction parametric;
|
||||||
};
|
};
|
||||||
@@ -123,44 +126,44 @@ typedef struct skcms_A2B {
|
|||||||
// Optional: N 1D "A" curves, followed by an N-dimensional CLUT.
|
// Optional: N 1D "A" curves, followed by an N-dimensional CLUT.
|
||||||
// If input_channels == 0, these curves and CLUT are skipped,
|
// If input_channels == 0, these curves and CLUT are skipped,
|
||||||
// Otherwise, input_channels must be in [1, 4].
|
// Otherwise, input_channels must be in [1, 4].
|
||||||
uint32_t input_channels;
|
|
||||||
skcms_Curve input_curves[4];
|
skcms_Curve input_curves[4];
|
||||||
uint8_t grid_points[4];
|
|
||||||
const uint8_t* grid_8;
|
const uint8_t* grid_8;
|
||||||
const uint8_t* grid_16;
|
const uint8_t* grid_16;
|
||||||
|
uint32_t input_channels;
|
||||||
|
uint8_t grid_points[4];
|
||||||
|
|
||||||
// Optional: 3 1D "M" curves, followed by a color matrix.
|
// Optional: 3 1D "M" curves, followed by a color matrix.
|
||||||
// If matrix_channels == 0, these curves and matrix are skipped,
|
// If matrix_channels == 0, these curves and matrix are skipped,
|
||||||
// Otherwise, matrix_channels must be 3.
|
// Otherwise, matrix_channels must be 3.
|
||||||
uint32_t matrix_channels;
|
|
||||||
skcms_Curve matrix_curves[3];
|
skcms_Curve matrix_curves[3];
|
||||||
skcms_Matrix3x4 matrix;
|
skcms_Matrix3x4 matrix;
|
||||||
|
uint32_t matrix_channels;
|
||||||
|
|
||||||
// Required: 3 1D "B" curves. Always present, and output_channels must be 3.
|
// Required: 3 1D "B" curves. Always present, and output_channels must be 3.
|
||||||
uint32_t output_channels;
|
uint32_t output_channels; // list first to pack with matrix_channels
|
||||||
skcms_Curve output_curves[3];
|
skcms_Curve output_curves[3];
|
||||||
} skcms_A2B;
|
} skcms_A2B;
|
||||||
|
|
||||||
typedef struct skcms_B2A {
|
typedef struct skcms_B2A {
|
||||||
// Required: 3 1D "B" curves. Always present, and input_channels must be 3.
|
// Required: 3 1D "B" curves. Always present, and input_channels must be 3.
|
||||||
uint32_t input_channels;
|
|
||||||
skcms_Curve input_curves[3];
|
skcms_Curve input_curves[3];
|
||||||
|
uint32_t input_channels;
|
||||||
|
|
||||||
// Optional: a color matrix, followed by 3 1D "M" curves.
|
// Optional: a color matrix, followed by 3 1D "M" curves.
|
||||||
// If matrix_channels == 0, this matrix and these curves are skipped,
|
// If matrix_channels == 0, this matrix and these curves are skipped,
|
||||||
// Otherwise, matrix_channels must be 3.
|
// Otherwise, matrix_channels must be 3.
|
||||||
uint32_t matrix_channels;
|
uint32_t matrix_channels; // list first to pack with input_channels
|
||||||
skcms_Matrix3x4 matrix;
|
|
||||||
skcms_Curve matrix_curves[3];
|
skcms_Curve matrix_curves[3];
|
||||||
|
skcms_Matrix3x4 matrix;
|
||||||
|
|
||||||
// Optional: an N-dimensional CLUT, followed by N 1D "A" curves.
|
// Optional: an N-dimensional CLUT, followed by N 1D "A" curves.
|
||||||
// If output_channels == 0, this CLUT and these curves are skipped,
|
// If output_channels == 0, this CLUT and these curves are skipped,
|
||||||
// Otherwise, output_channels must be in [1, 4].
|
// Otherwise, output_channels must be in [1, 4].
|
||||||
uint32_t output_channels;
|
skcms_Curve output_curves[4];
|
||||||
uint8_t grid_points[4];
|
|
||||||
const uint8_t* grid_8;
|
const uint8_t* grid_8;
|
||||||
const uint8_t* grid_16;
|
const uint8_t* grid_16;
|
||||||
skcms_Curve output_curves[4];
|
uint8_t grid_points[4];
|
||||||
|
uint32_t output_channels;
|
||||||
} skcms_B2A;
|
} skcms_B2A;
|
||||||
|
|
||||||
typedef struct skcms_CICP {
|
typedef struct skcms_CICP {
|
||||||
@@ -182,30 +185,31 @@ typedef struct skcms_ICCProfile {
|
|||||||
|
|
||||||
// If we can parse red, green and blue transfer curves from the profile,
|
// If we can parse red, green and blue transfer curves from the profile,
|
||||||
// trc will be set to those three curves, and has_trc will be true.
|
// trc will be set to those three curves, and has_trc will be true.
|
||||||
bool has_trc;
|
|
||||||
skcms_Curve trc[3];
|
skcms_Curve trc[3];
|
||||||
|
|
||||||
// If this profile's gamut can be represented by a 3x3 transform to XYZD50,
|
// If this profile's gamut can be represented by a 3x3 transform to XYZD50,
|
||||||
// skcms_Parse() sets toXYZD50 to that transform and has_toXYZD50 to true.
|
// skcms_Parse() sets toXYZD50 to that transform and has_toXYZD50 to true.
|
||||||
bool has_toXYZD50;
|
|
||||||
skcms_Matrix3x3 toXYZD50;
|
skcms_Matrix3x3 toXYZD50;
|
||||||
|
|
||||||
// If the profile has a valid A2B0 or A2B1 tag, skcms_Parse() sets A2B to
|
// If the profile has a valid A2B0 or A2B1 tag, skcms_Parse() sets A2B to
|
||||||
// that data, and has_A2B to true. skcms_ParseWithA2BPriority() does the
|
// that data, and has_A2B to true. skcms_ParseWithA2BPriority() does the
|
||||||
// same following any user-provided prioritization of A2B0, A2B1, or A2B2.
|
// same following any user-provided prioritization of A2B0, A2B1, or A2B2.
|
||||||
bool has_A2B;
|
|
||||||
skcms_A2B A2B;
|
skcms_A2B A2B;
|
||||||
|
|
||||||
// If the profile has a valid B2A0 or B2A1 tag, skcms_Parse() sets B2A to
|
// If the profile has a valid B2A0 or B2A1 tag, skcms_Parse() sets B2A to
|
||||||
// that data, and has_B2A to true. skcms_ParseWithA2BPriority() does the
|
// that data, and has_B2A to true. skcms_ParseWithA2BPriority() does the
|
||||||
// same following any user-provided prioritization of B2A0, B2A1, or B2A2.
|
// same following any user-provided prioritization of B2A0, B2A1, or B2A2.
|
||||||
bool has_B2A;
|
|
||||||
skcms_B2A B2A;
|
skcms_B2A B2A;
|
||||||
|
|
||||||
// If the profile has a valid CICP tag, skcms_Parse() sets CICP to that data,
|
// If the profile has a valid CICP tag, skcms_Parse() sets CICP to that data,
|
||||||
// and has_CICP to true.
|
// and has_CICP to true.
|
||||||
bool has_CICP;
|
|
||||||
skcms_CICP CICP;
|
skcms_CICP CICP;
|
||||||
|
|
||||||
|
bool has_trc;
|
||||||
|
bool has_toXYZD50;
|
||||||
|
bool has_A2B;
|
||||||
|
bool has_B2A;
|
||||||
|
bool has_CICP;
|
||||||
} skcms_ICCProfile;
|
} skcms_ICCProfile;
|
||||||
|
|
||||||
// The sRGB color profile is so commonly used that we offer a canonical skcms_ICCProfile for it.
|
// The sRGB color profile is so commonly used that we offer a canonical skcms_ICCProfile for it.
|
||||||
|
|||||||
1
gfx/skia/skia/modules/skcms/version.sha1
Executable file
1
gfx/skia/skia/modules/skcms/version.sha1
Executable file
@@ -0,0 +1 @@
|
|||||||
|
1e365691d01ad13edd93056c2731a5c6e0be2a15
|
||||||
@@ -15,8 +15,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
static constexpr double PI = 3.141592653589793;
|
|
||||||
|
|
||||||
static bool nearly_equal(double x, double y) {
|
static bool nearly_equal(double x, double y) {
|
||||||
if (sk_double_nearly_zero(x)) {
|
if (sk_double_nearly_zero(x)) {
|
||||||
return sk_double_nearly_zero(y);
|
return sk_double_nearly_zero(y);
|
||||||
@@ -92,11 +90,11 @@ int SkCubics::RootsReal(double A, double B, double C, double D, double solution[
|
|||||||
r = neg2RootQ * cos(theta / 3) - adiv3;
|
r = neg2RootQ * cos(theta / 3) - adiv3;
|
||||||
*roots++ = r;
|
*roots++ = r;
|
||||||
|
|
||||||
r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
|
r = neg2RootQ * cos((theta + 2 * SK_DoublePI) / 3) - adiv3;
|
||||||
if (!nearly_equal(solution[0], r)) {
|
if (!nearly_equal(solution[0], r)) {
|
||||||
*roots++ = r;
|
*roots++ = r;
|
||||||
}
|
}
|
||||||
r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
|
r = neg2RootQ * cos((theta - 2 * SK_DoublePI) / 3) - adiv3;
|
||||||
if (!nearly_equal(solution[0], r) &&
|
if (!nearly_equal(solution[0], r) &&
|
||||||
(roots - solution == 1 || !nearly_equal(solution[1], r))) {
|
(roots - solution == 1 || !nearly_equal(solution[1], r))) {
|
||||||
*roots++ = r;
|
*roots++ = r;
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
//
|
//
|
||||||
// This lock does not obey strict queue ordering. It will always alternate between readers and
|
// This lock does not obey strict queue ordering. It will always alternate between readers and
|
||||||
// a single writer.
|
// a single writer.
|
||||||
|
//
|
||||||
|
// This allows us to have a mutex without needing the one in
|
||||||
|
// the C++ std library which does not work with all clients.
|
||||||
|
// go/cstyle#Disallowed_Stdlib
|
||||||
class SK_CAPABILITY("mutex") SkSharedMutex {
|
class SK_CAPABILITY("mutex") SkSharedMutex {
|
||||||
public:
|
public:
|
||||||
SkSharedMutex();
|
SkSharedMutex();
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
SkTDStorage::SkTDStorage(int sizeOfT) : fSizeOfT{sizeOfT} {}
|
SkTDStorage::SkTDStorage(int sizeOfT) : fSizeOfT{sizeOfT} {}
|
||||||
|
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* C++11 range-for interface.
|
* C++11 range-for interface.
|
||||||
*/
|
*/
|
||||||
bool operator!=(const Iter& that) { return fCurr != that.fCurr; }
|
bool operator!=(const Iter& that) const { return fCurr != that.fCurr; }
|
||||||
T* operator*() { return this->get(); }
|
T* operator*() { return this->get(); }
|
||||||
void operator++() { this->next(); }
|
void operator++() { this->next(); }
|
||||||
|
|
||||||
|
|||||||
@@ -684,14 +684,12 @@ template <typename Fn, typename... Args, size_t... I>
|
|||||||
SI auto map(std::index_sequence<I...>,
|
SI auto map(std::index_sequence<I...>,
|
||||||
Fn&& fn, const Args&... args) -> skvx::Vec<sizeof...(I), decltype(fn(args[0]...))> {
|
Fn&& fn, const Args&... args) -> skvx::Vec<sizeof...(I), decltype(fn(args[0]...))> {
|
||||||
auto lane = [&](size_t i)
|
auto lane = [&](size_t i)
|
||||||
#if defined(__clang__)
|
|
||||||
// CFI, specifically -fsanitize=cfi-icall, seems to give a false positive here,
|
// CFI, specifically -fsanitize=cfi-icall, seems to give a false positive here,
|
||||||
// with errors like "control flow integrity check for type 'float (float)
|
// with errors like "control flow integrity check for type 'float (float)
|
||||||
// noexcept' failed during indirect function call... note: sqrtf.cfi_jt defined
|
// noexcept' failed during indirect function call... note: sqrtf.cfi_jt defined
|
||||||
// here". But we can be quite sure fn is the right type: it's all inferred!
|
// here". But we can be quite sure fn is the right type: it's all inferred!
|
||||||
// So, stifle CFI in this function.
|
// So, stifle CFI in this function.
|
||||||
__attribute__((no_sanitize("cfi")))
|
SK_NO_SANITIZE_CFI
|
||||||
#endif
|
|
||||||
{ return fn(args[static_cast<int>(i)]...); };
|
{ return fn(args[static_cast<int>(i)]...); };
|
||||||
|
|
||||||
return { lane(I)... };
|
return { lane(I)... };
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ class SkMakeZipDetail {
|
|||||||
public:
|
public:
|
||||||
template<typename... Ts>
|
template<typename... Ts>
|
||||||
static constexpr auto MakeZip(Ts&& ... ts) {
|
static constexpr auto MakeZip(Ts&& ... ts) {
|
||||||
|
// NOLINTBEGIN
|
||||||
// Pick the first collection that has a size, and use that for the size.
|
// Pick the first collection that has a size, and use that for the size.
|
||||||
size_t size = PickOneSize<DecayPointerT<Ts>...>::Size(std::forward<Ts>(ts)...);
|
size_t size = PickOneSize<DecayPointerT<Ts>...>::Size(std::forward<Ts>(ts)...);
|
||||||
|
|
||||||
@@ -197,6 +197,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
return SkZip<ValueType<Ts>...>(size, Span<Ts>::Data(std::forward<Ts>(ts))...);
|
return SkZip<ValueType<Ts>...>(size, Span<Ts>::Data(std::forward<Ts>(ts))...);
|
||||||
|
// NOLINTEND
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,560 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "include/codec/SkAndroidCodec.h"
|
|
||||||
|
|
||||||
#include "include/codec/SkCodec.h"
|
|
||||||
#include "include/codec/SkEncodedImageFormat.h"
|
|
||||||
#include "include/core/SkAlphaType.h"
|
|
||||||
#include "include/core/SkColorType.h"
|
|
||||||
#include "include/core/SkData.h"
|
|
||||||
#include "include/core/SkRect.h"
|
|
||||||
#include "include/core/SkStream.h"
|
|
||||||
#include "modules/skcms/skcms.h"
|
|
||||||
#include "src/codec/SkAndroidCodecAdapter.h"
|
|
||||||
#include "src/codec/SkCodecPriv.h"
|
|
||||||
#include "src/codec/SkSampledCodec.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <functional>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
class SkPngChunkReader;
|
|
||||||
|
|
||||||
static bool is_valid_sample_size(int sampleSize) {
|
|
||||||
// FIXME: As Leon has mentioned elsewhere, surely there is also a maximum sampleSize?
|
|
||||||
return sampleSize > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cicp_get_primaries(uint8_t primaries, skcms_Matrix3x3* sk_primaries) {
|
|
||||||
// Rec. ITU-T H.273, Table 2.
|
|
||||||
switch (primaries) {
|
|
||||||
case 0:
|
|
||||||
// Reserved.
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
*sk_primaries = SkNamedGamut::kSRGB;
|
|
||||||
return true;
|
|
||||||
case 2:
|
|
||||||
// Unspecified.
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// Reserved.
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f, 0.31f, 0.316f, sk_primaries);
|
|
||||||
case 5:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.64f, 0.33f, 0.29f, 0.60f, 0.15f, 0.06f, 0.3127f, 0.3290f, sk_primaries);
|
|
||||||
case 6:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f, 0.3127f, 0.3290f, sk_primaries);
|
|
||||||
case 7:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f, 0.3127f, 0.3290f, sk_primaries);
|
|
||||||
case 8:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.681f, 0.319f, 0.243f, 0.692f, 0.145f, 0.049f, 0.310f, 0.316f, sk_primaries);
|
|
||||||
case 9:
|
|
||||||
*sk_primaries = SkNamedGamut::kRec2020;
|
|
||||||
return true;
|
|
||||||
case 10:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f / 3.f, 1.f / 3.f, sk_primaries);
|
|
||||||
case 11:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, 0.314f, 0.351f, sk_primaries);
|
|
||||||
case 12:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, 0.3127f, 0.3290f, sk_primaries);
|
|
||||||
case 22:
|
|
||||||
return skcms_PrimariesToXYZD50(
|
|
||||||
0.630f, 0.340f, 0.295f, 0.605f, 0.155f, 0.077f, 0.3127f, 0.3290f, sk_primaries);
|
|
||||||
default:
|
|
||||||
// Reserved.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*sk_primaries = SkNamedGamut::kSRGB;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cicp_get_transfer_fn(uint8_t transfer_characteristics, skcms_TransferFunction* trfn) {
|
|
||||||
// Rec. ITU-T H.273, Table 3.
|
|
||||||
switch (transfer_characteristics) {
|
|
||||||
case 0:
|
|
||||||
// Reserved.
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
*trfn = SkNamedTransferFn::kRec2020;
|
|
||||||
return true;
|
|
||||||
case 2:
|
|
||||||
// Unspecified.
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// Reserved.
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
*trfn = {2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
return true;
|
|
||||||
case 5:
|
|
||||||
*trfn = {2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
return true;
|
|
||||||
case 6:
|
|
||||||
*trfn = SkNamedTransferFn::kRec2020;
|
|
||||||
return true;
|
|
||||||
case 7:
|
|
||||||
*trfn = {2.222222222222f,
|
|
||||||
0.899626676224f,
|
|
||||||
0.100373323776f,
|
|
||||||
0.25f,
|
|
||||||
0.091286342118f,
|
|
||||||
0.f,
|
|
||||||
0.f};
|
|
||||||
return true;
|
|
||||||
case 8:
|
|
||||||
*trfn = SkNamedTransferFn::kLinear;
|
|
||||||
return true;
|
|
||||||
case 9:
|
|
||||||
// Logarithmic transfer characteristic (100:1 range).
|
|
||||||
// Not supported by skcms
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
// Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range).
|
|
||||||
// Not supported by skcms
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
*trfn = SkNamedTransferFn::kSRGB;
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
// Rec. ITU-R BT.1361-0 extended colour gamut system (historical).
|
|
||||||
// Same as kRec709 on positive values, differs on negative values.
|
|
||||||
// Not supported by skcms
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
*trfn = SkNamedTransferFn::kSRGB;
|
|
||||||
return true;
|
|
||||||
case 14:
|
|
||||||
*trfn = SkNamedTransferFn::kRec2020;
|
|
||||||
return true;
|
|
||||||
case 15:
|
|
||||||
*trfn = SkNamedTransferFn::kRec2020;
|
|
||||||
return true;
|
|
||||||
case 16:
|
|
||||||
// Android expects PQ to match 203 nits to SDR white
|
|
||||||
*trfn = {-2.f,
|
|
||||||
-1.55522297832f,
|
|
||||||
1.86045365631f,
|
|
||||||
32 / 2523.0f,
|
|
||||||
2413 / 128.0f,
|
|
||||||
-2392 / 128.0f,
|
|
||||||
8192 / 1305.0f};
|
|
||||||
return true;
|
|
||||||
case 17:
|
|
||||||
*trfn = {2.6f, 1.034080527699f, 0.f, 0.f, 0.f, 0.f, 0.f};
|
|
||||||
return true;
|
|
||||||
case 18:
|
|
||||||
// Android expects HLG to match 203 nits to SDR white
|
|
||||||
if (skcms_TransferFunction_makeScaledHLGish(trfn,
|
|
||||||
0.314509843f,
|
|
||||||
2.f,
|
|
||||||
2.f,
|
|
||||||
1.f / 0.17883277f,
|
|
||||||
0.28466892f,
|
|
||||||
0.55991073f)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// 19-255 Reserved.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*trfn = SkNamedTransferFn::kSRGB;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sk_sp<SkColorSpace> cicp_get_sk_color_space(uint8_t color_primaries,
|
|
||||||
uint8_t transfer_characteristics,
|
|
||||||
uint8_t matrix_coefficients,
|
|
||||||
uint8_t full_range_flag) {
|
|
||||||
if (matrix_coefficients != 0) return nullptr;
|
|
||||||
|
|
||||||
if (full_range_flag != 1) return nullptr;
|
|
||||||
|
|
||||||
skcms_TransferFunction trfn;
|
|
||||||
if (!cicp_get_transfer_fn(transfer_characteristics, &trfn)) return nullptr;
|
|
||||||
|
|
||||||
skcms_Matrix3x3 primaries;
|
|
||||||
if (!cicp_get_primaries(color_primaries, &primaries)) return nullptr;
|
|
||||||
|
|
||||||
return SkColorSpace::MakeRGB(trfn, primaries);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkAndroidCodec::SkAndroidCodec(SkCodec* codec)
|
|
||||||
: fInfo(codec->getInfo())
|
|
||||||
, fCodec(codec)
|
|
||||||
{}
|
|
||||||
|
|
||||||
SkAndroidCodec::~SkAndroidCodec() {}
|
|
||||||
|
|
||||||
std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
|
||||||
SkPngChunkReader* chunkReader) {
|
|
||||||
auto codec = SkCodec::MakeFromStream(std::move(stream), nullptr, chunkReader);
|
|
||||||
return MakeFromCodec(std::move(codec));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromCodec(std::unique_ptr<SkCodec> codec) {
|
|
||||||
if (nullptr == codec) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkEncodedImageFormat format = codec->getEncodedFormat();
|
|
||||||
if (format == SkEncodedImageFormat::kAVIF) {
|
|
||||||
if (SkCodecs::HasDecoder("avif")) {
|
|
||||||
// If a dedicated AVIF decoder has been registered, SkAvifCodec can
|
|
||||||
// handle scaling internally.
|
|
||||||
return std::make_unique<SkAndroidCodecAdapter>(codec.release());
|
|
||||||
}
|
|
||||||
// This will fallback to SkHeifCodec, which needs sampling.
|
|
||||||
return std::make_unique<SkSampledCodec>(codec.release());
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case SkEncodedImageFormat::kPNG:
|
|
||||||
case SkEncodedImageFormat::kICO:
|
|
||||||
case SkEncodedImageFormat::kJPEG:
|
|
||||||
case SkEncodedImageFormat::kBMP:
|
|
||||||
case SkEncodedImageFormat::kWBMP:
|
|
||||||
case SkEncodedImageFormat::kHEIF:
|
|
||||||
return std::make_unique<SkSampledCodec>(codec.release());
|
|
||||||
case SkEncodedImageFormat::kGIF:
|
|
||||||
case SkEncodedImageFormat::kWEBP:
|
|
||||||
case SkEncodedImageFormat::kDNG:
|
|
||||||
return std::make_unique<SkAndroidCodecAdapter>(codec.release());
|
|
||||||
case SkEncodedImageFormat::kAVIF: // Handled above
|
|
||||||
case SkEncodedImageFormat::kPKM:
|
|
||||||
case SkEncodedImageFormat::kKTX:
|
|
||||||
case SkEncodedImageFormat::kASTC:
|
|
||||||
case SkEncodedImageFormat::kJPEGXL:
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
SkUNREACHABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkAndroidCodec> SkAndroidCodec::MakeFromData(sk_sp<SkData> data,
|
|
||||||
SkPngChunkReader* chunkReader) {
|
|
||||||
if (!data) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MakeFromStream(SkMemoryStream::Make(std::move(data)), chunkReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) {
|
|
||||||
bool highPrecision = fCodec->getEncodedInfo().bitsPerComponent() > 8;
|
|
||||||
uint8_t colorDepth = fCodec->getEncodedInfo().getColorDepth();
|
|
||||||
switch (requestedColorType) {
|
|
||||||
case kARGB_4444_SkColorType:
|
|
||||||
return kN32_SkColorType;
|
|
||||||
case kN32_SkColorType:
|
|
||||||
break;
|
|
||||||
case kAlpha_8_SkColorType:
|
|
||||||
// Fall through to kGray_8. Before kGray_8_SkColorType existed,
|
|
||||||
// we allowed clients to request kAlpha_8 when they wanted a
|
|
||||||
// grayscale decode.
|
|
||||||
case kGray_8_SkColorType:
|
|
||||||
if (kGray_8_SkColorType == this->getInfo().colorType()) {
|
|
||||||
return kGray_8_SkColorType;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case kRGB_565_SkColorType:
|
|
||||||
if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
|
|
||||||
return kRGB_565_SkColorType;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case kRGBA_1010102_SkColorType:
|
|
||||||
if (colorDepth == 10) {
|
|
||||||
return kRGBA_1010102_SkColorType;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case kRGBA_F16_SkColorType:
|
|
||||||
return kRGBA_F16_SkColorType;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// F16 is the Android default for high precision images.
|
|
||||||
return highPrecision ? kRGBA_F16_SkColorType :
|
|
||||||
(colorDepth == 10 ? kRGBA_1010102_SkColorType : kN32_SkColorType);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) {
|
|
||||||
if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
|
|
||||||
return kOpaque_SkAlphaType;
|
|
||||||
}
|
|
||||||
return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
|
|
||||||
}
|
|
||||||
|
|
||||||
sk_sp<SkColorSpace> SkAndroidCodec::computeOutputColorSpace(SkColorType outputColorType,
|
|
||||||
sk_sp<SkColorSpace> prefColorSpace) {
|
|
||||||
switch (outputColorType) {
|
|
||||||
case kRGBA_F16_SkColorType:
|
|
||||||
case kRGB_565_SkColorType:
|
|
||||||
case kRGBA_8888_SkColorType:
|
|
||||||
case kBGRA_8888_SkColorType:
|
|
||||||
case kRGBA_1010102_SkColorType: {
|
|
||||||
// If |prefColorSpace| is supplied, choose it.
|
|
||||||
if (prefColorSpace) {
|
|
||||||
return prefColorSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
const skcms_ICCProfile* encodedProfile = fCodec->getEncodedInfo().profile();
|
|
||||||
if (encodedProfile) {
|
|
||||||
// Prefer CICP information if it exists.
|
|
||||||
if (encodedProfile->has_CICP) {
|
|
||||||
const auto cicpColorSpace =
|
|
||||||
cicp_get_sk_color_space(encodedProfile->CICP.color_primaries,
|
|
||||||
encodedProfile->CICP.transfer_characteristics,
|
|
||||||
encodedProfile->CICP.matrix_coefficients,
|
|
||||||
encodedProfile->CICP.video_full_range_flag);
|
|
||||||
if (cicpColorSpace) {
|
|
||||||
return cicpColorSpace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (auto encodedSpace = SkColorSpace::Make(*encodedProfile)) {
|
|
||||||
// Leave the pixels in the encoded color space. Color space conversion
|
|
||||||
// will be handled after decode time.
|
|
||||||
return encodedSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encodedProfile->has_toXYZD50) {
|
|
||||||
return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
|
|
||||||
encodedProfile->toXYZD50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SkColorSpace::MakeSRGB();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// Color correction not supported for kGray.
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool supports_any_down_scale(const SkCodec* codec) {
|
|
||||||
return codec->getEncodedFormat() == SkEncodedImageFormat::kWEBP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are a variety of ways two SkISizes could be compared. This method
|
|
||||||
// returns true if either dimensions of a is < that of b.
|
|
||||||
// computeSampleSize also uses the opposite, which means that both
|
|
||||||
// dimensions of a >= b.
|
|
||||||
static inline bool smaller_than(const SkISize& a, const SkISize& b) {
|
|
||||||
return a.width() < b.width() || a.height() < b.height();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both dimensions of a > that of b.
|
|
||||||
static inline bool strictly_bigger_than(const SkISize& a, const SkISize& b) {
|
|
||||||
return a.width() > b.width() && a.height() > b.height();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkAndroidCodec::computeSampleSize(SkISize* desiredSize) const {
|
|
||||||
SkASSERT(desiredSize);
|
|
||||||
|
|
||||||
const auto origDims = fCodec->dimensions();
|
|
||||||
if (!desiredSize || *desiredSize == origDims) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smaller_than(origDims, *desiredSize)) {
|
|
||||||
*desiredSize = origDims;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle bad input:
|
|
||||||
if (desiredSize->width() < 1 || desiredSize->height() < 1) {
|
|
||||||
*desiredSize = SkISize::Make(std::max(1, desiredSize->width()),
|
|
||||||
std::max(1, desiredSize->height()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supports_any_down_scale(fCodec.get())) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sampleX = origDims.width() / desiredSize->width();
|
|
||||||
int sampleY = origDims.height() / desiredSize->height();
|
|
||||||
int sampleSize = std::min(sampleX, sampleY);
|
|
||||||
auto computedSize = this->getSampledDimensions(sampleSize);
|
|
||||||
if (computedSize == *desiredSize) {
|
|
||||||
return sampleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (computedSize == origDims || sampleSize == 1) {
|
|
||||||
// Cannot downscale
|
|
||||||
*desiredSize = computedSize;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strictly_bigger_than(computedSize, *desiredSize)) {
|
|
||||||
// See if there is a tighter fit.
|
|
||||||
while (true) {
|
|
||||||
auto smaller = this->getSampledDimensions(sampleSize + 1);
|
|
||||||
if (smaller == *desiredSize) {
|
|
||||||
return sampleSize + 1;
|
|
||||||
}
|
|
||||||
if (smaller == computedSize || smaller_than(smaller, *desiredSize)) {
|
|
||||||
// Cannot get any smaller without being smaller than desired.
|
|
||||||
*desiredSize = computedSize;
|
|
||||||
return sampleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
sampleSize++;
|
|
||||||
computedSize = smaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkASSERT(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!smaller_than(computedSize, *desiredSize)) {
|
|
||||||
// This means one of the computed dimensions is equal to desired, and
|
|
||||||
// the other is bigger. This is as close as we can get.
|
|
||||||
*desiredSize = computedSize;
|
|
||||||
return sampleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// computedSize is too small. Make it larger.
|
|
||||||
while (sampleSize > 2) {
|
|
||||||
auto bigger = this->getSampledDimensions(sampleSize - 1);
|
|
||||||
if (bigger == *desiredSize || !smaller_than(bigger, *desiredSize)) {
|
|
||||||
*desiredSize = bigger;
|
|
||||||
return sampleSize - 1;
|
|
||||||
}
|
|
||||||
sampleSize--;
|
|
||||||
}
|
|
||||||
|
|
||||||
*desiredSize = origDims;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
|
|
||||||
if (!is_valid_sample_size(sampleSize)) {
|
|
||||||
return {0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fast path for when we are not scaling.
|
|
||||||
if (1 == sampleSize) {
|
|
||||||
return fCodec->dimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->onGetSampledDimensions(sampleSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
|
|
||||||
if (!desiredSubset || !is_valid_subset(*desiredSubset, fCodec->dimensions())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->onGetSupportedSubset(desiredSubset);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
|
|
||||||
if (!is_valid_sample_size(sampleSize)) {
|
|
||||||
return {0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
// We require that the input subset is a subset that is supported by SkAndroidCodec.
|
|
||||||
// We test this by calling getSupportedSubset() and verifying that no modifications
|
|
||||||
// are made to the subset.
|
|
||||||
SkIRect copySubset = subset;
|
|
||||||
if (!this->getSupportedSubset(©Subset) || copySubset != subset) {
|
|
||||||
return {0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the subset is the entire image, for consistency, use getSampledDimensions().
|
|
||||||
if (fCodec->dimensions() == subset.size()) {
|
|
||||||
return this->getSampledDimensions(sampleSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should perhaps call a virtual function, but currently both of our subclasses
|
|
||||||
// want the same implementation.
|
|
||||||
return {get_scaled_dimension(subset.width(), sampleSize),
|
|
||||||
get_scaled_dimension(subset.height(), sampleSize)};
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& requestInfo,
|
|
||||||
void* requestPixels, size_t requestRowBytes, const AndroidOptions* options) {
|
|
||||||
if (!requestPixels) {
|
|
||||||
return SkCodec::kInvalidParameters;
|
|
||||||
}
|
|
||||||
if (requestRowBytes < requestInfo.minRowBytes()) {
|
|
||||||
return SkCodec::kInvalidParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
AndroidOptions defaultOptions;
|
|
||||||
if (!options) {
|
|
||||||
options = &defaultOptions;
|
|
||||||
} else {
|
|
||||||
if (options->fSubset) {
|
|
||||||
if (!is_valid_subset(*options->fSubset, fCodec->dimensions())) {
|
|
||||||
return SkCodec::kInvalidParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SkIRect::MakeSize(fCodec->dimensions()) == *options->fSubset) {
|
|
||||||
// The caller wants the whole thing, rather than a subset. Modify
|
|
||||||
// the AndroidOptions passed to onGetAndroidPixels to not specify
|
|
||||||
// a subset.
|
|
||||||
defaultOptions = *options;
|
|
||||||
defaultOptions.fSubset = nullptr;
|
|
||||||
options = &defaultOptions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We may need to have handleFrameIndex recursively call this method
|
|
||||||
// to resolve one frame depending on another. The recursion stops
|
|
||||||
// when we find a frame which does not require an earlier frame
|
|
||||||
// e.g. frame->getRequiredFrame() returns kNoFrame
|
|
||||||
auto getPixelsFn = [&](const SkImageInfo& info, void* pixels, size_t rowBytes,
|
|
||||||
const SkCodec::Options& opts, int requiredFrame
|
|
||||||
) -> SkCodec::Result {
|
|
||||||
SkAndroidCodec::AndroidOptions prevFrameOptions(
|
|
||||||
reinterpret_cast<const SkAndroidCodec::AndroidOptions&>(opts));
|
|
||||||
prevFrameOptions.fFrameIndex = requiredFrame;
|
|
||||||
return this->getAndroidPixels(info, pixels, rowBytes, &prevFrameOptions);
|
|
||||||
};
|
|
||||||
if (auto result = fCodec->handleFrameIndex(requestInfo, requestPixels, requestRowBytes,
|
|
||||||
*options, getPixelsFn); result != SkCodec::kSuccess) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->onGetAndroidPixels(requestInfo, requestPixels, requestRowBytes, *options);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
|
|
||||||
size_t rowBytes) {
|
|
||||||
return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkAndroidCodec::getGainmapAndroidCodec(SkGainmapInfo* info,
|
|
||||||
std::unique_ptr<SkAndroidCodec>* outCodec) {
|
|
||||||
if (outCodec) {
|
|
||||||
std::unique_ptr<SkCodec> gainmapCodec;
|
|
||||||
if (!fCodec->onGetGainmapCodec(info, &gainmapCodec)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*outCodec = MakeFromCodec(std::move(gainmapCodec));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return fCodec->onGetGainmapCodec(info, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkAndroidCodec::getAndroidGainmap(SkGainmapInfo* info,
|
|
||||||
std::unique_ptr<SkStream>* outGainmapImageStream) {
|
|
||||||
return fCodec->onGetGainmapInfo(info, outGainmapImageStream);
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "src/codec/SkAndroidCodecAdapter.h"
|
|
||||||
#include "src/codec/SkCodecPriv.h"
|
|
||||||
|
|
||||||
struct SkIRect;
|
|
||||||
struct SkImageInfo;
|
|
||||||
|
|
||||||
SkAndroidCodecAdapter::SkAndroidCodecAdapter(SkCodec* codec)
|
|
||||||
: INHERITED(codec)
|
|
||||||
{}
|
|
||||||
|
|
||||||
SkISize SkAndroidCodecAdapter::onGetSampledDimensions(int sampleSize) const {
|
|
||||||
float scale = get_scale_from_sample_size(sampleSize);
|
|
||||||
return this->codec()->getScaledDimensions(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkAndroidCodecAdapter::onGetSupportedSubset(SkIRect* desiredSubset) const {
|
|
||||||
return this->codec()->getValidSubset(desiredSubset);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkAndroidCodecAdapter::onGetAndroidPixels(const SkImageInfo& info, void* pixels,
|
|
||||||
size_t rowBytes, const AndroidOptions& options) {
|
|
||||||
return this->codec()->getPixels(info, pixels, rowBytes, &options);
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
#ifndef SkAndroidCodecAdapter_DEFINED
|
|
||||||
#define SkAndroidCodecAdapter_DEFINED
|
|
||||||
|
|
||||||
#include "include/codec/SkAndroidCodec.h"
|
|
||||||
#include "include/codec/SkCodec.h"
|
|
||||||
#include "include/core/SkSize.h"
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
struct SkIRect;
|
|
||||||
struct SkImageInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class wraps SkCodec to implement the functionality of SkAndroidCodec.
|
|
||||||
* The underlying SkCodec implements sampled decodes. SkCodec's that do not
|
|
||||||
* implement that are wrapped with SkSampledCodec instead.
|
|
||||||
*/
|
|
||||||
class SkAndroidCodecAdapter : public SkAndroidCodec {
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit SkAndroidCodecAdapter(SkCodec*);
|
|
||||||
|
|
||||||
~SkAndroidCodecAdapter() override {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
SkISize onGetSampledDimensions(int sampleSize) const override;
|
|
||||||
|
|
||||||
bool onGetSupportedSubset(SkIRect* desiredSubset) const override;
|
|
||||||
|
|
||||||
SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
|
|
||||||
const AndroidOptions& options) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
using INHERITED = SkAndroidCodec;
|
|
||||||
};
|
|
||||||
#endif // SkAndroidCodecAdapter_DEFINED
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "src/codec/SkAvifCodec.h"
|
|
||||||
|
|
||||||
#include "include/codec/SkAvifDecoder.h"
|
|
||||||
#include "include/codec/SkCodec.h"
|
|
||||||
#include "include/codec/SkCodecAnimation.h"
|
|
||||||
#include "include/core/SkColorType.h"
|
|
||||||
#include "include/core/SkImageInfo.h"
|
|
||||||
#include "include/core/SkSize.h"
|
|
||||||
#include "include/core/SkStream.h"
|
|
||||||
#include "include/core/SkTypes.h"
|
|
||||||
#include "modules/skcms/skcms.h"
|
|
||||||
#include "src/core/SkStreamPriv.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "avif/avif.h"
|
|
||||||
|
|
||||||
void AvifDecoderDeleter::operator()(avifDecoder* decoder) const {
|
|
||||||
if (decoder != nullptr) {
|
|
||||||
avifDecoderDestroy(decoder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkAvifCodec::IsAvif(const void* buffer, size_t bytesRead) {
|
|
||||||
avifROData avifData = {static_cast<const uint8_t*>(buffer), bytesRead};
|
|
||||||
bool isAvif = avifPeekCompatibleFileType(&avifData) == AVIF_TRUE;
|
|
||||||
if (isAvif) return true;
|
|
||||||
// Peeking sometimes fails if the ftyp box is too large. Check the signature
|
|
||||||
// just to be sure.
|
|
||||||
const char* bytes = static_cast<const char*>(buffer);
|
|
||||||
isAvif = bytesRead >= 12 && !memcmp(&bytes[4], "ftyp", 4) &&
|
|
||||||
(!memcmp(&bytes[8], "avif", 4) || !memcmp(&bytes[8], "avis", 4));
|
|
||||||
return isAvif;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkCodec> SkAvifCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
|
||||||
Result* result) {
|
|
||||||
SkASSERT(result);
|
|
||||||
if (!stream) {
|
|
||||||
*result = SkCodec::kInvalidInput;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
AvifDecoder avifDecoder(avifDecoderCreate());
|
|
||||||
if (avifDecoder == nullptr) {
|
|
||||||
*result = SkCodec::kInternalError;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
avifDecoder->ignoreXMP = AVIF_TRUE;
|
|
||||||
avifDecoder->ignoreExif = AVIF_TRUE;
|
|
||||||
avifDecoder->allowProgressive = AVIF_FALSE;
|
|
||||||
avifDecoder->allowIncremental = AVIF_FALSE;
|
|
||||||
avifDecoder->strictFlags = AVIF_STRICT_DISABLED;
|
|
||||||
// TODO(vigneshv): Enable threading based on number of CPU cores available.
|
|
||||||
avifDecoder->maxThreads = 1;
|
|
||||||
|
|
||||||
// libavif needs a contiguous data buffer.
|
|
||||||
sk_sp<SkData> data = nullptr;
|
|
||||||
if (stream->getMemoryBase()) {
|
|
||||||
// It is safe to make without copy because we'll hold onto the stream.
|
|
||||||
data = SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength());
|
|
||||||
} else {
|
|
||||||
data = SkCopyStreamToData(stream.get());
|
|
||||||
// If we are forced to copy the stream to a data, we can go ahead and
|
|
||||||
// delete the stream.
|
|
||||||
stream.reset(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
avifResult res = avifDecoderSetIOMemory(avifDecoder.get(), data->bytes(), data->size());
|
|
||||||
if (res != AVIF_RESULT_OK) {
|
|
||||||
*result = SkCodec::kInternalError;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = avifDecoderParse(avifDecoder.get());
|
|
||||||
if (res != AVIF_RESULT_OK) {
|
|
||||||
*result = SkCodec::kInvalidInput;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
|
|
||||||
// TODO(vigneshv): Get ICC Profile from the avif decoder.
|
|
||||||
|
|
||||||
const int bitsPerComponent = avifDecoder->image->depth > 8 ? 16 : 8;
|
|
||||||
SkEncodedInfo::Color color;
|
|
||||||
SkEncodedInfo::Alpha alpha;
|
|
||||||
if (avifDecoder->alphaPresent) {
|
|
||||||
color = SkEncodedInfo::kRGBA_Color;
|
|
||||||
alpha = SkEncodedInfo::kUnpremul_Alpha;
|
|
||||||
} else {
|
|
||||||
color = SkEncodedInfo::kRGB_Color;
|
|
||||||
alpha = SkEncodedInfo::kOpaque_Alpha;
|
|
||||||
}
|
|
||||||
SkEncodedInfo info = SkEncodedInfo::Make(avifDecoder->image->width,
|
|
||||||
avifDecoder->image->height,
|
|
||||||
color,
|
|
||||||
alpha,
|
|
||||||
bitsPerComponent,
|
|
||||||
std::move(profile),
|
|
||||||
avifDecoder->image->depth);
|
|
||||||
bool animation = avifDecoder->imageCount > 1;
|
|
||||||
*result = kSuccess;
|
|
||||||
return std::unique_ptr<SkCodec>(new SkAvifCodec(std::move(info),
|
|
||||||
std::move(stream),
|
|
||||||
std::move(data),
|
|
||||||
std::move(avifDecoder),
|
|
||||||
kDefault_SkEncodedOrigin,
|
|
||||||
animation));
|
|
||||||
}
|
|
||||||
|
|
||||||
SkAvifCodec::SkAvifCodec(SkEncodedInfo&& info,
|
|
||||||
std::unique_ptr<SkStream> stream,
|
|
||||||
sk_sp<SkData> data,
|
|
||||||
AvifDecoder avifDecoder,
|
|
||||||
SkEncodedOrigin origin,
|
|
||||||
bool useAnimation)
|
|
||||||
: INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream), origin)
|
|
||||||
, fData(std::move(data))
|
|
||||||
, fAvifDecoder(std::move(avifDecoder))
|
|
||||||
, fUseAnimation(useAnimation) {}
|
|
||||||
|
|
||||||
int SkAvifCodec::onGetFrameCount() {
|
|
||||||
if (!fUseAnimation) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fFrameHolder.size() == 0) {
|
|
||||||
if (fAvifDecoder->imageCount <= 1) {
|
|
||||||
fUseAnimation = false;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
fFrameHolder.reserve(fAvifDecoder->imageCount);
|
|
||||||
for (int i = 0; i < fAvifDecoder->imageCount; i++) {
|
|
||||||
Frame* frame = fFrameHolder.appendNewFrame(fAvifDecoder->alphaPresent == AVIF_TRUE);
|
|
||||||
frame->setXYWH(0, 0, fAvifDecoder->image->width, fAvifDecoder->image->height);
|
|
||||||
frame->setDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep);
|
|
||||||
avifImageTiming timing;
|
|
||||||
avifDecoderNthImageTiming(fAvifDecoder.get(), i, &timing);
|
|
||||||
frame->setDuration(timing.duration * 1000);
|
|
||||||
frame->setRequiredFrame(SkCodec::kNoFrame);
|
|
||||||
frame->setHasAlpha(fAvifDecoder->alphaPresent == AVIF_TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fFrameHolder.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkFrame* SkAvifCodec::FrameHolder::onGetFrame(int i) const {
|
|
||||||
return static_cast<const SkFrame*>(this->frame(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
SkAvifCodec::Frame* SkAvifCodec::FrameHolder::appendNewFrame(bool hasAlpha) {
|
|
||||||
const int i = this->size();
|
|
||||||
fFrames.emplace_back(i,
|
|
||||||
hasAlpha ? SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha);
|
|
||||||
return &fFrames[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkAvifCodec::Frame* SkAvifCodec::FrameHolder::frame(int i) const {
|
|
||||||
SkASSERT(i >= 0 && i < this->size());
|
|
||||||
return &fFrames[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkAvifCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
|
|
||||||
if (i >= fFrameHolder.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Frame* frame = fFrameHolder.frame(i);
|
|
||||||
if (!frame) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frameInfo) {
|
|
||||||
frame->fillIn(frameInfo, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkAvifCodec::onGetRepetitionCount() { return kRepetitionCountInfinite; }
|
|
||||||
|
|
||||||
SkCodec::Result SkAvifCodec::onGetPixels(const SkImageInfo& dstInfo,
|
|
||||||
void* dst,
|
|
||||||
size_t dstRowBytes,
|
|
||||||
const Options& options,
|
|
||||||
int* rowsDecoded) {
|
|
||||||
if (options.fSubset) {
|
|
||||||
return kUnimplemented;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkColorType dstColorType = dstInfo.colorType();
|
|
||||||
if (dstColorType != kRGBA_8888_SkColorType && dstColorType != kRGBA_F16_SkColorType) {
|
|
||||||
// TODO(vigneshv): Check if more color types need to be supported.
|
|
||||||
// Currently android supports at least RGB565 and BGRA8888 which is not
|
|
||||||
// supported here.
|
|
||||||
return kUnimplemented;
|
|
||||||
}
|
|
||||||
|
|
||||||
avifResult result = avifDecoderNthImage(fAvifDecoder.get(), options.fFrameIndex);
|
|
||||||
if (result != AVIF_RESULT_OK) {
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->dimensions() != dstInfo.dimensions()) {
|
|
||||||
result = avifImageScale(
|
|
||||||
fAvifDecoder->image, dstInfo.width(), dstInfo.height(), &fAvifDecoder->diag);
|
|
||||||
if (result != AVIF_RESULT_OK) {
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
avifRGBImage rgbImage;
|
|
||||||
avifRGBImageSetDefaults(&rgbImage, fAvifDecoder->image);
|
|
||||||
|
|
||||||
if (dstColorType == kRGBA_8888_SkColorType) {
|
|
||||||
rgbImage.depth = 8;
|
|
||||||
} else if (dstColorType == kRGBA_F16_SkColorType) {
|
|
||||||
rgbImage.depth = 16;
|
|
||||||
rgbImage.isFloat = AVIF_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
rgbImage.pixels = static_cast<uint8_t*>(dst);
|
|
||||||
rgbImage.rowBytes = dstRowBytes;
|
|
||||||
rgbImage.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST;
|
|
||||||
|
|
||||||
result = avifImageYUVToRGB(fAvifDecoder->image, &rgbImage);
|
|
||||||
if (result != AVIF_RESULT_OK) {
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
*rowsDecoded = fAvifDecoder->image->height;
|
|
||||||
return kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace SkAvifDecoder {
|
|
||||||
namespace LibAvif {
|
|
||||||
|
|
||||||
bool IsAvif(const void* data, size_t len) {
|
|
||||||
return SkAvifCodec::IsAvif(data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream> stream,
|
|
||||||
SkCodec::Result* outResult,
|
|
||||||
SkCodecs::DecodeContext) {
|
|
||||||
SkCodec::Result resultStorage;
|
|
||||||
if (!outResult) {
|
|
||||||
outResult = &resultStorage;
|
|
||||||
}
|
|
||||||
return SkAvifCodec::MakeFromStream(std::move(stream), outResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkCodec> Decode(sk_sp<SkData> data,
|
|
||||||
SkCodec::Result* outResult,
|
|
||||||
SkCodecs::DecodeContext) {
|
|
||||||
if (!data) {
|
|
||||||
if (outResult) {
|
|
||||||
*outResult = SkCodec::kInvalidInput;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return Decode(SkMemoryStream::Make(std::move(data)), outResult, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace LibAvif
|
|
||||||
} // namespace SkAvifDecoder
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SkAvifCodec_DEFINED
|
|
||||||
#define SkAvifCodec_DEFINED
|
|
||||||
|
|
||||||
#include "include/codec/SkEncodedImageFormat.h"
|
|
||||||
#include "include/codec/SkEncodedOrigin.h"
|
|
||||||
#include "include/core/SkData.h"
|
|
||||||
#include "include/core/SkRefCnt.h"
|
|
||||||
#include "include/private/SkEncodedInfo.h"
|
|
||||||
#include "src/codec/SkFrameHolder.h"
|
|
||||||
#include "src/codec/SkScalingCodec.h"
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class SkCodec;
|
|
||||||
class SkStream;
|
|
||||||
struct SkImageInfo;
|
|
||||||
struct avifDecoder;
|
|
||||||
struct AvifDecoderDeleter {
|
|
||||||
void operator()(avifDecoder* decoder) const;
|
|
||||||
};
|
|
||||||
using AvifDecoder = std::unique_ptr<avifDecoder, AvifDecoderDeleter>;
|
|
||||||
|
|
||||||
class SkAvifCodec : public SkScalingCodec {
|
|
||||||
public:
|
|
||||||
/*
|
|
||||||
* Returns true if an AVIF image is detected. Returns false otherwise.
|
|
||||||
*/
|
|
||||||
static bool IsAvif(const void*, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assumes IsAvif() was called and it returned true.
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Result onGetPixels(const SkImageInfo& dstInfo,
|
|
||||||
void* dst,
|
|
||||||
size_t dstRowBytes,
|
|
||||||
const Options& options,
|
|
||||||
int* rowsDecoded) override;
|
|
||||||
|
|
||||||
SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kAVIF; }
|
|
||||||
|
|
||||||
int onGetFrameCount() override;
|
|
||||||
bool onGetFrameInfo(int, FrameInfo*) const override;
|
|
||||||
int onGetRepetitionCount() override;
|
|
||||||
const SkFrameHolder* getFrameHolder() const override { return &fFrameHolder; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
SkAvifCodec(SkEncodedInfo&&,
|
|
||||||
std::unique_ptr<SkStream>,
|
|
||||||
sk_sp<SkData>,
|
|
||||||
AvifDecoder,
|
|
||||||
SkEncodedOrigin,
|
|
||||||
bool);
|
|
||||||
|
|
||||||
// fAvifDecoder has a pointer to this data. This should not be freed until
|
|
||||||
// the decode is completed. To ensure that, we declare this before
|
|
||||||
// fAvifDecoder.
|
|
||||||
sk_sp<SkData> fData;
|
|
||||||
|
|
||||||
AvifDecoder fAvifDecoder;
|
|
||||||
bool fUseAnimation;
|
|
||||||
|
|
||||||
class Frame : public SkFrame {
|
|
||||||
public:
|
|
||||||
Frame(int i, SkEncodedInfo::Alpha alpha) : INHERITED(i), fReportedAlpha(alpha) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
SkEncodedInfo::Alpha onReportedAlpha() const override { return fReportedAlpha; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const SkEncodedInfo::Alpha fReportedAlpha;
|
|
||||||
|
|
||||||
using INHERITED = SkFrame;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FrameHolder : public SkFrameHolder {
|
|
||||||
public:
|
|
||||||
~FrameHolder() override {}
|
|
||||||
void setScreenSize(int w, int h) {
|
|
||||||
fScreenWidth = w;
|
|
||||||
fScreenHeight = h;
|
|
||||||
}
|
|
||||||
Frame* appendNewFrame(bool hasAlpha);
|
|
||||||
const Frame* frame(int i) const;
|
|
||||||
int size() const { return static_cast<int>(fFrames.size()); }
|
|
||||||
void reserve(int size) { fFrames.reserve(size); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const SkFrame* onGetFrame(int i) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Frame> fFrames;
|
|
||||||
};
|
|
||||||
|
|
||||||
FrameHolder fFrameHolder;
|
|
||||||
using INHERITED = SkScalingCodec;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SkAvifCodec_DEFINED
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
#include "src/codec/SkBmpBaseCodec.h"
|
|
||||||
|
|
||||||
#include "include/core/SkStream.h"
|
|
||||||
#include "include/private/SkEncodedInfo.h"
|
|
||||||
#include "include/private/base/SkMalloc.h"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
SkBmpBaseCodec::~SkBmpBaseCodec() {}
|
|
||||||
|
|
||||||
SkBmpBaseCodec::SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
|
||||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
|
|
||||||
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
|
||||||
, fSrcBuffer(sk_malloc_canfail(this->srcRowBytes()))
|
|
||||||
{}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 SkBmpBaseCodec_DEFINED
|
|
||||||
#define SkBmpBaseCodec_DEFINED
|
|
||||||
|
|
||||||
#include "include/codec/SkCodec.h"
|
|
||||||
#include "include/private/base/SkTemplates.h"
|
|
||||||
#include "src/codec/SkBmpCodec.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class SkStream;
|
|
||||||
struct SkEncodedInfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Common base class for SkBmpStandardCodec and SkBmpMaskCodec.
|
|
||||||
*/
|
|
||||||
class SkBmpBaseCodec : public SkBmpCodec {
|
|
||||||
public:
|
|
||||||
~SkBmpBaseCodec() override;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Whether fSrcBuffer was successfully created.
|
|
||||||
*
|
|
||||||
* If false, this Codec must not be used.
|
|
||||||
*/
|
|
||||||
bool didCreateSrcBuffer() const { return fSrcBuffer != nullptr; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
|
|
||||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
|
|
||||||
|
|
||||||
uint8_t* srcBuffer() { return reinterpret_cast<uint8_t*>(fSrcBuffer.get()); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
skia_private::UniqueVoidPtr fSrcBuffer;
|
|
||||||
|
|
||||||
using INHERITED = SkBmpCodec;
|
|
||||||
};
|
|
||||||
#endif // SkBmpBaseCodec_DEFINED
|
|
||||||
@@ -1,695 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "src/codec/SkBmpCodec.h"
|
|
||||||
|
|
||||||
#include "include/codec/SkBmpDecoder.h"
|
|
||||||
#include "include/core/SkData.h"
|
|
||||||
#include "include/core/SkImageInfo.h"
|
|
||||||
#include "include/core/SkRefCnt.h"
|
|
||||||
#include "include/core/SkSize.h"
|
|
||||||
#include "include/core/SkStream.h"
|
|
||||||
#include "include/private/SkEncodedInfo.h"
|
|
||||||
#include "include/private/base/SkAlign.h"
|
|
||||||
#include "src/codec/SkBmpMaskCodec.h"
|
|
||||||
#include "src/codec/SkBmpRLECodec.h"
|
|
||||||
#include "src/codec/SkBmpStandardCodec.h"
|
|
||||||
#include "src/codec/SkCodecPriv.h"
|
|
||||||
#include "src/core/SkMasks.h"
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Defines the version and type of the second bitmap header
|
|
||||||
*/
|
|
||||||
enum BmpHeaderType {
|
|
||||||
kInfoV1_BmpHeaderType,
|
|
||||||
kInfoV2_BmpHeaderType,
|
|
||||||
kInfoV3_BmpHeaderType,
|
|
||||||
kInfoV4_BmpHeaderType,
|
|
||||||
kInfoV5_BmpHeaderType,
|
|
||||||
kOS2V1_BmpHeaderType,
|
|
||||||
kOS2VX_BmpHeaderType,
|
|
||||||
kUnknown_BmpHeaderType
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Possible bitmap compression types
|
|
||||||
*/
|
|
||||||
enum BmpCompressionMethod {
|
|
||||||
kNone_BmpCompressionMethod = 0,
|
|
||||||
k8BitRLE_BmpCompressionMethod = 1,
|
|
||||||
k4BitRLE_BmpCompressionMethod = 2,
|
|
||||||
kBitMasks_BmpCompressionMethod = 3,
|
|
||||||
kJpeg_BmpCompressionMethod = 4,
|
|
||||||
kPng_BmpCompressionMethod = 5,
|
|
||||||
kAlphaBitMasks_BmpCompressionMethod = 6,
|
|
||||||
kCMYK_BmpCompressionMethod = 11,
|
|
||||||
kCMYK8BitRLE_BmpCompressionMethod = 12,
|
|
||||||
kCMYK4BitRLE_BmpCompressionMethod = 13
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used to define the input format of the bmp
|
|
||||||
*/
|
|
||||||
enum BmpInputFormat {
|
|
||||||
kStandard_BmpInputFormat,
|
|
||||||
kRLE_BmpInputFormat,
|
|
||||||
kBitMask_BmpInputFormat,
|
|
||||||
kUnknown_BmpInputFormat
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Checks the start of the stream to see if the image is a bitmap
|
|
||||||
*/
|
|
||||||
bool SkBmpCodec::IsBmp(const void* buffer, size_t bytesRead) {
|
|
||||||
// TODO: Support "IC", "PT", "CI", "CP", "BA"
|
|
||||||
const char bmpSig[] = { 'B', 'M' };
|
|
||||||
return bytesRead >= sizeof(bmpSig) && !memcmp(buffer, bmpSig, sizeof(bmpSig));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assumes IsBmp was called and returned true
|
|
||||||
* Creates a bmp decoder
|
|
||||||
* Reads enough of the stream to determine the image format
|
|
||||||
*/
|
|
||||||
std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
|
||||||
Result* result) {
|
|
||||||
return SkBmpCodec::MakeFromStream(std::move(stream), result, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates a bmp decoder for a bmp embedded in ico
|
|
||||||
* Reads enough of the stream to determine the image format
|
|
||||||
*/
|
|
||||||
std::unique_ptr<SkCodec> SkBmpCodec::MakeFromIco(std::unique_ptr<SkStream> stream, Result* result) {
|
|
||||||
return SkBmpCodec::MakeFromStream(std::move(stream), result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header size constants
|
|
||||||
static constexpr uint32_t kBmpHeaderBytes = 14;
|
|
||||||
static constexpr uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4;
|
|
||||||
static constexpr uint32_t kBmpOS2V1Bytes = 12;
|
|
||||||
static constexpr uint32_t kBmpOS2V2Bytes = 64;
|
|
||||||
static constexpr uint32_t kBmpInfoBaseBytes = 16;
|
|
||||||
static constexpr uint32_t kBmpInfoV1Bytes = 40;
|
|
||||||
static constexpr uint32_t kBmpInfoV2Bytes = 52;
|
|
||||||
static constexpr uint32_t kBmpInfoV3Bytes = 56;
|
|
||||||
static constexpr uint32_t kBmpInfoV4Bytes = 108;
|
|
||||||
static constexpr uint32_t kBmpInfoV5Bytes = 124;
|
|
||||||
static constexpr uint32_t kBmpMaskBytes = 12;
|
|
||||||
|
|
||||||
static BmpHeaderType get_header_type(size_t infoBytes) {
|
|
||||||
if (infoBytes >= kBmpInfoBaseBytes) {
|
|
||||||
// Check the version of the header
|
|
||||||
switch (infoBytes) {
|
|
||||||
case kBmpInfoV1Bytes:
|
|
||||||
return kInfoV1_BmpHeaderType;
|
|
||||||
case kBmpInfoV2Bytes:
|
|
||||||
return kInfoV2_BmpHeaderType;
|
|
||||||
case kBmpInfoV3Bytes:
|
|
||||||
return kInfoV3_BmpHeaderType;
|
|
||||||
case kBmpInfoV4Bytes:
|
|
||||||
return kInfoV4_BmpHeaderType;
|
|
||||||
case kBmpInfoV5Bytes:
|
|
||||||
return kInfoV5_BmpHeaderType;
|
|
||||||
case 16:
|
|
||||||
case 20:
|
|
||||||
case 24:
|
|
||||||
case 28:
|
|
||||||
case 32:
|
|
||||||
case 36:
|
|
||||||
case 42:
|
|
||||||
case 46:
|
|
||||||
case 48:
|
|
||||||
case 60:
|
|
||||||
case kBmpOS2V2Bytes:
|
|
||||||
return kOS2VX_BmpHeaderType;
|
|
||||||
default:
|
|
||||||
SkCodecPrintf("Error: unknown bmp header format.\n");
|
|
||||||
return kUnknown_BmpHeaderType;
|
|
||||||
}
|
|
||||||
} if (infoBytes >= kBmpOS2V1Bytes) {
|
|
||||||
// The OS2V1 is treated separately because it has a unique format
|
|
||||||
return kOS2V1_BmpHeaderType;
|
|
||||||
} else {
|
|
||||||
// There are no valid bmp headers
|
|
||||||
SkCodecPrintf("Error: second bitmap header size is invalid.\n");
|
|
||||||
return kUnknown_BmpHeaderType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco,
|
|
||||||
std::unique_ptr<SkCodec>* codecOut) {
|
|
||||||
// The total bytes in the bmp file
|
|
||||||
// We only need to use this value for RLE decoding, so we will only
|
|
||||||
// check that it is valid in the RLE case.
|
|
||||||
uint32_t totalBytes;
|
|
||||||
// The offset from the start of the file where the pixel data begins
|
|
||||||
uint32_t offset;
|
|
||||||
// The size of the second (info) header in bytes
|
|
||||||
uint32_t infoBytes;
|
|
||||||
|
|
||||||
// Bmps embedded in Icos skip the first Bmp header
|
|
||||||
if (!inIco) {
|
|
||||||
// Read the first header and the size of the second header
|
|
||||||
uint8_t hBuffer[kBmpHeaderBytesPlusFour];
|
|
||||||
if (stream->read(hBuffer, kBmpHeaderBytesPlusFour) !=
|
|
||||||
kBmpHeaderBytesPlusFour) {
|
|
||||||
SkCodecPrintf("Error: unable to read first bitmap header.\n");
|
|
||||||
return kIncompleteInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalBytes = get_int(hBuffer, 2);
|
|
||||||
offset = get_int(hBuffer, 10);
|
|
||||||
if (offset < kBmpHeaderBytes + kBmpOS2V1Bytes) {
|
|
||||||
SkCodecPrintf("Error: invalid starting location for pixel data\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The size of the second (info) header in bytes
|
|
||||||
// The size is the first field of the second header, so we have already
|
|
||||||
// read the first four infoBytes.
|
|
||||||
infoBytes = get_int(hBuffer, 14);
|
|
||||||
if (infoBytes < kBmpOS2V1Bytes) {
|
|
||||||
SkCodecPrintf("Error: invalid second header size.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This value is only used by RLE compression. Bmp in Ico files do not
|
|
||||||
// use RLE. If the compression field is incorrectly signaled as RLE,
|
|
||||||
// we will catch this and signal an error below.
|
|
||||||
totalBytes = 0;
|
|
||||||
|
|
||||||
// Bmps in Ico cannot specify an offset. We will always assume that
|
|
||||||
// pixel data begins immediately after the color table. This value
|
|
||||||
// will be corrected below.
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
// Read the size of the second header
|
|
||||||
uint8_t hBuffer[4];
|
|
||||||
if (stream->read(hBuffer, 4) != 4) {
|
|
||||||
SkCodecPrintf("Error: unable to read size of second bitmap header.\n");
|
|
||||||
return kIncompleteInput;
|
|
||||||
}
|
|
||||||
infoBytes = get_int(hBuffer, 0);
|
|
||||||
if (infoBytes < kBmpOS2V1Bytes) {
|
|
||||||
SkCodecPrintf("Error: invalid second header size.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine image information depending on second header format
|
|
||||||
const BmpHeaderType headerType = get_header_type(infoBytes);
|
|
||||||
if (kUnknown_BmpHeaderType == headerType) {
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We already read the first four bytes of the info header to get the size
|
|
||||||
const uint32_t infoBytesRemaining = infoBytes - 4;
|
|
||||||
|
|
||||||
// Read the second header
|
|
||||||
std::unique_ptr<uint8_t[]> iBuffer(new uint8_t[infoBytesRemaining]);
|
|
||||||
if (stream->read(iBuffer.get(), infoBytesRemaining) != infoBytesRemaining) {
|
|
||||||
SkCodecPrintf("Error: unable to read second bitmap header.\n");
|
|
||||||
return kIncompleteInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The number of bits used per pixel in the pixel data
|
|
||||||
uint16_t bitsPerPixel;
|
|
||||||
|
|
||||||
// The compression method for the pixel data
|
|
||||||
uint32_t compression = kNone_BmpCompressionMethod;
|
|
||||||
|
|
||||||
// Number of colors in the color table, defaults to 0 or max (see below)
|
|
||||||
uint32_t numColors = 0;
|
|
||||||
|
|
||||||
// Bytes per color in the color table, early versions use 3, most use 4
|
|
||||||
uint32_t bytesPerColor;
|
|
||||||
|
|
||||||
// The image width and height
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
switch (headerType) {
|
|
||||||
case kInfoV1_BmpHeaderType:
|
|
||||||
case kInfoV2_BmpHeaderType:
|
|
||||||
case kInfoV3_BmpHeaderType:
|
|
||||||
case kInfoV4_BmpHeaderType:
|
|
||||||
case kInfoV5_BmpHeaderType:
|
|
||||||
case kOS2VX_BmpHeaderType:
|
|
||||||
// We check the size of the header before entering the if statement.
|
|
||||||
// We should not reach this point unless the size is large enough for
|
|
||||||
// these required fields.
|
|
||||||
SkASSERT(infoBytesRemaining >= 12);
|
|
||||||
width = get_int(iBuffer.get(), 0);
|
|
||||||
height = get_int(iBuffer.get(), 4);
|
|
||||||
bitsPerPixel = get_short(iBuffer.get(), 10);
|
|
||||||
|
|
||||||
// Some versions do not have these fields, so we check before
|
|
||||||
// overwriting the default value.
|
|
||||||
if (infoBytesRemaining >= 16) {
|
|
||||||
compression = get_int(iBuffer.get(), 12);
|
|
||||||
if (infoBytesRemaining >= 32) {
|
|
||||||
numColors = get_int(iBuffer.get(), 28);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All of the headers that reach this point, store color table entries
|
|
||||||
// using 4 bytes per pixel.
|
|
||||||
bytesPerColor = 4;
|
|
||||||
break;
|
|
||||||
case kOS2V1_BmpHeaderType:
|
|
||||||
// The OS2V1 is treated separately because it has a unique format
|
|
||||||
width = (int) get_short(iBuffer.get(), 0);
|
|
||||||
height = (int) get_short(iBuffer.get(), 2);
|
|
||||||
bitsPerPixel = get_short(iBuffer.get(), 6);
|
|
||||||
bytesPerColor = 3;
|
|
||||||
break;
|
|
||||||
case kUnknown_BmpHeaderType:
|
|
||||||
// We'll exit above in this case.
|
|
||||||
SkASSERT(false);
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for valid dimensions from header
|
|
||||||
SkCodec::SkScanlineOrder rowOrder = SkCodec::kBottomUp_SkScanlineOrder;
|
|
||||||
if (height < 0) {
|
|
||||||
// We can't negate INT32_MIN.
|
|
||||||
if (height == INT32_MIN) {
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
height = -height;
|
|
||||||
rowOrder = SkCodec::kTopDown_SkScanlineOrder;
|
|
||||||
}
|
|
||||||
// The height field for bmp in ico is double the actual height because they
|
|
||||||
// contain an XOR mask followed by an AND mask
|
|
||||||
if (inIco) {
|
|
||||||
height /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Arbitrary maximum. Matches Chromium.
|
|
||||||
constexpr int kMaxDim = 1 << 16;
|
|
||||||
if (width <= 0 || height <= 0 || width >= kMaxDim || height >= kMaxDim) {
|
|
||||||
SkCodecPrintf("Error: invalid bitmap dimensions.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create mask struct
|
|
||||||
SkMasks::InputMasks inputMasks;
|
|
||||||
memset(&inputMasks, 0, sizeof(SkMasks::InputMasks));
|
|
||||||
|
|
||||||
// Determine the input compression format and set bit masks if necessary
|
|
||||||
uint32_t maskBytes = 0;
|
|
||||||
BmpInputFormat inputFormat = kUnknown_BmpInputFormat;
|
|
||||||
switch (compression) {
|
|
||||||
case kNone_BmpCompressionMethod:
|
|
||||||
inputFormat = kStandard_BmpInputFormat;
|
|
||||||
|
|
||||||
// In addition to more standard pixel compression formats, bmp supports
|
|
||||||
// the use of bit masks to determine pixel components. The standard
|
|
||||||
// format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB),
|
|
||||||
// which does not map well to any Skia color formats. For this reason,
|
|
||||||
// we will always enable mask mode with 16 bits per pixel.
|
|
||||||
if (16 == bitsPerPixel) {
|
|
||||||
inputMasks.red = 0x7C00;
|
|
||||||
inputMasks.green = 0x03E0;
|
|
||||||
inputMasks.blue = 0x001F;
|
|
||||||
inputFormat = kBitMask_BmpInputFormat;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case k8BitRLE_BmpCompressionMethod:
|
|
||||||
if (bitsPerPixel != 8) {
|
|
||||||
SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
|
|
||||||
bitsPerPixel = 8;
|
|
||||||
}
|
|
||||||
inputFormat = kRLE_BmpInputFormat;
|
|
||||||
break;
|
|
||||||
case k4BitRLE_BmpCompressionMethod:
|
|
||||||
if (bitsPerPixel != 4) {
|
|
||||||
SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
|
|
||||||
bitsPerPixel = 4;
|
|
||||||
}
|
|
||||||
inputFormat = kRLE_BmpInputFormat;
|
|
||||||
break;
|
|
||||||
case kAlphaBitMasks_BmpCompressionMethod:
|
|
||||||
case kBitMasks_BmpCompressionMethod:
|
|
||||||
// Load the masks
|
|
||||||
inputFormat = kBitMask_BmpInputFormat;
|
|
||||||
switch (headerType) {
|
|
||||||
case kInfoV1_BmpHeaderType: {
|
|
||||||
// The V1 header stores the bit masks after the header
|
|
||||||
uint8_t buffer[kBmpMaskBytes];
|
|
||||||
if (stream->read(buffer, kBmpMaskBytes) != kBmpMaskBytes) {
|
|
||||||
SkCodecPrintf("Error: unable to read bit inputMasks.\n");
|
|
||||||
return kIncompleteInput;
|
|
||||||
}
|
|
||||||
maskBytes = kBmpMaskBytes;
|
|
||||||
inputMasks.red = get_int(buffer, 0);
|
|
||||||
inputMasks.green = get_int(buffer, 4);
|
|
||||||
inputMasks.blue = get_int(buffer, 8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kInfoV2_BmpHeaderType:
|
|
||||||
case kInfoV3_BmpHeaderType:
|
|
||||||
case kInfoV4_BmpHeaderType:
|
|
||||||
case kInfoV5_BmpHeaderType:
|
|
||||||
// Header types are matched based on size. If the header
|
|
||||||
// is V2+, we are guaranteed to be able to read at least
|
|
||||||
// this size.
|
|
||||||
SkASSERT(infoBytesRemaining >= 48);
|
|
||||||
inputMasks.red = get_int(iBuffer.get(), 36);
|
|
||||||
inputMasks.green = get_int(iBuffer.get(), 40);
|
|
||||||
inputMasks.blue = get_int(iBuffer.get(), 44);
|
|
||||||
|
|
||||||
if (kInfoV2_BmpHeaderType == headerType ||
|
|
||||||
(kInfoV3_BmpHeaderType == headerType && !inIco)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// V3+ bmp files introduce an alpha mask and allow the creator of the image
|
|
||||||
// to use the alpha channels. However, many of these images leave the
|
|
||||||
// alpha channel blank and expect to be rendered as opaque. This is the
|
|
||||||
// case for almost all V3 images, so we ignore the alpha mask. For V4+
|
|
||||||
// images in kMask mode, we will use the alpha mask. Additionally, V3
|
|
||||||
// bmp-in-ico expect us to use the alpha mask.
|
|
||||||
//
|
|
||||||
// skbug.com/4116: We should perhaps also apply the alpha mask in kStandard
|
|
||||||
// mode. We just haven't seen any images that expect this
|
|
||||||
// behavior.
|
|
||||||
//
|
|
||||||
// Header types are matched based on size. If the header is
|
|
||||||
// V3+, we are guaranteed to be able to read at least this size.
|
|
||||||
SkASSERT(infoBytesRemaining >= 52);
|
|
||||||
inputMasks.alpha = get_int(iBuffer.get(), 48);
|
|
||||||
break;
|
|
||||||
case kOS2VX_BmpHeaderType:
|
|
||||||
// TODO: Decide if we intend to support this.
|
|
||||||
// It is unsupported in the previous version and
|
|
||||||
// in chromium. I have not come across a test case
|
|
||||||
// that uses this format.
|
|
||||||
SkCodecPrintf("Error: huffman format unsupported.\n");
|
|
||||||
return kUnimplemented;
|
|
||||||
default:
|
|
||||||
SkCodecPrintf("Error: invalid bmp bit masks header.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case kJpeg_BmpCompressionMethod:
|
|
||||||
if (24 == bitsPerPixel) {
|
|
||||||
inputFormat = kRLE_BmpInputFormat;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
[[fallthrough]];
|
|
||||||
case kPng_BmpCompressionMethod:
|
|
||||||
// TODO: Decide if we intend to support this.
|
|
||||||
// It is unsupported in the previous version and
|
|
||||||
// in chromium. I think it is used mostly for printers.
|
|
||||||
SkCodecPrintf("Error: compression format not supported.\n");
|
|
||||||
return kUnimplemented;
|
|
||||||
case kCMYK_BmpCompressionMethod:
|
|
||||||
case kCMYK8BitRLE_BmpCompressionMethod:
|
|
||||||
case kCMYK4BitRLE_BmpCompressionMethod:
|
|
||||||
// TODO: Same as above.
|
|
||||||
SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n");
|
|
||||||
return kUnimplemented;
|
|
||||||
default:
|
|
||||||
SkCodecPrintf("Error: invalid format for bitmap decoding.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
iBuffer.reset();
|
|
||||||
|
|
||||||
// Calculate the number of bytes read so far
|
|
||||||
const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes;
|
|
||||||
if (!inIco && offset < bytesRead) {
|
|
||||||
// TODO (msarett): Do we really want to fail if the offset in the header is invalid?
|
|
||||||
// Seems like we can just assume that the offset is zero and try to decode?
|
|
||||||
// Maybe we don't want to try to decode corrupt images?
|
|
||||||
SkCodecPrintf("Error: pixel data offset less than header size.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
switch (inputFormat) {
|
|
||||||
case kStandard_BmpInputFormat: {
|
|
||||||
// BMPs are generally opaque, however BMPs-in-ICOs may contain
|
|
||||||
// a transparency mask after the image. Therefore, we mark the
|
|
||||||
// alpha as kBinary if the BMP is contained in an ICO.
|
|
||||||
// We use |isOpaque| to indicate if the BMP itself is opaque.
|
|
||||||
SkEncodedInfo::Alpha alpha = inIco ? SkEncodedInfo::kBinary_Alpha :
|
|
||||||
SkEncodedInfo::kOpaque_Alpha;
|
|
||||||
bool isOpaque = true;
|
|
||||||
|
|
||||||
SkEncodedInfo::Color color;
|
|
||||||
uint8_t bitsPerComponent;
|
|
||||||
switch (bitsPerPixel) {
|
|
||||||
// Palette formats
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 4:
|
|
||||||
case 8:
|
|
||||||
// In the case of ICO, kBGRA is actually the closest match,
|
|
||||||
// since we will need to apply a transparency mask.
|
|
||||||
if (inIco) {
|
|
||||||
color = SkEncodedInfo::kBGRA_Color;
|
|
||||||
bitsPerComponent = 8;
|
|
||||||
} else {
|
|
||||||
color = SkEncodedInfo::kPalette_Color;
|
|
||||||
bitsPerComponent = (uint8_t) bitsPerPixel;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 24:
|
|
||||||
// In the case of ICO, kBGRA is actually the closest match,
|
|
||||||
// since we will need to apply a transparency mask.
|
|
||||||
color = inIco ? SkEncodedInfo::kBGRA_Color : SkEncodedInfo::kBGR_Color;
|
|
||||||
bitsPerComponent = 8;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
// 32-bit BMP-in-ICOs actually use the alpha channel in place of a
|
|
||||||
// transparency mask.
|
|
||||||
if (inIco) {
|
|
||||||
isOpaque = false;
|
|
||||||
alpha = SkEncodedInfo::kUnpremul_Alpha;
|
|
||||||
color = SkEncodedInfo::kBGRA_Color;
|
|
||||||
} else {
|
|
||||||
color = SkEncodedInfo::kBGRX_Color;
|
|
||||||
}
|
|
||||||
bitsPerComponent = 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codecOut) {
|
|
||||||
// We require streams to have a memory base for Bmp-in-Ico decodes.
|
|
||||||
SkASSERT(!inIco || nullptr != stream->getMemoryBase());
|
|
||||||
|
|
||||||
// Set the image info and create a codec.
|
|
||||||
auto info = SkEncodedInfo::Make(width, height, color, alpha, bitsPerComponent);
|
|
||||||
*codecOut = std::make_unique<SkBmpStandardCodec>(std::move(info),
|
|
||||||
std::unique_ptr<SkStream>(stream),
|
|
||||||
bitsPerPixel, numColors, bytesPerColor,
|
|
||||||
offset - bytesRead, rowOrder, isOpaque,
|
|
||||||
inIco);
|
|
||||||
return static_cast<SkBmpStandardCodec*>(codecOut->get())->didCreateSrcBuffer()
|
|
||||||
? kSuccess : kInvalidInput;
|
|
||||||
}
|
|
||||||
return kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
case kBitMask_BmpInputFormat: {
|
|
||||||
// Bmp-in-Ico must be standard mode
|
|
||||||
if (inIco) {
|
|
||||||
SkCodecPrintf("Error: Icos may not use bit mask format.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (bitsPerPixel) {
|
|
||||||
case 16:
|
|
||||||
case 24:
|
|
||||||
case 32:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip to the start of the pixel array.
|
|
||||||
// We can do this here because there is no color table to read
|
|
||||||
// in bit mask mode.
|
|
||||||
if (stream->skip(offset - bytesRead) != offset - bytesRead) {
|
|
||||||
SkCodecPrintf("Error: unable to skip to image data.\n");
|
|
||||||
return kIncompleteInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codecOut) {
|
|
||||||
// Check that input bit masks are valid and create the masks object
|
|
||||||
SkASSERT(bitsPerPixel % 8 == 0);
|
|
||||||
std::unique_ptr<SkMasks> masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel/8));
|
|
||||||
if (nullptr == masks) {
|
|
||||||
SkCodecPrintf("Error: invalid input masks.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Masked bmps are not a great fit for SkEncodedInfo, since they have
|
|
||||||
// arbitrary component orderings and bits per component. Here we choose
|
|
||||||
// somewhat reasonable values - it's ok that we don't match exactly
|
|
||||||
// because SkBmpMaskCodec has its own mask swizzler anyway.
|
|
||||||
SkEncodedInfo::Color color;
|
|
||||||
SkEncodedInfo::Alpha alpha;
|
|
||||||
if (masks->getAlphaMask()) {
|
|
||||||
color = SkEncodedInfo::kBGRA_Color;
|
|
||||||
alpha = SkEncodedInfo::kUnpremul_Alpha;
|
|
||||||
} else {
|
|
||||||
color = SkEncodedInfo::kBGR_Color;
|
|
||||||
alpha = SkEncodedInfo::kOpaque_Alpha;
|
|
||||||
}
|
|
||||||
auto info = SkEncodedInfo::Make(width, height, color, alpha, 8);
|
|
||||||
*codecOut = std::make_unique<SkBmpMaskCodec>(std::move(info),
|
|
||||||
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
|
||||||
masks.release(), rowOrder);
|
|
||||||
return static_cast<SkBmpMaskCodec*>(codecOut->get())->didCreateSrcBuffer()
|
|
||||||
? kSuccess : kInvalidInput;
|
|
||||||
}
|
|
||||||
return kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
case kRLE_BmpInputFormat: {
|
|
||||||
// We should not reach this point without a valid value of bitsPerPixel.
|
|
||||||
SkASSERT(4 == bitsPerPixel || 8 == bitsPerPixel || 24 == bitsPerPixel);
|
|
||||||
|
|
||||||
// Check for a valid number of total bytes when in RLE mode
|
|
||||||
if (totalBytes <= offset) {
|
|
||||||
SkCodecPrintf("Error: RLE requires valid input size.\n");
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bmp-in-Ico must be standard mode
|
|
||||||
// When inIco is true, this line cannot be reached, since we
|
|
||||||
// require that RLE Bmps have a valid number of totalBytes, and
|
|
||||||
// Icos skip the header that contains totalBytes.
|
|
||||||
SkASSERT(!inIco);
|
|
||||||
|
|
||||||
if (codecOut) {
|
|
||||||
// RLE inputs may skip pixels, leaving them as transparent. This
|
|
||||||
// is uncommon, but we cannot be certain that an RLE bmp will be
|
|
||||||
// opaque or that we will be able to represent it with a palette.
|
|
||||||
// For that reason, we always indicate that we are kBGRA.
|
|
||||||
auto info = SkEncodedInfo::Make(width, height, SkEncodedInfo::kBGRA_Color,
|
|
||||||
SkEncodedInfo::kBinary_Alpha, 8);
|
|
||||||
*codecOut = std::make_unique<SkBmpRLECodec>(std::move(info),
|
|
||||||
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
|
||||||
numColors, bytesPerColor, offset - bytesRead,
|
|
||||||
rowOrder);
|
|
||||||
}
|
|
||||||
return kSuccess;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
SkASSERT(false);
|
|
||||||
return kInvalidInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates a bmp decoder
|
|
||||||
* Reads enough of the stream to determine the image format
|
|
||||||
*/
|
|
||||||
std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
|
||||||
Result* result, bool inIco) {
|
|
||||||
SkASSERT(result);
|
|
||||||
if (!stream) {
|
|
||||||
*result = SkCodec::kInvalidInput;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
std::unique_ptr<SkCodec> codec;
|
|
||||||
*result = ReadHeader(stream.get(), inIco, &codec);
|
|
||||||
if (codec) {
|
|
||||||
// codec has taken ownership of stream, so we do not need to delete it.
|
|
||||||
stream.release();
|
|
||||||
}
|
|
||||||
return kSuccess == *result ? std::move(codec) : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkBmpCodec::SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
|
||||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
|
|
||||||
: INHERITED(std::move(info), kXformSrcColorFormat, std::move(stream))
|
|
||||||
, fBitsPerPixel(bitsPerPixel)
|
|
||||||
, fRowOrder(rowOrder)
|
|
||||||
, fSrcRowBytes(SkAlign4(compute_row_bytes(this->dimensions().width(), fBitsPerPixel)))
|
|
||||||
, fXformBuffer(nullptr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool SkBmpCodec::onRewind() {
|
|
||||||
return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), nullptr) == kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const {
|
|
||||||
if (SkCodec::kTopDown_SkScanlineOrder == fRowOrder) {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
SkASSERT(SkCodec::kBottomUp_SkScanlineOrder == fRowOrder);
|
|
||||||
return height - y - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options& options) {
|
|
||||||
return this->onPrepareToDecode(dstInfo, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options& options) {
|
|
||||||
return prepareToDecode(dstInfo, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkBmpCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
|
|
||||||
// Create a new image info representing the portion of the image to decode
|
|
||||||
SkImageInfo rowInfo = this->dstInfo().makeWH(this->dstInfo().width(), count);
|
|
||||||
|
|
||||||
// Decode the requested rows
|
|
||||||
return this->decodeRows(rowInfo, dst, rowBytes, this->options());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkBmpCodec::skipRows(int count) {
|
|
||||||
const size_t bytesToSkip = count * fSrcRowBytes;
|
|
||||||
return this->stream()->skip(bytesToSkip) == bytesToSkip;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkBmpCodec::onSkipScanlines(int count) {
|
|
||||||
return this->skipRows(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace SkBmpDecoder {
|
|
||||||
bool IsBmp(const void* data, size_t len) {
|
|
||||||
return SkBmpCodec::IsBmp(data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream> stream,
|
|
||||||
SkCodec::Result* outResult,
|
|
||||||
SkCodecs::DecodeContext) {
|
|
||||||
SkCodec::Result resultStorage;
|
|
||||||
if (!outResult) {
|
|
||||||
outResult = &resultStorage;
|
|
||||||
}
|
|
||||||
return SkBmpCodec::MakeFromStream(std::move(stream), outResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SkCodec> Decode(sk_sp<SkData> data,
|
|
||||||
SkCodec::Result* outResult,
|
|
||||||
SkCodecs::DecodeContext) {
|
|
||||||
if (!data) {
|
|
||||||
if (outResult) {
|
|
||||||
*outResult = SkCodec::kInvalidInput;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return Decode(SkMemoryStream::Make(std::move(data)), outResult, nullptr);
|
|
||||||
}
|
|
||||||
} // namespace SkBmpDecoder
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
#ifndef SkBmpCodec_DEFINED
|
|
||||||
#define SkBmpCodec_DEFINED
|
|
||||||
|
|
||||||
#include "include/codec/SkCodec.h"
|
|
||||||
#include "include/codec/SkEncodedImageFormat.h"
|
|
||||||
#include "include/core/SkColorType.h"
|
|
||||||
#include "include/core/SkTypes.h"
|
|
||||||
#include "modules/skcms/skcms.h"
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class SkStream;
|
|
||||||
struct SkEncodedInfo;
|
|
||||||
struct SkImageInfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This class enables code sharing between its bmp codec subclasses. The
|
|
||||||
* subclasses actually do the work.
|
|
||||||
*/
|
|
||||||
class SkBmpCodec : public SkCodec {
|
|
||||||
public:
|
|
||||||
static bool IsBmp(const void*, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assumes IsBmp was called and returned true
|
|
||||||
* Creates a bmp decoder
|
|
||||||
* Reads enough of the stream to determine the image format
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates a bmp decoder for a bmp embedded in ico
|
|
||||||
* Reads enough of the stream to determine the image format
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<SkCodec> MakeFromIco(std::unique_ptr<SkStream>, Result*);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
|
|
||||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
|
|
||||||
|
|
||||||
SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kBMP; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read enough of the stream to initialize the SkBmpCodec.
|
|
||||||
* On kSuccess, if codecOut is not nullptr, it will be set to a new SkBmpCodec.
|
|
||||||
*/
|
|
||||||
static Result ReadHeader(SkStream*, bool inIco, std::unique_ptr<SkCodec>* codecOut);
|
|
||||||
|
|
||||||
bool onRewind() override;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns whether this BMP is part of an ICO image.
|
|
||||||
*/
|
|
||||||
bool inIco() const {
|
|
||||||
return this->onInIco();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool onInIco() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the destination row number corresponding to the encoded row number.
|
|
||||||
* For kTopDown, we simply return y, but for kBottomUp, the rows will be
|
|
||||||
* decoded in reverse order.
|
|
||||||
*
|
|
||||||
* @param y Iterates from 0 to height, indicating the current row.
|
|
||||||
* @param height The height of the current subset of the image that we are
|
|
||||||
* decoding. This is generally equal to the full height
|
|
||||||
* when we want to decode the full or one when we are
|
|
||||||
* sampling.
|
|
||||||
*/
|
|
||||||
int32_t getDstRow(int32_t y, int32_t height) const;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Accessors used by subclasses
|
|
||||||
*/
|
|
||||||
uint16_t bitsPerPixel() const { return fBitsPerPixel; }
|
|
||||||
SkScanlineOrder onGetScanlineOrder() const override { return fRowOrder; }
|
|
||||||
size_t srcRowBytes() const { return fSrcRowBytes; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To be overriden by bmp subclasses, which provide unique implementations.
|
|
||||||
* Performs subclass specific setup.
|
|
||||||
*
|
|
||||||
* @param dstInfo Contains output information. Height specifies
|
|
||||||
* the total number of rows that will be decoded.
|
|
||||||
* @param options Additonal options to pass to the decoder.
|
|
||||||
*/
|
|
||||||
virtual SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options& options) = 0;
|
|
||||||
SkCodec::Result prepareToDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options& options);
|
|
||||||
|
|
||||||
uint32_t* xformBuffer() const { return fXformBuffer.get(); }
|
|
||||||
void resetXformBuffer(int count) { fXformBuffer.reset(new uint32_t[count]); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* BMPs are typically encoded as BGRA/BGR so this is a more efficient choice
|
|
||||||
* than RGBA.
|
|
||||||
*/
|
|
||||||
inline static constexpr SkColorType kXformSrcColorType = kBGRA_8888_SkColorType;
|
|
||||||
inline static constexpr auto kXformSrcColorFormat = skcms_PixelFormat_BGRA_8888;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates a bmp decoder
|
|
||||||
* Reads enough of the stream to determine the image format
|
|
||||||
*/
|
|
||||||
static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*, bool inIco);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decodes the next dstInfo.height() lines.
|
|
||||||
*
|
|
||||||
* onGetPixels() uses this for full image decodes.
|
|
||||||
* SkScaledCodec::onGetPixels() uses the scanline decoder to call this with
|
|
||||||
* dstInfo.height() = 1, in order to implement sampling.
|
|
||||||
* A potential future use is to allow the caller to decode a subset of the
|
|
||||||
* lines in the image.
|
|
||||||
*
|
|
||||||
* @param dstInfo Contains output information. Height specifies the
|
|
||||||
* number of rows to decode at this time.
|
|
||||||
* @param dst Memory location to store output pixels
|
|
||||||
* @param dstRowBytes Bytes in a row of the destination
|
|
||||||
* @return Number of rows successfully decoded
|
|
||||||
*/
|
|
||||||
virtual int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
|
|
||||||
const Options& opts) = 0;
|
|
||||||
|
|
||||||
virtual bool skipRows(int count);
|
|
||||||
|
|
||||||
Result onStartScanlineDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options&) override;
|
|
||||||
|
|
||||||
int onGetScanlines(void* dst, int count, size_t rowBytes) override;
|
|
||||||
|
|
||||||
bool onSkipScanlines(int count) override;
|
|
||||||
|
|
||||||
const uint16_t fBitsPerPixel;
|
|
||||||
const SkScanlineOrder fRowOrder;
|
|
||||||
const size_t fSrcRowBytes;
|
|
||||||
std::unique_ptr<uint32_t[]> fXformBuffer;
|
|
||||||
|
|
||||||
using INHERITED = SkCodec;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "src/codec/SkBmpMaskCodec.h"
|
|
||||||
|
|
||||||
#include "include/core/SkAlphaType.h"
|
|
||||||
#include "include/core/SkImageInfo.h"
|
|
||||||
#include "include/core/SkSize.h"
|
|
||||||
#include "include/core/SkStream.h"
|
|
||||||
#include "include/private/SkEncodedInfo.h"
|
|
||||||
#include "include/private/base/SkTemplates.h"
|
|
||||||
#include "src/codec/SkCodecPriv.h"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates an instance of the decoder
|
|
||||||
*/
|
|
||||||
SkBmpMaskCodec::SkBmpMaskCodec(SkEncodedInfo&& info,
|
|
||||||
std::unique_ptr<SkStream> stream,
|
|
||||||
uint16_t bitsPerPixel, SkMasks* masks,
|
|
||||||
SkCodec::SkScanlineOrder rowOrder)
|
|
||||||
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
|
||||||
, fMasks(masks)
|
|
||||||
, fMaskSwizzler(nullptr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initiates the bitmap decode
|
|
||||||
*/
|
|
||||||
SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo,
|
|
||||||
void* dst, size_t dstRowBytes,
|
|
||||||
const Options& opts,
|
|
||||||
int* rowsDecoded) {
|
|
||||||
if (opts.fSubset) {
|
|
||||||
// Subsets are not supported.
|
|
||||||
return kUnimplemented;
|
|
||||||
}
|
|
||||||
if (dstInfo.dimensions() != this->dimensions()) {
|
|
||||||
SkCodecPrintf("Error: scaling not supported.\n");
|
|
||||||
return kInvalidScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result result = this->prepareToDecode(dstInfo, opts);
|
|
||||||
if (kSuccess != result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
|
|
||||||
if (rows != dstInfo.height()) {
|
|
||||||
*rowsDecoded = rows;
|
|
||||||
return kIncompleteInput;
|
|
||||||
}
|
|
||||||
return kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkBmpMaskCodec::onPrepareToDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options& options) {
|
|
||||||
if (this->colorXform()) {
|
|
||||||
this->resetXformBuffer(dstInfo.width());
|
|
||||||
}
|
|
||||||
|
|
||||||
SkImageInfo swizzlerInfo = dstInfo;
|
|
||||||
if (this->colorXform()) {
|
|
||||||
swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType);
|
|
||||||
if (kPremul_SkAlphaType == dstInfo.alphaType()) {
|
|
||||||
swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool srcIsOpaque = this->getEncodedInfo().opaque();
|
|
||||||
fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(swizzlerInfo, srcIsOpaque,
|
|
||||||
fMasks.get(), this->bitsPerPixel(), options));
|
|
||||||
SkASSERT(fMaskSwizzler);
|
|
||||||
|
|
||||||
return SkCodec::kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Performs the decoding
|
|
||||||
*/
|
|
||||||
int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo,
|
|
||||||
void* dst, size_t dstRowBytes,
|
|
||||||
const Options& opts) {
|
|
||||||
// Iterate over rows of the image
|
|
||||||
uint8_t* srcRow = this->srcBuffer();
|
|
||||||
const int height = dstInfo.height();
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
// Read a row of the input
|
|
||||||
if (this->stream()->read(srcRow, this->srcRowBytes()) != this->srcRowBytes()) {
|
|
||||||
SkCodecPrintf("Warning: incomplete input stream.\n");
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode the row in destination format
|
|
||||||
uint32_t row = this->getDstRow(y, height);
|
|
||||||
void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes);
|
|
||||||
|
|
||||||
if (this->colorXform()) {
|
|
||||||
fMaskSwizzler->swizzle(this->xformBuffer(), srcRow);
|
|
||||||
this->applyColorXform(dstRow, this->xformBuffer(), fMaskSwizzler->swizzleWidth());
|
|
||||||
} else {
|
|
||||||
fMaskSwizzler->swizzle(dstRow, srcRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finished decoding the entire image
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SkBmpMaskCodec_DEFINED
|
|
||||||
#define SkBmpMaskCodec_DEFINED
|
|
||||||
|
|
||||||
#include "include/codec/SkCodec.h"
|
|
||||||
#include "include/core/SkTypes.h"
|
|
||||||
#include "src/codec/SkBmpBaseCodec.h"
|
|
||||||
#include "src/codec/SkMaskSwizzler.h"
|
|
||||||
#include "src/core/SkMasks.h"
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class SkSampler;
|
|
||||||
class SkStream;
|
|
||||||
struct SkEncodedInfo;
|
|
||||||
struct SkImageInfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This class implements the decoding for bmp images using bit masks
|
|
||||||
*/
|
|
||||||
class SkBmpMaskCodec : public SkBmpBaseCodec {
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates an instance of the decoder
|
|
||||||
*
|
|
||||||
* Called only by SkBmpCodec::MakeFromStream
|
|
||||||
* There should be no other callers despite this being public
|
|
||||||
*
|
|
||||||
* @param info contains properties of the encoded data
|
|
||||||
* @param stream the stream of encoded image data
|
|
||||||
* @param bitsPerPixel the number of bits used to store each pixel
|
|
||||||
* @param masks color masks for certain bmp formats
|
|
||||||
* @param rowOrder indicates whether rows are ordered top-down or bottom-up
|
|
||||||
*/
|
|
||||||
SkBmpMaskCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
|
|
||||||
uint16_t bitsPerPixel, SkMasks* masks,
|
|
||||||
SkCodec::SkScanlineOrder rowOrder);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Result onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
|
||||||
size_t dstRowBytes, const Options&,
|
|
||||||
int*) override;
|
|
||||||
|
|
||||||
SkCodec::Result onPrepareToDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options& options) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
SkSampler* getSampler(bool createIfNecessary) override {
|
|
||||||
SkASSERT(fMaskSwizzler);
|
|
||||||
return fMaskSwizzler.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
|
|
||||||
const Options& opts) override;
|
|
||||||
|
|
||||||
std::unique_ptr<SkMasks> fMasks;
|
|
||||||
std::unique_ptr<SkMaskSwizzler> fMaskSwizzler;
|
|
||||||
|
|
||||||
using INHERITED = SkBmpBaseCodec;
|
|
||||||
};
|
|
||||||
#endif // SkBmpMaskCodec_DEFINED
|
|
||||||
@@ -1,581 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "src/codec/SkBmpRLECodec.h"
|
|
||||||
|
|
||||||
#include "include/core/SkAlphaType.h"
|
|
||||||
#include "include/core/SkColor.h"
|
|
||||||
#include "include/core/SkColorPriv.h"
|
|
||||||
#include "include/core/SkColorType.h"
|
|
||||||
#include "include/core/SkImageInfo.h"
|
|
||||||
#include "include/core/SkSize.h"
|
|
||||||
#include "include/core/SkStream.h"
|
|
||||||
#include "include/private/SkColorData.h"
|
|
||||||
#include "include/private/SkEncodedInfo.h"
|
|
||||||
#include "include/private/base/SkAlign.h"
|
|
||||||
#include "include/private/base/SkMalloc.h"
|
|
||||||
#include "include/private/base/SkTemplates.h"
|
|
||||||
#include "src/codec/SkCodecPriv.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates an instance of the decoder
|
|
||||||
* Called only by NewFromStream
|
|
||||||
*/
|
|
||||||
SkBmpRLECodec::SkBmpRLECodec(SkEncodedInfo&& info,
|
|
||||||
std::unique_ptr<SkStream> stream,
|
|
||||||
uint16_t bitsPerPixel, uint32_t numColors,
|
|
||||||
uint32_t bytesPerColor, uint32_t offset,
|
|
||||||
SkCodec::SkScanlineOrder rowOrder)
|
|
||||||
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
|
||||||
, fColorTable(nullptr)
|
|
||||||
, fNumColors(numColors)
|
|
||||||
, fBytesPerColor(bytesPerColor)
|
|
||||||
, fOffset(offset)
|
|
||||||
, fBytesBuffered(0)
|
|
||||||
, fCurrRLEByte(0)
|
|
||||||
, fSampleX(1)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initiates the bitmap decode
|
|
||||||
*/
|
|
||||||
SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo,
|
|
||||||
void* dst, size_t dstRowBytes,
|
|
||||||
const Options& opts,
|
|
||||||
int* rowsDecoded) {
|
|
||||||
if (opts.fSubset) {
|
|
||||||
// Subsets are not supported.
|
|
||||||
return kUnimplemented;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result result = this->prepareToDecode(dstInfo, opts);
|
|
||||||
if (kSuccess != result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the decode
|
|
||||||
int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
|
|
||||||
if (rows != dstInfo.height()) {
|
|
||||||
// We set rowsDecoded equal to the height because the background has already
|
|
||||||
// been filled. RLE encodings sometimes skip pixels, so we always start by
|
|
||||||
// filling the background.
|
|
||||||
*rowsDecoded = dstInfo.height();
|
|
||||||
return kIncompleteInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
return kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Process the color table for the bmp input
|
|
||||||
*/
|
|
||||||
bool SkBmpRLECodec::createColorTable(SkColorType dstColorType) {
|
|
||||||
// Allocate memory for color table
|
|
||||||
uint32_t colorBytes = 0;
|
|
||||||
SkPMColor colorTable[256];
|
|
||||||
if (this->bitsPerPixel() <= 8) {
|
|
||||||
// Inform the caller of the number of colors
|
|
||||||
uint32_t maxColors = 1 << this->bitsPerPixel();
|
|
||||||
// Don't bother reading more than maxColors.
|
|
||||||
const uint32_t numColorsToRead =
|
|
||||||
fNumColors == 0 ? maxColors : std::min(fNumColors, maxColors);
|
|
||||||
|
|
||||||
// Read the color table from the stream
|
|
||||||
colorBytes = numColorsToRead * fBytesPerColor;
|
|
||||||
std::unique_ptr<uint8_t[]> cBuffer(new uint8_t[colorBytes]);
|
|
||||||
if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) {
|
|
||||||
SkCodecPrintf("Error: unable to read color table.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in the color table
|
|
||||||
PackColorProc packARGB = choose_pack_color_proc(false, dstColorType);
|
|
||||||
uint32_t i = 0;
|
|
||||||
for (; i < numColorsToRead; i++) {
|
|
||||||
uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
|
|
||||||
uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
|
|
||||||
uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
|
|
||||||
colorTable[i] = packARGB(0xFF, red, green, blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// To avoid segmentation faults on bad pixel data, fill the end of the
|
|
||||||
// color table with black. This is the same the behavior as the
|
|
||||||
// chromium decoder.
|
|
||||||
for (; i < maxColors; i++) {
|
|
||||||
colorTable[i] = SkPackARGB32(0xFF, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the color table
|
|
||||||
fColorTable.reset(new SkColorPalette(colorTable, maxColors));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that we have not read past the pixel array offset
|
|
||||||
if(fOffset < colorBytes) {
|
|
||||||
// This may occur on OS 2.1 and other old versions where the color
|
|
||||||
// table defaults to max size, and the bmp tries to use a smaller
|
|
||||||
// color table. This is invalid, and our decision is to indicate
|
|
||||||
// an error, rather than try to guess the intended size of the
|
|
||||||
// color table.
|
|
||||||
SkCodecPrintf("Error: pixel data offset less than color table size.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// After reading the color table, skip to the start of the pixel array
|
|
||||||
if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) {
|
|
||||||
SkCodecPrintf("Error: unable to skip to image data.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true on success
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkBmpRLECodec::initializeStreamBuffer() {
|
|
||||||
fBytesBuffered = this->stream()->read(fStreamBuffer, kBufferSize);
|
|
||||||
if (fBytesBuffered == 0) {
|
|
||||||
SkCodecPrintf("Error: could not read RLE image data.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fCurrRLEByte = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @return the number of bytes remaining in the stream buffer after
|
|
||||||
* attempting to read more bytes from the stream
|
|
||||||
*/
|
|
||||||
size_t SkBmpRLECodec::checkForMoreData() {
|
|
||||||
const size_t remainingBytes = fBytesBuffered - fCurrRLEByte;
|
|
||||||
uint8_t* buffer = fStreamBuffer;
|
|
||||||
|
|
||||||
// We will be reusing the same buffer, starting over from the beginning.
|
|
||||||
// Move any remaining bytes to the start of the buffer.
|
|
||||||
// We use memmove() instead of memcpy() because there is risk that the dst
|
|
||||||
// and src memory will overlap in corrupt images.
|
|
||||||
memmove(buffer, SkTAddOffset<uint8_t>(buffer, fCurrRLEByte), remainingBytes);
|
|
||||||
|
|
||||||
// Adjust the buffer ptr to the start of the unfilled data.
|
|
||||||
buffer += remainingBytes;
|
|
||||||
|
|
||||||
// Try to read additional bytes from the stream. There are fCurrRLEByte
|
|
||||||
// bytes of additional space remaining in the buffer, assuming that we
|
|
||||||
// have already copied remainingBytes to the start of the buffer.
|
|
||||||
size_t additionalBytes = this->stream()->read(buffer, fCurrRLEByte);
|
|
||||||
|
|
||||||
// Update counters and return the number of bytes we currently have
|
|
||||||
// available. We are at the start of the buffer again.
|
|
||||||
fCurrRLEByte = 0;
|
|
||||||
fBytesBuffered = remainingBytes + additionalBytes;
|
|
||||||
return fBytesBuffered;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set an RLE pixel using the color table
|
|
||||||
*/
|
|
||||||
void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes,
|
|
||||||
const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
|
|
||||||
uint8_t index) {
|
|
||||||
if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
|
|
||||||
// Set the row
|
|
||||||
uint32_t row = this->getDstRow(y, dstInfo.height());
|
|
||||||
|
|
||||||
// Set the pixel based on destination color type
|
|
||||||
const int dstX = get_dst_coord(x, fSampleX);
|
|
||||||
switch (dstInfo.colorType()) {
|
|
||||||
case kRGBA_8888_SkColorType:
|
|
||||||
case kBGRA_8888_SkColorType: {
|
|
||||||
SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
|
|
||||||
dstRow[dstX] = fColorTable->operator[](index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kRGB_565_SkColorType: {
|
|
||||||
uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
|
|
||||||
dstRow[dstX] = SkPixel32ToPixel16(fColorTable->operator[](index));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// This case should not be reached. We should catch an invalid
|
|
||||||
// color type when we check that the conversion is possible.
|
|
||||||
SkASSERT(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set an RLE pixel from R, G, B values
|
|
||||||
*/
|
|
||||||
void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes,
|
|
||||||
const SkImageInfo& dstInfo, uint32_t x,
|
|
||||||
uint32_t y, uint8_t red, uint8_t green,
|
|
||||||
uint8_t blue) {
|
|
||||||
if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
|
|
||||||
// Set the row
|
|
||||||
uint32_t row = this->getDstRow(y, dstInfo.height());
|
|
||||||
|
|
||||||
// Set the pixel based on destination color type
|
|
||||||
const int dstX = get_dst_coord(x, fSampleX);
|
|
||||||
switch (dstInfo.colorType()) {
|
|
||||||
case kRGBA_8888_SkColorType: {
|
|
||||||
SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
|
|
||||||
dstRow[dstX] = SkPackARGB_as_RGBA(0xFF, red, green, blue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kBGRA_8888_SkColorType: {
|
|
||||||
SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
|
|
||||||
dstRow[dstX] = SkPackARGB_as_BGRA(0xFF, red, green, blue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kRGB_565_SkColorType: {
|
|
||||||
uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
|
|
||||||
dstRow[dstX] = SkPack888ToRGB16(red, green, blue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// This case should not be reached. We should catch an invalid
|
|
||||||
// color type when we check that the conversion is possible.
|
|
||||||
SkASSERT(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SkCodec::Result SkBmpRLECodec::onPrepareToDecode(const SkImageInfo& dstInfo,
|
|
||||||
const SkCodec::Options& options) {
|
|
||||||
// FIXME: Support subsets for scanline decodes.
|
|
||||||
if (options.fSubset) {
|
|
||||||
// Subsets are not supported.
|
|
||||||
return kUnimplemented;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset fSampleX. If it needs to be a value other than 1, it will get modified by
|
|
||||||
// the sampler.
|
|
||||||
fSampleX = 1;
|
|
||||||
fLinesToSkip = 0;
|
|
||||||
|
|
||||||
SkColorType colorTableColorType = dstInfo.colorType();
|
|
||||||
if (this->colorXform()) {
|
|
||||||
// Just set a known colorType for the colorTable. No need to actually transform
|
|
||||||
// the colors in the colorTable.
|
|
||||||
colorTableColorType = kBGRA_8888_SkColorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the color table if necessary and prepare the stream for decode
|
|
||||||
// Note that if it is non-NULL, inputColorCount will be modified
|
|
||||||
if (!this->createColorTable(colorTableColorType)) {
|
|
||||||
SkCodecPrintf("Error: could not create color table.\n");
|
|
||||||
return SkCodec::kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize a buffer for encoded RLE data
|
|
||||||
if (!this->initializeStreamBuffer()) {
|
|
||||||
SkCodecPrintf("Error: cannot initialize stream buffer.\n");
|
|
||||||
return SkCodec::kInvalidInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SkCodec::kSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Performs the bitmap decoding for RLE input format
|
|
||||||
* RLE decoding is performed all at once, rather than a one row at a time
|
|
||||||
*/
|
|
||||||
int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowBytes,
|
|
||||||
const Options& opts) {
|
|
||||||
int height = info.height();
|
|
||||||
|
|
||||||
// Account for sampling.
|
|
||||||
SkImageInfo dstInfo = info.makeWH(this->fillWidth(), height);
|
|
||||||
|
|
||||||
// Set the background as transparent. Then, if the RLE code skips pixels,
|
|
||||||
// the skipped pixels will be transparent.
|
|
||||||
if (dst) {
|
|
||||||
SkSampler::Fill(dstInfo, dst, dstRowBytes, opts.fZeroInitialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust the height and the dst if the previous call to decodeRows() left us
|
|
||||||
// with lines that need to be skipped.
|
|
||||||
if (height > fLinesToSkip) {
|
|
||||||
height -= fLinesToSkip;
|
|
||||||
if (dst) {
|
|
||||||
dst = SkTAddOffset<void>(dst, fLinesToSkip * dstRowBytes);
|
|
||||||
}
|
|
||||||
fLinesToSkip = 0;
|
|
||||||
|
|
||||||
dstInfo = dstInfo.makeWH(dstInfo.width(), height);
|
|
||||||
} else {
|
|
||||||
fLinesToSkip -= height;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* decodeDst = dst;
|
|
||||||
size_t decodeRowBytes = dstRowBytes;
|
|
||||||
SkImageInfo decodeInfo = dstInfo;
|
|
||||||
if (decodeDst) {
|
|
||||||
if (this->colorXform()) {
|
|
||||||
decodeInfo = decodeInfo.makeColorType(kXformSrcColorType);
|
|
||||||
if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
|
|
||||||
int count = height * dstInfo.width();
|
|
||||||
this->resetXformBuffer(count);
|
|
||||||
sk_bzero(this->xformBuffer(), count * sizeof(uint32_t));
|
|
||||||
decodeDst = this->xformBuffer();
|
|
||||||
decodeRowBytes = dstInfo.width() * sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int decodedHeight = this->decodeRLE(decodeInfo, decodeDst, decodeRowBytes);
|
|
||||||
if (this->colorXform() && decodeDst) {
|
|
||||||
for (int y = 0; y < decodedHeight; y++) {
|
|
||||||
this->applyColorXform(dst, decodeDst, dstInfo.width());
|
|
||||||
decodeDst = SkTAddOffset<void>(decodeDst, decodeRowBytes);
|
|
||||||
dst = SkTAddOffset<void>(dst, dstRowBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return decodedHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkBmpRLECodec::decodeRLE(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes) {
|
|
||||||
// Use the original width to count the number of pixels in each row.
|
|
||||||
const int width = this->dimensions().width();
|
|
||||||
|
|
||||||
// This tells us the number of rows that we are meant to decode.
|
|
||||||
const int height = dstInfo.height();
|
|
||||||
|
|
||||||
// Set RLE flags
|
|
||||||
constexpr uint8_t RLE_ESCAPE = 0;
|
|
||||||
constexpr uint8_t RLE_EOL = 0;
|
|
||||||
constexpr uint8_t RLE_EOF = 1;
|
|
||||||
constexpr uint8_t RLE_DELTA = 2;
|
|
||||||
|
|
||||||
// Destination parameters
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// If we have reached a row that is beyond the requested height, we have
|
|
||||||
// succeeded.
|
|
||||||
if (y >= height) {
|
|
||||||
// It would be better to check for the EOF marker before indicating
|
|
||||||
// success, but we may be performing a scanline decode, which
|
|
||||||
// would require us to stop before decoding the full height.
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Every entry takes at least two bytes
|
|
||||||
if ((int) fBytesBuffered - fCurrRLEByte < 2) {
|
|
||||||
if (this->checkForMoreData() < 2) {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the next two bytes. These bytes have different meanings
|
|
||||||
// depending on their values. In the first interpretation, the first
|
|
||||||
// byte is an escape flag and the second byte indicates what special
|
|
||||||
// task to perform.
|
|
||||||
const uint8_t flag = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
const uint8_t task = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
|
|
||||||
// Perform decoding
|
|
||||||
if (RLE_ESCAPE == flag) {
|
|
||||||
switch (task) {
|
|
||||||
case RLE_EOL:
|
|
||||||
x = 0;
|
|
||||||
y++;
|
|
||||||
break;
|
|
||||||
case RLE_EOF:
|
|
||||||
return height;
|
|
||||||
case RLE_DELTA: {
|
|
||||||
// Two bytes are needed to specify delta
|
|
||||||
if ((int) fBytesBuffered - fCurrRLEByte < 2) {
|
|
||||||
if (this->checkForMoreData() < 2) {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Modify x and y
|
|
||||||
const uint8_t dx = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
const uint8_t dy = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
x += dx;
|
|
||||||
y += dy;
|
|
||||||
if (x > width) {
|
|
||||||
SkCodecPrintf("Warning: invalid RLE input.\n");
|
|
||||||
return y - dy;
|
|
||||||
} else if (y > height) {
|
|
||||||
fLinesToSkip = y - height;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
// If task does not match any of the above signals, it
|
|
||||||
// indicates that we have a sequence of non-RLE pixels.
|
|
||||||
// Furthermore, the value of task is equal to the number
|
|
||||||
// of pixels to interpret.
|
|
||||||
uint8_t numPixels = task;
|
|
||||||
const size_t rowBytes = compute_row_bytes(numPixels,
|
|
||||||
this->bitsPerPixel());
|
|
||||||
if (x + numPixels > width) {
|
|
||||||
SkCodecPrintf("Warning: invalid RLE input.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abort if there are not enough bytes
|
|
||||||
// remaining in the stream to set numPixels.
|
|
||||||
|
|
||||||
// At most, alignedRowBytes can be 255 (max uint8_t) *
|
|
||||||
// 3 (max bytes per pixel) + 1 (aligned) = 766. If
|
|
||||||
// fStreamBuffer was smaller than this,
|
|
||||||
// checkForMoreData would never succeed for some bmps.
|
|
||||||
static_assert(255 * 3 + 1 < kBufferSize,
|
|
||||||
"kBufferSize needs to be larger!");
|
|
||||||
const size_t alignedRowBytes = SkAlign2(rowBytes);
|
|
||||||
if ((int) fBytesBuffered - fCurrRLEByte < alignedRowBytes) {
|
|
||||||
SkASSERT(alignedRowBytes < kBufferSize);
|
|
||||||
if (this->checkForMoreData() < alignedRowBytes) {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Set numPixels number of pixels
|
|
||||||
while ((numPixels > 0) && (x < width)) {
|
|
||||||
switch(this->bitsPerPixel()) {
|
|
||||||
case 4: {
|
|
||||||
SkASSERT(fCurrRLEByte < fBytesBuffered);
|
|
||||||
uint8_t val = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
setPixel(dst, dstRowBytes, dstInfo, x++,
|
|
||||||
y, val >> 4);
|
|
||||||
numPixels--;
|
|
||||||
if (numPixels != 0) {
|
|
||||||
setPixel(dst, dstRowBytes, dstInfo,
|
|
||||||
x++, y, val & 0xF);
|
|
||||||
numPixels--;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 8:
|
|
||||||
SkASSERT(fCurrRLEByte < fBytesBuffered);
|
|
||||||
setPixel(dst, dstRowBytes, dstInfo, x++,
|
|
||||||
y, fStreamBuffer[fCurrRLEByte++]);
|
|
||||||
numPixels--;
|
|
||||||
break;
|
|
||||||
case 24: {
|
|
||||||
SkASSERT(fCurrRLEByte + 2 < fBytesBuffered);
|
|
||||||
uint8_t blue = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
uint8_t green = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
uint8_t red = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
setRGBPixel(dst, dstRowBytes, dstInfo,
|
|
||||||
x++, y, red, green, blue);
|
|
||||||
numPixels--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
SkASSERT(false);
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Skip a byte if necessary to maintain alignment
|
|
||||||
if (!SkIsAlign2(rowBytes)) {
|
|
||||||
fCurrRLEByte++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the first byte read is not a flag, it indicates the number of
|
|
||||||
// pixels to set in RLE mode.
|
|
||||||
const uint8_t numPixels = flag;
|
|
||||||
const int endX = std::min<int>(x + numPixels, width);
|
|
||||||
|
|
||||||
if (24 == this->bitsPerPixel()) {
|
|
||||||
// In RLE24, the second byte read is part of the pixel color.
|
|
||||||
// There are two more required bytes to finish encoding the
|
|
||||||
// color.
|
|
||||||
if ((int) fBytesBuffered - fCurrRLEByte < 2) {
|
|
||||||
if (this->checkForMoreData() < 2) {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the pixels up to endX with the specified color
|
|
||||||
uint8_t blue = task;
|
|
||||||
uint8_t green = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
uint8_t red = fStreamBuffer[fCurrRLEByte++];
|
|
||||||
while (x < endX) {
|
|
||||||
setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// In RLE8 or RLE4, the second byte read gives the index in the
|
|
||||||
// color table to look up the pixel color.
|
|
||||||
// RLE8 has one color index that gets repeated
|
|
||||||
// RLE4 has two color indexes in the upper and lower 4 bits of
|
|
||||||
// the bytes, which are alternated
|
|
||||||
uint8_t indices[2] = { task, task };
|
|
||||||
if (4 == this->bitsPerPixel()) {
|
|
||||||
indices[0] >>= 4;
|
|
||||||
indices[1] &= 0xf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the indicated number of pixels
|
|
||||||
for (int which = 0; x < endX; x++) {
|
|
||||||
setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]);
|
|
||||||
which = !which;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkBmpRLECodec::skipRows(int count) {
|
|
||||||
const SkImageInfo rowInfo = SkImageInfo::Make(this->dimensions().width(), count,
|
|
||||||
kN32_SkColorType, kUnpremul_SkAlphaType);
|
|
||||||
return count == this->decodeRows(rowInfo, nullptr, 0, this->options());
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Make SkBmpRLECodec have no knowledge of sampling.
|
|
||||||
// Or it should do all sampling natively.
|
|
||||||
// It currently is a hybrid that needs to know what SkScaledCodec is doing.
|
|
||||||
class SkBmpRLESampler : public SkSampler {
|
|
||||||
public:
|
|
||||||
SkBmpRLESampler(SkBmpRLECodec* codec)
|
|
||||||
: fCodec(codec)
|
|
||||||
{
|
|
||||||
SkASSERT(fCodec);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fillWidth() const override {
|
|
||||||
return fCodec->fillWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int onSetSampleX(int sampleX) override {
|
|
||||||
return fCodec->setSampleX(sampleX);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unowned pointer. fCodec will delete this class in its destructor.
|
|
||||||
SkBmpRLECodec* fCodec;
|
|
||||||
};
|
|
||||||
|
|
||||||
SkSampler* SkBmpRLECodec::getSampler(bool createIfNecessary) {
|
|
||||||
if (!fSampler && createIfNecessary) {
|
|
||||||
fSampler = std::make_unique<SkBmpRLESampler>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fSampler.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkBmpRLECodec::setSampleX(int sampleX) {
|
|
||||||
fSampleX = sampleX;
|
|
||||||
return this->fillWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SkBmpRLECodec::fillWidth() const {
|
|
||||||
return get_scaled_dimension(this->dimensions().width(), fSampleX);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user