1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "shader.h"
17 
18 #include <stdio.h>
19 
20 #include <memory>
21 
22 // Given shader source, load and compile it
loadShader(GLenum type,const char * shaderSrc,const char * name)23 static GLuint loadShader(GLenum type, const char* shaderSrc, const char* name) {
24     // Create the shader object
25     GLuint shader = glCreateShader(type);
26     if (shader == 0) {
27         return 0;
28     }
29 
30     // Load and compile the shader
31     glShaderSource(shader, 1, &shaderSrc, nullptr);
32     glCompileShader(shader);
33 
34     // Verify the compilation worked as expected
35     GLint compiled = 0;
36     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
37     if (!compiled) {
38         printf("Error compiling %s shader for %s\n", (type == GL_VERTEX_SHADER) ? "vtx" : "pxl",
39                name);
40 
41         GLint size = 0;
42         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
43         if (size > 0) {
44             // Get and report the error message
45             std::unique_ptr<char> infoLog(new char[size]);
46             glGetShaderInfoLog(shader, size, NULL, infoLog.get());
47             printf("  msg:\n%s\n", infoLog.get());
48         }
49 
50         glDeleteShader(shader);
51         return 0;
52     }
53 
54     return shader;
55 }
56 
57 // Create a program object given vertex and pixels shader source
buildShaderProgram(const char * vtxSrc,const char * pxlSrc,const char * name)58 GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name) {
59     GLuint program = glCreateProgram();
60     if (program == 0) {
61         printf("Failed to allocate program object\n");
62         return 0;
63     }
64 
65     // Compile the shaders and bind them to this program
66     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vtxSrc, name);
67     if (vertexShader == 0) {
68         printf("Failed to load vertex shader\n");
69         glDeleteProgram(program);
70         return 0;
71     }
72     GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pxlSrc, name);
73     if (pixelShader == 0) {
74         printf("Failed to load pixel shader\n");
75         glDeleteProgram(program);
76         glDeleteShader(vertexShader);
77         return 0;
78     }
79     glAttachShader(program, vertexShader);
80     glAttachShader(program, pixelShader);
81 
82     // Link the program
83     glLinkProgram(program);
84     GLint linked = 0;
85     glGetProgramiv(program, GL_LINK_STATUS, &linked);
86     if (!linked) {
87         printf("Error linking program.\n");
88         GLint size = 0;
89         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
90         if (size > 0) {
91             // Get and report the error message
92             std::unique_ptr<char> infoLog(new char[size]);
93             glGetProgramInfoLog(program, size, NULL, infoLog.get());
94             printf("  msg:  %s\n", infoLog.get());
95         }
96 
97         glDeleteProgram(program);
98         glDeleteShader(vertexShader);
99         glDeleteShader(pixelShader);
100         return 0;
101     }
102 
103 #if defined(DEBUG)  // Debug output to diagnose shader parameters
104     GLint numShaderParams;
105     GLchar paramName[128];
106     GLint paramSize;
107     GLenum paramType;
108     const char* typeName = "?";
109     printf("Shader parameters for %s:\n", name);
110     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numShaderParams);
111     for (GLint i = 0; i < numShaderParams; i++) {
112         glGetActiveUniform(program, i, sizeof(paramName), nullptr, &paramSize, &paramType,
113                            paramName);
114         switch (paramType) {
115             case GL_FLOAT:
116                 typeName = "GL_FLOAT";
117                 break;
118             case GL_FLOAT_VEC4:
119                 typeName = "GL_FLOAT_VEC4";
120                 break;
121             case GL_FLOAT_MAT4:
122                 typeName = "GL_FLOAT_MAT4";
123                 break;
124             case GL_SAMPLER_2D:
125                 typeName = "GL_SAMPLER_2D";
126                 break;
127         }
128 
129         printf("  %2d: %s\t (%d) of type %s(%d)\n", i, paramName, paramSize, typeName, paramType);
130     }
131 #endif
132 
133     return program;
134 }
135