blob: 1485ca7cd197805a301f3bb7c402e9f3dc84c4b6 [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 "GrProcessor.h"
#include "GrGeometryProcessor.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 GrProcessorStage {
public:
explicit GrProcessorStage(const GrProcessor* proc)
: fProc(SkRef(proc)) {
fCoordChangeMatrixSet = false;
}
GrProcessorStage(const GrProcessorStage& other) {
fCoordChangeMatrixSet = other.fCoordChangeMatrixSet;
if (other.fCoordChangeMatrixSet) {
fCoordChangeMatrix = other.fCoordChangeMatrix;
}
fProc.initAndRef(other.fProc);
}
static bool AreCompatible(const GrProcessorStage& a, const GrProcessorStage& 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 GrProcessorStage;
};
/**
* 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 GrProcessor* getProcessor() const { return fProc.get(); }
void convertToPendingExec() { fProc.convertToPendingExec(); }
private:
bool fCoordChangeMatrixSet;
SkMatrix fCoordChangeMatrix;
GrProgramElementRef<const GrProcessor> fProc;
};
class GrFragmentStage : public GrProcessorStage {
public:
GrFragmentStage(const GrFragmentProcessor* fp) : GrProcessorStage(fp) {}
const GrFragmentProcessor* getFragmentProcessor() const {
return static_cast<const GrFragmentProcessor*>(this->getProcessor());
}
};
class GrGeometryStage : public GrProcessorStage {
public:
GrGeometryStage(const GrGeometryProcessor* gp) : GrProcessorStage(gp) {}
const GrGeometryProcessor* getGeometryProcessor() const {
return static_cast<const GrGeometryProcessor*>(this->getProcessor());
}
};
#endif