9a725dd948
Bug: skia:6173 Change-Id: I21042d484d9a7b3eee04aa3301d9793d00ad6908 Reviewed-on: https://skia-review.googlesource.com/48183 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
205 lines
7.7 KiB
C++
205 lines
7.7 KiB
C++
/*
|
|
* 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 GrProcessorSet_DEFINED
|
|
#define GrProcessorSet_DEFINED
|
|
|
|
#include "GrFragmentProcessor.h"
|
|
#include "GrPaint.h"
|
|
#include "GrProcessorAnalysis.h"
|
|
#include "SkTemplates.h"
|
|
#include "GrXferProcessor.h"
|
|
|
|
class GrAppliedClip;
|
|
class GrXPFactory;
|
|
|
|
class GrProcessorSet {
|
|
private:
|
|
// Arbitrary constructor arg for empty set and analysis
|
|
enum class Empty { kEmpty };
|
|
|
|
public:
|
|
GrProcessorSet(GrPaint&&);
|
|
GrProcessorSet(SkBlendMode);
|
|
GrProcessorSet(std::unique_ptr<GrFragmentProcessor> colorFP);
|
|
GrProcessorSet(GrProcessorSet&&);
|
|
GrProcessorSet(const GrProcessorSet&) = delete;
|
|
GrProcessorSet& operator=(const GrProcessorSet&) = delete;
|
|
|
|
~GrProcessorSet();
|
|
|
|
int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; }
|
|
int numCoverageFragmentProcessors() const {
|
|
return this->numFragmentProcessors() - fColorFragmentProcessorCnt;
|
|
}
|
|
|
|
const GrFragmentProcessor* colorFragmentProcessor(int idx) const {
|
|
SkASSERT(idx < fColorFragmentProcessorCnt);
|
|
return fFragmentProcessors[idx + fFragmentProcessorOffset].get();
|
|
}
|
|
const GrFragmentProcessor* coverageFragmentProcessor(int idx) const {
|
|
return fFragmentProcessors[idx + fColorFragmentProcessorCnt +
|
|
fFragmentProcessorOffset].get();
|
|
}
|
|
|
|
const GrXferProcessor* xferProcessor() const {
|
|
SkASSERT(this->isFinalized());
|
|
return fXP.fProcessor;
|
|
}
|
|
sk_sp<const GrXferProcessor> refXferProcessor() const {
|
|
SkASSERT(this->isFinalized());
|
|
return sk_ref_sp(fXP.fProcessor);
|
|
}
|
|
|
|
std::unique_ptr<const GrFragmentProcessor> detachColorFragmentProcessor(int idx) {
|
|
SkASSERT(idx < fColorFragmentProcessorCnt);
|
|
return std::move(fFragmentProcessors[idx + fFragmentProcessorOffset]);
|
|
}
|
|
|
|
std::unique_ptr<const GrFragmentProcessor> detachCoverageFragmentProcessor(int idx) {
|
|
return std::move(
|
|
fFragmentProcessors[idx + fFragmentProcessorOffset + fColorFragmentProcessorCnt]);
|
|
}
|
|
|
|
/** Comparisons are only legal on finalized processor sets. */
|
|
bool operator==(const GrProcessorSet& that) const;
|
|
bool operator!=(const GrProcessorSet& that) const { return !(*this == that); }
|
|
|
|
/**
|
|
* This is used to report results of processor analysis when a processor set is finalized (see
|
|
* below).
|
|
*/
|
|
class Analysis {
|
|
public:
|
|
Analysis(const Analysis&) = default;
|
|
Analysis() { *reinterpret_cast<uint32_t*>(this) = 0; }
|
|
|
|
bool isInitialized() const { return fIsInitialized; }
|
|
bool usesLocalCoords() const { return fUsesLocalCoords; }
|
|
bool requiresDstTexture() const { return fRequiresDstTexture; }
|
|
bool canCombineOverlappedStencilAndCover() const {
|
|
return fCanCombineOverlappedStencilAndCover;
|
|
}
|
|
bool requiresBarrierBetweenOverlappingDraws() const {
|
|
return fRequiresBarrierBetweenOverlappingDraws;
|
|
}
|
|
bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
|
|
|
|
bool inputColorIsIgnored() const { return fInputColorType == kIgnored_InputColorType; }
|
|
bool inputColorIsOverridden() const {
|
|
return fInputColorType == kOverridden_InputColorType;
|
|
}
|
|
|
|
private:
|
|
constexpr Analysis(Empty)
|
|
: fUsesLocalCoords(false)
|
|
, fCompatibleWithCoverageAsAlpha(true)
|
|
, fRequiresDstTexture(false)
|
|
, fCanCombineOverlappedStencilAndCover(true)
|
|
, fRequiresBarrierBetweenOverlappingDraws(false)
|
|
, fIsInitialized(true)
|
|
, fInputColorType(kOriginal_InputColorType) {}
|
|
enum InputColorType : uint32_t {
|
|
kOriginal_InputColorType,
|
|
kOverridden_InputColorType,
|
|
kIgnored_InputColorType
|
|
};
|
|
|
|
// MSVS 2015 won't pack different underlying types
|
|
using PackedBool = uint32_t;
|
|
using PackedInputColorType = uint32_t;
|
|
|
|
PackedBool fUsesLocalCoords : 1;
|
|
PackedBool fCompatibleWithCoverageAsAlpha : 1;
|
|
PackedBool fRequiresDstTexture : 1;
|
|
PackedBool fCanCombineOverlappedStencilAndCover : 1;
|
|
PackedBool fRequiresBarrierBetweenOverlappingDraws : 1;
|
|
PackedBool fIsInitialized : 1;
|
|
PackedInputColorType fInputColorType : 2;
|
|
|
|
friend class GrProcessorSet;
|
|
};
|
|
GR_STATIC_ASSERT(sizeof(Analysis) <= sizeof(uint32_t));
|
|
|
|
/**
|
|
* This analyzes the processors given an op's input color and coverage as well as a clip. The
|
|
* state of the processor set may change to an equivalent but more optimal set of processors.
|
|
* This new state requires that the caller respect the returned 'inputColorOverride'. This is
|
|
* indicated by the returned Analysis's inputColorIsOverriden(). 'inputColorOverride' will not
|
|
* be written if the analysis does not override the input color.
|
|
*
|
|
* This must be called before the processor set is used to construct a GrPipeline and may only
|
|
* be called once.
|
|
*
|
|
* This also puts the processors in "pending execution" state and must be called when an op
|
|
* that owns a processor set is recorded to ensure pending and writes are propagated to
|
|
* resources referred to by the processors. Otherwise, data hazards may occur.
|
|
*/
|
|
Analysis finalize(const GrProcessorAnalysisColor& colorInput,
|
|
const GrProcessorAnalysisCoverage coverageInput, const GrAppliedClip*,
|
|
bool isMixedSamples, const GrCaps&, GrPixelConfigIsClamped,
|
|
GrColor* inputColorOverride);
|
|
|
|
bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); }
|
|
|
|
/** These are valid only for non-LCD coverage. */
|
|
static const GrProcessorSet& EmptySet();
|
|
static GrProcessorSet MakeEmptySet();
|
|
static constexpr const Analysis EmptySetAnalysis() { return Analysis(Empty::kEmpty); }
|
|
|
|
SkString dumpProcessors() const;
|
|
|
|
void visitProxies(const std::function<void(GrSurfaceProxy*)>& func) const {
|
|
for (int i = 0; i < this->numFragmentProcessors(); ++i) {
|
|
GrFragmentProcessor::TextureAccessIter iter(this->fragmentProcessor(i));
|
|
while (const GrResourceIOProcessor::TextureSampler* sampler = iter.next()) {
|
|
func(sampler->proxy());
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrProcessorSet(Empty) : fXP((const GrXferProcessor*)nullptr), fFlags(kFinalized_Flag) {}
|
|
|
|
int numFragmentProcessors() const {
|
|
return fFragmentProcessors.count() - fFragmentProcessorOffset;
|
|
}
|
|
|
|
const GrFragmentProcessor* fragmentProcessor(int idx) const {
|
|
return fFragmentProcessors[idx + fFragmentProcessorOffset].get();
|
|
}
|
|
|
|
// This absurdly large limit allows Analysis and this to pack fields together.
|
|
static constexpr int kMaxColorProcessors = UINT8_MAX;
|
|
|
|
enum Flags : uint16_t { kFinalized_Flag = 0x1 };
|
|
|
|
union XP {
|
|
XP(const GrXPFactory* factory) : fFactory(factory) {}
|
|
XP(const GrXferProcessor* processor) : fProcessor(processor) {}
|
|
explicit XP(XP&& that) : fProcessor(that.fProcessor) {
|
|
SkASSERT(fProcessor == that.fProcessor);
|
|
that.fProcessor = nullptr;
|
|
}
|
|
const GrXPFactory* fFactory;
|
|
const GrXferProcessor* fProcessor;
|
|
};
|
|
|
|
const GrXPFactory* xpFactory() const {
|
|
SkASSERT(!this->isFinalized());
|
|
return fXP.fFactory;
|
|
}
|
|
|
|
SkAutoSTArray<4, std::unique_ptr<const GrFragmentProcessor>> fFragmentProcessors;
|
|
XP fXP;
|
|
uint8_t fColorFragmentProcessorCnt = 0;
|
|
uint8_t fFragmentProcessorOffset = 0;
|
|
uint8_t fFlags;
|
|
};
|
|
|
|
#endif
|