blob: fa4b20c6be7c543b77495e68a7cf7619adee1b42 [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 "include/core/SkRefCnt.h"
#include "src/gpu/ganesh/GrColor.h"
#include "src/gpu/ganesh/GrDstProxyView.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "src/gpu/ganesh/GrProcessorSet.h"
#include "src/gpu/ganesh/GrScissorState.h"
#include "src/gpu/ganesh/GrSurfaceProxyView.h"
#include "src/gpu/ganesh/GrTextureProxy.h"
#include "src/gpu/ganesh/GrUserStencilSettings.h"
#include "src/gpu/ganesh/GrWindowRectsState.h"
#include "src/gpu/ganesh/effects/GrPorterDuffXferProcessor.h"
class GrAppliedClip;
class GrAppliedHardClip;
struct GrGLSLBuiltinUniformHandles;
class GrGLSLProgramDataManager;
class GrOp;
class GrTextureEffect;
/**
* This immutable object contains information needed to build a shader program and set API
* state for a draw. It is used along with a GrGeometryProcessor and a source of geometric
* data to draw.
*/
class GrPipeline {
public:
///////////////////////////////////////////////////////////////////////////
/// @name Creation
// Pipeline options that the caller may enable.
// NOTE: This enum is extended later by GrPipeline::Flags.
enum class InputFlags : uint8_t {
kNone = 0,
/**
* Cause every pixel to be rasterized that is touched by the triangle anywhere (not just at
* pixel center). Additionally, if using MSAA, the sample mask will always have 100%
* coverage.
* NOTE: The primitive type must be a triangle type.
*/
kConservativeRaster = (1 << 1),
/**
* Draws triangles as outlines.
*/
kWireframe = (1 << 2),
/**
* Modifies the vertex shader so that vertices will be positioned at pixel centers.
*/
kSnapVerticesToPixelCenters = (1 << 3), // This value must be last. (See kLastInputFlag.)
};
struct InitArgs {
InputFlags fInputFlags = InputFlags::kNone;
const GrCaps* fCaps = nullptr;
GrDstProxyView fDstProxyView;
skgpu::Swizzle fWriteSwizzle;
};
/**
* Creates a simple pipeline with default settings and no processors. The provided blend mode
* must be "Porter Duff" (<= kLastCoeffMode). If using GrScissorTest::kEnabled, the caller must
* specify a scissor rectangle through the DynamicState struct.
**/
GrPipeline(GrScissorTest scissor,
SkBlendMode blend,
const skgpu::Swizzle& writeSwizzle,
InputFlags flags = InputFlags::kNone)
: GrPipeline(scissor,
GrPorterDuffXPFactory::MakeNoCoverageXP(blend),
writeSwizzle,
flags) {}
GrPipeline(GrScissorTest,
sk_sp<const GrXferProcessor>,
const skgpu::Swizzle& writeSwizzle,
InputFlags = InputFlags::kNone);
GrPipeline(const InitArgs& args, sk_sp<const GrXferProcessor>, const GrAppliedHardClip&);
GrPipeline(const InitArgs&, GrProcessorSet&&, GrAppliedClip&&);
GrPipeline(const GrPipeline&) = delete;
GrPipeline& operator=(const GrPipeline&) = delete;
/// @}
///////////////////////////////////////////////////////////////////////////
/// @name GrFragmentProcessors
int numFragmentProcessors() const { return fFragmentProcessors.count(); }
int numColorFragmentProcessors() const { return fNumColorProcessors; }
bool isColorFragmentProcessor(int idx) const { return idx < fNumColorProcessors; }
bool isCoverageFragmentProcessor(int idx) const { return idx >= fNumColorProcessors; }
bool usesLocalCoords() const {
// The sample coords for the top level FPs are implicitly the GP's local coords.
for (const auto& fp : fFragmentProcessors) {
if (fp->usesSampleCoords()) {
return true;
}
}
return false;
}
void visitTextureEffects(const std::function<void(const GrTextureEffect&)>&) const;
const GrXferProcessor& getXferProcessor() const {
if (fXferProcessor) {
return *fXferProcessor;
} 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();
}
}
// Helper functions to quickly know if this GrPipeline will access the dst as a texture or an
// input attachment.
bool usesDstTexture() const { return this->dstProxyView() && !this->usesDstInputAttachment(); }
bool usesDstInputAttachment() const {
return this->dstSampleFlags() & GrDstSampleFlags::kAsInputAttachment;
}
/**
* This returns the GrSurfaceProxyView for the texture used to access the dst color. If the
* GrXferProcessor does not use the dst color then the proxy on the GrSurfaceProxyView will be
* nullptr.
*/
const GrSurfaceProxyView& dstProxyView() const { return fDstProxy.proxyView(); }
SkIPoint dstTextureOffset() const { return fDstProxy.offset(); }
GrDstSampleFlags dstSampleFlags() const { return fDstProxy.dstSampleFlags(); }
/** If this GrXferProcessor uses a texture to access the dst color, returns that texture. */
GrTexture* peekDstTexture() const {
if (!this->usesDstTexture()) {
return nullptr;
}
if (GrTextureProxy* dstProxy = this->dstProxyView().asTextureProxy()) {
return dstProxy->peekTexture();
}
return nullptr;
}
const GrFragmentProcessor& getFragmentProcessor(int idx) const {
return *fFragmentProcessors[idx];
}
/// @}
bool isScissorTestEnabled() const {
return SkToBool(fFlags & Flags::kScissorTestEnabled);
}
const GrWindowRectsState& getWindowRectsState() const { return fWindowRectsState; }
bool usesConservativeRaster() const { return fFlags & InputFlags::kConservativeRaster; }
bool isWireframe() const { return fFlags & InputFlags::kWireframe; }
bool snapVerticesToPixelCenters() const {
return fFlags & InputFlags::kSnapVerticesToPixelCenters;
}
bool hasStencilClip() const {
return SkToBool(fFlags & Flags::kHasStencilClip);
}
#ifdef SK_DEBUG
bool allProxiesInstantiated() const {
for (int i = 0; i < fFragmentProcessors.count(); ++i) {
if (!fFragmentProcessors[i]->isInstantiated()) {
return false;
}
}
if (this->dstProxyView().proxy()) {
return this->dstProxyView().proxy()->isInstantiated();
}
return true;
}
#endif
GrXferBarrierType xferBarrierType(const GrCaps&) const;
// Used by Vulkan and Metal to cache their respective pipeline objects
void genKey(skgpu::KeyBuilder*, const GrCaps&) const;
const skgpu::Swizzle& writeSwizzle() const { return fWriteSwizzle; }
void visitProxies(const GrVisitProxyFunc&) const;
void setDstTextureUniforms(const GrGLSLProgramDataManager& pdm,
GrGLSLBuiltinUniformHandles* fBuiltinUniformHandles) const;
private:
inline static constexpr uint8_t kLastInputFlag =
(uint8_t)InputFlags::kSnapVerticesToPixelCenters;
/** This is a continuation of the public "InputFlags" enum. */
enum class Flags : uint8_t {
kHasStencilClip = (kLastInputFlag << 1),
kScissorTestEnabled = (kLastInputFlag << 2),
};
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags);
friend bool operator&(Flags, InputFlags);
// A pipeline can contain up to three processors: color, paint coverage, and clip coverage.
using FragmentProcessorArray =
skia_private::AutoSTArray<3, std::unique_ptr<const GrFragmentProcessor>>;
GrDstProxyView fDstProxy;
GrWindowRectsState fWindowRectsState;
Flags fFlags;
sk_sp<const GrXferProcessor> fXferProcessor;
FragmentProcessorArray fFragmentProcessors;
// This value is also the index in fFragmentProcessors where coverage processors begin.
int fNumColorProcessors = 0;
skgpu::Swizzle fWriteSwizzle;
};
GR_MAKE_BITFIELD_CLASS_OPS(GrPipeline::InputFlags)
GR_MAKE_BITFIELD_CLASS_OPS(GrPipeline::Flags)
inline bool operator&(GrPipeline::Flags flags, GrPipeline::InputFlags inputFlag) {
return (flags & (GrPipeline::Flags)inputFlag);
}
#endif