1 /*
2  * Copyright 2014 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 "GrGLVertexShaderBuilder.h"
9 #include "GrGLProgramBuilder.h"
10 #include "../GrGLGpu.h"
11 
12 #define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X)
13 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(), R, X)
14 
GrGLVertexBuilder(GrGLProgramBuilder * program)15 GrGLVertexBuilder::GrGLVertexBuilder(GrGLProgramBuilder* program)
16     : INHERITED(program)
17     , fRtAdjustName(NULL) {
18 }
19 
addVarying(const char * name,GrGLVarying * v)20 void GrGLVertexBuilder::addVarying(const char* name, GrGLVarying* v) {
21     fOutputs.push_back();
22     fOutputs.back().setType(v->fType);
23     fOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
24     fProgramBuilder->nameVariable(fOutputs.back().accessName(), 'v', name);
25     v->fVsOut = fOutputs.back().getName().c_str();
26 }
27 
emitAttributes(const GrGeometryProcessor & gp)28 void GrGLVertexBuilder::emitAttributes(const GrGeometryProcessor& gp) {
29     int vaCount = gp.numAttribs();
30     for (int i = 0; i < vaCount; i++) {
31         this->addAttribute(&gp.getAttrib(i));
32     }
33     return;
34 }
35 
transformToNormalizedDeviceSpace(const GrShaderVar & posVar)36 void GrGLVertexBuilder::transformToNormalizedDeviceSpace(const GrShaderVar& posVar) {
37     SkASSERT(!fRtAdjustName);
38 
39     // setup RT Uniform
40     fProgramBuilder->fUniformHandles.fRTAdjustmentUni =
41             fProgramBuilder->addUniform(GrGLProgramBuilder::kVertex_Visibility,
42                                         kVec4f_GrSLType, kDefault_GrSLPrecision,
43                                         fProgramBuilder->rtAdjustment(),
44                                         &fRtAdjustName);
45     if (this->getProgramBuilder()->desc().header().fSnapVerticesToPixelCenters) {
46         if (kVec3f_GrSLType == posVar.getType()) {
47             const char* p = posVar.c_str();
48             this->codeAppendf("{vec2 _posTmp = vec2(%s.x/%s.z, %s.y/%s.z);", p, p, p, p);
49         } else {
50             SkASSERT(kVec2f_GrSLType == posVar.getType());
51             this->codeAppendf("{vec2 _posTmp = %s;", posVar.c_str());
52         }
53         this->codeAppendf("_posTmp = floor(_posTmp) + vec2(0.5, 0.5);"
54                           "gl_Position = vec4(_posTmp.x * %s.x + %s.y, _posTmp.y * %s.z + %s.w, 0, 1);}",
55                           fRtAdjustName, fRtAdjustName, fRtAdjustName, fRtAdjustName);
56     } else if (kVec3f_GrSLType == posVar.getType()) {
57         this->codeAppendf("gl_Position = vec4(dot(%s.xz, %s.xy)/%s.z, dot(%s.yz, %s.zw)/%s.z, 0, 1);",
58                           posVar.c_str(), fRtAdjustName, posVar.c_str(),
59                           posVar.c_str(), fRtAdjustName, posVar.c_str());
60     } else {
61         SkASSERT(kVec2f_GrSLType == posVar.getType());
62         this->codeAppendf("gl_Position = vec4(%s.x * %s.x + %s.y, %s.y * %s.z + %s.w, 0, 1);",
63                           posVar.c_str(), fRtAdjustName, fRtAdjustName,
64                           posVar.c_str(), fRtAdjustName, fRtAdjustName);
65     }
66     // We could have the GrGeometryProcessor do this, but its just easier to have it performed
67     // here. If we ever need to set variable pointsize, then we can reinvestigate
68     this->codeAppend("gl_PointSize = 1.0;");
69 }
70 
bindVertexAttributes(GrGLuint programID)71 void GrGLVertexBuilder::bindVertexAttributes(GrGLuint programID) {
72     const GrPrimitiveProcessor& primProc = fProgramBuilder->primitiveProcessor();
73 
74     int vaCount = primProc.numAttribs();
75     for (int i = 0; i < vaCount; i++) {
76         GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
77     }
78     return;
79 }
80 
81 bool
compileAndAttachShaders(GrGLuint programId,SkTDArray<GrGLuint> * shaderIds)82 GrGLVertexBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) {
83     this->versionDecl() = GrGetGLSLVersionDecl(fProgramBuilder->ctxInfo());
84     this->compileAndAppendLayoutQualifiers();
85     fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kVertex_Visibility, &this->uniforms());
86     this->appendDecls(fInputs, &this->inputs());
87     this->appendDecls(fOutputs, &this->outputs());
88     return this->finalize(programId, GR_GL_VERTEX_SHADER, shaderIds);
89 }
90 
addAttribute(const GrShaderVar & var)91 bool GrGLVertexBuilder::addAttribute(const GrShaderVar& var) {
92     SkASSERT(GrShaderVar::kAttribute_TypeModifier == var.getTypeModifier());
93     for (int i = 0; i < fInputs.count(); ++i) {
94         const GrGLShaderVar& attr = fInputs[i];
95         // if attribute already added, don't add it again
96         if (attr.getName().equals(var.getName())) {
97             return false;
98         }
99     }
100     fInputs.push_back(var);
101     return true;
102 }
103