| Flutter Impeller |

Classes | Public Member Functions | Friends | List of all members
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
Trampoline & | operator= (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()) {
60 VALIDATION_LOG
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) {
74 VALIDATION_LOG
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 }

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 }

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_texture | The source OpenGL texture.
  [in] | dst_texture | The 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(kAttributeIndexPosition, 2, GL_FLOAT, GL_FALSE,
276 sizeof(VertexData),
277 (void*)offsetof(VertexData, position));
278 gl.VertexAttribPointer(kAttributeIndexTexCoord, 2, GL_FLOAT, GL_FALSE,
279 sizeof(VertexData),
280 (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 }

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 }

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:

- impeller/toolkit/glvk/trampoline.h
- impeller/toolkit/glvk/trampoline.cc

impeller::egl::Samples::kOne
@ kOne
impeller::glvk::Trampoline::MakeCurrentContext
AutoTrampolineContext MakeCurrentContext() const
Make the EGL context associated with this trampoline current on the calling thread.
Definition: trampoline.cc:313
impeller::glvk::kAttributeIndexTexCoord
static GLuint kAttributeIndexTexCoord
Definition: trampoline.cc:21
impeller::glvk::kAttributeIndexPosition
static GLuint kAttributeIndexPosition
Definition: trampoline.cc:20
impeller::glvk::Trampoline::AutoTrampolineContext
friend class AutoTrampolineContext
Definition: trampoline.h:111
impeller::egl::DepthBits::kZero
@ kZero
impeller::egl::StencilBits::kZero
@ kZero
impeller::egl::CreateProcAddressResolver
std::function< void *(const char *)> CreateProcAddressResolver()
Creates a proc address resolver that resolves function pointers to EGL and OpenGL (ES) procs.
Definition: egl.h:23
impeller::glvk::kFragShader
static constexpr const char * kFragShader
Definition: trampoline.cc:39
impeller::egl::API::kOpenGLES2
@ kOpenGLES2
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::glvk::kVertShader
static constexpr const char * kVertShader
Definition: trampoline.cc:23
impeller::glvk::CreateEGLImageFromAHBTexture
static UniqueEGLImageKHR CreateEGLImageFromAHBTexture(const EGLDisplay &display, const AHBTextureSourceVK &to_texture)
Definition: trampoline.cc:165
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91
impeller::egl::ColorFormat::kRGBA8888
@ kRGBA8888
impeller::egl::SurfaceType::kPBuffer
@ kPBuffer