xref: /third_party/skia/src/gpu/gl/GrGLProgram.cpp (revision cb93a386)
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/gpu/gl/GrGLProgram.h"
9
10#include "src/gpu/GrFragmentProcessor.h"
11#include "src/gpu/GrGeometryProcessor.h"
12#include "src/gpu/GrPipeline.h"
13#include "src/gpu/GrProcessor.h"
14#include "src/gpu/GrProgramInfo.h"
15#include "src/gpu/GrTexture.h"
16#include "src/gpu/GrXferProcessor.h"
17#include "src/gpu/effects/GrTextureEffect.h"
18#include "src/gpu/gl/GrGLBuffer.h"
19#include "src/gpu/gl/GrGLGpu.h"
20#include "src/sksl/SkSLCompiler.h"
21
22#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
23#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
24
25///////////////////////////////////////////////////////////////////////////////////////////////////
26
27sk_sp<GrGLProgram> GrGLProgram::Make(
28        GrGLGpu* gpu,
29        const GrGLSLBuiltinUniformHandles& builtinUniforms,
30        GrGLuint programID,
31        const UniformInfoArray& uniforms,
32        const UniformInfoArray& textureSamplers,
33        std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl,
34        std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl,
35        std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls,
36        std::unique_ptr<Attribute[]> attributes,
37        int vertexAttributeCnt,
38        int instanceAttributeCnt,
39        int vertexStride,
40        int instanceStride) {
41    sk_sp<GrGLProgram> program(new GrGLProgram(gpu,
42                                               builtinUniforms,
43                                               programID,
44                                               uniforms,
45                                               textureSamplers,
46                                               std::move(gpImpl),
47                                               std::move(xpImpl),
48                                               std::move(fpImpls),
49                                               std::move(attributes),
50                                               vertexAttributeCnt,
51                                               instanceAttributeCnt,
52                                               vertexStride,
53                                               instanceStride));
54    // Assign texture units to sampler uniforms one time up front.
55    gpu->flushProgram(program);
56    program->fProgramDataManager.setSamplerUniforms(textureSamplers, 0);
57    return program;
58}
59
60GrGLProgram::GrGLProgram(GrGLGpu* gpu,
61                         const GrGLSLBuiltinUniformHandles& builtinUniforms,
62                         GrGLuint programID,
63                         const UniformInfoArray& uniforms,
64                         const UniformInfoArray& textureSamplers,
65                         std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl,
66                         std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl,
67                         std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls,
68                         std::unique_ptr<Attribute[]> attributes,
69                         int vertexAttributeCnt,
70                         int instanceAttributeCnt,
71                         int vertexStride,
72                         int instanceStride)
73        : fBuiltinUniformHandles(builtinUniforms)
74        , fProgramID(programID)
75        , fGPImpl(std::move(gpImpl))
76        , fXPImpl(std::move(xpImpl))
77        , fFPImpls(std::move(fpImpls))
78        , fAttributes(std::move(attributes))
79        , fVertexAttributeCnt(vertexAttributeCnt)
80        , fInstanceAttributeCnt(instanceAttributeCnt)
81        , fVertexStride(vertexStride)
82        , fInstanceStride(instanceStride)
83        , fGpu(gpu)
84        , fProgramDataManager(gpu, uniforms)
85        , fNumTextureSamplers(textureSamplers.count()) {}
86
87GrGLProgram::~GrGLProgram() {
88    if (fProgramID) {
89        GL_CALL(DeleteProgram(fProgramID));
90    }
91}
92
93void GrGLProgram::abandon() {
94    fProgramID = 0;
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
99void GrGLProgram::updateUniforms(const GrRenderTarget* renderTarget,
100                                 const GrProgramInfo& programInfo) {
101    this->setRenderTargetState(renderTarget, programInfo.origin(), programInfo.geomProc());
102
103    // we set the uniforms for installed processors in a generic way, but subclasses of GLProgram
104    // determine how to set coord transforms
105
106    // We must bind to texture units in the same order in which we set the uniforms in
107    // GrGLProgramDataManager. That is, we bind textures for processors in this order:
108    // primProc, fragProcs, XP.
109    fGPImpl->setData(fProgramDataManager, *fGpu->caps()->shaderCaps(), programInfo.geomProc());
110
111    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
112        const auto& fp = programInfo.pipeline().getFragmentProcessor(i);
113        fp.visitWithImpls([&](const GrFragmentProcessor& fp,
114                              GrFragmentProcessor::ProgramImpl& impl) {
115            impl.setData(fProgramDataManager, fp);
116        }, *fFPImpls[i]);
117    }
118
119    programInfo.pipeline().setDstTextureUniforms(fProgramDataManager, &fBuiltinUniformHandles);
120    fXPImpl->setData(fProgramDataManager, programInfo.pipeline().getXferProcessor());
121}
122
123void GrGLProgram::bindTextures(const GrGeometryProcessor& geomProc,
124                               const GrSurfaceProxy* const geomProcTextures[],
125                               const GrPipeline& pipeline) {
126    // Bind textures from the geometry processor.
127    for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
128        SkASSERT(geomProcTextures[i]->asTextureProxy());
129        auto* overrideTexture = static_cast<GrGLTexture*>(geomProcTextures[i]->peekTexture());
130        fGpu->bindTexture(i, geomProc.textureSampler(i).samplerState(),
131                          geomProc.textureSampler(i).swizzle(), overrideTexture);
132    }
133    int nextTexSamplerIdx = geomProc.numTextureSamplers();
134    // Bind texture from the destination proxy view.
135    GrTexture* dstTexture = pipeline.peekDstTexture();
136    if (dstTexture) {
137        fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerState::Filter::kNearest,
138                          pipeline.dstProxyView().swizzle(), static_cast<GrGLTexture*>(dstTexture));
139    }
140    // Bind textures from all of the fragment processors.
141    pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
142        GrSamplerState samplerState = te.samplerState();
143        GrSwizzle swizzle = te.view().swizzle();
144        auto* texture = static_cast<GrGLTexture*>(te.texture());
145        fGpu->bindTexture(nextTexSamplerIdx++, samplerState, swizzle, texture);
146    });
147
148    SkASSERT(nextTexSamplerIdx == fNumTextureSamplers);
149}
150
151void GrGLProgram::setRenderTargetState(const GrRenderTarget* rt,
152                                       GrSurfaceOrigin origin,
153                                       const GrGeometryProcessor& geomProc) {
154    // Set RT adjustment and RT flip
155    SkISize dimensions = rt->dimensions();
156    if (fRenderTargetState.fRenderTargetOrigin != origin ||
157        fRenderTargetState.fRenderTargetSize != dimensions) {
158        fRenderTargetState.fRenderTargetSize = dimensions;
159        fRenderTargetState.fRenderTargetOrigin = origin;
160
161        // The client will mark a swap buffer as kBottomLeft when making a SkSurface because
162        // GL's framebuffer space has (0, 0) at the bottom left. In NDC (-1, -1) is also the
163        // bottom left. However, Skia's device coords has (0, 0) at the top left, so a flip is
164        // required when the origin is kBottomLeft.
165        bool flip = (origin == kBottomLeft_GrSurfaceOrigin);
166        std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(dimensions, flip);
167        fProgramDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data());
168        if (fBuiltinUniformHandles.fRTFlipUni.isValid()) {
169            std::array<float, 2> d = SkSL::Compiler::GetRTFlipVector(dimensions.height(), flip);
170            fProgramDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data());
171        }
172    }
173}
174