Flutter Engine
 
Loading...
Searching...
No Matches
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.
 
 ~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.
 
 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.
 
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.
 
AutoTrampolineContext MakeCurrentContext () const
 Make the EGL context associated with this trampoline current on the calling thread.
 

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}
#define FML_CHECK(condition)
Definition logging.h:104
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, FML_CHECK, 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.

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/flutter/blob/master/docs/engine/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}
#define FML_DCHECK(condition)
Definition logging.h:122
static UniqueEGLImageKHR CreateEGLImageFromAHBTexture(const EGLDisplay &display, const AHBTextureSourceVK &to_texture)
TPoint< Scalar > Point
Definition point.h:327
#define TRACE_EVENT0(category_group, name)

References impeller::glvk::CreateEGLImageFromAHBTexture(), FML_CHECK, FML_DCHECK, impeller::TextureSourceVK::GetTextureDescriptor(), impeller::glvk::kAttributeIndexPosition, impeller::glvk::kAttributeIndexTexCoord, impeller::TextureDescriptor::size, impeller::glvk::Trampoline::GLTextureInfo::target, impeller::glvk::Trampoline::GLTextureInfo::texture, TRACE_EVENT0, 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

References FML_DCHECK.

Referenced by ~Trampoline().

◆ operator=()

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

Friends And Related Symbol 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: