blob: 6f8496db06d7e60fc7820047e1ed0a9622318dee [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrProcessorStage_DEFINED
#define GrProcessorStage_DEFINED
#include "GrBackendProcessorFactory.h"
#include "GrCoordTransform.h"
#include "GrFragmentProcessor.h"
#include "GrProgramElementRef.h"
#include "SkMatrix.h"
#include "SkShader.h"
// TODO: Make two variations on this class: One for GrDrawState that only owns regular refs
// and supports compatibility checks and changing local coords. The second is for GrOptDrawState,
// is immutable, and only owns pending execution refs. This requries removing the common base
// class from GrDrawState and GrOptDrawState called GrRODrawState and converting to GrOptDrawState
// when draws are enqueued in the GrInOrderDrawBuffer.
class GrFragmentStage {
public:
explicit GrFragmentStage(const GrFragmentProcessor* proc)
: fProc(SkRef(proc)) {
fCoordChangeMatrixSet = false;
}
GrFragmentStage(const GrFragmentStage& other) {
fCoordChangeMatrixSet = other.fCoordChangeMatrixSet;
if (other.fCoordChangeMatrixSet) {
fCoordChangeMatrix = other.fCoordChangeMatrix;
}
fProc.initAndRef(other.fProc);
}
static bool AreCompatible(const GrFragmentStage& a, const GrFragmentStage& b,
bool usingExplicitLocalCoords) {
SkASSERT(a.fProc.get());
SkASSERT(b.fProc.get());
if (!a.getProcessor()->isEqual(*b.getProcessor())) {
return false;
}
// We always track the coord change matrix, but it has no effect when explicit local coords
// are used.
if (usingExplicitLocalCoords) {
return true;
}
if (a.fCoordChangeMatrixSet != b.fCoordChangeMatrixSet) {
return false;
}
if (!a.fCoordChangeMatrixSet) {
return true;
}
return a.fCoordChangeMatrix == b.fCoordChangeMatrix;
}
/**
* This is called when the coordinate system in which the geometry is specified will change.
*
* @param matrix The transformation from the old coord system in which geometry is specified
* to the new one from which it will actually be drawn.
*/
void localCoordChange(const SkMatrix& matrix) {
if (fCoordChangeMatrixSet) {
fCoordChangeMatrix.preConcat(matrix);
} else {
fCoordChangeMatrixSet = true;
fCoordChangeMatrix = matrix;
}
}
class SavedCoordChange {
public:
SkDEBUGCODE(SavedCoordChange() : fEffectUniqueID(SK_InvalidUniqueID) {})
private:
bool fCoordChangeMatrixSet;
SkMatrix fCoordChangeMatrix;
SkDEBUGCODE(mutable uint32_t fEffectUniqueID;)
friend class GrFragmentStage;
};
/**
* This gets the current coordinate system change. It is the accumulation of
* localCoordChange calls since the effect was installed. It is used when then caller
* wants to temporarily change the source geometry coord system, draw something, and then
* restore the previous coord system (e.g. temporarily draw in device coords).
*/
void saveCoordChange(SavedCoordChange* savedCoordChange) const {
savedCoordChange->fCoordChangeMatrixSet = fCoordChangeMatrixSet;
if (fCoordChangeMatrixSet) {
savedCoordChange->fCoordChangeMatrix = fCoordChangeMatrix;
}
SkASSERT(SK_InvalidUniqueID == savedCoordChange->fEffectUniqueID);
SkDEBUGCODE(savedCoordChange->fEffectUniqueID = fProc->getUniqueID();)
}
/**
* This balances the saveCoordChange call.
*/
void restoreCoordChange(const SavedCoordChange& savedCoordChange) {
fCoordChangeMatrixSet = savedCoordChange.fCoordChangeMatrixSet;
if (fCoordChangeMatrixSet) {
fCoordChangeMatrix = savedCoordChange.fCoordChangeMatrix;
}
SkASSERT(savedCoordChange.fEffectUniqueID == fProc->getUniqueID());
SkDEBUGCODE(savedCoordChange.fEffectUniqueID = SK_InvalidUniqueID);
}
/**
* Gets the matrix representing all changes of coordinate system since the GrProcessor was
* installed in the stage.
*/
const SkMatrix& getCoordChangeMatrix() const {
if (fCoordChangeMatrixSet) {
return fCoordChangeMatrix;
} else {
return SkMatrix::I();
}
}
bool isPerspectiveCoordTransform(int matrixIndex, bool useExplicitLocalCoords) const {
const GrCoordTransform& coordTransform = this->getProcessor()->coordTransform(matrixIndex);
SkMatrix::TypeMask type0 = coordTransform.getMatrix().getType();
SkMatrix::TypeMask type1 = SkMatrix::kIdentity_Mask;
if (kLocal_GrCoordSet == coordTransform.sourceCoords()) {
type1 = useExplicitLocalCoords ?
SkMatrix::kIdentity_Mask : this->getCoordChangeMatrix().getType();
}
int combinedTypes = type0 | type1;
if (SkMatrix::kPerspective_Mask & combinedTypes) {
return true;
} else {
return false;
}
}
const GrFragmentProcessor* getProcessor() const { return fProc.get(); }
void convertToPendingExec() { fProc.convertToPendingExec(); }
protected:
bool fCoordChangeMatrixSet;
SkMatrix fCoordChangeMatrix;
GrProgramElementRef<const GrFragmentProcessor> fProc;
};
#endif