blob: 73050dd483f202ac472e6637ebbaa7fbbded2581 [file] [log] [blame]
/*
* Copyright 2012 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/GrGLProgramDataManager.h"
#include "include/core/SkMatrix.h"
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/gl/GrGLGpu.h"
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
GrGLProgramDataManager::UniformManager::UniformManager(const GrUniformAggregator& uniformAggregator,
GrGLuint programID,
GrGLint firstUniformLocation,
const GrGLContext& ctx) {
GrGLint location = firstUniformLocation;
fUniforms.reserve(uniformAggregator.uniformCount());
for (int p = 0; p < uniformAggregator.numProcessors(); ++p) {
fUniforms.push_back({});
for (const GrUniformAggregator::Record& record : uniformAggregator.processorRecords(p)) {
const GrProcessor::Uniform& u = record.uniform();
if (ctx.caps()->bindUniformLocationSupport()) {
GR_GL_CALL(ctx.glInterface(),
BindUniformLocation(programID, location++, record.name.c_str()));
} else {
GR_GL_CALL_RET(ctx.glInterface(),
location,
GetUniformLocation(programID, record.name.c_str()));
}
fUniforms.back().push_back({
record.indexInProcessor,
u.type(),
u.count(),
location,
});
}
}
}
void GrGLProgramDataManager::UniformManager::setUniforms(const GrGLInterface* gl,
const GrProgramInfo& info) {
auto set = [&, processorIndex = 0](const GrProcessor& p) mutable {
const ProcessorUniforms& uniforms = fUniforms[processorIndex];
for (const Uniform& u : uniforms) {
if (u.location < 0) {
// Presumably this got optimized out.
continue;
}
size_t index = u.indexInProcessor;
SkASSERT(u.count >= 0);
static_assert(GrShaderVar::kNonArray == 0);
int n = std::max(1, u.count);
switch (u.type) {
case kInt_GrSLType: {
const int32_t* values = p.uniformData<int32_t>(index);
GR_GL_CALL(gl, Uniform1iv(u.location, n, values));
break;
}
case kInt2_GrSLType: {
const int32_t* values = p.uniformData<int32_t>(index);
GR_GL_CALL(gl, Uniform2iv(u.location, n, values));
break;
}
case kInt3_GrSLType: {
const int32_t* values = p.uniformData<int32_t>(index);
GR_GL_CALL(gl, Uniform3iv(u.location, n, values));
break;
}
case kInt4_GrSLType: {
const int32_t* values = p.uniformData<int32_t>(index);
GR_GL_CALL(gl, Uniform4iv(u.location, n, values));
break;
}
case kHalf_GrSLType:
case kFloat_GrSLType: {
const float* values = p.uniformData<float>(index);
GR_GL_CALL(gl, Uniform1fv(u.location, n, values));
break;
}
case kHalf2_GrSLType:
case kFloat2_GrSLType: {
const float* values = p.uniformData<float>(index);
GR_GL_CALL(gl, Uniform2fv(u.location, n, values));
break;
}
case kHalf3_GrSLType:
case kFloat3_GrSLType: {
const float* values = p.uniformData<float>(index);
GR_GL_CALL(gl, Uniform3fv(u.location, n, values));
break;
}
case kHalf4_GrSLType:
case kFloat4_GrSLType: {
const float* values = p.uniformData<float>(index);
GR_GL_CALL(gl, Uniform4fv(u.location, n, values));
break;
}
case kHalf2x2_GrSLType:
case kFloat2x2_GrSLType: {
const float* values = p.uniformData<float>(index);
GR_GL_CALL(gl, UniformMatrix2fv(u.location, n, false, values));
break;
}
case kHalf3x3_GrSLType:
case kFloat3x3_GrSLType: {
switch (p.uniforms()[index].ctype()) {
case GrProcessor::Uniform::CType::kDefault: {
const float* values = p.uniformData<float>(index);
GR_GL_CALL(gl, UniformMatrix3fv(u.location, n, false, values));
break;
}
case GrProcessor::Uniform::CType::kSkMatrix: {
const SkMatrix* matrix = p.uniformData<SkMatrix>(index);
int location = u.location;
for (int i = 0; i < n; ++i, ++matrix, ++location) {
float mt[] = {
matrix->get(SkMatrix::kMScaleX),
matrix->get(SkMatrix::kMSkewY),
matrix->get(SkMatrix::kMPersp0),
matrix->get(SkMatrix::kMSkewX),
matrix->get(SkMatrix::kMScaleY),
matrix->get(SkMatrix::kMPersp1),
matrix->get(SkMatrix::kMTransX),
matrix->get(SkMatrix::kMTransY),
matrix->get(SkMatrix::kMPersp2),
};
GR_GL_CALL(gl, UniformMatrix3fv(location, 1, false, mt));
}
break;
}
}
break;
}
case kHalf4x4_GrSLType:
case kFloat4x4_GrSLType: {
const float* values = p.uniformData<float>(index);
GR_GL_CALL(gl, UniformMatrix4fv(u.location, n, false, values));
break;
}
default:
SK_ABORT("Unexpect uniform type");
}
}
++processorIndex;
};
info.visitProcessors(set);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#define ASSERT_ARRAY_UPLOAD_IN_BOUNDS(UNI, COUNT) \
SkASSERT((COUNT) <= (UNI).fArrayCount || \
(1 == (COUNT) && GrShaderVar::kNonArray == (UNI).fArrayCount))
GrGLint get_first_unused_uniform_location(
const GrGLProgramDataManager::UniformInfoArray& uniforms) {
GrGLint id = -1;
for (int i = 0; i < uniforms.count(); ++i) {
id = std::max(id, uniforms.item(i).fLocation);
}
return id + 1;
}
GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu,
const UniformInfoArray& uniforms,
GrGLuint programID,
const GrUniformAggregator& uniformAggregator)
: fGpu(gpu)
, fManager(uniformAggregator,
programID,
get_first_unused_uniform_location(uniforms),
gpu->glContext()) {
fUniforms.push_back_n(uniforms.count());
int i = 0;
for (const GLUniformInfo& builderUniform : uniforms.items()) {
Uniform& uniform = fUniforms[i++];
SkASSERT(GrShaderVar::kNonArray == builderUniform.fVariable.getArrayCount() ||
builderUniform.fVariable.getArrayCount() > 0);
SkDEBUGCODE(
uniform.fArrayCount = builderUniform.fVariable.getArrayCount();
uniform.fType = builderUniform.fVariable.getType();
)
uniform.fLocation = builderUniform.fLocation;
}
}
void GrGLProgramDataManager::setUniforms(const GrProgramInfo& info) {
fManager.setUniforms(fGpu->glInterface(), info);
}
void GrGLProgramDataManager::setSamplerUniforms(const UniformInfoArray& samplers,
int startUnit) const {
int i = 0;
for (const GLUniformInfo& sampler : samplers.items()) {
SkASSERT(sampler.fVisibility);
if (kUnusedUniform != sampler.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform1i(sampler.fLocation, i + startUnit));
}
++i;
}
}
void GrGLProgramDataManager::set1i(UniformHandle u, int32_t i) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform1i(uni.fLocation, i));
}
}
void GrGLProgramDataManager::set1iv(UniformHandle u,
int arrayCount,
const int32_t v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform1iv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::set1f(UniformHandle u, float v0) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform1f(uni.fLocation, v0));
}
}
void GrGLProgramDataManager::set1fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
// This assert fires in some instances of the two-pt gradient for its VSParams.
// Once the uniform manager is responsible for inserting the duplicate uniform
// arrays in VS and FS driver bug workaround, this can be enabled.
// this->printUni(uni);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform1fv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::set2i(UniformHandle u, int32_t i0, int32_t i1) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform2i(uni.fLocation, i0, i1));
}
}
void GrGLProgramDataManager::set2iv(UniformHandle u,
int arrayCount,
const int32_t v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform2iv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::set2f(UniformHandle u, float v0, float v1) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform2f(uni.fLocation, v0, v1));
}
}
void GrGLProgramDataManager::set2fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform2fv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::set3i(UniformHandle u, int32_t i0, int32_t i1, int32_t i2) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform3i(uni.fLocation, i0, i1, i2));
}
}
void GrGLProgramDataManager::set3iv(UniformHandle u,
int arrayCount,
const int32_t v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform3iv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform3f(uni.fLocation, v0, v1, v2));
}
}
void GrGLProgramDataManager::set3fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform3fv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::set4i(UniformHandle u,
int32_t i0,
int32_t i1,
int32_t i2,
int32_t i3) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform4i(uni.fLocation, i0, i1, i2, i3));
}
}
void GrGLProgramDataManager::set4iv(UniformHandle u,
int arrayCount,
const int32_t v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform4iv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::set4f(UniformHandle u,
float v0,
float v1,
float v2,
float v3) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform4f(uni.fLocation, v0, v1, v2, v3));
}
}
void GrGLProgramDataManager::set4fv(UniformHandle u,
int arrayCount,
const float v[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
GR_GL_CALL(fGpu->glInterface(), Uniform4fv(uni.fLocation, arrayCount, v));
}
}
void GrGLProgramDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const {
this->setMatrices<2>(u, 1, matrix);
}
void GrGLProgramDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
this->setMatrices<3>(u, 1, matrix);
}
void GrGLProgramDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
this->setMatrices<4>(u, 1, matrix);
}
void GrGLProgramDataManager::setMatrix2fv(UniformHandle u, int arrayCount, const float m[]) const {
this->setMatrices<2>(u, arrayCount, m);
}
void GrGLProgramDataManager::setMatrix3fv(UniformHandle u, int arrayCount, const float m[]) const {
this->setMatrices<3>(u, arrayCount, m);
}
void GrGLProgramDataManager::setMatrix4fv(UniformHandle u, int arrayCount, const float m[]) const {
this->setMatrices<4>(u, arrayCount, m);
}
template<int N> struct set_uniform_matrix;
template<int N> inline void GrGLProgramDataManager::setMatrices(UniformHandle u,
int arrayCount,
const float matrices[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat2x2_GrSLType + (N - 2) ||
uni.fType == kHalf2x2_GrSLType + (N - 2));
SkASSERT(arrayCount > 0);
ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
if (kUnusedUniform != uni.fLocation) {
set_uniform_matrix<N>::set(fGpu->glInterface(), uni.fLocation, arrayCount, matrices);
}
}
template<> struct set_uniform_matrix<2> {
inline static void set(const GrGLInterface* gli, const GrGLint loc, int cnt, const float m[]) {
GR_GL_CALL(gli, UniformMatrix2fv(loc, cnt, false, m));
}
};
template<> struct set_uniform_matrix<3> {
inline static void set(const GrGLInterface* gli, const GrGLint loc, int cnt, const float m[]) {
GR_GL_CALL(gli, UniformMatrix3fv(loc, cnt, false, m));
}
};
template<> struct set_uniform_matrix<4> {
inline static void set(const GrGLInterface* gli, const GrGLint loc, int cnt, const float m[]) {
GR_GL_CALL(gli, UniformMatrix4fv(loc, cnt, false, m));
}
};