forked from cirosantilli/cpp-cheat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
glfw_compute_shader.c
174 lines (153 loc) · 5.44 KB
/
glfw_compute_shader.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
Compute shader hello world.
Does a simple computation, and writes it directly to the
texture seen by the frament shader.
This could be done easily on a fragment shader,
so this is is just an useless sanity check example.
The main advantage of compute shaders (which we are not doing here),
is that they can keep state data on the GPU between draw calls.
This is basically the upper limit speed of compute to texture operations,
since we are only doing a very simple operaiton on the shader.
TODO understand:
GL_MAX_COMPUTE_WORK_GROUP_COUNT
GL_MAX_COMPUTE_WORK_GROUP_SIZE
GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS
glDispatchCompute
glMemoryBarrier
local_size_x
binding
*/
#include "common.h"
static const GLuint WIDTH = 512;
static const GLuint HEIGHT = 512;
static const GLfloat vertices_xy_uv[] = {
-1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, 1.0, 1.0,
};
static const GLuint indices[] = {
0, 1, 2,
0, 2, 3,
};
static const GLchar *vertex_shader_source =
"#version 330 core\n"
"in vec2 coord2d;\n"
"in vec2 vertexUv;\n"
"out vec2 fragmentUv;\n"
"void main() {\n"
" gl_Position = vec4(coord2d, 0, 1);\n"
" fragmentUv = vertexUv;\n"
"}\n";
static const GLchar *fragment_shader_source =
"#version 330 core\n"
"in vec2 fragmentUv;\n"
"out vec3 color;\n"
"uniform sampler2D textureSampler;\n"
"void main() {\n"
" color = texture(textureSampler, fragmentUv.yx).rgb;\n"
"}\n";
static const char *compute_shader_source =
"#version 430\n"
"layout (local_size_x = 1, local_size_y = 1) in;\n"
"layout (rgba32f, binding = 0) uniform image2D img_output;\n"
"void main () {\n"
" ivec2 gid = ivec2(gl_GlobalInvocationID.xy);\n"
" ivec2 dims = imageSize(img_output);\n"
" vec4 pixel = vec4(gid.x / float(dims.x), gid.y / float(dims.y), 1.0, 1.0);\n"
" imageStore(img_output, gid, pixel);\n"
"}\n";
int main(void) {
GLFWwindow *window;
GLint
coord2d_location,
textureSampler_location,
vertexUv_location
;
GLuint
ebo,
program,
compute_program,
texture,
vbo,
vao
;
unsigned int
width = WIDTH,
height = HEIGHT
;
/* Window. */
glfwInit();
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(width, height, __FILE__, NULL, NULL);
glfwMakeContextCurrent(window);
glewInit();
/* Shader. */
program = common_get_shader_program(vertex_shader_source, fragment_shader_source);
coord2d_location = glGetAttribLocation(program, "coord2d");
vertexUv_location = glGetAttribLocation(program, "vertexUv");
textureSampler_location = glGetUniformLocation(program, "textureSampler");
/* Compute shader. */
compute_program = common_get_compute_program(compute_shader_source);
/* vbo */
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_xy_uv), vertices_xy_uv, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
/* ebo */
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
/* vao */
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(coord2d_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(vertices_xy_uv[0]), (GLvoid*)0);
glEnableVertexAttribArray(coord2d_location);
glVertexAttribPointer(vertexUv_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(vertices_xy_uv[0]), (GLvoid*)(2 * sizeof(vertices_xy_uv[0])));
glEnableVertexAttribArray(vertexUv_location);
glBindVertexArray(0);
/* Texture. */
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
/* Same internal format as compute shader input.
* data=NULL to just allocate the memory but not set it to anything. */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
/* Bind to image unit, to allow writting to it from the compute shader. */
glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
/* Compute. */
glUseProgram(compute_program);
/* Dimensions given here appear in gl_GlobalInvocationID.xy in the shader. */
glDispatchCompute((GLuint)width, (GLuint)height, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
/* Global state. */
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
/* Main loop. */
common_fps_init();
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glUniform1i(textureSampler_location, 0);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
common_fps_print();
}
/* Cleanup. */
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteTextures(1, &texture);
glDeleteProgram(program);
glDeleteProgram(compute_program);
glfwTerminate();
return EXIT_SUCCESS;
}