| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "GrGLProgram.h" | |
| #include "GrAllocator.h" | |
| #include "GrProcessor.h" | |
| #include "GrCoordTransform.h" | |
| #include "GrGLGeometryProcessor.h" | |
| #include "GrGLProcessor.h" | |
| #include "GrGLXferProcessor.h" | |
| #include "GrGLGpu.h" | |
| #include "GrGLPathRendering.h" | |
| #include "GrGLShaderVar.h" | |
| #include "GrGLSL.h" | |
| #include "GrOptDrawState.h" | |
| #include "GrXferProcessor.h" | |
| #include "SkXfermode.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) | |
| /** | |
| * Retrieves the final matrix that a transform needs to apply to its source coords. | |
| */ | |
| static SkMatrix get_transform_matrix(const GrPendingFragmentStage& stage, | |
| int transformIdx, | |
| const SkMatrix& localMatrix) { | |
| const GrCoordTransform& coordTransform = stage.processor()->coordTransform(transformIdx); | |
| SkMatrix combined; | |
| // We only apply the localmatrix to localcoords | |
| if (kLocal_GrCoordSet == coordTransform.sourceCoords()) { | |
| combined.setConcat(coordTransform.getMatrix(), localMatrix); | |
| } else { | |
| combined = coordTransform.getMatrix(); | |
| } | |
| 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 combined; | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| GrGLProgram::GrGLProgram(GrGLGpu* gpu, | |
| const GrProgramDesc& desc, | |
| const BuiltinUniformHandles& builtinUniforms, | |
| GrGLuint programID, | |
| const UniformInfoArray& uniforms, | |
| GrGLInstalledGeoProc* geometryProcessor, | |
| GrGLInstalledXferProc* xferProcessor, | |
| GrGLInstalledFragProcs* fragmentProcessors) | |
| : fColor(GrColor_ILLEGAL) | |
| , fCoverage(0) | |
| , fDstCopyTexUnit(-1) | |
| , fBuiltinUniformHandles(builtinUniforms) | |
| , fProgramID(programID) | |
| , fGeometryProcessor(geometryProcessor) | |
| , fXferProcessor(xferProcessor) | |
| , fFragmentProcessors(SkRef(fragmentProcessors)) | |
| , fDesc(desc) | |
| , fGpu(gpu) | |
| , fProgramDataManager(gpu, uniforms) { | |
| this->initSamplerUniforms(); | |
| } | |
| GrGLProgram::~GrGLProgram() { | |
| if (fProgramID) { | |
| GL_CALL(DeleteProgram(fProgramID)); | |
| } | |
| } | |
| void GrGLProgram::abandon() { | |
| fProgramID = 0; | |
| } | |
| void GrGLProgram::initSamplerUniforms() { | |
| GL_CALL(UseProgram(fProgramID)); | |
| GrGLint texUnitIdx = 0; | |
| if (fBuiltinUniformHandles.fDstCopySamplerUni.isValid()) { | |
| fProgramDataManager.setSampler(fBuiltinUniformHandles.fDstCopySamplerUni, texUnitIdx); | |
| fDstCopyTexUnit = texUnitIdx++; | |
| } | |
| if (fGeometryProcessor.get()) { | |
| this->initSamplers(fGeometryProcessor.get(), &texUnitIdx); | |
| } | |
| if (fXferProcessor.get()) { | |
| this->initSamplers(fXferProcessor.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())); | |
| } | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| void GrGLProgram::setData(const GrOptDrawState& optState) { | |
| this->setRenderTargetState(optState); | |
| const GrDeviceCoordTexture* dstCopy = optState.getDstCopy(); | |
| if (dstCopy) { | |
| if (fBuiltinUniformHandles.fDstCopyTopLeftUni.isValid()) { | |
| fProgramDataManager.set2f(fBuiltinUniformHandles.fDstCopyTopLeftUni, | |
| static_cast<GrGLfloat>(dstCopy->offset().fX), | |
| static_cast<GrGLfloat>(dstCopy->offset().fY)); | |
| fProgramDataManager.set2f(fBuiltinUniformHandles.fDstCopyScaleUni, | |
| 1.f / dstCopy->texture()->width(), | |
| 1.f / dstCopy->texture()->height()); | |
| GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture()); | |
| static GrTextureParams kParams; // the default is clamp, nearest filtering. | |
| fGpu->bindTexture(fDstCopyTexUnit, kParams, texture); | |
| } else { | |
| SkASSERT(!fBuiltinUniformHandles.fDstCopyScaleUni.isValid()); | |
| SkASSERT(!fBuiltinUniformHandles.fDstCopySamplerUni.isValid()); | |
| } | |
| } else { | |
| SkASSERT(!fBuiltinUniformHandles.fDstCopyTopLeftUni.isValid()); | |
| SkASSERT(!fBuiltinUniformHandles.fDstCopyScaleUni.isValid()); | |
| 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 | |
| const GrPrimitiveProcessor& primProc = *optState.getPrimitiveProcessor(); | |
| const GrBatchTracker& bt = optState.getBatchTracker(); | |
| fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc, bt); | |
| this->bindTextures(fGeometryProcessor, primProc); | |
| if (fXferProcessor.get()) { | |
| const GrXferProcessor& xp = *optState.getXferProcessor(); | |
| fXferProcessor->fGLProc->setData(fProgramDataManager, xp); | |
| this->bindTextures(fXferProcessor, xp); | |
| } | |
| this->setFragmentData(optState); | |
| // Some of GrGLProgram subclasses need to update state here | |
| this->didSetData(optState.drawType()); | |
| } | |
| void GrGLProgram::setFragmentData(const GrOptDrawState& optState) { | |
| int numProcessors = fFragmentProcessors->fProcs.count(); | |
| for (int e = 0; e < numProcessors; ++e) { | |
| const GrPendingFragmentStage& stage = optState.getFragmentStage(e); | |
| const GrProcessor& processor = *stage.processor(); | |
| fFragmentProcessors->fProcs[e]->fGLProc->setData(fProgramDataManager, processor); | |
| const SkMatrix& localMatrix = optState.getPrimitiveProcessor()->localMatrix(); | |
| this->setTransformData(stage, localMatrix, fFragmentProcessors->fProcs[e]); | |
| this->bindTextures(fFragmentProcessors->fProcs[e], processor); | |
| } | |
| } | |
| void GrGLProgram::setTransformData(const GrPendingFragmentStage& processor, | |
| const SkMatrix& localMatrix, | |
| GrGLInstalledFragProc* ip) { | |
| SkTArray<GrGLInstalledFragProc::Transform, true>& transforms = ip->fTransforms; | |
| int numTransforms = transforms.count(); | |
| SkASSERT(numTransforms == processor.processor()->numTransforms()); | |
| for (int t = 0; t < numTransforms; ++t) { | |
| SkASSERT(transforms[t].fHandle.isValid()); | |
| const SkMatrix& matrix = get_transform_matrix(processor, t, localMatrix); | |
| if (!transforms[t].fCurrentValue.cheapEqualTo(matrix)) { | |
| fProgramDataManager.setSkMatrix(transforms[t].fHandle.convertToUniformHandle(), matrix); | |
| transforms[t].fCurrentValue = matrix; | |
| } | |
| } | |
| } | |
| void GrGLProgram::didSetData(GrGpu::DrawType drawType) { | |
| SkASSERT(!GrGpu::IsPathRenderingDrawType(drawType)); | |
| } | |
| void GrGLProgram::setRenderTargetState(const GrOptDrawState& optState) { | |
| // Load the RT height uniform if it is needed to y-flip gl_FragCoord. | |
| if (fBuiltinUniformHandles.fRTHeightUni.isValid() && | |
| fRenderTargetState.fRenderTargetSize.fHeight != optState.getRenderTarget()->height()) { | |
| fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, | |
| SkIntToScalar(optState.getRenderTarget()->height())); | |
| } | |
| // call subclasses to set the actual view matrix | |
| this->onSetRenderTargetState(optState); | |
| } | |
| void GrGLProgram::onSetRenderTargetState(const GrOptDrawState& optState) { | |
| const GrRenderTarget* rt = optState.getRenderTarget(); | |
| SkISize size; | |
| size.set(rt->width(), rt->height()); | |
| if (fRenderTargetState.fRenderTargetOrigin != rt->origin() || | |
| fRenderTargetState.fRenderTargetSize != size) { | |
| fRenderTargetState.fRenderTargetSize = size; | |
| fRenderTargetState.fRenderTargetOrigin = rt->origin(); | |
| GrGLfloat rtAdjustmentVec[4]; | |
| fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); | |
| fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); | |
| } | |
| } | |
| ///////////////////////////////////////////////////////////////////////////////////////// | |
| GrGLNvprProgramBase::GrGLNvprProgramBase(GrGLGpu* gpu, | |
| const GrProgramDesc& desc, | |
| const BuiltinUniformHandles& builtinUniforms, | |
| GrGLuint programID, | |
| const UniformInfoArray& uniforms, | |
| GrGLInstalledGeoProc* primProc, | |
| GrGLInstalledXferProc* xferProcessor, | |
| GrGLInstalledFragProcs* fragmentProcessors) | |
| : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, primProc, | |
| xferProcessor, fragmentProcessors) { | |
| } | |
| void GrGLNvprProgramBase::onSetRenderTargetState(const GrOptDrawState& optState) { | |
| SkASSERT(GrGpu::IsPathRenderingDrawType(optState.drawType())); | |
| const GrRenderTarget* rt = optState.getRenderTarget(); | |
| SkISize size; | |
| size.set(rt->width(), rt->height()); | |
| fGpu->glPathRendering()->setProjectionMatrix(optState.getPrimitiveProcessor()->viewMatrix(), | |
| size, rt->origin()); | |
| } | |
| ///////////////////////////////////////////////////////////////////////////////////////// | |
| GrGLNvprProgram::GrGLNvprProgram(GrGLGpu* gpu, | |
| const GrProgramDesc& desc, | |
| const BuiltinUniformHandles& builtinUniforms, | |
| GrGLuint programID, | |
| const UniformInfoArray& uniforms, | |
| GrGLInstalledGeoProc* primProc, | |
| GrGLInstalledXferProc* xferProcessor, | |
| GrGLInstalledFragProcs* fragmentProcessors, | |
| const SeparableVaryingInfoArray& separableVaryings) | |
| : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, primProc, | |
| xferProcessor, 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 GrPendingFragmentStage& proc, | |
| const SkMatrix& localMatrix, | |
| GrGLInstalledFragProc* ip) { | |
| SkTArray<GrGLInstalledFragProc::Transform, true>& transforms = ip->fTransforms; | |
| int numTransforms = transforms.count(); | |
| SkASSERT(numTransforms == proc.processor()->numTransforms()); | |
| for (int t = 0; t < numTransforms; ++t) { | |
| SkASSERT(transforms[t].fHandle.isValid()); | |
| const SkMatrix& transform = get_transform_matrix(proc, t, localMatrix); | |
| 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(GrGLGpu* gpu, | |
| const GrProgramDesc& desc, | |
| const BuiltinUniformHandles& builtinUniforms, | |
| GrGLuint programID, | |
| const UniformInfoArray& uniforms, | |
| GrGLInstalledGeoProc* primProc, | |
| GrGLInstalledXferProc* xp, | |
| GrGLInstalledFragProcs* fps, | |
| int texCoordSetCnt) | |
| : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, primProc, xp, fps) | |
| , fTexCoordSetCnt(texCoordSetCnt) { | |
| } | |
| void GrGLLegacyNvprProgram::didSetData(GrGpu::DrawType drawType) { | |
| SkASSERT(GrGpu::IsPathRenderingDrawType(drawType)); | |
| fGpu->glPathRendering()->flushPathTexGenSettings(fTexCoordSetCnt); | |
| } | |
| void | |
| GrGLLegacyNvprProgram::setTransformData(const GrPendingFragmentStage& proc, | |
| const SkMatrix& localMatrix, | |
| 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.processor()->numTransforms(); | |
| for (int t = 0; t < numTransforms; ++t) { | |
| const SkMatrix& transform = get_transform_matrix(proc, t, localMatrix); | |
| GrGLPathRendering::PathTexGenComponents components = | |
| GrGLPathRendering::kST_PathTexGenComponents; | |
| if (proc.isPerspectiveCoordTransform(t)) { | |
| components = GrGLPathRendering::kSTR_PathTexGenComponents; | |
| } | |
| fGpu->glPathRendering()->enablePathTexGen(texCoordIndex++, components, transform); | |
| } | |
| } |