/* * 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& 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& 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(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(dstCopy->offset().fX), static_cast(dstCopy->offset().fY)); fProgramDataManager.set2f(fBuiltinUniformHandles.fDstCopyScaleUni, 1.f / dstCopy->texture()->width(), 1.f / dstCopy->texture()->height()); GrGLTexture* texture = static_cast(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& 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& 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); } }