e3e057b64023412da1346f046355af2b9309ab7c
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / graphics / emugl / Renderer.cpp
1 /*
2 * Copyright (C) 2011-2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define GLM_ENABLE_EXPERIMENTAL
17 #include "anbox/graphics/emugl/Renderer.h"
18 #include "anbox/graphics/emugl/DispatchTables.h"
19 #include "anbox/graphics/emugl/RenderThreadInfo.h"
20 #include "anbox/graphics/emugl/TimeUtils.h"
21 #include "anbox/graphics/gl_extensions.h"
22 #include "anbox/logger.h"
23
24 #include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
25
26 // Generated with emugl at build time
27 #include "gles2_dec.h"
28
29 #include <stdio.h>
30
31 #include <glm/glm.hpp>
32 #include <glm/gtc/type_ptr.hpp>
33 #include <glm/gtx/transform.hpp>
34
35 namespace {
36
37 // Helper class to call the bind_locked() / unbind_locked() properly.
38 class ScopedBind {
39  public:
40   // Constructor will call bind_locked() on |fb|.
41   // Use isValid() to check for errors.
42   ScopedBind(Renderer *fb) : mFb(fb) {
43     if (!fb->bind_locked()) {
44       mFb = NULL;
45     }
46   }
47
48   // Returns true if contruction bound the framebuffer context properly.
49   bool isValid() const { return mFb != NULL; }
50
51   // Unbound the framebuffer explictly. This is also called by the
52   // destructor.
53   void release() {
54     if (mFb) {
55       mFb->unbind_locked();
56       mFb = NULL;
57     }
58   }
59
60   // Destructor will call release().
61   ~ScopedBind() { release(); }
62
63  private:
64   Renderer *mFb;
65 };
66
67 // Implementation of a ColorBuffer::Helper instance that redirects calls
68 // to a FrameBuffer instance.
69 class ColorBufferHelper : public ColorBuffer::Helper {
70  public:
71   ColorBufferHelper(Renderer *fb) : mFb(fb) {}
72
73   virtual bool setupContext() { return mFb->bind_locked(); }
74
75   virtual void teardownContext() { mFb->unbind_locked(); }
76
77   virtual TextureDraw *getTextureDraw() const { return mFb->getTextureDraw(); }
78
79  private:
80   Renderer *mFb;
81 };
82 }  // namespace
83
84 HandleType Renderer::s_nextHandle = 0;
85
86 void Renderer::finalize() {
87   m_colorbuffers.clear();
88   m_windows.clear();
89   m_contexts.clear();
90   s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL);
91   s_egl.eglDestroyContext(m_eglDisplay, m_eglContext);
92   s_egl.eglDestroyContext(m_eglDisplay, m_pbufContext);
93   s_egl.eglDestroySurface(m_eglDisplay, m_pbufSurface);
94 }
95
96 bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) {
97   m_eglDisplay = s_egl.eglGetDisplay(nativeDisplay);
98   if (m_eglDisplay == EGL_NO_DISPLAY) {
99     ERROR("Failed to Initialize backend EGL display");
100     return false;
101   }
102
103   if (!s_egl.eglInitialize(m_eglDisplay, &m_caps.eglMajor, &m_caps.eglMinor)) {
104     ERROR("Failed to initialize EGL");
105     return false;
106   }
107
108   anbox::graphics::GLExtensions egl_extensions{s_egl.eglQueryString(m_eglDisplay, EGL_EXTENSIONS)};
109
110   const auto surfaceless_supported = egl_extensions.support("EGL_KHR_surfaceless_context");
111   if (!surfaceless_supported)
112     DEBUG("EGL doesn't support surfaceless context");
113
114   s_egl.eglBindAPI(EGL_OPENGL_ES_API);
115
116   // Create EGL context for framebuffer post rendering.
117   GLint surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
118   const GLint configAttribs[] = {EGL_RED_SIZE, 8,
119                                  EGL_GREEN_SIZE, 8,
120                                  EGL_BLUE_SIZE, 8,
121                                  EGL_SURFACE_TYPE, surfaceType,
122                                  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
123                                  EGL_NONE};
124
125   int n;
126   if ((s_egl.eglChooseConfig(m_eglDisplay, configAttribs, &m_eglConfig,
127                              1, &n) == EGL_FALSE) || n == 0) {
128     ERROR("Failed to select EGL configuration");
129     return false;
130   }
131
132   static const GLint glContextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
133                                            EGL_NONE};
134
135   m_eglContext = s_egl.eglCreateContext(m_eglDisplay, m_eglConfig,
136                                         EGL_NO_CONTEXT, glContextAttribs);
137   if (m_eglContext == EGL_NO_CONTEXT) {
138     ERROR("Failed to create context: error=0x%x", s_egl.eglGetError());
139     return false;
140   }
141
142   // Create another context which shares with the eglContext to be used
143   // when we bind the pbuffer. That prevent switching drawable binding
144   // back and forth on framebuffer context.
145   // The main purpose of it is to solve a "blanking" behaviour we see on
146   // on Mac platform when switching binded drawable for a context however
147   // it is more efficient on other platforms as well.
148   m_pbufContext = s_egl.eglCreateContext(m_eglDisplay, m_eglConfig, m_eglContext, glContextAttribs);
149   if (m_pbufContext == EGL_NO_CONTEXT) {
150     ERROR("Failed to create pbuffer context: error=0x%x", s_egl.eglGetError());
151     return false;
152   }
153
154   if (!surfaceless_supported) {
155     // Create a 1x1 pbuffer surface which will be used for binding
156     // the FB context. The FB output will go to a subwindow, if one exist.
157     static const EGLint pbufAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
158
159     m_pbufSurface = s_egl.eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pbufAttribs);
160     if (m_pbufSurface == EGL_NO_SURFACE) {
161       ERROR("Failed to create pbuffer surface: error=0x%x", s_egl.eglGetError());
162       return false;
163     }
164   } else {
165     DEBUG("Using a surfaceless EGL context");
166     m_pbufSurface = EGL_NO_SURFACE;
167   }
168
169   // Make the context current
170   ScopedBind bind(this);
171   if (!bind.isValid()) {
172     ERROR("Failed to make current");
173     return false;
174   }
175
176   anbox::graphics::GLExtensions gl_extensions{reinterpret_cast<const char *>(s_gles2.glGetString(GL_EXTENSIONS))};
177   if (gl_extensions.support("GL_OES_EGL_image")) {
178     m_caps.has_eglimage_texture_2d = egl_extensions.support("EGL_KHR_gl_texture_2D_image");
179     m_caps.has_eglimage_renderbuffer = egl_extensions.support("EGL_KHR_gl_renderbuffer_image");
180   } else {
181     m_caps.has_eglimage_texture_2d = false;
182     m_caps.has_eglimage_renderbuffer = false;
183   }
184
185   // Fail initialization if not all of the following extensions
186   // exist:
187   //     EGL_KHR_gl_texture_2d_image
188   //     GL_OES_EGL_IMAGE
189   if (!m_caps.has_eglimage_texture_2d) {
190     ERROR("Failed: Missing egl_image related extension(s)");
191     bind.release();
192     return false;
193   }
194
195   // Initialize set of configs
196   m_configs = new RendererConfigList(m_eglDisplay);
197   if (m_configs->empty()) {
198     ERROR("Failed: Initialize set of configs");
199     bind.release();
200     return false;
201   }
202
203   // Check that we have config for each GLES and GLES2
204   size_t nConfigs = m_configs->size();
205   int nGLConfigs = 0;
206   int nGL2Configs = 0;
207   for (size_t i = 0; i < nConfigs; ++i) {
208     GLint rtype = m_configs->get(i)->getRenderableType();
209     if (0 != (rtype & EGL_OPENGL_ES_BIT)) {
210       nGLConfigs++;
211     }
212     if (0 != (rtype & EGL_OPENGL_ES2_BIT)) {
213       nGL2Configs++;
214     }
215   }
216
217   // Fail initialization if no GLES configs exist
218   if (nGLConfigs == 0) {
219     bind.release();
220     return false;
221   }
222
223   // If no GLES2 configs exist - not GLES2 capability
224   if (nGL2Configs == 0) {
225     ERROR("Failed: No GLES 2.x configs found!");
226     bind.release();
227     return false;
228   }
229
230   // Cache the GL strings so we don't have to think about threading or
231   // current-context when asked for them.
232   m_glVendor = reinterpret_cast<const char *>(s_gles2.glGetString(GL_VENDOR));
233   m_glRenderer = reinterpret_cast<const char *>(s_gles2.glGetString(GL_RENDERER));
234   m_glVersion = reinterpret_cast<const char *>(s_gles2.glGetString(GL_VERSION));
235
236   m_textureDraw = new TextureDraw(m_eglDisplay);
237   if (!m_textureDraw) {
238     ERROR("Failed: creation of TextureDraw instance");
239     bind.release();
240     return false;
241   }
242
243   m_defaultProgram = m_family.add_program(vshader, defaultFShader);
244   m_alphaProgram = m_family.add_program(vshader, alphaFShader);
245
246   bind.release();
247
248   DEBUG("Successfully initialized EGL");
249
250   return true;
251 }
252
253 Renderer::Program::Program(GLuint program_id) {
254   id = program_id;
255   position_attr = s_gles2.glGetAttribLocation(id, "position");
256   texcoord_attr = s_gles2.glGetAttribLocation(id, "texcoord");
257   tex_uniform = s_gles2.glGetUniformLocation(id, "tex");
258   center_uniform = s_gles2.glGetUniformLocation(id, "center");
259   display_transform_uniform =
260       s_gles2.glGetUniformLocation(id, "display_transform");
261   transform_uniform = s_gles2.glGetUniformLocation(id, "transform");
262   screen_to_gl_coords_uniform =
263       s_gles2.glGetUniformLocation(id, "screen_to_gl_coords");
264   alpha_uniform = s_gles2.glGetUniformLocation(id, "alpha");
265 }
266
267 Renderer::Renderer()
268     : m_configs(NULL),
269       m_eglDisplay(EGL_NO_DISPLAY),
270       m_colorBufferHelper(new ColorBufferHelper(this)),
271       m_eglContext(EGL_NO_CONTEXT),
272       m_pbufContext(EGL_NO_CONTEXT),
273       m_prevContext(EGL_NO_CONTEXT),
274       m_prevReadSurf(EGL_NO_SURFACE),
275       m_prevDrawSurf(EGL_NO_SURFACE),
276       m_textureDraw(NULL),
277       m_lastPostedColorBuffer(0),
278       m_statsNumFrames(0),
279       m_statsStartTime(0LL),
280       m_glVendor(NULL),
281       m_glRenderer(NULL),
282       m_glVersion(NULL) {
283   m_fpsStats = getenv("SHOW_FPS_STATS") != NULL;
284 }
285
286 Renderer::~Renderer() {
287   delete m_textureDraw;
288   delete m_configs;
289   delete m_colorBufferHelper;
290 }
291
292 struct RendererWindow {
293   EGLNativeWindowType native_window = 0;
294   EGLSurface surface = EGL_NO_SURFACE;
295   anbox::graphics::Rect viewport;
296   glm::mat4 screen_to_gl_coords = glm::mat4(1.0f);
297   glm::mat4 display_transform = glm::mat4(1.0f);
298 };
299
300 RendererWindow *Renderer::createNativeWindow(
301     EGLNativeWindowType native_window) {
302   m_lock.lock();
303
304   auto window = new RendererWindow;
305   window->native_window = native_window;
306   window->surface = s_egl.eglCreateWindowSurface(
307       m_eglDisplay, m_eglConfig, window->native_window, nullptr);
308   if (window->surface == EGL_NO_SURFACE) {
309     delete window;
310     m_lock.unlock();
311     return nullptr;
312   }
313
314   if (!bindWindow_locked(window)) {
315     s_egl.eglDestroySurface(m_eglDisplay, window->surface);
316     delete window;
317     m_lock.unlock();
318     return nullptr;
319   }
320
321   s_gles2.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
322                   GL_STENCIL_BUFFER_BIT);
323   s_egl.eglSwapBuffers(m_eglDisplay, window->surface);
324
325   unbind_locked();
326
327   m_nativeWindows.insert({native_window, window});
328
329   m_lock.unlock();
330
331   return window;
332 }
333
334 void Renderer::destroyNativeWindow(EGLNativeWindowType native_window) {
335   auto w = m_nativeWindows.find(native_window);
336   if (w == m_nativeWindows.end()) return;
337
338   m_lock.lock();
339
340   s_egl.eglMakeCurrent(m_eglDisplay, nullptr, nullptr, nullptr);
341
342   if (w->second->surface != EGL_NO_SURFACE)
343     s_egl.eglDestroySurface(m_eglDisplay, w->second->surface);
344
345   delete w->second;
346   m_nativeWindows.erase(w);
347
348   m_lock.unlock();
349 }
350
351 HandleType Renderer::genHandle() {
352   HandleType id;
353   do {
354     id = ++s_nextHandle;
355   } while (id == 0 || m_contexts.find(id) != m_contexts.end() ||
356            m_windows.find(id) != m_windows.end());
357
358   return id;
359 }
360
361 HandleType Renderer::createColorBuffer(int p_width, int p_height,
362                                        GLenum p_internalFormat) {
363   std::unique_lock<std::mutex> l(m_lock);
364
365   HandleType ret = 0;
366
367   ColorBufferPtr cb(ColorBuffer::create(
368       getDisplay(), p_width, p_height, p_internalFormat,
369       getCaps().has_eglimage_texture_2d, m_colorBufferHelper));
370   if (cb) {
371     ret = genHandle();
372     m_colorbuffers[ret].cb = cb;
373     m_colorbuffers[ret].refcount = 1;
374   }
375   return ret;
376 }
377
378 HandleType Renderer::createRenderContext(int p_config, HandleType p_share,
379                                          bool p_isGL2) {
380   std::unique_lock<std::mutex> l(m_lock);
381
382   HandleType ret = 0;
383
384   const RendererConfig *config = getConfigs()->get(p_config);
385   if (!config) {
386     return ret;
387   }
388
389   RenderContextPtr share(NULL);
390   if (p_share != 0) {
391     RenderContextMap::iterator s(m_contexts.find(p_share));
392     if (s == m_contexts.end()) {
393       return ret;
394     }
395     share = (*s).second;
396   }
397   EGLContext sharedContext =
398       share ? share->getEGLContext() : EGL_NO_CONTEXT;
399
400   RenderContextPtr rctx(RenderContext::create(
401       m_eglDisplay, config->getEglConfig(), sharedContext, p_isGL2));
402   if (rctx) {
403     ret = genHandle();
404     m_contexts[ret] = rctx;
405     RenderThreadInfo *tinfo = RenderThreadInfo::get();
406     tinfo->m_contextSet.insert(ret);
407   }
408   return ret;
409 }
410
411 HandleType Renderer::createWindowSurface(int p_config, int p_width,
412                                          int p_height) {
413   std::unique_lock<std::mutex> l(m_lock);
414
415   HandleType ret = 0;
416
417   const RendererConfig *config = getConfigs()->get(p_config);
418   if (!config) {
419     return ret;
420   }
421
422   WindowSurfacePtr win(WindowSurface::create(
423       getDisplay(), config->getEglConfig(), p_width, p_height));
424   if (win) {
425     ret = genHandle();
426     m_windows[ret] = std::pair<WindowSurfacePtr, HandleType>(win, 0);
427     RenderThreadInfo *tinfo = RenderThreadInfo::get();
428     tinfo->m_windowSet.insert(ret);
429   }
430
431   return ret;
432 }
433
434 void Renderer::drainRenderContext() {
435   std::unique_lock<std::mutex> l(m_lock);
436
437   RenderThreadInfo *tinfo = RenderThreadInfo::get();
438   if (tinfo->m_contextSet.empty()) return;
439   for (std::set<HandleType>::iterator it = tinfo->m_contextSet.begin();
440        it != tinfo->m_contextSet.end(); ++it) {
441     HandleType contextHandle = *it;
442     m_contexts.erase(contextHandle);
443   }
444   tinfo->m_contextSet.clear();
445 }
446
447 void Renderer::drainWindowSurface() {
448   std::unique_lock<std::mutex> l(m_lock);
449
450   RenderThreadInfo *tinfo = RenderThreadInfo::get();
451   if (tinfo->m_windowSet.empty()) return;
452   for (std::set<HandleType>::iterator it = tinfo->m_windowSet.begin();
453        it != tinfo->m_windowSet.end(); ++it) {
454     HandleType windowHandle = *it;
455     if (m_windows.find(windowHandle) != m_windows.end()) {
456       HandleType oldColorBufferHandle = m_windows[windowHandle].second;
457       if (oldColorBufferHandle) {
458         ColorBufferMap::iterator cit(m_colorbuffers.find(oldColorBufferHandle));
459         if (cit != m_colorbuffers.end()) {
460           if (--(*cit).second.refcount == 0) {
461             m_colorbuffers.erase(cit);
462           }
463         }
464       }
465       m_windows.erase(windowHandle);
466     }
467   }
468   tinfo->m_windowSet.clear();
469 }
470
471 void Renderer::DestroyRenderContext(HandleType p_context) {
472   std::unique_lock<std::mutex> l(m_lock);
473
474   m_contexts.erase(p_context);
475   RenderThreadInfo *tinfo = RenderThreadInfo::get();
476   if (tinfo->m_contextSet.empty()) return;
477   tinfo->m_contextSet.erase(p_context);
478 }
479
480 void Renderer::DestroyWindowSurface(HandleType p_surface) {
481   std::unique_lock<std::mutex> l(m_lock);
482
483   if (m_windows.find(p_surface) != m_windows.end()) {
484     m_windows.erase(p_surface);
485     RenderThreadInfo *tinfo = RenderThreadInfo::get();
486     if (tinfo->m_windowSet.empty()) return;
487     tinfo->m_windowSet.erase(p_surface);
488   }
489 }
490
491 int Renderer::openColorBuffer(HandleType p_colorbuffer) {
492   std::unique_lock<std::mutex> l(m_lock);
493
494   ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
495   if (c == m_colorbuffers.end()) {
496     // bad colorbuffer handle
497     ERROR("FB: openColorBuffer cb handle %#x not found", p_colorbuffer);
498     return -1;
499   }
500   (*c).second.refcount++;
501   return 0;
502 }
503
504 void Renderer::closeColorBuffer(HandleType p_colorbuffer) {
505   std::unique_lock<std::mutex> l(m_lock);
506
507   ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
508   if (c == m_colorbuffers.end()) {
509     // This is harmless: it is normal for guest system to issue
510     // closeColorBuffer command when the color buffer is already
511     // garbage collected on the host. (we dont have a mechanism
512     // to give guest a notice yet)
513     return;
514   }
515   if (--(*c).second.refcount == 0) {
516     m_colorbuffers.erase(c);
517   }
518 }
519
520 bool Renderer::flushWindowSurfaceColorBuffer(HandleType p_surface) {
521   std::unique_lock<std::mutex> l(m_lock);
522
523   WindowSurfaceMap::iterator w(m_windows.find(p_surface));
524   if (w == m_windows.end()) {
525     ERROR("FB::flushWindowSurfaceColorBuffer: window handle %#x not found",
526         p_surface);
527     // bad surface handle
528     return false;
529   }
530
531   auto surface = (*w).second.first;
532   if (!surface)
533     return false;
534
535   surface->flushColorBuffer();
536
537   return true;
538 }
539
540 bool Renderer::setWindowSurfaceColorBuffer(HandleType p_surface,
541                                            HandleType p_colorbuffer) {
542   std::unique_lock<std::mutex> l(m_lock);
543
544   WindowSurfaceMap::iterator w(m_windows.find(p_surface));
545   if (w == m_windows.end()) {
546     // bad surface handle
547     ERROR("%s: bad window surface handle %#x", __FUNCTION__, p_surface);
548     return false;
549   }
550
551   ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
552   if (c == m_colorbuffers.end()) {
553     DEBUG("%s: bad color buffer handle %#x", __FUNCTION__, p_colorbuffer);
554     // bad colorbuffer handle
555     return false;
556   }
557
558   (*w).second.first->setColorBuffer((*c).second.cb);
559   (*w).second.second = p_colorbuffer;
560   return true;
561 }
562
563 void Renderer::readColorBuffer(HandleType p_colorbuffer, int x, int y,
564                                int width, int height, GLenum format,
565                                GLenum type, void *pixels) {
566   std::unique_lock<std::mutex> l(m_lock);
567
568   ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
569   if (c == m_colorbuffers.end()) {
570     // bad colorbuffer handle
571     return;
572   }
573
574   (*c).second.cb->readPixels(x, y, width, height, format, type, pixels);
575 }
576
577 bool Renderer::updateColorBuffer(HandleType p_colorbuffer, int x, int y,
578                                  int width, int height, GLenum format,
579                                  GLenum type, void *pixels) {
580   std::unique_lock<std::mutex> l(m_lock);
581
582   ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
583   if (c == m_colorbuffers.end()) {
584     // bad colorbuffer handle
585     return false;
586   }
587
588   (*c).second.cb->subUpdate(x, y, width, height, format, type, pixels);
589
590   return true;
591 }
592
593 bool Renderer::bindColorBufferToTexture(HandleType p_colorbuffer) {
594   std::unique_lock<std::mutex> l(m_lock);
595
596   ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
597   if (c == m_colorbuffers.end()) {
598     // bad colorbuffer handle
599     return false;
600   }
601
602   return (*c).second.cb->bindToTexture();
603 }
604
605 bool Renderer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) {
606   std::unique_lock<std::mutex> l(m_lock);
607
608   ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
609   if (c == m_colorbuffers.end()) {
610     // bad colorbuffer handle
611     return false;
612   }
613
614   return (*c).second.cb->bindToRenderbuffer();
615 }
616
617 bool Renderer::bindContext(HandleType p_context, HandleType p_drawSurface,
618                            HandleType p_readSurface) {
619   std::unique_lock<std::mutex> l(m_lock);
620
621   WindowSurfacePtr draw(NULL), read(NULL);
622   RenderContextPtr ctx(NULL);
623
624   //
625   // if this is not an unbind operation - make sure all handles are good
626   //
627   if (p_context || p_drawSurface || p_readSurface) {
628     RenderContextMap::iterator r(m_contexts.find(p_context));
629     if (r == m_contexts.end()) {
630       // bad context handle
631       return false;
632     }
633
634     ctx = (*r).second;
635     WindowSurfaceMap::iterator w(m_windows.find(p_drawSurface));
636     if (w == m_windows.end()) {
637       // bad surface handle
638       return false;
639     }
640     draw = (*w).second.first;
641
642     if (p_readSurface != p_drawSurface) {
643       WindowSurfaceMap::iterator w(m_windows.find(p_readSurface));
644       if (w == m_windows.end()) {
645         // bad surface handle
646         return false;
647       }
648       read = (*w).second.first;
649     } else {
650       read = draw;
651     }
652   }
653
654   if (!s_egl.eglMakeCurrent(m_eglDisplay,
655                             draw ? draw->getEGLSurface() : EGL_NO_SURFACE,
656                             read ? read->getEGLSurface() : EGL_NO_SURFACE,
657                             ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT)) {
658     ERROR("eglMakeCurrent failed: 0x%04x", s_egl.eglGetError());
659     return false;
660   }
661
662   //
663   // Bind the surface(s) to the context
664   //
665   RenderThreadInfo *tinfo = RenderThreadInfo::get();
666   WindowSurfacePtr bindDraw, bindRead;
667   if (!draw && !read) {
668     // Unbind the current read and draw surfaces from the context
669     bindDraw = tinfo->currDrawSurf;
670     bindRead = tinfo->currReadSurf;
671   } else {
672     bindDraw = draw;
673     bindRead = read;
674   }
675
676   if (bindDraw && bindRead) {
677     if (bindDraw != bindRead) {
678       bindDraw->bind(ctx, WindowSurface::BIND_DRAW);
679       bindRead->bind(ctx, WindowSurface::BIND_READ);
680     } else {
681       bindDraw->bind(ctx, WindowSurface::BIND_READDRAW);
682     }
683   }
684
685   //
686   // update thread info with current bound context
687   //
688   tinfo->currContext = ctx;
689   tinfo->currDrawSurf = draw;
690   tinfo->currReadSurf = read;
691   if (ctx) {
692     if (ctx->isGL2())
693       tinfo->m_gl2Dec.setContextData(&ctx->decoderContextData());
694     else
695       tinfo->m_glDec.setContextData(&ctx->decoderContextData());
696   } else {
697     tinfo->m_glDec.setContextData(NULL);
698     tinfo->m_gl2Dec.setContextData(NULL);
699   }
700   return true;
701 }
702
703 HandleType Renderer::createClientImage(HandleType context, EGLenum target,
704                                        GLuint buffer) {
705   RenderContextPtr ctx(NULL);
706
707   if (context) {
708     RenderContextMap::iterator r(m_contexts.find(context));
709     if (r == m_contexts.end()) {
710       // bad context handle
711       return false;
712     }
713
714     ctx = (*r).second;
715   }
716
717   EGLContext eglContext = ctx ? ctx->getEGLContext() : EGL_NO_CONTEXT;
718   EGLImageKHR image =
719       s_egl.eglCreateImageKHR(m_eglDisplay, eglContext, target,
720                               reinterpret_cast<EGLClientBuffer>(buffer), NULL);
721
722   return static_cast<HandleType>(reinterpret_cast<uintptr_t>(image));
723 }
724
725 EGLBoolean Renderer::destroyClientImage(HandleType image) {
726   return s_egl.eglDestroyImageKHR(m_eglDisplay,
727                                   reinterpret_cast<EGLImageKHR>(image));
728 }
729
730 //
731 // The framebuffer lock should be held when calling this function !
732 //
733 bool Renderer::bind_locked() {
734   EGLContext prevContext = s_egl.eglGetCurrentContext();
735   EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
736   EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
737
738   if (!s_egl.eglMakeCurrent(m_eglDisplay, m_pbufSurface, m_pbufSurface,
739                             m_pbufContext)) {
740     ERROR("eglMakeCurrent failed: 0x%04x", s_egl.eglGetError());
741     return false;
742   }
743
744   m_prevContext = prevContext;
745   m_prevReadSurf = prevReadSurf;
746   m_prevDrawSurf = prevDrawSurf;
747   return true;
748 }
749
750 bool Renderer::bindWindow_locked(RendererWindow *window) {
751   EGLContext prevContext = s_egl.eglGetCurrentContext();
752   EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
753   EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
754
755   if (!s_egl.eglMakeCurrent(m_eglDisplay, window->surface, window->surface,
756                             m_eglContext)) {
757     ERROR("eglMakeCurrent failed");
758     return false;
759   }
760
761   m_prevContext = prevContext;
762   m_prevReadSurf = prevReadSurf;
763   m_prevDrawSurf = prevDrawSurf;
764   return true;
765 }
766
767 bool Renderer::unbind_locked() {
768   if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf, m_prevReadSurf,
769                             m_prevContext)) {
770     return false;
771   }
772
773   m_prevContext = EGL_NO_CONTEXT;
774   m_prevReadSurf = EGL_NO_SURFACE;
775   m_prevDrawSurf = EGL_NO_SURFACE;
776   return true;
777 }
778
779 const GLchar *const Renderer::vshader = {
780     "attribute vec3 position;"
781     "attribute vec2 texcoord;"
782     "uniform mat4 screen_to_gl_coords;"
783     "uniform mat4 display_transform;"
784     "uniform mat4 transform;"
785     "uniform vec2 center;"
786     "varying vec2 v_texcoord;"
787     "void main() {"
788     "   vec4 mid = vec4(center, 0.0, 0.0);"
789     "   vec4 transformed = (transform * (vec4(position, 1.0) - mid)) + mid;"
790     "   gl_Position = display_transform * screen_to_gl_coords * transformed;"
791     "   v_texcoord = texcoord;"
792     "}"};
793
794 const GLchar *const Renderer::alphaFShader = {
795     "precision mediump float;"
796     "uniform sampler2D tex;"
797     "uniform float alpha;"
798     "varying vec2 v_texcoord;"
799     "void main() {"
800     "   vec4 frag = texture2D(tex, v_texcoord);"
801     "   gl_FragColor = alpha*frag;"
802     "}"};
803
804 const GLchar *const Renderer::defaultFShader =
805     {  // This is the fastest fragment shader. Use it when you can.
806         "precision mediump float;"
807         "uniform sampler2D tex;"
808         "varying vec2 v_texcoord;"
809         "void main() {"
810         "   gl_FragColor = texture2D(tex, v_texcoord);"
811         "}"};
812
813 void Renderer::setupViewport(RendererWindow *window,
814                              const anbox::graphics::Rect &rect) {
815   /*
816    * Here we provide a 3D perspective projection with a default 30 degrees
817    * vertical field of view. This projection matrix is carefully designed
818    * such that any vertices at depth z=0 will fit the screen coordinates. So
819    * client texels will fit screen pixels perfectly as long as the surface is
820    * at depth zero. But if you want to do anything fancy, you can also choose
821    * a different depth and it will appear to come out of or go into the
822    * screen.
823    */
824   window->screen_to_gl_coords =
825       glm::translate(glm::mat4(1.0f), glm::vec3{-1.0f, 1.0f, 0.0f});
826
827   /*
828    * Perspective division is one thing that can't be done in a matrix
829    * multiplication. It happens after the matrix multiplications. GL just
830    * scales {x,y} by 1/w. So modify the final part of the projection matrix
831    * to set w ([3]) to be the incoming z coordinate ([2]).
832    */
833   window->screen_to_gl_coords[2][3] = -1.0f;
834
835   float const vertical_fov_degrees = 30.0f;
836   float const near = (rect.height() / 2.0f) /
837                      std::tan((vertical_fov_degrees * M_PI / 180.0f) / 2.0f);
838   float const far = -near;
839
840   window->screen_to_gl_coords =
841       glm::scale(window->screen_to_gl_coords,
842                  glm::vec3{2.0f / rect.width(), -2.0f / rect.height(),
843                            2.0f / (near - far)});
844   window->screen_to_gl_coords = glm::translate(
845       window->screen_to_gl_coords, glm::vec3{-rect.left(), -rect.top(), 0.0f});
846
847   window->viewport = rect;
848 }
849
850 void Renderer::tessellate(std::vector<anbox::graphics::Primitive> &primitives,
851                           const anbox::graphics::Rect &buf_size,
852                           const Renderable &renderable) {
853   auto rect = renderable.screen_position();
854   GLfloat left = rect.left();
855   GLfloat right = rect.right();
856   GLfloat top = rect.top();
857   GLfloat bottom = rect.bottom();
858
859   anbox::graphics::Primitive rectangle;
860   rectangle.tex_id = 0;
861   rectangle.type = GL_TRIANGLE_STRIP;
862
863   GLfloat tex_left =
864       static_cast<GLfloat>(renderable.crop().left()) / buf_size.width();
865   GLfloat tex_top =
866       static_cast<GLfloat>(renderable.crop().top()) / buf_size.height();
867   GLfloat tex_right =
868       static_cast<GLfloat>(renderable.crop().right()) / buf_size.width();
869   GLfloat tex_bottom =
870       static_cast<GLfloat>(renderable.crop().bottom()) / buf_size.height();
871
872   auto &vertices = rectangle.vertices;
873   vertices[0] = {{left, top, 0.0f}, {tex_left, tex_top}};
874   vertices[1] = {{left, bottom, 0.0f}, {tex_left, tex_bottom}};
875   vertices[2] = {{right, top, 0.0f}, {tex_right, tex_top}};
876   vertices[3] = {{right, bottom, 0.0f}, {tex_right, tex_bottom}};
877
878   primitives.resize(1);
879   primitives[0] = rectangle;
880 }
881
882 void Renderer::draw(RendererWindow *window, const Renderable &renderable,
883                     const Program &prog) {
884   const auto &color_buffer = m_colorbuffers.find(renderable.buffer());
885   if (color_buffer == m_colorbuffers.end()) return;
886
887   const auto &cb = color_buffer->second.cb;
888
889   s_gles2.glUseProgram(prog.id);
890   s_gles2.glUniform1i(prog.tex_uniform, 0);
891   s_gles2.glUniformMatrix4fv(prog.display_transform_uniform, 1, GL_FALSE,
892                              glm::value_ptr(window->display_transform));
893   s_gles2.glUniformMatrix4fv(prog.screen_to_gl_coords_uniform, 1, GL_FALSE,
894                              glm::value_ptr(window->screen_to_gl_coords));
895
896   s_gles2.glActiveTexture(GL_TEXTURE0);
897
898   auto const &rect = renderable.screen_position();
899   GLfloat centerx = rect.left() + rect.width() / 2.0f;
900   GLfloat centery = rect.top() + rect.height() / 2.0f;
901   s_gles2.glUniform2f(prog.center_uniform, centerx, centery);
902
903   s_gles2.glUniformMatrix4fv(prog.transform_uniform, 1, GL_FALSE,
904                              glm::value_ptr(renderable.transformation()));
905
906   if (prog.alpha_uniform >= 0)
907     s_gles2.glUniform1f(prog.alpha_uniform, renderable.alpha());
908
909   s_gles2.glEnableVertexAttribArray(prog.position_attr);
910   s_gles2.glEnableVertexAttribArray(prog.texcoord_attr);
911
912   m_primitives.clear();
913   tessellate(m_primitives, {
914              static_cast<int32_t>(cb->getWidth()),
915              static_cast<int32_t>(cb->getHeight())}, renderable);
916
917   for (auto const &p : m_primitives) {
918     cb->bind();
919
920     s_gles2.glVertexAttribPointer(prog.position_attr, 3, GL_FLOAT, GL_FALSE,
921                                   sizeof(anbox::graphics::Vertex),
922                                   &p.vertices[0].position);
923     s_gles2.glVertexAttribPointer(prog.texcoord_attr, 2, GL_FLOAT, GL_FALSE,
924                                   sizeof(anbox::graphics::Vertex),
925                                   &p.vertices[0].texcoord);
926
927     s_gles2.glEnable(GL_BLEND);
928     s_gles2.glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
929                                 GL_ONE_MINUS_SRC_ALPHA);
930
931     s_gles2.glDrawArrays(p.type, 0, p.nvertices);
932   }
933
934   s_gles2.glDisableVertexAttribArray(prog.texcoord_attr);
935   s_gles2.glDisableVertexAttribArray(prog.position_attr);
936 }
937
938 bool Renderer::draw(EGLNativeWindowType native_window,
939                     const anbox::graphics::Rect &window_frame,
940                     const RenderableList &renderables) {
941
942   std::unique_lock<std::mutex> l(m_lock);
943
944   auto w = m_nativeWindows.find(native_window);
945   if (w == m_nativeWindows.end()) return false;
946
947   if (!bindWindow_locked(w->second))
948     return false;
949
950   setupViewport(w->second, window_frame);
951   s_gles2.glViewport(0, 0, window_frame.width(), window_frame.height());
952   s_gles2.glClearColor(0.0, 0.0, 0.0, 1.0);
953   s_gles2.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
954   s_gles2.glClear(GL_COLOR_BUFFER_BIT);
955
956   for (const auto &r : renderables)
957     draw(w->second, r, r.alpha() < 1.0f ? m_alphaProgram : m_defaultProgram);
958
959   s_egl.eglSwapBuffers(m_eglDisplay, w->second->surface);
960
961   unbind_locked();
962
963   return false;
964 }