#include "GrGLProgram.h"
-#include "builders/GrGLFullProgramBuilder.h"
-#include "builders/GrGLFragmentOnlyProgramBuilder.h"
#include "GrAllocator.h"
#include "GrProcessor.h"
#include "GrCoordTransform.h"
+#include "GrGLGeometryProcessor.h"
#include "GrGLProcessor.h"
#include "GrGpuGL.h"
#include "GrGLPathRendering.h"
#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
-GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu,
- const GrGLProgramDesc& desc,
- const GrGeometryStage* geometryProcessor,
- const GrFragmentStage* colorStages[],
- const GrFragmentStage* coverageStages[]) {
- SkAutoTDelete<GrGLProgramBuilder> builder;
- if (desc.getHeader().fUseFragShaderOnly) {
- SkASSERT(gpu->glCaps().pathRenderingSupport());
- SkASSERT(gpu->glPathRendering()->texturingMode() ==
- GrGLPathRendering::FixedFunction_TexturingMode);
- SkASSERT(NULL == geometryProcessor);
- builder.reset(SkNEW_ARGS(GrGLFragmentOnlyProgramBuilder, (gpu, desc)));
+/**
+ * Retrieves the final matrix that a transform needs to apply to its source coords.
+ */
+static SkMatrix get_transform_matrix(const GrFragmentStage& processorStage,
+ bool useExplicitLocalCoords,
+ int transformIdx) {
+ const GrCoordTransform& coordTransform =
+ processorStage.getProcessor()->coordTransform(transformIdx);
+ SkMatrix combined;
+
+ if (kLocal_GrCoordSet == coordTransform.sourceCoords()) {
+ // If we have explicit local coords then we shouldn't need a coord change.
+ const SkMatrix& ccm =
+ useExplicitLocalCoords ? SkMatrix::I() : processorStage.getCoordChangeMatrix();
+ combined.setConcat(coordTransform.getMatrix(), ccm);
} else {
- builder.reset(SkNEW_ARGS(GrGLFullProgramBuilder, (gpu, desc)));
+ combined = coordTransform.getMatrix();
}
- if (builder->genProgram(geometryProcessor, colorStages, coverageStages)) {
- SkASSERT(0 != builder->getProgramID());
- return SkNEW_ARGS(GrGLProgram, (gpu, desc, *builder));
+ if (coordTransform.reverseY()) {
+ // combined.postScale(1,-1);
+ // combined.postTranslate(0,1);
+ combined.set(SkMatrix::kMSkewY,
+ combined[SkMatrix::kMPersp0] - combined[SkMatrix::kMSkewY]);
+ combined.set(SkMatrix::kMScaleY,
+ combined[SkMatrix::kMPersp1] - combined[SkMatrix::kMScaleY]);
+ combined.set(SkMatrix::kMTransY,
+ combined[SkMatrix::kMPersp2] - combined[SkMatrix::kMTransY]);
}
- return NULL;
+ return combined;
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
GrGLProgram::GrGLProgram(GrGpuGL* gpu,
- const GrGLProgramDesc& desc,
- const GrGLProgramBuilder& builder)
+ const GrProgramDesc& desc,
+ const BuiltinUniformHandles& builtinUniforms,
+ GrGLuint programID,
+ const UniformInfoArray& uniforms,
+ GrGLInstalledGeoProc* geometryProcessor,
+ GrGLInstalledFragProcs* fragmentProcessors)
: fColor(GrColor_ILLEGAL)
- , fCoverage(GrColor_ILLEGAL)
+ , fCoverage(0)
, fDstCopyTexUnit(-1)
- , fBuiltinUniformHandles(builder.getBuiltinUniformHandles())
- , fGeometryProcessor(SkSafeRef(builder.getGeometryProcessor()))
- , fColorEffects(SkRef(builder.getColorEffects()))
- , fCoverageEffects(SkRef(builder.getCoverageEffects()))
- , fProgramID(builder.getProgramID())
- , fHasVertexShader(builder.hasVertexShader())
- , fTexCoordSetCnt(builder.getTexCoordSetCount())
+ , fBuiltinUniformHandles(builtinUniforms)
+ , fProgramID(programID)
+ , fGeometryProcessor(geometryProcessor)
+ , fFragmentProcessors(SkRef(fragmentProcessors))
, fDesc(desc)
, fGpu(gpu)
- , fProgramDataManager(gpu, this, builder) {
+ , fProgramDataManager(gpu, uniforms) {
this->initSamplerUniforms();
}
fDstCopyTexUnit = texUnitIdx++;
}
if (fGeometryProcessor.get()) {
- fGeometryProcessor->initSamplers(fProgramDataManager, &texUnitIdx);
+ this->initSamplers(fGeometryProcessor.get(), &texUnitIdx);
+ }
+ int numProcs = fFragmentProcessors->fProcs.count();
+ for (int i = 0; i < numProcs; i++) {
+ this->initSamplers(fFragmentProcessors->fProcs[i], &texUnitIdx);
+ }
+}
+
+void GrGLProgram::initSamplers(GrGLInstalledProc* ip, int* texUnitIdx) {
+ SkTArray<GrGLInstalledProc::Sampler, true>& samplers = ip->fSamplers;
+ int numSamplers = samplers.count();
+ for (int s = 0; s < numSamplers; ++s) {
+ SkASSERT(samplers[s].fUniform.isValid());
+ fProgramDataManager.setSampler(samplers[s].fUniform, *texUnitIdx);
+ samplers[s].fTextureUnit = (*texUnitIdx)++;
+ }
+}
+
+void GrGLProgram::bindTextures(const GrGLInstalledProc* ip, const GrProcessor& processor) {
+ const SkTArray<GrGLInstalledProc::Sampler, true>& samplers = ip->fSamplers;
+ int numSamplers = samplers.count();
+ SkASSERT(numSamplers == processor.numTextures());
+ for (int s = 0; s < numSamplers; ++s) {
+ SkASSERT(samplers[s].fTextureUnit >= 0);
+ const GrTextureAccess& textureAccess = processor.textureAccess(s);
+ fGpu->bindTexture(samplers[s].fTextureUnit,
+ textureAccess.getParams(),
+ static_cast<GrGLTexture*>(textureAccess.getTexture()));
}
- fColorEffects->initSamplers(fProgramDataManager, &texUnitIdx);
- fCoverageEffects->initSamplers(fProgramDataManager, &texUnitIdx);
}
+
///////////////////////////////////////////////////////////////////////////////
void GrGLProgram::setData(const GrOptDrawState& optState,
GrGpu::DrawType drawType,
- const GrGeometryStage* geometryProcessor,
- const GrFragmentStage* colorStages[],
- const GrFragmentStage* coverageStages[],
- const GrDeviceCoordTexture* dstCopy,
- SharedGLState* sharedState) {
+ const GrDeviceCoordTexture* dstCopy) {
GrColor color = optState.getColor();
- GrColor coverage = optState.getCoverageColor();
+ uint8_t coverage = optState.getCoverage();
- this->setColor(optState, color, sharedState);
- this->setCoverage(optState, coverage, sharedState);
+ this->setColor(optState, color);
+ this->setCoverage(optState, coverage);
this->setMatrixAndRenderTargetHeight(drawType, optState);
if (dstCopy) {
SkASSERT(!fBuiltinUniformHandles.fDstCopySamplerUni.isValid());
}
+ // we set the textures, and uniforms for installed processors in a generic way, but subclasses
+ // of GLProgram determine how to set coord transforms
if (fGeometryProcessor.get()) {
- SkASSERT(geometryProcessor);
- fGeometryProcessor->setData(fGpu, drawType, fProgramDataManager, geometryProcessor);
- }
- fColorEffects->setData(fGpu, drawType, fProgramDataManager, colorStages);
- fCoverageEffects->setData(fGpu, drawType, fProgramDataManager, coverageStages);
-
- // PathTexGen state applies to the the fixed function vertex shader. For
- // custom shaders, it's ignored, so we don't need to change the texgen
- // settings in that case.
- if (!fHasVertexShader) {
- fGpu->glPathRendering()->flushPathTexGenSettings(fTexCoordSetCnt);
- }
-}
-
-void GrGLProgram::setColor(const GrOptDrawState& optState,
- GrColor color,
- SharedGLState* sharedState) {
- const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
- if (!optState.hasColorVertexAttribute()) {
- switch (header.fColorInput) {
- case GrGLProgramDesc::kAttribute_ColorInput:
- SkASSERT(-1 != header.fColorAttributeIndex);
- if (sharedState->fConstAttribColor != color ||
- sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) {
- // OpenGL ES only supports the float varieties of glVertexAttrib
- GrGLfloat c[4];
- GrColorToRGBAFloat(color, c);
- GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c));
- sharedState->fConstAttribColor = color;
- sharedState->fConstAttribColorIndex = header.fColorAttributeIndex;
- }
- break;
- case GrGLProgramDesc::kUniform_ColorInput:
- if (fColor != color && fBuiltinUniformHandles.fColorUni.isValid()) {
- // OpenGL ES doesn't support unsigned byte varieties of glUniform
- GrGLfloat c[4];
- GrColorToRGBAFloat(color, c);
- fProgramDataManager.set4fv(fBuiltinUniformHandles.fColorUni, 1, c);
- fColor = color;
- }
- sharedState->fConstAttribColorIndex = -1;
- break;
- case GrGLProgramDesc::kAllOnes_ColorInput:
- sharedState->fConstAttribColorIndex = -1;
- break;
- default:
- SkFAIL("Unexpected color type.");
- }
- } else {
- sharedState->fConstAttribColorIndex = -1;
- }
-}
-
-void GrGLProgram::setCoverage(const GrOptDrawState& optState,
- GrColor coverage,
- SharedGLState* sharedState) {
- const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
- if (!optState.hasCoverageVertexAttribute()) {
- switch (header.fCoverageInput) {
- case GrGLProgramDesc::kAttribute_ColorInput:
- if (sharedState->fConstAttribCoverage != coverage ||
- sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) {
- // OpenGL ES only supports the float varieties of glVertexAttrib
- GrGLfloat c[4];
- GrColorToRGBAFloat(coverage, c);
- GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c));
- sharedState->fConstAttribCoverage = coverage;
- sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex;
- }
- break;
- case GrGLProgramDesc::kUniform_ColorInput:
- if (fCoverage != coverage) {
- // OpenGL ES doesn't support unsigned byte varieties of glUniform
- GrGLfloat c[4];
- GrColorToRGBAFloat(coverage, c);
- fProgramDataManager.set4fv(fBuiltinUniformHandles.fCoverageUni, 1, c);
- fCoverage = coverage;
- }
- sharedState->fConstAttribCoverageIndex = -1;
- break;
- case GrGLProgramDesc::kAllOnes_ColorInput:
- sharedState->fConstAttribCoverageIndex = -1;
- break;
- default:
- SkFAIL("Unexpected coverage type.");
+ SkASSERT(optState.hasGeometryProcessor());
+ const GrGeometryProcessor& gp = *optState.getGeometryProcessor();
+ fGeometryProcessor->fGLProc->setData(fProgramDataManager, gp);
+ this->bindTextures(fGeometryProcessor, gp);
+ }
+ this->setFragmentData(optState);
+
+ // Some of GrGLProgram subclasses need to update state here
+ this->didSetData(drawType);
+}
+
+void GrGLProgram::setFragmentData(const GrOptDrawState& optState) {
+ int numProcessors = fFragmentProcessors->fProcs.count();
+ for (int e = 0; e < numProcessors; ++e) {
+ const GrFragmentStage& stage = optState.getFragmentStage(e);
+ const GrProcessor& processor = *stage.getProcessor();
+ fFragmentProcessors->fProcs[e]->fGLProc->setData(fProgramDataManager, processor);
+ this->setTransformData(stage, fFragmentProcessors->fProcs[e]);
+ this->bindTextures(fFragmentProcessors->fProcs[e], processor);
+ }
+}
+void GrGLProgram::setTransformData(const GrFragmentStage& processor, GrGLInstalledFragProc* ip) {
+ SkTArray<GrGLInstalledFragProc::Transform, true>& transforms = ip->fTransforms;
+ int numTransforms = transforms.count();
+ SkASSERT(numTransforms == processor.getProcessor()->numTransforms());
+ for (int t = 0; t < numTransforms; ++t) {
+ SkASSERT(transforms[t].fHandle.isValid());
+ const SkMatrix& matrix = get_transform_matrix(processor, ip->fLocalCoordAttrib, t);
+ if (!transforms[t].fCurrentValue.cheapEqualTo(matrix)) {
+ fProgramDataManager.setSkMatrix(transforms[t].fHandle.convertToUniformHandle(), matrix);
+ transforms[t].fCurrentValue = matrix;
}
- } else {
- sharedState->fConstAttribCoverageIndex = -1;
+ }
+}
+
+void GrGLProgram::didSetData(GrGpu::DrawType drawType) {
+ SkASSERT(!GrGpu::IsPathRenderingDrawType(drawType));
+}
+
+void GrGLProgram::setColor(const GrOptDrawState& optState, GrColor color) {
+ const GrProgramDesc::KeyHeader& header = fDesc.header();
+ switch (header.fColorInput) {
+ case GrProgramDesc::kAttribute_ColorInput:
+ // Attribute case is handled in GrGpuGL::setupGeometry
+ break;
+ case GrProgramDesc::kUniform_ColorInput:
+ if (fColor != color && fBuiltinUniformHandles.fColorUni.isValid()) {
+ // OpenGL ES doesn't support unsigned byte varieties of glUniform
+ GrGLfloat c[4];
+ GrColorToRGBAFloat(color, c);
+ fProgramDataManager.set4fv(fBuiltinUniformHandles.fColorUni, 1, c);
+ fColor = color;
+ }
+ break;
+ case GrProgramDesc::kAllOnes_ColorInput:
+ // Handled by shader creation
+ break;
+ default:
+ SkFAIL("Unexpected color type.");
+ }
+}
+
+void GrGLProgram::setCoverage(const GrOptDrawState& optState, uint8_t coverage) {
+ const GrProgramDesc::KeyHeader& header = fDesc.header();
+ switch (header.fCoverageInput) {
+ case GrProgramDesc::kAttribute_ColorInput:
+ // Attribute case is handled in GrGpuGL::setupGeometry
+ break;
+ case GrProgramDesc::kUniform_ColorInput:
+ if (fCoverage != coverage) {
+ // OpenGL ES doesn't support unsigned byte varieties of glUniform
+ GrGLfloat c = GrNormalizeByteToFloat(coverage);
+ fProgramDataManager.set1f(fBuiltinUniformHandles.fCoverageUni, c);
+ fCoverage = coverage;
+ }
+ break;
+ case GrProgramDesc::kAllOnes_ColorInput:
+ // Handled by shader creation
+ break;
+ default:
+ SkFAIL("Unexpected coverage type.");
}
}
void GrGLProgram::setMatrixAndRenderTargetHeight(GrGpu::DrawType drawType,
const GrOptDrawState& optState) {
- const GrRenderTarget* rt = optState.getRenderTarget();
- SkISize size;
- size.set(rt->width(), rt->height());
-
// Load the RT height uniform if it is needed to y-flip gl_FragCoord.
if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
- fMatrixState.fRenderTargetSize.fHeight != size.fHeight) {
+ fMatrixState.fRenderTargetSize.fHeight != optState.getRenderTarget()->height()) {
fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni,
- SkIntToScalar(size.fHeight));
+ SkIntToScalar(optState.getRenderTarget()->height()));
}
- if (GrGpu::IsPathRenderingDrawType(drawType)) {
- fGpu->glPathRendering()->setProjectionMatrix(optState.getViewMatrix(), size, rt->origin());
- } else if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
- fMatrixState.fRenderTargetSize != size ||
- !fMatrixState.fViewMatrix.cheapEqualTo(optState.getViewMatrix())) {
+ // call subclasses to set the actual view matrix
+ this->onSetMatrixAndRenderTargetHeight(drawType, optState);
+}
+
+void GrGLProgram::onSetMatrixAndRenderTargetHeight(GrGpu::DrawType drawType,
+ const GrOptDrawState& optState) {
+ const GrRenderTarget* rt = optState.getRenderTarget();
+ SkISize size;
+ size.set(rt->width(), rt->height());
+ if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
+ fMatrixState.fRenderTargetSize != size ||
+ !fMatrixState.fViewMatrix.cheapEqualTo(optState.getViewMatrix())) {
SkASSERT(fBuiltinUniformHandles.fViewMatrixUni.isValid());
fMatrixState.fViewMatrix = optState.getViewMatrix();
fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
}
}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+GrGLNvprProgramBase::GrGLNvprProgramBase(GrGpuGL* gpu,
+ const GrProgramDesc& desc,
+ const BuiltinUniformHandles& builtinUniforms,
+ GrGLuint programID,
+ const UniformInfoArray& uniforms,
+ GrGLInstalledFragProcs* fragmentProcessors)
+ : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL, fragmentProcessors) {
+}
+
+void GrGLNvprProgramBase::onSetMatrixAndRenderTargetHeight(GrGpu::DrawType drawType,
+ const GrOptDrawState& optState) {
+ SkASSERT(GrGpu::IsPathRenderingDrawType(drawType));
+ const GrRenderTarget* rt = optState.getRenderTarget();
+ SkISize size;
+ size.set(rt->width(), rt->height());
+ fGpu->glPathRendering()->setProjectionMatrix(optState.getViewMatrix(), size, rt->origin());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+GrGLNvprProgram::GrGLNvprProgram(GrGpuGL* gpu,
+ const GrProgramDesc& desc,
+ const BuiltinUniformHandles& builtinUniforms,
+ GrGLuint programID,
+ const UniformInfoArray& uniforms,
+ GrGLInstalledFragProcs* fragmentProcessors,
+ const SeparableVaryingInfoArray& separableVaryings)
+ : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fragmentProcessors) {
+ int count = separableVaryings.count();
+ fVaryings.push_back_n(count);
+ for (int i = 0; i < count; i++) {
+ Varying& varying = fVaryings[i];
+ const SeparableVaryingInfo& builderVarying = separableVaryings[i];
+ SkASSERT(GrGLShaderVar::kNonArray == builderVarying.fVariable.getArrayCount());
+ SkDEBUGCODE(
+ varying.fType = builderVarying.fVariable.getType();
+ );
+ varying.fLocation = builderVarying.fLocation;
+ }
+}
+
+void GrGLNvprProgram::didSetData(GrGpu::DrawType drawType) {
+ SkASSERT(GrGpu::IsPathRenderingDrawType(drawType));
+}
+
+void GrGLNvprProgram::setTransformData(const GrFragmentStage& proc, GrGLInstalledFragProc* ip) {
+ SkTArray<GrGLInstalledFragProc::Transform, true>& transforms = ip->fTransforms;
+ int numTransforms = transforms.count();
+ SkASSERT(numTransforms == proc.getProcessor()->numTransforms());
+ for (int t = 0; t < numTransforms; ++t) {
+ SkASSERT(transforms[t].fHandle.isValid());
+ const SkMatrix& transform = get_transform_matrix(proc, false, t);
+ if (transforms[t].fCurrentValue.cheapEqualTo(transform)) {
+ continue;
+ }
+ transforms[t].fCurrentValue = transform;
+ const Varying& fragmentInput = fVaryings[transforms[t].fHandle.handle()];
+ SkASSERT(transforms[t].fType == kVec2f_GrSLType || transforms[t].fType == kVec3f_GrSLType);
+ unsigned components = transforms[t].fType == kVec2f_GrSLType ? 2 : 3;
+ fGpu->glPathRendering()->setProgramPathFragmentInputTransform(fProgramID,
+ fragmentInput.fLocation,
+ GR_GL_OBJECT_LINEAR,
+ components,
+ transform);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+GrGLLegacyNvprProgram::GrGLLegacyNvprProgram(GrGpuGL* gpu,
+ const GrProgramDesc& desc,
+ const BuiltinUniformHandles& builtinUniforms,
+ GrGLuint programID,
+ const UniformInfoArray& uniforms,
+ GrGLInstalledFragProcs* fps,
+ int texCoordSetCnt)
+ : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fps)
+ , fTexCoordSetCnt(texCoordSetCnt) {
+}
+
+void GrGLLegacyNvprProgram::didSetData(GrGpu::DrawType drawType) {
+ SkASSERT(GrGpu::IsPathRenderingDrawType(drawType));
+ fGpu->glPathRendering()->flushPathTexGenSettings(fTexCoordSetCnt);
+}
+
+void
+GrGLLegacyNvprProgram::setTransformData(const GrFragmentStage& proc, GrGLInstalledFragProc* ip) {
+ // We've hidden the texcoord index in the first entry of the transforms array for each effect
+ int texCoordIndex = ip->fTransforms[0].fHandle.handle();
+ int numTransforms = proc.getProcessor()->numTransforms();
+ for (int t = 0; t < numTransforms; ++t) {
+ const SkMatrix& transform = get_transform_matrix(proc, false, t);
+ GrGLPathRendering::PathTexGenComponents components =
+ GrGLPathRendering::kST_PathTexGenComponents;
+ if (proc.isPerspectiveCoordTransform(t, false)) {
+ components = GrGLPathRendering::kSTR_PathTexGenComponents;
+ }
+ fGpu->glPathRendering()->enablePathTexGen(texCoordIndex++, components, transform);
+ }
+}