blob: 078cb6843788f1d4ef59b72547aac03c7b9de1a7 [file] [log] [blame]
/*
* 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 GrPipeline_DEFINED
#define GrPipeline_DEFINED
#include "GrColor.h"
#include "GrFragmentProcessor.h"
#include "GrNonAtomicRef.h"
#include "GrPendingProgramElement.h"
#include "GrProcessorSet.h"
#include "GrProgramDesc.h"
#include "GrRect.h"
#include "GrScissorState.h"
#include "GrUserStencilSettings.h"
#include "GrWindowRectsState.h"
#include "SkMatrix.h"
#include "SkRefCnt.h"
#include "effects/GrCoverageSetOpXP.h"
#include "effects/GrDisableColorXP.h"
#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrSimpleTextureEffect.h"
class GrAppliedClip;
class GrDeviceCoordTexture;
class GrOp;
class GrPipelineBuilder;
class GrRenderTargetContext;
/**
* Class that holds an optimized version of a GrPipelineBuilder. It is meant to be an immutable
* class, and contains all data needed to set the state for a gpu draw.
*/
class GrPipeline : public GrNonAtomicRef<GrPipeline> {
public:
///////////////////////////////////////////////////////////////////////////
/// @name Creation
enum Flags {
/**
* Perform HW anti-aliasing. This means either HW FSAA, if supported by the render target,
* or smooth-line rendering if a line primitive is drawn and line smoothing is supported by
* the 3D API.
*/
kHWAntialias_Flag = 0x1,
/**
* Modifies the vertex shader so that vertices will be positioned at pixel centers.
*/
kSnapVerticesToPixelCenters_Flag = 0x2,
/** Disables conversion to sRGB from linear when writing to a sRGB destination. */
kDisableOutputConversionToSRGB_Flag = 0x4,
/** Allows conversion from sRGB to linear when reading from processor's sRGB texture. */
kAllowSRGBInputs_Flag = 0x8,
};
static uint32_t SRGBFlagsFromPaint(const GrPaint& paint) {
uint32_t flags = 0;
if (paint.getAllowSRGBInputs()) {
flags |= kAllowSRGBInputs_Flag;
}
if (paint.getDisableOutputConversionToSRGB()) {
flags |= kDisableOutputConversionToSRGB_Flag;
}
return flags;
}
struct InitArgs {
uint32_t fFlags = 0;
const GrProcessorSet* fProcessors = nullptr; // Must be finalized
const GrUserStencilSettings* fUserStencil = &GrUserStencilSettings::kUnused;
const GrAppliedClip* fAppliedClip = nullptr;
GrRenderTarget* fRenderTarget = nullptr;
const GrCaps* fCaps = nullptr;
GrResourceProvider* fResourceProvider = nullptr;
GrXferProcessor::DstProxy fDstProxy;
};
/**
* A Default constructed pipeline is unusable until init() is called.
**/
GrPipeline() = default;
/**
* Creates a simple pipeline with default settings and no processors. The provided blend mode
* must be "Porter Duff" (<= kLastCoeffMode). This pipeline is initialized without requiring
* a call to init().
**/
GrPipeline(GrRenderTarget*, SkBlendMode);
GrPipeline(const InitArgs& args) { this->init(args); }
/** (Re)initializes a pipeline. After initialization the pipeline can be used. */
void init(const InitArgs&);
/** True if the pipeline has been initialized. */
bool isInitialized() const { return SkToBool(fRenderTarget.get()); }
/// @}
///////////////////////////////////////////////////////////////////////////
/// @name Comparisons
/**
* Returns true if these pipelines are equivalent. Coord transforms may be applied either on
* the GPU or the CPU. When we apply them on the CPU then the matrices need not agree in order
* to combine draws. Therefore we take a param that indicates whether coord transforms should be
* compared."
*/
static bool AreEqual(const GrPipeline& a, const GrPipeline& b);
/**
* Allows a GrOp subclass to determine whether two GrOp instances can combine. This is a
* stricter test than isEqual because it also considers blend barriers when the two ops'
* bounds overlap
*/
static bool CanCombine(const GrPipeline& a, const SkRect& aBounds,
const GrPipeline& b, const SkRect& bBounds,
const GrCaps& caps) {
if (!AreEqual(a, b)) {
return false;
}
if (a.xferBarrierType(caps)) {
return !GrRectsTouchOrOverlap(aBounds, bBounds);
}
return true;
}
/// @}
///////////////////////////////////////////////////////////////////////////
/// @name GrFragmentProcessors
// Make the renderTarget's GrOpList (if it exists) be dependent on any
// GrOpLists in this pipeline
void addDependenciesTo(GrRenderTargetProxy*) const;
int numColorFragmentProcessors() const { return fNumColorProcessors; }
int numCoverageFragmentProcessors() const {
return fFragmentProcessors.count() - fNumColorProcessors;
}
int numFragmentProcessors() const { return fFragmentProcessors.count(); }
const GrXferProcessor& getXferProcessor() const {
if (fXferProcessor) {
return *fXferProcessor.get();
} else {
// A null xp member means the common src-over case. GrXferProcessor's ref'ing
// mechanism is not thread safe so we do not hold a ref on this global.
return GrPorterDuffXPFactory::SimpleSrcOverXP();
}
}
/**
* If the GrXferProcessor uses a texture to access the dst color, then this returns that
* texture and the offset to the dst contents within that texture.
*/
GrTextureProxy* dstTextureProxy(SkIPoint* offset = nullptr) const {
if (offset) {
*offset = fDstTextureOffset;
}
return fDstTextureProxy.get();
}
GrTexture* peekDstTexture(SkIPoint* offset = nullptr) const {
if (GrTextureProxy* dstProxy = this->dstTextureProxy(offset)) {
return dstProxy->priv().peekTexture();
}
return nullptr;
}
const GrFragmentProcessor& getColorFragmentProcessor(int idx) const {
SkASSERT(idx < this->numColorFragmentProcessors());
return *fFragmentProcessors[idx].get();
}
const GrFragmentProcessor& getCoverageFragmentProcessor(int idx) const {
SkASSERT(idx < this->numCoverageFragmentProcessors());
return *fFragmentProcessors[fNumColorProcessors + idx].get();
}
const GrFragmentProcessor& getFragmentProcessor(int idx) const {
return *fFragmentProcessors[idx].get();
}
/// @}
/**
* Retrieves the currently set render-target.
*
* @return The currently set render target.
*/
GrRenderTarget* getRenderTarget() const { return fRenderTarget.get(); }
const GrUserStencilSettings* getUserStencil() const { return fUserStencilSettings; }
const GrScissorState& getScissorState() const { return fScissorState; }
const GrWindowRectsState& getWindowRectsState() const { return fWindowRectsState; }
bool isHWAntialiasState() const { return SkToBool(fFlags & kHWAntialias_Flag); }
bool snapVerticesToPixelCenters() const {
return SkToBool(fFlags & kSnapVerticesToPixelCenters_Flag);
}
bool getDisableOutputConversionToSRGB() const {
return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag);
}
bool getAllowSRGBInputs() const {
return SkToBool(fFlags & kAllowSRGBInputs_Flag);
}
bool hasStencilClip() const {
return SkToBool(fFlags & kHasStencilClip_Flag);
}
bool isStencilEnabled() const {
return SkToBool(fFlags & kStencilEnabled_Flag);
}
bool isBad() const { return SkToBool(fFlags & kIsBad_Flag); }
GrXferBarrierType xferBarrierType(const GrCaps& caps) const {
if (fDstTextureProxy.get() &&
fDstTextureProxy.get()->priv().peekTexture() == fRenderTarget.get()->asTexture()) {
return kTexture_GrXferBarrierType;
}
return this->getXferProcessor().xferBarrierType(caps);
}
private:
void markAsBad() { fFlags |= kIsBad_Flag; }
/** This is a continuation of the public "Flags" enum. */
enum PrivateFlags {
kHasStencilClip_Flag = 0x10,
kStencilEnabled_Flag = 0x20,
kIsBad_Flag = 0x40,
};
using RenderTarget = GrPendingIOResource<GrRenderTarget, kWrite_GrIOType>;
using DstTextureProxy = GrPendingIOResource<GrTextureProxy, kRead_GrIOType>;
using PendingFragmentProcessor = GrPendingProgramElement<const GrFragmentProcessor>;
using FragmentProcessorArray = SkAutoSTArray<8, PendingFragmentProcessor>;
DstTextureProxy fDstTextureProxy;
SkIPoint fDstTextureOffset;
RenderTarget fRenderTarget;
GrScissorState fScissorState;
GrWindowRectsState fWindowRectsState;
const GrUserStencilSettings* fUserStencilSettings;
uint16_t fFlags;
sk_sp<const GrXferProcessor> fXferProcessor;
FragmentProcessorArray fFragmentProcessors;
// This value is also the index in fFragmentProcessors where coverage processors begin.
int fNumColorProcessors;
typedef SkRefCnt INHERITED;
};
#endif