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.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

occlusion.cc 5.3KB

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