/* * 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/GrFragmentProcessor.h" #include "src/gpu/GrGeometryProcessor.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/effects/GrTextureEffect.h" #include "src/gpu/gl/GrGLBuffer.h" #include "src/gpu/gl/GrGLGpu.h" #include "src/sksl/SkSLCompiler.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 gpImpl, std::unique_ptr xpImpl, 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(gpImpl), std::move(xpImpl), 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 gpImpl, std::unique_ptr xpImpl, std::vector> fpImpls, std::unique_ptr attributes, int vertexAttributeCnt, int instanceAttributeCnt, int vertexStride, int instanceStride) : fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) , fGPImpl(std::move(gpImpl)) , fXPImpl(std::move(xpImpl)) , 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. fGPImpl->setData(fProgramDataManager, *fGpu->caps()->shaderCaps(), programInfo.geomProc()); for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) { const auto& fp = programInfo.pipeline().getFragmentProcessor(i); fp.visitWithImpls([&](const GrFragmentProcessor& fp, GrFragmentProcessor::ProgramImpl& impl) { impl.setData(fProgramDataManager, fp); }, *fFPImpls[i]); } programInfo.pipeline().setDstTextureUniforms(fProgramDataManager, &fBuiltinUniformHandles); fXPImpl->setData(fProgramDataManager, programInfo.pipeline().getXferProcessor()); } void GrGLProgram::bindTextures(const GrGeometryProcessor& geomProc, const GrSurfaceProxy* const geomProcTextures[], const GrPipeline& pipeline) { // Bind textures from the geometry processor. 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(); // Bind texture from the destination proxy view. GrTexture* dstTexture = pipeline.peekDstTexture(); if (dstTexture) { fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerState::Filter::kNearest, pipeline.dstProxyView().swizzle(), static_cast(dstTexture)); } // Bind textures from all of the fragment processors. 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); }); SkASSERT(nextTexSamplerIdx == fNumTextureSamplers); } void GrGLProgram::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin, const GrGeometryProcessor& geomProc) { // Set RT adjustment and RT flip SkISize dimensions = rt->dimensions(); if (fRenderTargetState.fRenderTargetOrigin != origin || fRenderTargetState.fRenderTargetSize != dimensions) { fRenderTargetState.fRenderTargetSize = dimensions; fRenderTargetState.fRenderTargetOrigin = origin; // The client will mark a swap buffer as kBottomLeft when making a SkSurface because // GL's framebuffer space has (0, 0) at the bottom left. In NDC (-1, -1) is also the // bottom left. However, Skia's device coords has (0, 0) at the top left, so a flip is // required when the origin is kBottomLeft. bool flip = (origin == kBottomLeft_GrSurfaceOrigin); std::array v = SkSL::Compiler::GetRTAdjustVector(dimensions, flip); fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data()); if (fBuiltinUniformHandles.fRTFlipUni.isValid()) { std::array d = SkSL::Compiler::GetRTFlipVector(dimensions.height(), flip); fProgramDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data()); } } }