OpenGLContext.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/OwnPtr.h>
  7. #include <AK/String.h>
  8. #include <LibGfx/PaintingSurface.h>
  9. #include <LibWeb/WebGL/OpenGLContext.h>
  10. #ifdef AK_OS_MACOS
  11. # include <EGL/egl.h>
  12. # include <EGL/eglext.h>
  13. # include <EGL/eglext_angle.h>
  14. # include <GLES2/gl2.h>
  15. # include <GLES2/gl2ext.h>
  16. # include <GLES2/gl2ext_angle.h>
  17. #endif
  18. namespace Web::WebGL {
  19. struct OpenGLContext::Impl {
  20. #ifdef AK_OS_MACOS
  21. EGLDisplay display { nullptr };
  22. EGLConfig config { nullptr };
  23. EGLContext context { nullptr };
  24. EGLSurface surface { nullptr };
  25. GLuint framebuffer { 0 };
  26. GLuint depth_buffer { 0 };
  27. #endif
  28. };
  29. OpenGLContext::OpenGLContext(NonnullRefPtr<Gfx::SkiaBackendContext> skia_backend_context, Impl impl)
  30. : m_skia_backend_context(move(skia_backend_context))
  31. , m_impl(make<Impl>(impl))
  32. {
  33. }
  34. OpenGLContext::~OpenGLContext()
  35. {
  36. #ifdef AK_OS_MACOS
  37. eglMakeCurrent(m_impl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  38. glDeleteFramebuffers(1, &m_impl->framebuffer);
  39. glDeleteRenderbuffers(1, &m_impl->depth_buffer);
  40. eglDestroyContext(m_impl->display, m_impl->context);
  41. eglDestroySurface(m_impl->display, m_impl->surface);
  42. #endif
  43. }
  44. #ifdef AK_OS_MACOS
  45. static EGLConfig get_egl_config(EGLDisplay display)
  46. {
  47. EGLint const config_attribs[] = {
  48. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  49. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  50. EGL_RED_SIZE, 8,
  51. EGL_GREEN_SIZE, 8,
  52. EGL_BLUE_SIZE, 8,
  53. EGL_ALPHA_SIZE, 8,
  54. EGL_DEPTH_SIZE, 24,
  55. EGL_STENCIL_SIZE, 8,
  56. EGL_NONE
  57. };
  58. EGLint number_of_configs;
  59. eglChooseConfig(display, config_attribs, NULL, 0, &number_of_configs);
  60. Vector<EGLConfig> configs;
  61. configs.resize(number_of_configs);
  62. eglChooseConfig(display, config_attribs, configs.data(), number_of_configs, &number_of_configs);
  63. return configs[0];
  64. }
  65. #endif
  66. OwnPtr<OpenGLContext> OpenGLContext::create(NonnullRefPtr<Gfx::SkiaBackendContext> skia_backend_context)
  67. {
  68. #ifdef AK_OS_MACOS
  69. EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  70. if (display == EGL_NO_DISPLAY) {
  71. dbgln("Failed to get EGL display");
  72. return {};
  73. }
  74. EGLint major, minor;
  75. if (!eglInitialize(display, &major, &minor)) {
  76. dbgln("Failed to initialize EGL");
  77. return {};
  78. }
  79. auto* config = get_egl_config(display);
  80. EGLint context_attributes[] = {
  81. EGL_CONTEXT_CLIENT_VERSION, 2,
  82. EGL_NONE
  83. };
  84. EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
  85. if (context == EGL_NO_CONTEXT) {
  86. dbgln("Failed to create EGL context");
  87. return {};
  88. }
  89. return make<OpenGLContext>(skia_backend_context, Impl { .display = display, .config = config, .context = context });
  90. #else
  91. (void)skia_backend_context;
  92. return nullptr;
  93. #endif
  94. }
  95. void OpenGLContext::notify_content_will_change()
  96. {
  97. m_painting_surface->notify_content_will_change();
  98. }
  99. void OpenGLContext::clear_buffer_to_default_values()
  100. {
  101. }
  102. void OpenGLContext::allocate_painting_surface_if_needed()
  103. {
  104. #ifdef AK_OS_MACOS
  105. if (m_painting_surface)
  106. return;
  107. VERIFY(!m_size.is_empty());
  108. auto iosurface = Core::IOSurfaceHandle::create(m_size.width(), m_size.height());
  109. m_painting_surface = Gfx::PaintingSurface::wrap_iosurface(iosurface, m_skia_backend_context);
  110. m_painting_surface->set_flip_vertically();
  111. auto width = m_size.width();
  112. auto height = m_size.height();
  113. auto* display = m_impl->display;
  114. auto* config = m_impl->config;
  115. EGLint target = 0;
  116. eglGetConfigAttrib(display, config, EGL_BIND_TO_TEXTURE_TARGET_ANGLE, &target);
  117. EGLint const surface_attributes[] = {
  118. EGL_WIDTH,
  119. width,
  120. EGL_HEIGHT,
  121. height,
  122. EGL_IOSURFACE_PLANE_ANGLE,
  123. 0,
  124. EGL_TEXTURE_TARGET,
  125. target,
  126. EGL_TEXTURE_INTERNAL_FORMAT_ANGLE,
  127. GL_BGRA_EXT,
  128. EGL_TEXTURE_FORMAT,
  129. EGL_TEXTURE_RGBA,
  130. EGL_TEXTURE_TYPE_ANGLE,
  131. GL_UNSIGNED_BYTE,
  132. EGL_NONE,
  133. EGL_NONE,
  134. };
  135. m_impl->surface = eglCreatePbufferFromClientBuffer(display, EGL_IOSURFACE_ANGLE, iosurface.core_foundation_pointer(), config, surface_attributes);
  136. eglMakeCurrent(m_impl->display, m_impl->surface, m_impl->surface, m_impl->context);
  137. EGLint texture_target_angle = 0;
  138. eglGetConfigAttrib(display, config, EGL_BIND_TO_TEXTURE_TARGET_ANGLE, &texture_target_angle);
  139. VERIFY(texture_target_angle == EGL_TEXTURE_RECTANGLE_ANGLE);
  140. GLuint texture = 0;
  141. glGenTextures(1, &texture);
  142. glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, texture);
  143. auto result = eglBindTexImage(display, m_impl->surface, EGL_BACK_BUFFER);
  144. VERIFY(result == EGL_TRUE);
  145. glGenFramebuffers(1, &m_impl->framebuffer);
  146. glBindFramebuffer(GL_FRAMEBUFFER, m_impl->framebuffer);
  147. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, texture, 0);
  148. // NOTE: ANGLE doesn't allocate depth buffer for us, so we need to do it manually
  149. // FIXME: Depth buffer only needs to be allocated if it's configured in WebGL context attributes
  150. glGenRenderbuffers(1, &m_impl->depth_buffer);
  151. glBindRenderbuffer(GL_RENDERBUFFER, m_impl->depth_buffer);
  152. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
  153. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_impl->depth_buffer);
  154. #endif
  155. }
  156. void OpenGLContext::set_size(Gfx::IntSize const& size)
  157. {
  158. if (m_size != size) {
  159. m_painting_surface = nullptr;
  160. }
  161. m_size = size;
  162. }
  163. void OpenGLContext::make_current()
  164. {
  165. #ifdef AK_OS_MACOS
  166. allocate_painting_surface_if_needed();
  167. eglMakeCurrent(m_impl->display, m_impl->surface, m_impl->surface, m_impl->context);
  168. #endif
  169. }
  170. RefPtr<Gfx::PaintingSurface> OpenGLContext::surface()
  171. {
  172. return m_painting_surface;
  173. }
  174. }