/* * 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 "src/gpu/GrAllocator.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrPathProcessor.h" #include "src/gpu/GrPipeline.h" #include "src/gpu/GrProcessor.h" #include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrTexturePriv.h" #include "src/gpu/GrXferProcessor.h" #include "src/gpu/gl/GrGLBuffer.h" #include "src/gpu/gl/GrGLGpu.h" #include "src/gpu/gl/GrGLPathRendering.h" #include "src/gpu/gl/GrGLProgram.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLGeometryProcessor.h" #include "src/gpu/glsl/GrGLSLXferProcessor.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( GrGLGpu* gpu, const GrGLSLBuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, const UniformInfoArray& textureSamplers, const VaryingInfoArray& pathProcVaryings, std::unique_ptr geometryProcessor, std::unique_ptr xferProcessor, std::unique_ptr[]> fragmentProcessors, int fragmentProcessorCnt, std::unique_ptr attributes, int vertexAttributeCnt, int instanceAttributeCnt, int vertexStride, int instanceStride) : fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) , fPrimitiveProcessor(std::move(geometryProcessor)) , fXferProcessor(std::move(xferProcessor)) , fFragmentProcessors(std::move(fragmentProcessors)) , fFragmentProcessorCnt(fragmentProcessorCnt) , fAttributes(std::move(attributes)) , fVertexAttributeCnt(vertexAttributeCnt) , fInstanceAttributeCnt(instanceAttributeCnt) , fVertexStride(vertexStride) , fInstanceStride(instanceStride) , fGpu(gpu) , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) , fNumTextureSamplers(textureSamplers.count()) { // Assign texture units to sampler uniforms one time up front. GL_CALL(UseProgram(fProgramID)); fProgramDataManager.setSamplerUniforms(textureSamplers, 0); } GrGLProgram::~GrGLProgram() { if (fProgramID) { GL_CALL(DeleteProgram(fProgramID)); } } void GrGLProgram::abandon() { fProgramID = 0; } /////////////////////////////////////////////////////////////////////////////// void GrGLProgram::updateUniformsAndTextureBindings(const GrRenderTarget* renderTarget, const GrProgramInfo& programInfo) { this->setRenderTargetState(renderTarget, programInfo.origin(), programInfo.primProc()); // we set the textures, and uniforms for installed processors in a generic way, but subclasses // of GLProgram determine how to set coord transforms // We must bind to texture units in the same order in which we set the uniforms in // GrGLProgramDataManager. That is, we bind textures for processors in this order: // primProc, fragProcs, XP. fPrimitiveProcessor->setData(fProgramDataManager, programInfo.primProc(), GrFragmentProcessor::CoordTransformIter(programInfo.pipeline())); if (programInfo.hasFixedPrimProcTextures()) { this->updatePrimitiveProcessorTextureBindings(programInfo.primProc(), programInfo.fixedPrimProcTextures()); } int nextTexSamplerIdx = programInfo.primProc().numTextureSamplers(); this->setFragmentData(programInfo.pipeline(), &nextTexSamplerIdx); const GrXferProcessor& xp = programInfo.pipeline().getXferProcessor(); SkIPoint offset; GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset); fXferProcessor->setData(fProgramDataManager, xp, dstTexture, offset); if (dstTexture) { fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerState::ClampNearest(), programInfo.pipeline().dstTextureProxy()->textureSwizzle(), static_cast(dstTexture)); } SkASSERT(nextTexSamplerIdx == fNumTextureSamplers); } void GrGLProgram::updatePrimitiveProcessorTextureBindings(const GrPrimitiveProcessor& primProc, const GrTextureProxy* const proxies[]) { for (int i = 0; i < primProc.numTextureSamplers(); ++i) { auto* tex = static_cast(proxies[i]->peekTexture()); fGpu->bindTexture(i, primProc.textureSampler(i).samplerState(), primProc.textureSampler(i).swizzle(), tex); } } void GrGLProgram::setFragmentData(const GrPipeline& pipeline, int* nextTexSamplerIdx) { GrFragmentProcessor::Iter iter(pipeline); GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt); const GrFragmentProcessor* fp = iter.next(); GrGLSLFragmentProcessor* glslFP = glslIter.next(); while (fp && glslFP) { glslFP->setData(fProgramDataManager, *fp); for (int i = 0; i < fp->numTextureSamplers(); ++i) { const GrFragmentProcessor::TextureSampler& sampler = fp->textureSampler(i); fGpu->bindTexture((*nextTexSamplerIdx)++, sampler.samplerState(), sampler.swizzle(), static_cast(sampler.peekTexture())); } fp = iter.next(); glslFP = glslIter.next(); } SkASSERT(!fp && !glslFP); } void GrGLProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin, const GrPrimitiveProcessor& primProc) { // Load the RT size uniforms if they are needed if (fBuiltinUniformHandles.fRTWidthUni.isValid() && fRenderTargetState.fRenderTargetSize.fWidth != rt->width()) { fProgramDataManager.set1f(fBuiltinUniformHandles.fRTWidthUni, SkIntToScalar(rt->width())); } if (fBuiltinUniformHandles.fRTHeightUni.isValid() && fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); } // set RT adjustment SkISize size; size.set(rt->width(), rt->height()); if (!primProc.isPathRendering()) { if (fRenderTargetState.fRenderTargetOrigin != origin || fRenderTargetState.fRenderTargetSize != size) { fRenderTargetState.fRenderTargetSize = size; fRenderTargetState.fRenderTargetOrigin = origin; float rtAdjustmentVec[4]; fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); } } else { SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport()); const GrPathProcessor& pathProc = primProc.cast(); fGpu->glPathRendering()->setProjectionMatrix(pathProc.viewMatrix(), size, origin); } }