Flutter Engine
 
Loading...
Searching...
No Matches
trampoline.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <array>
8
17
18namespace impeller::glvk {
19
20static GLuint kAttributeIndexPosition = 0u;
21static GLuint kAttributeIndexTexCoord = 1u;
22
23static constexpr const char* kVertShader = R"IMPELLER_SHADER(#version 100
24
25precision mediump float;
26
27attribute vec2 aPosition;
28attribute vec2 aTexCoord;
29
30varying vec2 vTexCoord;
31
32void main() {
33 gl_Position = vec4(aPosition, 0.0, 1.0);
34 vTexCoord = aTexCoord;
35
36}
37)IMPELLER_SHADER";
38
39static constexpr const char* kFragShader = R"IMPELLER_SHADER(#version 100
40
41#extension GL_OES_EGL_image_external : require
42
43precision mediump float;
44
45uniform samplerExternalOES uTexture;
46uniform mat4 uUVTransformation;
47
48varying vec2 vTexCoord;
49
50void main() {
51 vec2 texture_coords = (uUVTransformation * vec4(vTexCoord, 0, 1)).xy;
52 gl_FragColor = texture2D(uTexture, texture_coords);
53}
54
55)IMPELLER_SHADER";
56
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;
69 egl_config_desc.stencil_bits = egl::StencilBits::kZero;
70 egl_config_desc.depth_bits = egl::DepthBits::kZero;
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}
152
154 if (!is_valid_) {
155 return;
156 }
157 auto context = MakeCurrentContext();
158 gl_->DeleteProgram(program_);
159}
160
162 return is_valid_;
163}
164
166 const EGLDisplay& display,
167 const AHBTextureSourceVK& to_texture) {
168 if (!android::GetProcTable().eglGetNativeClientBufferANDROID.IsAvailable()) {
169 VALIDATION_LOG << "Could not get native client buffer.";
170 return {};
171 }
172
173 EGLClientBuffer client_buffer =
174 android::GetProcTable().eglGetNativeClientBufferANDROID(
175 to_texture.GetBackingStore()->GetHandle());
176
177 if (!client_buffer) {
179 << "Could not get client buffer from Android hardware buffer.";
180 return {};
181 }
182
183 auto image = ::eglCreateImageKHR(display, //
184 EGL_NO_CONTEXT, //
185 EGL_NATIVE_BUFFER_ANDROID, //
186 client_buffer, //
187 nullptr //
188 );
189 if (image == NULL) {
190 VALIDATION_LOG << "Could not create EGL Image.";
191 return {};
192 }
193
195}
196
198 const GLTextureInfo& src_texture,
199 const AHBTextureSourceVK& dst_texture) const {
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}
312
317
319 : context_(trampoline.egl_context_.get()),
320 surface_(trampoline.egl_surface_.get()) {
321 if (!context_->IsCurrent() && !context_->MakeCurrent(*surface_)) {
322 VALIDATION_LOG << "Could not make context current.";
323 }
324};
325
327 if (!context_->ClearCurrent()) {
328 VALIDATION_LOG << "Could not clear current context.";
329 }
330}
331
332} // namespace impeller::glvk
A texture source that wraps an instance of AHardwareBuffer.
const android::HardwareBuffer * GetBackingStore() const
const TextureDescriptor & GetTextureDescriptor() const
Gets the texture descriptor for this image source.
AHardwareBuffer * GetHandle() const
bool IsCurrent() const
Definition context.cc:102
bool MakeCurrent(const Surface &surface) const
Make the context current on the calling thread. It is the caller responsibility to ensure that any co...
Definition context.cc:45
bool ClearCurrent() const
Clear the thread association of this context.
Definition context.cc:61
An RAII object that makes the trampolines EGL context current when constructed and clears the EGL bin...
Definition trampoline.h:127
~AutoTrampolineContext()
Destroys the object and clears the previous EGL binding.
AutoTrampolineContext(const Trampoline &trampoline)
Constructs a new instance and makes the trampolines EGL context current on the calling thread.
An object used to interoperate between OpenGL and Vulkan.
Definition trampoline.h:27
~Trampoline()
Destroys the trampoline. There are no threading restrictions. EGL contexts on already bound to the ca...
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.
bool IsValid() const
Determines if this is a valid trampoline. There is no error recovery mechanism if a trampoline cannot...
AutoTrampolineContext MakeCurrentContext() const
Make the EGL context associated with this trampoline current on the calling thread.
Trampoline()
Constructs a new trampoline. It is recommended that these objects be cached and reused for all conver...
Definition trampoline.cc:57
FlutterVulkanImage * image
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
EGLSurface surface_
const ProcTable & GetProcTable()
Definition proc_table.cc:12
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 UniqueEGLImageKHR CreateEGLImageFromAHBTexture(const EGLDisplay &display, const AHBTextureSourceVK &to_texture)
static constexpr const char * kFragShader
Definition trampoline.cc:39
static constexpr const char * kVertShader
Definition trampoline.cc:23
fml::UniqueObject< EGLImageKHRWithDisplay, EGLImageKHRWithDisplayTraits > UniqueEGLImageKHR
Definition image.h:62
Describes an OpenGL texture along with information on how to sample from it.
Definition trampoline.h:62
#define TRACE_EVENT0(category_group, name)
#define VALIDATION_LOG
Definition validation.h:91