Binary that renders a triangle using Open GL, scans the resulting image to a PNG, and makes an occlusion query to determine the number of fragments shaded. To be used as reference when developing Turnip.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

occlusion.cc 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #include <png.h>
  2. #include <EGL/egl.h>
  3. #include <GLES2/gl2.h>
  4. #include <GLES2/gl2ext.h>
  5. #include <fstream>
  6. #include <iostream>
  7. #include <sstream>
  8. #include <string>
  9. const uint32_t kWidth = 255;
  10. const uint32_t kHeight = 255;
  11. const std::string kVertexShaderPath = "occlusion.vert";
  12. const std::string kFragmentShaderPath = "occlusion.frag";
  13. #define ERROR(message) \
  14. std::cerr << message << std::endl; \
  15. std::exit(EXIT_FAILURE)
  16. void InitializeEGL() {
  17. EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  18. eglInitialize(display, nullptr, nullptr);
  19. eglBindAPI(EGL_OPENGL_ES_API);
  20. const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
  21. const EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_DONT_CARE, EGL_RENDERABLE_TYPE,
  22. EGL_OPENGL_ES2_BIT, EGL_NONE };
  23. EGLConfig egl_config;
  24. EGLint num_configs;
  25. if (!eglChooseConfig(display, config_attribs, &egl_config, 1, &num_configs)) {
  26. ERROR("Unable to choose EGL config");
  27. }
  28. EGLContext context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
  29. if (context == EGL_NO_CONTEXT) {
  30. ERROR("Failed to create GLES context");
  31. }
  32. if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context)) {
  33. ERROR("Failed to make GLES context current");
  34. }
  35. }
  36. void SetUpFramebuffer() {
  37. GLuint color_buffer;
  38. glGenRenderbuffers(1, &color_buffer);
  39. glBindRenderbuffer(GL_RENDERBUFFER, color_buffer);
  40. glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, kWidth, kHeight);
  41. GLuint depth_buffer;
  42. glGenRenderbuffers(1, &depth_buffer);
  43. glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
  44. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, kWidth, kHeight);
  45. GLuint framebuffer;
  46. glGenFramebuffers(1, &framebuffer);
  47. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  48. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_buffer);
  49. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer);
  50. }
  51. GLuint CompileShader(GLenum type, std::string path) {
  52. std::ifstream fstream(path);
  53. if (!fstream) {
  54. ERROR("Unable to read shader: " << path);
  55. }
  56. std::stringstream buffer;
  57. buffer << fstream.rdbuf();
  58. // TODO(brkho): Read the shader source in more intelligently.
  59. std::string shader_source_tmp = buffer.str();
  60. const char* shader_source = shader_source_tmp.c_str();
  61. GLuint shader = glCreateShader(type);
  62. if (!shader) {
  63. ERROR("Failed to create shader of type: " << type);
  64. }
  65. glShaderSource(shader, 1, &shader_source, nullptr);
  66. glCompileShader(shader);
  67. GLint status;
  68. glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
  69. if (!status) {
  70. GLint log_length;
  71. glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
  72. char shader_log[log_length];
  73. glGetShaderInfoLog(shader, log_length, nullptr, shader_log);
  74. ERROR("Failed to compile shader: " << shader_log);
  75. }
  76. return shader;
  77. }
  78. GLuint CreateProgram() {
  79. GLuint vertex_shader = CompileShader(GL_VERTEX_SHADER, kVertexShaderPath);
  80. GLuint fragment_shader = CompileShader(GL_FRAGMENT_SHADER, kFragmentShaderPath);
  81. GLuint program = glCreateProgram();
  82. if (!program) {
  83. ERROR("Failed to create program");
  84. }
  85. glAttachShader(program, vertex_shader);
  86. glAttachShader(program, fragment_shader);
  87. glLinkProgram(program);
  88. GLint status;
  89. glGetProgramiv(program, GL_LINK_STATUS, &status);
  90. if (!status) {
  91. GLint log_length = 0;
  92. glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
  93. char program_log[log_length];
  94. glGetProgramInfoLog(program, log_length, nullptr, program_log);
  95. ERROR("Failed to link program: " << program_log);
  96. }
  97. glDetachShader(program, vertex_shader);
  98. glDetachShader(program, fragment_shader);
  99. glDeleteShader(vertex_shader);
  100. glDeleteShader(fragment_shader);
  101. return program;
  102. }
  103. void Draw(GLuint program) {
  104. glViewport(0, 0, kWidth, kHeight);
  105. glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
  106. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  107. glEnable(GL_DEPTH_TEST);
  108. glUseProgram(program);
  109. glDrawArrays(GL_TRIANGLES, 0, 6);
  110. glFinish();
  111. }
  112. GLubyte* ReadFramebuffer() {
  113. // TODO(brkho): Maybe use a std::array instead?
  114. GLubyte* pixels = static_cast<GLubyte*>(malloc(kWidth * kHeight * 4));
  115. glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
  116. return pixels;
  117. }
  118. void WriteImage(GLubyte* pixels) {
  119. FILE *f = fopen("occlusion.png", "wb");
  120. png_image image_info = {};
  121. image_info.version = PNG_IMAGE_VERSION;
  122. image_info.width = kWidth;
  123. image_info.height = kHeight;
  124. image_info.format = PNG_FORMAT_RGBA;
  125. if (png_image_write_to_stdio(&image_info, f, 0, pixels, kWidth * 4, nullptr) == 0) {
  126. ERROR("Error writing PNG: " << image_info.message);
  127. }
  128. fclose(f);
  129. }
  130. int main() {
  131. InitializeEGL();
  132. SetUpFramebuffer();
  133. GLuint program = CreateProgram();
  134. Draw(program);
  135. GLubyte* pixels = ReadFramebuffer();
  136. WriteImage(pixels);
  137. return EXIT_SUCCESS;
  138. }