Flutter Impeller
impeller::glvk::Trampoline Class Reference

An object used to interoperate between OpenGL and Vulkan. More...

#include <trampoline.h>

Classes

struct  GLTextureInfo
 Describes an OpenGL texture along with information on how to sample from it. More...
 

Public Member Functions

 Trampoline ()
 Constructs a new trampoline. It is recommended that these objects be cached and reused for all conversion operations. More...
 
 ~Trampoline ()
 Destroys the trampoline. There are no threading restrictions. EGL contexts on already bound to the callers thread may become unbound after a call to this method. More...
 
 Trampoline (const Trampoline &)=delete
 
Trampolineoperator= (const Trampoline &)=delete
 
bool IsValid () const
 Determines if this is a valid trampoline. There is no error recovery mechanism if a trampoline cannot be constructed and an invalid trampoline must be immediately discarded. More...
 
bool BlitTextureOpenGLToVulkan (const GLTextureInfo &src_texture, const AHBTextureSourceVK &dst_texture) const
 Perform a blit operation from the source OpenGL texture to a target Vulkan texture. More...
 
AutoTrampolineContext MakeCurrentContext () const
 Make the EGL context associated with this trampoline current on the calling thread. More...
 

Friends

class AutoTrampolineContext
 

Detailed Description

An object used to interoperate between OpenGL and Vulkan.

        While these are not super expensive to create, they do manage an
        internal EGL context as well as some OpenGL state. For this
        reason, it is recommended that callers cache these for the
        duration of the lifecycle of main rendering context.

Definition at line 27 of file trampoline.h.

Constructor & Destructor Documentation

◆ Trampoline() [1/2]

impeller::glvk::Trampoline::Trampoline ( )

Constructs a new trampoline. It is recommended that these objects be cached and reused for all conversion operations.

EGL contexts on already bound to the callers thread may become unbound after a call to this method.

Definition at line 57 of file trampoline.cc.

