/* * 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 "GrGLGpu.h" #include "GrGLBuffer.h" #include "GrGLPathRendering.h" #include "GrPathProcessor.h" #include "GrPipeline.h" #include "GrXferProcessor.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "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 GrProgramDesc& desc, const BuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, const UniformInfoArray& textureSamplers, const UniformInfoArray& texelBuffers, const VaryingInfoArray& pathProcVaryings, std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, std::unique_ptr<GrGLSLXferProcessor> xferProcessor, const GrGLSLFragProcs& fragmentProcessors) : fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) , fGeometryProcessor(std::move(geometryProcessor)) , fXferProcessor(std::move(xferProcessor)) , fFragmentProcessors(fragmentProcessors) , fDesc(desc) , fGpu(gpu) , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) , fNumTextureSamplers(textureSamplers.count()) , fNumTexelBuffers(texelBuffers.count()) { // Assign texture units to sampler uniforms one time up front. GL_CALL(UseProgram(fProgramID)); fProgramDataManager.setSamplerUniforms(textureSamplers, 0); fProgramDataManager.setSamplerUniforms(texelBuffers, fNumTextureSamplers); } GrGLProgram::~GrGLProgram() { if (fProgramID) { GL_CALL(DeleteProgram(fProgramID)); } for (int i = 0; i < fFragmentProcessors.count(); ++i) { delete fFragmentProcessors[i]; } } void GrGLProgram::abandon() { fProgramID = 0; } /////////////////////////////////////////////////////////////////////////////// void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) { this->setRenderTargetState(primProc, pipeline.proxy()); // 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 first all texture samplers and then texel buffers. // Within each group we will bind them in primProc, fragProcs, XP order. int nextTexSamplerIdx = 0; int nextTexelBufferIdx = fNumTextureSamplers; fGeometryProcessor->setData(fProgramDataManager, primProc, GrFragmentProcessor::CoordTransformIter(pipeline)); this->bindTextures(primProc, pipeline.getAllowSRGBInputs(), &nextTexSamplerIdx, &nextTexelBufferIdx); this->setFragmentData(primProc, pipeline, &nextTexSamplerIdx, &nextTexelBufferIdx); const GrXferProcessor& xp = pipeline.getXferProcessor(); SkIPoint offset; GrTexture* dstTexture = pipeline.peekDstTexture(&offset); fXferProcessor->setData(fProgramDataManager, xp, dstTexture, offset); if (dstTexture) { fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerState::ClampNearest(), true, static_cast<GrGLTexture*>(dstTexture), pipeline.dstTextureProxy()->origin()); } SkASSERT(nextTexSamplerIdx == fNumTextureSamplers); SkASSERT(nextTexelBufferIdx == fNumTextureSamplers + fNumTexelBuffers); } void GrGLProgram::generateMipmaps(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) { this->generateMipmaps(primProc, pipeline.getAllowSRGBInputs()); GrFragmentProcessor::Iter iter(pipeline); while (const GrFragmentProcessor* fp = iter.next()) { this->generateMipmaps(*fp, pipeline.getAllowSRGBInputs()); } } void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, int* nextTexSamplerIdx, int* nextTexelBufferIdx) { GrFragmentProcessor::Iter iter(pipeline); GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.begin(), fFragmentProcessors.count()); const GrFragmentProcessor* fp = iter.next(); GrGLSLFragmentProcessor* glslFP = glslIter.next(); while (fp && glslFP) { glslFP->setData(fProgramDataManager, *fp); this->bindTextures(*fp, pipeline.getAllowSRGBInputs(), nextTexSamplerIdx, nextTexelBufferIdx); fp = iter.next(); glslFP = glslIter.next(); } SkASSERT(!fp && !glslFP); } void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc, const GrRenderTargetProxy* proxy) { GrRenderTarget* rt = proxy->priv().peekRenderTarget(); // Load the RT height uniform if it is needed to y-flip gl_FragCoord. 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 != proxy->origin() || fRenderTargetState.fRenderTargetSize != size) { fRenderTargetState.fRenderTargetSize = size; fRenderTargetState.fRenderTargetOrigin = proxy->origin(); float rtAdjustmentVec[4]; fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); } } else { SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport()); const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>(); fGpu->glPathRendering()->setProjectionMatrix(pathProc.viewMatrix(), size, proxy->origin()); } } void GrGLProgram::bindTextures(const GrResourceIOProcessor& processor, bool allowSRGBInputs, int* nextTexSamplerIdx, int* nextTexelBufferIdx) { for (int i = 0; i < processor.numTextureSamplers(); ++i) { const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i); fGpu->bindTexture((*nextTexSamplerIdx)++, sampler.samplerState(), allowSRGBInputs, static_cast<GrGLTexture*>(sampler.peekTexture()), sampler.proxy()->origin()); } for (int i = 0; i < processor.numBuffers(); ++i) { const GrResourceIOProcessor::BufferAccess& access = processor.bufferAccess(i); fGpu->bindTexelBuffer((*nextTexelBufferIdx)++, access.texelConfig(), static_cast<GrGLBuffer*>(access.buffer())); } } void GrGLProgram::generateMipmaps(const GrResourceIOProcessor& processor, bool allowSRGBInputs) { for (int i = 0; i < processor.numTextureSamplers(); ++i) { const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i); fGpu->generateMipmaps(sampler.samplerState(), allowSRGBInputs, static_cast<GrGLTexture*>(sampler.peekTexture()), sampler.proxy()->origin()); } }