test program that renders a quad using spirv shaders, used for debugging
[glquad-spirv] / src / main.cc
1 #include <GL/glew.h>
2
3 #include <GL/freeglut.h>
4 #include <GL/glext.h>
5 #include <GL/glx.h>
6
7 #include <assert.h>
8
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #define VERTEX_LOC 0
14
15 struct Ubo {
16         float color[4] = {0, 1, 0, 1};
17 };
18
19 static bool init();
20 static void cleanup();
21
22 static void display();
23 static void keydown(unsigned char key, int x, int y);
24 static unsigned int load_shader(const char *fname, int type);
25 static unsigned int create_program(const char *vfname, const char *pfname);
26 static bool link_program(unsigned int prog);
27
28 static const char *vs_path = "data/spirv/vertex.spv";
29 static const char *fs_path = "data/spirv/pixel.spv";
30
31 static unsigned int sprog;
32 static unsigned int vbo;
33 static unsigned int vao;
34
35 static float vertices[] = {
36         -0.5, -0.5,
37         0.5, -0.5,
38         0.5, 0.5,
39
40         -0.5, -0.5,
41         0.5, 0.5,
42         -0.5, 0.5
43 };
44
45 static int num_vertices = 6;
46 static Ubo test_ubo;
47 static unsigned int ubo;
48
49 int main(int argc, char **argv)
50 {
51         glutInitContextProfile(GLUT_CORE_PROFILE);
52         glutInitContextVersion(4, 5);
53
54         glutInit(&argc, argv);
55
56         glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
57         glutInitWindowSize(800, 600);
58         glutCreateWindow("gltest");
59
60
61         glClear(GL_COLOR_BUFFER_BIT);
62
63         glutDisplayFunc(display);
64         glutKeyboardFunc(keydown);
65
66         if(!init())
67                 return 1;
68
69         atexit(cleanup);
70         glutMainLoop();
71 }
72
73 static bool init()
74 {
75         glewInit();
76
77         glClearColor(0.0, 0.0, 1.0, 1.0);
78
79         glGenBuffers(1, &ubo);
80         glBindBuffer(GL_UNIFORM_BUFFER, ubo);
81         glBufferData(GL_UNIFORM_BUFFER, sizeof test_ubo, &test_ubo, GL_STREAM_DRAW);
82
83         glGenVertexArrays(1, &vao);
84         glBindVertexArray(vao);
85
86         glGenBuffers(1, &vbo);
87         glBindBuffer(GL_ARRAY_BUFFER, vbo);
88         glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
89         glBindBuffer(GL_ARRAY_BUFFER, 0);
90
91         if(!(sprog = create_program(vs_path, fs_path))) {
92                 fprintf(stderr, "Failed to create shader program.\n");
93                 return false;
94         }
95
96         glUseProgram(sprog);
97
98         assert(glGetError() == GL_NO_ERROR);
99         return true;
100 }
101
102 static void display()
103 {
104         glEnableVertexAttribArray(VERTEX_LOC);
105         glBindBuffer(GL_ARRAY_BUFFER, vbo);
106
107         glVertexAttribPointer(VERTEX_LOC, 2, GL_FLOAT, GL_FALSE, 0, 0);
108
109         glBindBuffer(GL_ARRAY_BUFFER, 0);
110
111         glBindBuffer(GL_UNIFORM_BUFFER, ubo);
112         glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof test_ubo, &test_ubo);
113         glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo);
114
115         glDrawArrays(GL_TRIANGLES, 0, num_vertices);
116
117         assert(glGetError() == GL_NO_ERROR);
118
119         glutSwapBuffers();
120 }
121
122 static void keydown(unsigned char key, int /*x*/, int /*y*/)
123 {
124         switch(key) {
125         case 27:
126                 exit(0);
127         }
128 }
129
130 static unsigned int create_program(const char *vfname, const char *pfname)
131 {
132         unsigned int vs, ps;
133         unsigned int prog;
134
135         if(!(vs = load_shader(vfname, GL_VERTEX_SHADER)))
136                 return false;
137         if(!(ps = load_shader(pfname, GL_FRAGMENT_SHADER))) {
138                 glDeleteShader(vs);
139                 return false;
140         }
141
142         prog = glCreateProgram();
143         glAttachShader(prog, vs);
144         glAttachShader(prog, ps);
145
146         if(!link_program(prog)) {
147                 glDeleteShader(vs);
148                 glDeleteShader(ps);
149                 glDeleteProgram(prog);
150                 return false;
151         }
152
153         glDetachShader(prog, vs);
154         glDetachShader(prog, ps);
155
156         return prog;
157 }
158
159 static bool link_program(unsigned int prog)
160 {
161                 int status, loglen;
162         char *buf;
163
164         glLinkProgram(prog);
165
166         glGetProgramiv(prog, GL_LINK_STATUS, &status);
167         if(status) {
168                 printf("successfully linked shader program\n");
169         } else {
170                 printf("failed to link shader program\n");
171         }
172
173         glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &loglen);
174         if(loglen > 0 && (buf = (char*)malloc(loglen + 1))) {
175                 glGetProgramInfoLog(prog, loglen, 0, buf);
176                 buf[loglen] = 0;
177                 printf("%s\n", buf);
178                 free(buf);
179         }
180
181         return status ? true : false;
182 }
183
184 unsigned int load_shader(const char *fname, int type)
185 {
186         unsigned int sdr;
187         unsigned int fsz;
188         char *buf;
189         FILE *fp;
190         int status, loglen;
191
192         if(!(fp = fopen(fname, "rb"))) {
193                 fprintf(stderr, "failed to open shader: %s\n", fname);
194                 return 0;
195         }
196         fseek(fp, 0, SEEK_END);
197         fsz = ftell(fp);
198         rewind(fp);
199
200         if(!(buf = (char*)malloc(fsz + 1))) {
201                 fprintf(stderr, "failed to allocate %d bytes\n", fsz + 1);
202                 fclose(fp);
203                 return 0;
204         }
205         if(fread(buf, 1, fsz, fp) < fsz) {
206                 fprintf(stderr, "failed to read shader: %s\n", fname);
207                 free(buf);
208                 fclose(fp);
209                 return 0;
210         }
211         buf[fsz] = 0;
212         fclose(fp);
213
214         sdr = glCreateShader(type);
215
216         glShaderBinary(1, &sdr, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, buf, fsz);
217         glSpecializeShaderARB(sdr, "main", 0, 0, 0);
218
219                 free(buf);
220
221         glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
222         if(status) {
223                 printf("successfully compiled shader: %s\n", fname);
224         } else {
225                 printf("failed to compile shader: %s\n", fname);
226         }
227
228         glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
229         if(loglen > 0 && (buf = (char*)malloc(loglen + 1))) {
230                 glGetShaderInfoLog(sdr, loglen, 0, buf);
231                 buf[loglen] = 0;
232                 printf("%s\n", buf);
233                 free(buf);
234         }
235
236         if(!status) {
237                 glDeleteShader(sdr);
238                 return 0;
239         }
240
241         return sdr;
242 }
243
244 static void cleanup()
245 {
246         glDeleteVertexArrays(1, &vao);
247         glDeleteBuffers(1, &vbo);
248         glDeleteBuffers(1, &ubo);
249 }