/* * 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/gl/GrGLProgram.h" #include "src/gpu/GrPipeline.h" #include "src/gpu/GrProcessor.h" #include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrTexture.h" #include "src/gpu/GrXferProcessor.h" #include "src/gpu/gl/GrGLBuffer.h" #include "src/gpu/gl/GrGLGpu.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) /////////////////////////////////////////////////////////////////////////////////////////////////// sk_sp GrGLProgram::Make( GrGLGpu* gpu, const GrGLSLBuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, const UniformInfoArray& textureSamplers, std::unique_ptr geometryProcessor, std::unique_ptr xferProcessor, std::vector> fpImpls, std::unique_ptr attributes, int vertexAttributeCnt, int instanceAttributeCnt, int vertexStride, int instanceStride) { sk_sp program(new GrGLProgram(gpu, builtinUniforms, programID, uniforms, textureSamplers, std::move(geometryProcessor), std::move(xferProcessor), std::move(fpImpls), std::move(attributes), vertexAttributeCnt, instanceAttributeCnt, vertexStride, instanceStride)); // Assign texture units to sampler uniforms one time up front. gpu->flushProgram(program); program->fProgramDataManager.setSamplerUniforms(textureSamplers, 0); return program; } GrGLProgram::GrGLProgram(GrGLGpu* gpu, const GrGLSLBuiltinUniformHandles& builtinUniforms, GrGLuint programID, const UniformInfoArray& uniforms, const UniformInfoArray& textureSamplers, std::unique_ptr geometryProcessor, std::unique_ptr xferProcessor, std::vector> fpImpls, std::unique_ptr attributes, int vertexAttributeCnt, int instanceAttributeCnt, int vertexStride, int instanceStride) : fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) , fGeometryProcessor(std::move(geometryProcessor)) , fXferProcessor(std::move(xferProcessor)) , fFPImpls(std::move(fpImpls)) , fAttributes(std::move(attributes)) , fVertexAttributeCnt(vertexAttributeCnt) , fInstanceAttributeCnt(instanceAttributeCnt) , fVertexStride(vertexStride) , fInstanceStride(instanceStride) , fGpu(gpu) , fProgramDataManager(gpu, uniforms) , fNumTextureSamplers(textureSamplers.count()) { } GrGLProgram::~GrGLProgram() { if (fProgramID) { GL_CALL(DeleteProgram(fProgramID)); } } void GrGLProgram::abandon() { fProgramID = 0; } /////////////////////////////////////////////////////////////////////////////// void GrGLProgram::updateUniforms(const GrRenderTarget* renderTarget, const GrProgramInfo& programInfo) { this->setRenderTargetState(renderTarget, programInfo.origin(), programInfo.geomProc()); // we set the 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. fGeometryProcessor->setData(fProgramDataManager, *fGpu->caps()->shaderCaps(), programInfo.geomProc()); for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) { auto& fp = programInfo.pipeline().getFragmentProcessor(i); for (auto [fp, impl] : GrGLSLFragmentProcessor::ParallelRange(fp, *fFPImpls[i])) { impl.setData(fProgramDataManager, fp); } } const GrXferProcessor& xp = programInfo.pipeline().getXferProcessor(); SkIPoint offset; GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset); fXferProcessor->setData(fProgramDataManager, xp, dstTexture, offset); } void GrGLProgram::bindTextures(const GrGeometryProcessor& geomProc, const GrSurfaceProxy* const geomProcTextures[], const GrPipeline& pipeline) { for (int i = 0; i < geomProc.numTextureSamplers(); ++i) { SkASSERT(geomProcTextures[i]->asTextureProxy()); auto* overrideTexture = static_cast(geomProcTextures[i]->peekTexture()); fGpu->bindTexture(i, geomProc.textureSampler(i).samplerState(), geomProc.textureSampler(i).swizzle(), overrideTexture); } int nextTexSamplerIdx = geomProc.numTextureSamplers(); pipeline.visitTextureEffects([&](const GrTextureEffect& te) { GrSamplerState samplerState = te.samplerState(); GrSwizzle swizzle = te.view().swizzle(); auto* texture = static_cast(te.texture()); fGpu->bindTexture(nextTexSamplerIdx++, samplerState, swizzle, texture); }); SkIPoint offset; GrTexture* dstTexture = pipeline.peekDstTexture(&offset); if (dstTexture) { fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerState::Filter::kNearest, pipeline.dstProxyView().swizzle(), static_cast(dstTexture)); } SkASSERT(nextTexSamplerIdx == fNumTextureSamplers); } void GrGLProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin, const GrGeometryProcessor& geomProc) { // Load the RT height uniform if it is needed if (fBuiltinUniformHandles.fRTHeightUni.isValid() && fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); } // set RT adjustment SkISize dimensions = rt->dimensions(); if (fRenderTargetState.fRenderTargetOrigin != origin || fRenderTargetState.fRenderTargetSize != dimensions) { fRenderTargetState.fRenderTargetSize = dimensions; fRenderTargetState.fRenderTargetOrigin = origin; float rtAdjustmentVec[4]; fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); } }