blob: 678edeeabc228a5bf59b3e55d2628d98a78813b5 [file] [log] [blame]
/*
* 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());
}
}
}