blob: 256321413c6f7c9c2fd2228a0bb1913dec3a67d0 [file] [log] [blame]
/*
* Copyright 2019 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef AtlasPathRenderer_DEFINED
#define AtlasPathRenderer_DEFINED
#include "include/gpu/GrTypes.h"
#include "src/core/SkIPoint16.h"
#include "src/core/SkTHash.h"
#include "src/gpu/ganesh/GrDynamicAtlas.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "src/gpu/ganesh/GrOnFlushResourceProvider.h"
#include "src/gpu/ganesh/PathRenderer.h"
class GrOp;
class GrRecordingContext;
namespace skgpu::ganesh {
class AtlasRenderTask;
// Draws paths by first rendering their coverage mask into an offscreen atlas.
class AtlasPathRenderer final : public PathRenderer, public GrOnFlushCallbackObject {
public:
static bool IsSupported(GrRecordingContext*);
// Returns a GrAtlasPathRenderer if it is supported, otherwise null.
static sk_sp<AtlasPathRenderer> Make(GrRecordingContext* rContext);
const char* name() const override { return "GrAtlasPathRenderer"; }
// Returns a fragment processor that modulates inputFP by the given deviceSpacePath's coverage,
// implemented using an internal atlas.
//
// Returns 'inputFP' wrapped in GrFPFailure() if the path was too large, or if the current atlas
// is full and already used by either opBeingClipped or inputFP. (Currently, "too large" means
// larger than fMaxAtlasSize in either dimension, more than 256^2 total pixels, or more than
// 128^2 total pixels if the surfaceDrawContext supports MSAA or DMSAA.)
//
// Also returns GrFPFailure() if the view matrix has perspective.
GrFPResult makeAtlasClipEffect(const skgpu::ganesh::SurfaceDrawContext*,
const GrOp* opBeingClipped,
std::unique_ptr<GrFragmentProcessor> inputFP,
const SkIRect& drawBounds,
const SkMatrix&,
const SkPath&);
private:
// The atlas is not compatible with DDL. We can only use it on direct contexts.
AtlasPathRenderer(GrDirectContext*);
StencilSupport onGetStencilSupport(const GrStyledShape&) const override {
return kNoSupport_StencilSupport;
}
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
// Returns true if the given device-space path bounds are small enough to fit in an atlas and to
// benefit from atlasing. (Currently, "small enough" means no larger than fMaxAtlasSize in
// either dimension, no more than 256^2 total pixels, or no more than 128^2 total pixels if the
// fallbackAAType is kMSAA.)
bool pathFitsInAtlas(const SkRect& pathDevBounds, GrAAType fallbackAAType) const;
// Returns true if the draw being set up already uses the given atlasProxy.
using DrawRefsAtlasCallback = std::function<bool(const GrSurfaceProxy* atlasProxy)>;
// Adds the filled path to an atlas.
//
// pathFitsInAtlas() and is_visible() both must have returned true before making this call.
//
// Fails and returns false if the current atlas is full and already in use according to
// DrawRefsAtlasCallback.
bool addPathToAtlas(GrRecordingContext*,
const SkMatrix&,
const SkPath&,
const SkRect& pathDevBounds,
SkIRect* devIBounds,
SkIPoint16* locationInAtlas,
bool* transposedInAtlas,
const DrawRefsAtlasCallback&);
// Instantiates texture(s) for all atlases we've created since the last flush. Atlases that are
// the same size will be instantiated with the same backing texture.
bool preFlush(GrOnFlushResourceProvider*) override;
float fAtlasMaxSize = 0;
float fAtlasMaxPathWidth = 0;
int fAtlasInitialSize = 0;
// A collection of all atlases we've created and used since the last flush. We instantiate these
// at flush time during preFlush().
skia_private::STArray<4, sk_sp<AtlasRenderTask>> fAtlasRenderTasks;
// This simple cache remembers the locations of cacheable path masks in the most recent atlas.
// Its main motivation is for clip paths.
struct AtlasPathKey {
void set(const SkMatrix&, const SkPath&);
bool operator==(const AtlasPathKey& k) const {
static_assert(sizeof(*this) == sizeof(uint32_t) * 8);
return !memcmp(this, &k, sizeof(*this));
}
uint32_t fPathGenID;
float fAffineMatrix[6];
uint32_t fFillRule;
using Hash = SkForceDirectHash<AtlasPathKey>;
};
skia_private::THashMap<AtlasPathKey, SkIPoint16, AtlasPathKey::Hash> fAtlasPathCache;
};
} // namespace skgpu::ganesh
#endif // GrAtlasPathRenderer_DEFINED