57  {
58  auto egl_display = std::make_unique<egl::Display>();
59  if (!egl_display->IsValid()) {
61  << "Could not create EGL display for external texture interop.";
62  return;
63  }
64 
65  egl::ConfigDescriptor egl_config_desc;
66  egl_config_desc.api = egl::API::kOpenGLES2;
67  egl_config_desc.samples = egl::Samples::kOne;
68  egl_config_desc.color_format = egl::ColorFormat::kRGBA8888;
69  egl_config_desc.stencil_bits = egl::StencilBits::kZero;
70  egl_config_desc.depth_bits = egl::DepthBits::kZero;
71  egl_config_desc.surface_type = egl::SurfaceType::kPBuffer;
72  auto egl_config = egl_display->ChooseConfig(egl_config_desc);
73  if (!egl_config) {
75  << "Could not choose EGL config for external texture interop.";
76  return;
77  }
78 
79  auto egl_surface = egl_display->CreatePixelBufferSurface(*egl_config, 1u, 1u);
80  auto egl_context = egl_display->CreateContext(*egl_config, nullptr);
81 
82  if (!egl_surface || !egl_context) {
83  VALIDATION_LOG << "Could not create EGL surface and/or context for "
84  "external texture interop.";
85  return;
86  }
87 
88  // Make the context current so the proc addresses can be resolved.
89  if (!egl_context->MakeCurrent(*egl_surface)) {
90  VALIDATION_LOG << "Could not make the context current.";
91  return;
92  }
93 
94  auto gl = std::make_unique<ProcTable>(egl::CreateProcAddressResolver());
95 
96  if (!gl->IsValid()) {
97  egl_context->ClearCurrent();
98  VALIDATION_LOG << "Could not setup trampoline proc table.";
99  return;
100  }
101 
102  // Generate program object.
103  auto vert_shader = gl->CreateShader(GL_VERTEX_SHADER);
104  auto frag_shader = gl->CreateShader(GL_FRAGMENT_SHADER);
105 
106  GLint vert_shader_size = strlen(kVertShader);
107  GLint frag_shader_size = strlen(kFragShader);
108 
109  gl->ShaderSource(vert_shader, 1u, &kVertShader, &vert_shader_size);
110  gl->ShaderSource(frag_shader, 1u, &kFragShader, &frag_shader_size);
111 
112  gl->CompileShader(vert_shader);
113  gl->CompileShader(frag_shader);
114 
115  GLint vert_status = GL_FALSE;
116  GLint frag_status = GL_FALSE;
117 
118  gl->GetShaderiv(vert_shader, GL_COMPILE_STATUS, &vert_status);
119  gl->GetShaderiv(frag_shader, GL_COMPILE_STATUS, &frag_status);
120 
121  FML_CHECK(vert_status == GL_TRUE);
122  FML_CHECK(frag_status == GL_TRUE);
123 
124  program_ = gl->CreateProgram();
125  gl->AttachShader(program_, vert_shader);
126  gl->AttachShader(program_, frag_shader);
127 
128  gl->BindAttribLocation(program_, kAttributeIndexPosition, "aPosition");
129  gl->BindAttribLocation(program_, kAttributeIndexTexCoord, "aTexCoord");
130 
131  gl->LinkProgram(program_);
132 
133  GLint link_status = GL_FALSE;
134  gl->GetProgramiv(program_, GL_LINK_STATUS, &link_status);
135  FML_CHECK(link_status == GL_TRUE);
136 
137  texture_uniform_location_ = gl->GetUniformLocation(program_, "uTexture");
138  uv_transformation_location_ =
139  gl->GetUniformLocation(program_, "uUVTransformation");
140 
141  gl->DeleteShader(vert_shader);
142  gl->DeleteShader(frag_shader);
143 
144  egl_context->ClearCurrent();
145 
146  gl_ = std::move(gl);
147  egl_display_ = std::move(egl_display);
148  egl_context_ = std::move(egl_context);
149  egl_surface_ = std::move(egl_surface);
150  is_valid_ = true;
151 }
std::function< void *(const char *)> CreateProcAddressResolver()
Creates a proc address resolver that resolves function pointers to EGL and OpenGL (ES) procs.
Definition: egl.cc:12
static GLuint kAttributeIndexTexCoord
Definition: trampoline.cc:21
static GLuint kAttributeIndexPosition
Definition: trampoline.cc:20
static constexpr const char * kFragShader
Definition: trampoline.cc:39
static constexpr const char * kVertShader
Definition: trampoline.cc:23
#define VALIDATION_LOG
Definition: validation.h:91

References impeller::egl::ConfigDescriptor::api, impeller::egl::ConfigDescriptor::color_format, impeller::egl::CreateProcAddressResolver(), impeller::egl::ConfigDescriptor::depth_bits, impeller::glvk::kAttributeIndexPosition, impeller::glvk::kAttributeIndexTexCoord, impeller::glvk::kFragShader, impeller::egl::kOne, impeller::egl::kOpenGLES2, impeller::egl::kPBuffer, impeller::egl::kRGBA8888, impeller::glvk::kVertShader, impeller::egl::kZero, impeller::egl::ConfigDescriptor::samples, impeller::egl::ConfigDescriptor::stencil_bits, impeller::egl::ConfigDescriptor::surface_type, and VALIDATION_LOG.

◆ ~Trampoline()

impeller::glvk::Trampoline::~Trampoline ( )

Destroys the trampoline. There are no threading restrictions. EGL contexts on already bound to the callers thread may become unbound after a call to this method.

Definition at line 153 of file trampoline.cc.

153  {
154  if (!is_valid_) {
155  return;
156  }
157  auto context = MakeCurrentContext();
158  gl_->DeleteProgram(program_);
159 }
AutoTrampolineContext MakeCurrentContext() const
Make the EGL context associated with this trampoline current on the calling thread.
Definition: trampoline.cc:313

References MakeCurrentContext().

◆ Trampoline() [2/2]

impeller::glvk::Trampoline::Trampoline ( const Trampoline )
delete

