| /* |
| * 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> GrGLProgram::Make( |
| GrGLGpu* gpu, |
| const GrGLSLBuiltinUniformHandles& builtinUniforms, |
| GrGLuint programID, |
| const UniformInfoArray& uniforms, |
| const UniformInfoArray& textureSamplers, |
| std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl, |
| std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl, |
| std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls, |
| std::unique_ptr<Attribute[]> attributes, |
| int vertexAttributeCnt, |
| int instanceAttributeCnt, |
| int vertexStride, |
| int instanceStride) { |
| sk_sp<GrGLProgram> 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<GrGeometryProcessor::ProgramImpl> gpImpl, |
| std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl, |
| std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls, |
| std::unique_ptr<Attribute[]> 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<GrGLTexture*>(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<GrGLTexture*>(dstTexture)); |
| } |
| // Bind textures from all of the fragment processors. |
| pipeline.visitTextureEffects([&](const GrTextureEffect& te) { |
| GrSamplerState samplerState = te.samplerState(); |
| skgpu::Swizzle swizzle = te.view().swizzle(); |
| auto* texture = static_cast<GrGLTexture*>(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<float, 4> v = SkSL::Compiler::GetRTAdjustVector(dimensions, flip); |
| fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data()); |
| if (fBuiltinUniformHandles.fRTFlipUni.isValid()) { |
| std::array<float, 2> d = SkSL::Compiler::GetRTFlipVector(dimensions.height(), flip); |
| fProgramDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data()); |
| } |
| } |
| } |