• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // DisplayGbm.cpp: Gbm implementation of egl::Display
8 
9 #include "libANGLE/renderer/gl/egl/gbm/DisplayGbm.h"
10 
11 #include <fcntl.h>
12 #include <poll.h>
13 #include <sys/time.h>
14 #include <unistd.h>
15 
16 #include <EGL/eglext.h>
17 
18 #include <drm_fourcc.h>
19 #include <gbm.h>
20 
21 #include "common/debug.h"
22 #include "libANGLE/Config.h"
23 #include "libANGLE/Display.h"
24 #include "libANGLE/Surface.h"
25 #include "libANGLE/renderer/gl/ContextGL.h"
26 #include "libANGLE/renderer/gl/FramebufferGL.h"
27 #include "libANGLE/renderer/gl/RendererGL.h"
28 #include "libANGLE/renderer/gl/StateManagerGL.h"
29 #include "libANGLE/renderer/gl/egl/ContextEGL.h"
30 #include "libANGLE/renderer/gl/egl/DisplayEGL.h"
31 #include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h"
32 #include "libANGLE/renderer/gl/egl/gbm/SurfaceGbm.h"
33 #include "platform/PlatformMethods.h"
34 
35 // ARM-specific extension needed to make Mali GPU behave - not in any
36 // published header file.
37 #ifndef EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM
38 #    define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A
39 #endif
40 
41 #ifndef EGL_NO_CONFIG_MESA
42 #    define EGL_NO_CONFIG_MESA ((EGLConfig)0)
43 #endif
44 
45 namespace
46 {
47 
UnsignedToSigned(uint32_t u)48 EGLint UnsignedToSigned(uint32_t u)
49 {
50     return *reinterpret_cast<const EGLint *>(&u);
51 }
52 
ChooseMode(drmModeConnectorPtr conn)53 drmModeModeInfoPtr ChooseMode(drmModeConnectorPtr conn)
54 {
55     drmModeModeInfoPtr mode = nullptr;
56     ASSERT(conn);
57     ASSERT(conn->connection == DRM_MODE_CONNECTED);
58     // use first preferred mode if any, else end up with last mode in list
59     for (int i = 0; i < conn->count_modes; ++i)
60     {
61         mode = conn->modes + i;
62         if (mode->type & DRM_MODE_TYPE_PREFERRED)
63         {
64             break;
65         }
66     }
67     return mode;
68 }
69 
ChooseCRTC(int fd,drmModeConnectorPtr conn)70 int ChooseCRTC(int fd, drmModeConnectorPtr conn)
71 {
72     for (int i = 0; i < conn->count_encoders; ++i)
73     {
74         drmModeEncoderPtr enc = drmModeGetEncoder(fd, conn->encoders[i]);
75         unsigned long crtcs   = enc->possible_crtcs;
76         drmModeFreeEncoder(enc);
77         if (crtcs)
78         {
79             return __builtin_ctzl(crtcs);
80         }
81     }
82     return -1;
83 }
84 }  // namespace
85 
86 namespace rx
87 {
88 
Buffer(DisplayGbm * display,uint32_t useFlags,uint32_t gbmFormat,uint32_t drmFormat,uint32_t drmFormatFB,int depthBits,int stencilBits)89 DisplayGbm::Buffer::Buffer(DisplayGbm *display,
90                            uint32_t useFlags,
91                            uint32_t gbmFormat,
92                            uint32_t drmFormat,
93                            uint32_t drmFormatFB,
94                            int depthBits,
95                            int stencilBits)
96     : mDisplay(display),
97       mNative(nullptr),
98       mWidth(0),
99       mHeight(0),
100       mDepthBits(depthBits),
101       mStencilBits(stencilBits),
102       mUseFlags(useFlags),
103       mGBMFormat(gbmFormat),
104       mDRMFormat(drmFormat),
105       mDRMFormatFB(drmFormatFB),
106       mBO(nullptr),
107       mDMABuf(-1),
108       mHasDRMFB(false),
109       mDRMFB(0),
110       mImage(EGL_NO_IMAGE_KHR),
111       mColorBuffer(0),
112       mDSBuffer(0),
113       mTexture(0)
114 {}
115 
~Buffer()116 DisplayGbm::Buffer::~Buffer()
117 {
118     reset();
119 
120     const FunctionsGL *gl = mDisplay->mRenderer->getFunctions();
121     gl->deleteRenderbuffers(1, &mColorBuffer);
122     mColorBuffer = 0;
123     gl->deleteRenderbuffers(1, &mDSBuffer);
124     mDSBuffer = 0;
125 }
126 
reset()127 void DisplayGbm::Buffer::reset()
128 {
129     if (mHasDRMFB)
130     {
131         int fd = gbm_device_get_fd(mDisplay->mGBM);
132         drmModeRmFB(fd, mDRMFB);
133         mHasDRMFB = false;
134     }
135 
136     // Make sure to keep the color and depth stencil buffers alive so they maintain the same GL IDs
137     // if they are bound to any emulated default framebuffer.
138 
139     if (mImage != EGL_NO_IMAGE_KHR)
140     {
141         mDisplay->mEGL->destroyImageKHR(mImage);
142         mImage = EGL_NO_IMAGE_KHR;
143     }
144 
145     if (mTexture)
146     {
147         const FunctionsGL *gl = mDisplay->mRenderer->getFunctions();
148         gl->deleteTextures(1, &mTexture);
149         mTexture = 0;
150     }
151 
152     if (mDMABuf >= 0)
153     {
154         close(mDMABuf);
155         mDMABuf = -1;
156     }
157 
158     if (mBO)
159     {
160         gbm_bo_destroy(mBO);
161         mBO = nullptr;
162     }
163 }
164 
resize(int32_t width,int32_t height)165 bool DisplayGbm::Buffer::resize(int32_t width, int32_t height)
166 {
167     if (mWidth == width && mHeight == height)
168     {
169         return true;
170     }
171 
172     reset();
173 
174     if (width <= 0 || height <= 0)
175     {
176         return true;
177     }
178 
179     mBO = gbm_bo_create(mDisplay->mGBM, width, height, mGBMFormat, mUseFlags);
180     if (!mBO)
181     {
182         return false;
183     }
184 
185     mDMABuf = gbm_bo_get_fd(mBO);
186     if (mDMABuf < 0)
187     {
188         return false;
189     }
190 
191     // clang-format off
192     const EGLint attr[] =
193     {
194         EGL_WIDTH, width,
195         EGL_HEIGHT, height,
196         EGL_LINUX_DRM_FOURCC_EXT, UnsignedToSigned(mDRMFormat),
197         EGL_DMA_BUF_PLANE0_FD_EXT, mDMABuf,
198         EGL_DMA_BUF_PLANE0_PITCH_EXT, UnsignedToSigned(gbm_bo_get_stride(mBO)),
199         EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
200         EGL_NONE,
201     };
202     // clang-format on
203 
204     mImage = mDisplay->mEGL->createImageKHR(EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attr);
205     if (mImage == EGL_NO_IMAGE_KHR)
206     {
207         return false;
208     }
209 
210     const FunctionsGL *gl = mDisplay->mRenderer->getFunctions();
211     StateManagerGL *sm    = mDisplay->mRenderer->getStateManager();
212 
213     // Update the storage of the renderbuffers but don't generate new IDs. This will update all
214     // framebuffers they are bound to.
215     sm->bindRenderbuffer(GL_RENDERBUFFER, mColorBuffer);
216     gl->eGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, mImage);
217 
218     if (mDepthBits || mStencilBits)
219     {
220         sm->bindRenderbuffer(GL_RENDERBUFFER, mDSBuffer);
221         gl->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
222     }
223 
224     mWidth  = width;
225     mHeight = height;
226     return true;
227 }
228 
initialize(const NativeWindow * native)229 bool DisplayGbm::Buffer::initialize(const NativeWindow *native)
230 {
231     mNative = native;
232     return createRenderbuffers() && resize(native->width, native->height);
233 }
234 
initialize(int width,int height)235 bool DisplayGbm::Buffer::initialize(int width, int height)
236 {
237     return createRenderbuffers() && resize(width, height);
238 }
239 
bindTexImage()240 void DisplayGbm::Buffer::bindTexImage()
241 {
242     const FunctionsGL *gl = mDisplay->mRenderer->getFunctions();
243     gl->eGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
244 }
245 
getTexture()246 GLuint DisplayGbm::Buffer::getTexture()
247 {
248     // TODO(fjhenigman) Try not to create a new texture every time.  That already works on Intel
249     // and should work on Mali with proper fences.
250     const FunctionsGL *gl = mDisplay->mRenderer->getFunctions();
251     StateManagerGL *sm    = mDisplay->mRenderer->getStateManager();
252 
253     gl->genTextures(1, &mTexture);
254     sm->bindTexture(gl::TextureType::_2D, mTexture);
255     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
256     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
257     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
258     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
259     ASSERT(mImage != EGL_NO_IMAGE_KHR);
260     gl->eGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
261     return mTexture;
262 }
263 
getDRMFB()264 uint32_t DisplayGbm::Buffer::getDRMFB()
265 {
266     if (!mHasDRMFB)
267     {
268         int fd              = gbm_device_get_fd(mDisplay->mGBM);
269         uint32_t handles[4] = {gbm_bo_get_handle(mBO).u32};
270         uint32_t pitches[4] = {gbm_bo_get_stride(mBO)};
271         uint32_t offsets[4] = {0};
272         if (drmModeAddFB2(fd, mWidth, mHeight, mDRMFormatFB, handles, pitches, offsets, &mDRMFB, 0))
273         {
274             WARN() << "drmModeAddFB2 failed: " << errno << " " << strerror(errno);
275         }
276         else
277         {
278             mHasDRMFB = true;
279         }
280     }
281 
282     return mDRMFB;
283 }
284 
createGLFB(const gl::Context * context)285 GLuint DisplayGbm::Buffer::createGLFB(const gl::Context *context)
286 {
287     const FunctionsGL *functions = GetFunctionsGL(context);
288     StateManagerGL *stateManager = GetStateManagerGL(context);
289 
290     GLuint framebuffer = 0;
291     functions->genFramebuffers(1, &framebuffer);
292     stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
293 
294     functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER,
295                                        mColorBuffer);
296 
297     if (mDepthBits)
298     {
299         functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
300                                            mDSBuffer);
301     }
302 
303     if (mStencilBits)
304     {
305         functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
306                                            mDSBuffer);
307     }
308 
309     return framebuffer;
310 }
311 
framebufferGL(const gl::Context * context,const gl::FramebufferState & state)312 FramebufferGL *DisplayGbm::Buffer::framebufferGL(const gl::Context *context,
313                                                  const gl::FramebufferState &state)
314 {
315     return new FramebufferGL(state, createGLFB(context), true, false);
316 }
317 
present(const gl::Context * context)318 void DisplayGbm::Buffer::present(const gl::Context *context)
319 {
320     if (mNative)
321     {
322         if (mNative->visible)
323         {
324             mDisplay->drawBuffer(context, this);
325         }
326         resize(mNative->width, mNative->height);
327     }
328 }
329 
createRenderbuffers()330 bool DisplayGbm::Buffer::createRenderbuffers()
331 {
332     const FunctionsGL *gl = mDisplay->mRenderer->getFunctions();
333     StateManagerGL *sm    = mDisplay->mRenderer->getStateManager();
334 
335     gl->genRenderbuffers(1, &mColorBuffer);
336     sm->bindRenderbuffer(GL_RENDERBUFFER, mColorBuffer);
337 
338     if (mDepthBits || mStencilBits)
339     {
340         gl->genRenderbuffers(1, &mDSBuffer);
341         sm->bindRenderbuffer(GL_RENDERBUFFER, mDSBuffer);
342     }
343 
344     return true;
345 }
346 
DisplayGbm(const egl::DisplayState & state)347 DisplayGbm::DisplayGbm(const egl::DisplayState &state)
348     : DisplayEGL(state),
349       mGBM(nullptr),
350       mConnector(nullptr),
351       mMode(nullptr),
352       mCRTC(nullptr),
353       mSetCRTC(true),
354       mWidth(1280),
355       mHeight(1024),
356       mScanning(nullptr),
357       mPending(nullptr),
358       mDrawing(nullptr),
359       mUnused(nullptr),
360       mProgram(0),
361       mVertexShader(0),
362       mFragmentShader(0),
363       mVertexBuffer(0),
364       mIndexBuffer(0),
365       mCenterUniform(0),
366       mWindowSizeUniform(0),
367       mBorderSizeUniform(0),
368       mDepthUniform(0)
369 {}
370 
~DisplayGbm()371 DisplayGbm::~DisplayGbm() {}
372 
hasUsableScreen(int fd)373 bool DisplayGbm::hasUsableScreen(int fd)
374 {
375     drmModeResPtr resources = drmModeGetResources(fd);
376     if (!resources)
377     {
378         return false;
379     }
380     if (resources->count_connectors < 1)
381     {
382         drmModeFreeResources(resources);
383         return false;
384     }
385 
386     mConnector = nullptr;
387     for (int i = 0; i < resources->count_connectors; ++i)
388     {
389         drmModeFreeConnector(mConnector);
390         mConnector = drmModeGetConnector(fd, resources->connectors[i]);
391         if (!mConnector || mConnector->connection != DRM_MODE_CONNECTED)
392         {
393             continue;
394         }
395         mMode = ChooseMode(mConnector);
396         if (!mMode)
397         {
398             continue;
399         }
400         int n = ChooseCRTC(fd, mConnector);
401         if (n < 0)
402         {
403             continue;
404         }
405         mCRTC = drmModeGetCrtc(fd, resources->crtcs[n]);
406         if (mCRTC)
407         {
408             // found a screen
409             mGBM = gbm_create_device(fd);
410             if (mGBM)
411             {
412                 mWidth  = mMode->hdisplay;
413                 mHeight = mMode->vdisplay;
414                 drmModeFreeResources(resources);
415                 return true;
416             }
417             // can't use this screen
418             drmModeFreeCrtc(mCRTC);
419             mCRTC = nullptr;
420         }
421     }
422 
423     drmModeFreeResources(resources);
424     return false;
425 }
426 
initialize(egl::Display * display)427 egl::Error DisplayGbm::initialize(egl::Display *display)
428 {
429     int fd;
430     char deviceName[30];
431 
432     for (int i = 0; i < 64; ++i)
433     {
434         snprintf(deviceName, sizeof(deviceName), "/dev/dri/card%d", i);
435         fd = open(deviceName, O_RDWR | O_CLOEXEC);
436         if (fd >= 0)
437         {
438             if (hasUsableScreen(fd))
439             {
440                 break;
441             }
442             close(fd);
443         }
444     }
445 
446     if (!mGBM)
447     {
448         // there's no usable screen so try to proceed without one
449         for (int i = 128; i < 192; ++i)
450         {
451             snprintf(deviceName, sizeof(deviceName), "/dev/dri/renderD%d", i);
452             fd = open(deviceName, O_RDWR | O_CLOEXEC);
453             if (fd >= 0)
454             {
455                 mGBM = gbm_create_device(fd);
456                 if (mGBM)
457                 {
458                     break;
459                 }
460                 close(fd);
461             }
462         }
463     }
464 
465     if (!mGBM)
466     {
467         return egl::EglNotInitialized() << "Could not open drm device.";
468     }
469 
470     // ANGLE builds its executables with an RPATH so they pull in ANGLE's libGL and libEGL.
471     // Here we need to open the native libEGL.  An absolute path would work, but then we
472     // couldn't use LD_LIBRARY_PATH which is often useful during development.  Instead we take
473     // advantage of the fact that the system lib is available under multiple names (for example
474     // with a .1 suffix) while Angle only installs libEGL.so.
475     FunctionsEGLDL *egl = new FunctionsEGLDL();
476     mEGL                = egl;
477     ANGLE_TRY(egl->initialize(display->getNativeDisplayId(), "libEGL.so.1", nullptr));
478 
479     const char *necessaryExtensions[] = {
480         "EGL_KHR_image_base",
481         "EGL_EXT_image_dma_buf_import",
482         "EGL_KHR_surfaceless_context",
483     };
484     for (const char *ext : necessaryExtensions)
485     {
486         if (!mEGL->hasExtension(ext))
487         {
488             return egl::EglNotInitialized() << "need " << ext;
489         }
490     }
491 
492     if (mEGL->hasExtension("EGL_MESA_configless_context"))
493     {
494         mConfig = EGL_NO_CONFIG_MESA;
495     }
496     else
497     {
498         // clang-format off
499         const EGLint attrib[] =
500         {
501             // We want RGBA8 and DEPTH24_STENCIL8
502             EGL_RED_SIZE, 8,
503             EGL_GREEN_SIZE, 8,
504             EGL_BLUE_SIZE, 8,
505             EGL_ALPHA_SIZE, 8,
506             EGL_DEPTH_SIZE, 24,
507             EGL_STENCIL_SIZE, 8,
508             EGL_NONE,
509         };
510         // clang-format on
511         EGLint numConfig;
512         EGLConfig config[1];
513         if (!mEGL->chooseConfig(attrib, config, 1, &numConfig) || numConfig < 1)
514         {
515             return egl::EglNotInitialized() << "Could not get EGL config.";
516         }
517         mConfig = config[0];
518     }
519 
520     EGLContext context = EGL_NO_CONTEXT;
521     native_egl::AttributeVector attribs;
522     ANGLE_TRY(initializeContext(EGL_NO_CONTEXT, display->getAttributeMap(), &context, &attribs));
523 
524     if (!mEGL->makeCurrent(EGL_NO_SURFACE, context))
525     {
526         return egl::EglNotInitialized() << "Could not make context current.";
527     }
528 
529     std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
530     functionsGL->initialize(display->getAttributeMap());
531 
532     mRenderer.reset(new RendererEGL(std::move(functionsGL), display->getAttributeMap(), this,
533                                     context, attribs, false));
534     const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
535     if (maxVersion < gl::Version(2, 0))
536     {
537         return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
538     }
539 
540     return DisplayGL::initialize(display);
541 }
542 
pageFlipHandler(int fd,unsigned int sequence,unsigned int tv_sec,unsigned int tv_usec,void * data)543 void DisplayGbm::pageFlipHandler(int fd,
544                                  unsigned int sequence,
545                                  unsigned int tv_sec,
546                                  unsigned int tv_usec,
547                                  void *data)
548 {
549     DisplayGbm *display = reinterpret_cast<DisplayGbm *>(data);
550     uint64_t tv         = tv_sec;
551     display->pageFlipHandler(sequence, tv * 1000000 + tv_usec);
552 }
553 
pageFlipHandler(unsigned int sequence,uint64_t tv)554 void DisplayGbm::pageFlipHandler(unsigned int sequence, uint64_t tv)
555 {
556     ASSERT(mPending);
557     mUnused   = mScanning;
558     mScanning = mPending;
559     mPending  = nullptr;
560 }
561 
presentScreen()562 void DisplayGbm::presentScreen()
563 {
564     if (!mCRTC)
565     {
566         // no monitor
567         return;
568     }
569 
570     // see if pending flip has finished, without blocking
571     int fd = gbm_device_get_fd(mGBM);
572     if (mPending)
573     {
574         pollfd pfd;
575         pfd.fd     = fd;
576         pfd.events = POLLIN;
577         if (poll(&pfd, 1, 0) < 0)
578         {
579             WARN() << "poll failed: " << errno << " " << strerror(errno);
580         }
581         if (pfd.revents & POLLIN)
582         {
583             drmEventContext event;
584             event.version           = DRM_EVENT_CONTEXT_VERSION;
585             event.page_flip_handler = pageFlipHandler;
586             drmHandleEvent(fd, &event);
587         }
588     }
589 
590     // if pending flip has finished, schedule next one
591     if (!mPending && mDrawing)
592     {
593         flushGL();
594         if (mSetCRTC)
595         {
596             if (drmModeSetCrtc(fd, mCRTC->crtc_id, mDrawing->getDRMFB(), 0, 0,
597                                &mConnector->connector_id, 1, mMode))
598             {
599                 WARN() << "set crtc failed: " << errno << " " << strerror(errno);
600             }
601             mSetCRTC = false;
602         }
603         if (drmModePageFlip(fd, mCRTC->crtc_id, mDrawing->getDRMFB(), DRM_MODE_PAGE_FLIP_EVENT,
604                             this))
605         {
606             WARN() << "page flip failed: " << errno << " " << strerror(errno);
607         }
608         mPending = mDrawing;
609         mDrawing = nullptr;
610     }
611 }
612 
makeShader(GLuint type,const char * src)613 GLuint DisplayGbm::makeShader(GLuint type, const char *src)
614 {
615     const FunctionsGL *gl = mRenderer->getFunctions();
616     GLuint shader         = gl->createShader(type);
617     gl->shaderSource(shader, 1, &src, nullptr);
618     gl->compileShader(shader);
619 
620     GLchar buf[999];
621     GLsizei len;
622     GLint compiled;
623     gl->getShaderInfoLog(shader, sizeof(buf), &len, buf);
624     gl->getShaderiv(shader, GL_COMPILE_STATUS, &compiled);
625     if (compiled != GL_TRUE)
626     {
627         WARN() << "DisplayGbm shader compilation error: " << buf;
628     }
629 
630     return shader;
631 }
632 
drawWithTexture(const gl::Context * context,Buffer * buffer)633 void DisplayGbm::drawWithTexture(const gl::Context *context, Buffer *buffer)
634 {
635     const FunctionsGL *gl = mRenderer->getFunctions();
636     StateManagerGL *sm    = mRenderer->getStateManager();
637 
638     if (!mProgram)
639     {
640         const GLchar *vertexSource =
641             "#version 100\n"
642             "attribute vec3 vertex;\n"
643             "uniform vec2 center;\n"
644             "uniform vec2 windowSize;\n"
645             "uniform vec2 borderSize;\n"
646             "uniform float depth;\n"
647             "varying vec3 texCoord;\n"
648             "void main()\n"
649             "{\n"
650             "    vec2 pos = vertex.xy * (windowSize + borderSize * vertex.z);\n"
651             "    gl_Position = vec4(center + pos, depth, 1);\n"
652             "    texCoord = vec3(pos / windowSize * vec2(.5, -.5) + vec2(.5, .5), vertex.z);\n"
653             "}\n";
654 
655         const GLchar *fragmentSource =
656             "#version 100\n"
657             "precision mediump float;\n"
658             "uniform sampler2D tex;\n"
659             "varying vec3 texCoord;\n"
660             "void main()\n"
661             "{\n"
662             "    if (texCoord.z > 0.)\n"
663             "    {\n"
664             "        float c = abs((texCoord.z * 2.) - 1.);\n"
665             "        gl_FragColor = vec4(c, c, c, 1);\n"
666             "    }\n"
667             "    else\n"
668             "    {\n"
669             "        gl_FragColor = texture2D(tex, texCoord.xy);\n"
670             "    }\n"
671             "}\n";
672 
673         mVertexShader   = makeShader(GL_VERTEX_SHADER, vertexSource);
674         mFragmentShader = makeShader(GL_FRAGMENT_SHADER, fragmentSource);
675         mProgram        = gl->createProgram();
676         gl->attachShader(mProgram, mVertexShader);
677         gl->attachShader(mProgram, mFragmentShader);
678         gl->bindAttribLocation(mProgram, 0, "vertex");
679         gl->linkProgram(mProgram);
680         GLint linked;
681         gl->getProgramiv(mProgram, GL_LINK_STATUS, &linked);
682         if (!linked)
683         {
684             WARN() << "shader link failed: cannot display buffer";
685             return;
686         }
687         mCenterUniform     = gl->getUniformLocation(mProgram, "center");
688         mWindowSizeUniform = gl->getUniformLocation(mProgram, "windowSize");
689         mBorderSizeUniform = gl->getUniformLocation(mProgram, "borderSize");
690         mDepthUniform      = gl->getUniformLocation(mProgram, "depth");
691         GLint texUniform   = gl->getUniformLocation(mProgram, "tex");
692         sm->useProgram(mProgram);
693         gl->uniform1i(texUniform, 0);
694 
695         // clang-format off
696         const GLfloat vertices[] =
697         {
698              // window corners, and window border inside corners
699              1, -1, 0,
700             -1, -1, 0,
701              1,  1, 0,
702             -1,  1, 0,
703              // window border outside corners
704              1, -1, 1,
705             -1, -1, 1,
706              1,  1, 1,
707             -1,  1, 1,
708         };
709         // clang-format on
710         gl->genBuffers(1, &mVertexBuffer);
711         sm->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
712         gl->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
713 
714         // window border triangle strip
715         const GLuint borderStrip[] = {5, 0, 4, 2, 6, 3, 7, 1, 5, 0};
716 
717         gl->genBuffers(1, &mIndexBuffer);
718         sm->bindBuffer(gl::BufferBinding::ElementArray, mIndexBuffer);
719         gl->bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(borderStrip), borderStrip, GL_STATIC_DRAW);
720     }
721     else
722     {
723         sm->useProgram(mProgram);
724         sm->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
725         sm->bindBuffer(gl::BufferBinding::ElementArray, mIndexBuffer);
726     }
727 
728     // convert from pixels to "-1 to 1" space
729     const NativeWindow *n = buffer->getNative();
730     double x              = n->x * 2. / mWidth - 1;
731     double y              = n->y * 2. / mHeight - 1;
732     double halfw          = n->width * 1. / mWidth;
733     double halfh          = n->height * 1. / mHeight;
734     double borderw        = n->borderWidth * 2. / mWidth;
735     double borderh        = n->borderHeight * 2. / mHeight;
736 
737     gl->uniform2f(mCenterUniform, x + halfw, y + halfh);
738     gl->uniform2f(mWindowSizeUniform, halfw, halfh);
739     gl->uniform2f(mBorderSizeUniform, borderw, borderh);
740     gl->uniform1f(mDepthUniform, n->depth / 1e6);
741 
742     sm->setBlendEnabled(false);
743     sm->setCullFaceEnabled(false);
744     sm->setStencilTestEnabled(false);
745     sm->setScissorTestEnabled(false);
746     sm->setDepthTestEnabled(true);
747     sm->setColorMask(true, true, true, true);
748     sm->setDepthMask(true);
749     sm->setDepthRange(0, 1);
750     sm->setDepthFunc(GL_LESS);
751     sm->setViewport(gl::Rectangle(0, 0, mWidth, mHeight));
752     sm->activeTexture(0);
753     GLuint tex = buffer->getTexture();
754     sm->bindTexture(gl::TextureType::_2D, tex);
755     gl->vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
756     gl->enableVertexAttribArray(0);
757     GLuint fbo = mDrawing->createGLFB(context);
758     sm->bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
759     gl->drawArrays(GL_TRIANGLE_STRIP, 0, 4);
760     gl->drawElements(GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, 0);
761     sm->deleteTexture(tex);
762     sm->deleteFramebuffer(fbo);
763 }
764 
drawBuffer(const gl::Context * context,Buffer * buffer)765 void DisplayGbm::drawBuffer(const gl::Context *context, Buffer *buffer)
766 {
767     if (!mDrawing)
768     {
769         // get buffer on which to draw window
770         if (mUnused)
771         {
772             mDrawing = mUnused;
773             mUnused  = nullptr;
774         }
775         else
776         {
777             mDrawing = new Buffer(this, GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT,
778                                   GBM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888,
779                                   true, true);  // XXX shouldn't need stencil
780             if (!mDrawing || !mDrawing->initialize(mWidth, mHeight))
781             {
782                 return;
783             }
784         }
785 
786         const FunctionsGL *gl = mRenderer->getFunctions();
787         StateManagerGL *sm    = mRenderer->getStateManager();
788 
789         GLuint fbo = mDrawing->createGLFB(context);
790         sm->bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
791         sm->setClearColor(gl::ColorF(0, 0, 0, 1));
792         sm->setClearDepth(1);
793         sm->setScissorTestEnabled(false);
794         sm->setColorMask(true, true, true, true);
795         sm->setDepthMask(true);
796         gl->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
797         sm->deleteFramebuffer(fbo);
798     }
799 
800     drawWithTexture(context, buffer);
801     presentScreen();
802 }
803 
flushGL()804 void DisplayGbm::flushGL()
805 {
806     const FunctionsGL *gl = mRenderer->getFunctions();
807     gl->flush();
808     if (mEGL->hasExtension("EGL_KHR_fence_sync"))
809     {
810         const EGLint attrib[] = {EGL_SYNC_CONDITION_KHR,
811                                  EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, EGL_NONE};
812         EGLSyncKHR fence      = mEGL->createSyncKHR(EGL_SYNC_FENCE_KHR, attrib);
813         if (fence)
814         {
815             // TODO(fjhenigman) Figure out the right way to use fences on Mali GPU
816             // to maximize throughput and avoid hangs when a program is interrupted.
817             // This busy wait was an attempt to reduce hangs when interrupted by SIGINT,
818             // but we still get some.
819             for (;;)
820             {
821                 EGLint r = mEGL->clientWaitSyncKHR(fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 0);
822                 if (r != EGL_TIMEOUT_EXPIRED_KHR)
823                 {
824                     break;
825                 }
826                 usleep(99);
827             }
828             mEGL->destroySyncKHR(fence);
829             return;
830         }
831     }
832 }
833 
terminate()834 void DisplayGbm::terminate()
835 {
836     SafeDelete(mScanning);
837     SafeDelete(mPending);
838     SafeDelete(mDrawing);
839     SafeDelete(mUnused);
840 
841     if (mProgram)
842     {
843         const FunctionsGL *gl = mRenderer->getFunctions();
844         gl->deleteProgram(mProgram);
845         gl->deleteShader(mVertexShader);
846         gl->deleteShader(mFragmentShader);
847         gl->deleteBuffers(1, &mVertexBuffer);
848         gl->deleteBuffers(1, &mIndexBuffer);
849         mProgram = 0;
850     }
851 
852     DisplayGL::terminate();
853 
854     mRenderer.reset();
855 
856     if (mEGL)
857     {
858         // Mesa might crash if you terminate EGL with a context current then re-initialize EGL, so
859         // make our context not current.
860         mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
861 
862         ANGLE_SWALLOW_ERR(mEGL->terminate());
863         SafeDelete(mEGL);
864     }
865 
866     drmModeFreeConnector(mConnector);
867     mConnector = nullptr;
868     mMode      = nullptr;
869     drmModeFreeCrtc(mCRTC);
870     mCRTC = nullptr;
871 
872     if (mGBM)
873     {
874         int fd = gbm_device_get_fd(mGBM);
875         gbm_device_destroy(mGBM);
876         mGBM = nullptr;
877         close(fd);
878     }
879 }
880 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)881 SurfaceImpl *DisplayGbm::createWindowSurface(const egl::SurfaceState &state,
882                                              EGLNativeWindowType window,
883                                              const egl::AttributeMap &attribs)
884 {
885     Buffer *buffer = new Buffer(this, GBM_BO_USE_RENDERING, GBM_FORMAT_ARGB8888,
886                                 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, true, true);
887     if (!buffer || !buffer->initialize(reinterpret_cast<const NativeWindow *>(window)))
888     {
889         return nullptr;
890     }
891     return new SurfaceGbm(state, buffer);
892 }
893 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)894 SurfaceImpl *DisplayGbm::createPbufferSurface(const egl::SurfaceState &state,
895                                               const egl::AttributeMap &attribs)
896 {
897     EGLAttrib width  = attribs.get(EGL_WIDTH, 0);
898     EGLAttrib height = attribs.get(EGL_HEIGHT, 0);
899     Buffer *buffer   = new Buffer(this, GBM_BO_USE_RENDERING, GBM_FORMAT_ARGB8888,
900                                 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, true, true);
901     if (!buffer || !buffer->initialize(static_cast<int>(width), static_cast<int>(height)))
902     {
903         return nullptr;
904     }
905     return new SurfaceGbm(state, buffer);
906 }
907 
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)908 ContextImpl *DisplayGbm::createContext(const gl::State &state,
909                                        gl::ErrorSet *errorSet,
910                                        const egl::Config *configuration,
911                                        const gl::Context *shareContext,
912                                        const egl::AttributeMap &attribs)
913 {
914     // All contexts on Gbm are virtualized and share the same renderer.
915     return new ContextEGL(state, errorSet, mRenderer,
916                           RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED);
917 }
918 
makeCurrent(egl::Display * display,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)919 egl::Error DisplayGbm::makeCurrent(egl::Display *display,
920                                    egl::Surface *drawSurface,
921                                    egl::Surface *readSurface,
922                                    gl::Context *context)
923 {
924     return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
925 }
926 
validateEglConfig(const EGLint * configAttribs)927 bool DisplayGbm::validateEglConfig(const EGLint *configAttribs)
928 {
929     EGLint numConfigs;
930     if (!mEGL->chooseConfig(configAttribs, NULL, 0, &numConfigs))
931     {
932         ERR() << "eglChooseConfig failed with error " << egl::Error(mEGL->getError());
933         return false;
934     }
935     if (numConfigs == 0)
936     {
937         return false;
938     }
939     return true;
940 }
941 
generateConfigs()942 egl::ConfigSet DisplayGbm::generateConfigs()
943 {
944     // clang-format off
945     std::vector<EGLint> configAttribs8888 =
946     {
947         EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
948         EGL_SURFACE_TYPE, EGL_DONT_CARE,
949         EGL_CONFIG_CAVEAT, EGL_NONE,
950         EGL_CONFORMANT, EGL_DONT_CARE,
951         EGL_RENDERABLE_TYPE, EGL_DONT_CARE,
952         EGL_RED_SIZE, 8,
953         EGL_GREEN_SIZE, 8,
954         EGL_BLUE_SIZE, 8,
955         EGL_ALPHA_SIZE, 8,
956         EGL_BUFFER_SIZE, 32,
957         EGL_DEPTH_SIZE, 24,
958         EGL_NONE
959     };
960     // clang-format on
961 
962     if (!validateEglConfig(configAttribs8888.data()))
963     {
964         ERR() << "No suitable EGL configs found.";
965         return egl::ConfigSet();
966     }
967     mConfigAttribList = configAttribs8888;
968     return DisplayEGL::generateConfigs();
969 }
970 
isValidNativeWindow(EGLNativeWindowType window) const971 bool DisplayGbm::isValidNativeWindow(EGLNativeWindowType window) const
972 {
973     return true;
974 }
975 
setSwapInterval(EGLSurface drawable,SwapControlData * data)976 void DisplayGbm::setSwapInterval(EGLSurface drawable, SwapControlData *data)
977 {
978     ASSERT(data != nullptr);
979 }
980 
generateExtensions(egl::DisplayExtensions * outExtensions) const981 void DisplayGbm::generateExtensions(egl::DisplayExtensions *outExtensions) const
982 {
983     DisplayEGL::generateExtensions(outExtensions);
984 
985     // Surfaceless contexts are emulated even if there is no native support.
986     outExtensions->surfacelessContext = true;
987 }
988 
989 class WorkerContextGbm final : public WorkerContext
990 {
991   public:
992     WorkerContextGbm(EGLContext context, FunctionsEGL *functions);
993     ~WorkerContextGbm() override;
994 
995     bool makeCurrent() override;
996     void unmakeCurrent() override;
997 
998   private:
999     EGLContext mContext;
1000     FunctionsEGL *mFunctions;
1001 };
1002 
WorkerContextGbm(EGLContext context,FunctionsEGL * functions)1003 WorkerContextGbm::WorkerContextGbm(EGLContext context, FunctionsEGL *functions)
1004     : mContext(context), mFunctions(functions)
1005 {}
1006 
~WorkerContextGbm()1007 WorkerContextGbm::~WorkerContextGbm()
1008 {
1009     mFunctions->destroyContext(mContext);
1010 }
1011 
makeCurrent()1012 bool WorkerContextGbm::makeCurrent()
1013 {
1014     if (mFunctions->makeCurrent(EGL_NO_SURFACE, mContext) == EGL_FALSE)
1015     {
1016         ERR() << "Unable to make the EGL context current.";
1017         return false;
1018     }
1019     return true;
1020 }
1021 
unmakeCurrent()1022 void WorkerContextGbm::unmakeCurrent()
1023 {
1024     mFunctions->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
1025 }
1026 
createWorkerContext(std::string * infoLog,EGLContext sharedContext,const native_egl::AttributeVector workerAttribs)1027 WorkerContext *DisplayGbm::createWorkerContext(std::string *infoLog,
1028                                                EGLContext sharedContext,
1029                                                const native_egl::AttributeVector workerAttribs)
1030 {
1031     EGLContext context = mEGL->createContext(mConfig, sharedContext, workerAttribs.data());
1032     if (context == EGL_NO_CONTEXT)
1033     {
1034         *infoLog += "Unable to create the EGL context.";
1035         return nullptr;
1036     }
1037     return new WorkerContextGbm(context, mEGL);
1038 }
1039 
fixSurfaceType(EGLint surfaceType) const1040 EGLint DisplayGbm::fixSurfaceType(EGLint surfaceType) const
1041 {
1042     EGLint type = DisplayEGL::fixSurfaceType(surfaceType);
1043     // Ozone native surfaces don't support EGL_WINDOW_BIT,
1044     // but ANGLE uses renderbuffers to emulate windows
1045     return type | EGL_WINDOW_BIT;
1046 }
1047 
1048 }  // namespace rx
1049