Member Function Documentation

◆ BlitTextureOpenGLToVulkan()

bool impeller::glvk::Trampoline::BlitTextureOpenGLToVulkan ( const GLTextureInfo src_texture,
const AHBTextureSourceVK dst_texture 
) const

Perform a blit operation from the source OpenGL texture to a target Vulkan texture.

It is the callers responsibility to ensure that the EGL context associated with the trampoline is already current before making this call.

It is also the responsibility of the caller to ensure that the destination texture is the color-attachment-optimal layout. Failure to ensure this will lead to validation error.

See also
MakeCurrentContext
Parameters
[in]src_textureThe source OpenGL texture.
[in]dst_textureThe destination Vulkan texture.
Returns
True if the blit was successful, False otherwise.

Definition at line 197 of file trampoline.cc.

199  {
200  TRACE_EVENT0("impeller", __FUNCTION__);
201  if (!is_valid_) {
202  return false;
203  }
204 
205  FML_DCHECK(egl_context_->IsCurrent());
206 
207  auto dst_egl_image =
208  CreateEGLImageFromAHBTexture(egl_display_->GetHandle(), dst_texture);
209  if (!dst_egl_image.is_valid()) {
210  VALIDATION_LOG << "Could not create EGL image from AHB texture.";
211  return false;
212  }
213 
214  const auto& gl = *gl_;
215 
216  GLuint dst_gl_texture = GL_NONE;
217  gl.GenTextures(1u, &dst_gl_texture);
218  gl.BindTexture(GL_TEXTURE_2D, dst_gl_texture);
219  gl.EGLImageTargetTexture2DOES(GL_TEXTURE_2D, dst_egl_image.get().image);
220 
221  GLuint offscreen_fbo = GL_NONE;
222  gl.GenFramebuffers(1u, &offscreen_fbo);
223  gl.BindFramebuffer(GL_FRAMEBUFFER, offscreen_fbo);
224  gl.FramebufferTexture2D(GL_FRAMEBUFFER, //
225  GL_COLOR_ATTACHMENT0, //
226  GL_TEXTURE_2D, //
227  dst_gl_texture, //
228  0 //
229  );
230 
231  FML_CHECK(gl.CheckFramebufferStatus(GL_FRAMEBUFFER) ==
232  GL_FRAMEBUFFER_COMPLETE);
233 
234  gl.Disable(GL_BLEND);
235  gl.Disable(GL_SCISSOR_TEST);
236  gl.Disable(GL_DITHER);
237  gl.Disable(GL_CULL_FACE);
238  gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
239 
240  gl.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
241  gl.Clear(GL_COLOR_BUFFER_BIT);
242 
243  const auto& fb_size = dst_texture.GetTextureDescriptor().size;
244  gl.Viewport(0, 0, fb_size.width, fb_size.height);
245 
246  gl.UseProgram(program_);
247 
248  struct VertexData {
249  Point position;
250  Point tex_coord;
251  };
252 
253  // The vertex coordinates assume OpenGL NDC because that's the API we are
254  // using to draw the quad. But the texture will be sampled in Vulkan so the
255  // texture coordinate system assumes Vulkan convention.
256  //
257  // See the following help link for an overview of the different coordinate
258  // systems:
259  // https://github.com/flutter/engine/blob/5810b3fc791f4bb82b9a454014310990eddc1181/impeller/docs/coordinate_system.md
260  static constexpr const VertexData kVertData[] = {
261  {{-1, -1}, {0, 1}}, // bottom left
262  {{-1, +1}, {0, 0}}, // top left
263  {{+1, +1}, {1, 0}}, // top right
264  {{+1, -1}, {1, 1}}, // bottom right
265  };
266 
267  // This is tedious but we assume no vertex array objects (VAO) are available
268  // because of ES 2 versioning constraints.
269  GLuint vertex_buffer = GL_NONE;
270  gl.GenBuffers(1u, &vertex_buffer);
271  gl.BindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
272  gl.BufferData(GL_ARRAY_BUFFER, sizeof(kVertData), kVertData, GL_STATIC_DRAW);
273  gl.EnableVertexAttribArray(kAttributeIndexPosition);
274  gl.EnableVertexAttribArray(kAttributeIndexTexCoord);
275  gl.VertexAttribPointer(
276  kAttributeIndexPosition, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData),
277  reinterpret_cast<void*>(offsetof(VertexData, position)));
278  gl.VertexAttribPointer(
279  kAttributeIndexTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData),
280  reinterpret_cast<void*>(offsetof(VertexData, tex_coord)));
281 
282  gl.ActiveTexture(GL_TEXTURE0);
283  gl.BindTexture(src_texture.target, src_texture.texture);
284  gl.TexParameteri(src_texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
285  gl.TexParameteri(src_texture.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
286  gl.TexParameteri(src_texture.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
287  gl.TexParameteri(src_texture.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
288  gl.Uniform1i(texture_uniform_location_, 0u);
289 
290  auto gl_uv_transformation = src_texture.uv_transformation;
291 
292  gl.UniformMatrix4fv(uv_transformation_location_, 1u, GL_FALSE,
293  reinterpret_cast<GLfloat*>(&gl_uv_transformation));
294 
295  gl.DrawArrays(GL_TRIANGLE_FAN, 0, 4);
296 
297  gl.UseProgram(GL_NONE);
298 
299  gl.Flush();
300 
301  gl.DeleteFramebuffers(1u, &offscreen_fbo);
302  gl.DeleteTextures(1u, &dst_gl_texture);
303  gl.DeleteBuffers(1u, &vertex_buffer);
304 
305  // Theoretically, this does nothing because the surface is a 1x1 pbuffer
306  // surface. But frame capture tools use this to denote a frame boundary in
307  // OpenGL. So add this as a debugging aid anyway.
308  eglSwapBuffers(egl_display_->GetHandle(), egl_surface_->GetHandle());
309 
310  return true;
311 }
static UniqueEGLImageKHR CreateEGLImageFromAHBTexture(const EGLDisplay &display, const AHBTextureSourceVK &to_texture)
Definition: trampoline.cc:165
TPoint< Scalar > Point
Definition: point.h:327

References impeller::glvk::CreateEGLImageFromAHBTexture(), impeller::TextureSourceVK::GetTextureDescriptor(), impeller::glvk::kAttributeIndexPosition, impeller::glvk::kAttributeIndexTexCoord, impeller::TextureDescriptor::size, impeller::glvk::Trampoline::GLTextureInfo::target, impeller::glvk::Trampoline::GLTextureInfo::texture, impeller::glvk::Trampoline::GLTextureInfo::uv_transformation, and VALIDATION_LOG.

◆ IsValid()

bool impeller::glvk::Trampoline::IsValid ( ) const

Determines if this is a valid trampoline. There is no error recovery mechanism if a trampoline cannot be constructed and an invalid trampoline must be immediately discarded.

Returns
True if valid, False otherwise.

Definition at line 161 of file trampoline.cc.

161  {
162  return is_valid_;
163 }

◆ MakeCurrentContext()

AutoTrampolineContext impeller::glvk::Trampoline::MakeCurrentContext ( ) const

Make the EGL context associated with this trampoline current on the calling thread.

Returns
The automatic trampoline context. The collection of this context clears the threads EGL binding.

Definition at line 313 of file trampoline.cc.

313  {
314  FML_DCHECK(is_valid_);
315  return AutoTrampolineContext{*this};
316 }
friend class AutoTrampolineContext
Definition: trampoline.h:111

Referenced by ~Trampoline().

◆ operator=()

Trampoline& impeller::glvk::Trampoline::operator= ( const Trampoline )
delete

Friends And Related Function Documentation

◆ AutoTrampolineContext

friend class AutoTrampolineContext
friend

Definition at line 111 of file trampoline.h.


The documentation for this class was generated from the following files: