• 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->getRenderer()->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->getFunctionsEGL()->destroyImageKHR(mImage);
142         mImage = EGL_NO_IMAGE_KHR;
143     }
144 
145     if (mTexture)
146     {
147         const FunctionsGL *gl = mDisplay->getRenderer()->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->getFunctionsEGL()->createImageKHR(EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
205                                                          nullptr, attr);
206     if (mImage == EGL_NO_IMAGE_KHR)
207     {
208         return false;
209     }
210 
211     const FunctionsGL *gl = mDisplay->getRenderer()->getFunctions();
212     StateManagerGL *sm    = mDisplay->getRenderer()->getStateManager();
213 
214     // Update the storage of the renderbuffers but don't generate new IDs. This will update all
215     // framebuffers they are bound to.
216     sm->bindRenderbuffer(GL_RENDERBUFFER, mColorBuffer);
217     gl->eGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, mImage);
218 
219     if (mDepthBits || mStencilBits)
220     {
221         sm->bindRenderbuffer(GL_RENDERBUFFER, mDSBuffer);
222         gl->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
223     }
224 
225     mWidth  = width;
226     mHeight = height;
227     return true;
228 }
229 
initialize(const NativeWindow * native)230 bool DisplayGbm::Buffer::initialize(const NativeWindow *native)
231 {
232     mNative = native;
233     return createRenderbuffers() && resize(native->width, native->height);
234 }
235 
initialize(int width,int height)236 bool DisplayGbm::Buffer::initialize(int width, int height)
237 {
238     return createRenderbuffers() && resize(width, height);
239 }
240 
bindTexImage()241 void DisplayGbm::Buffer::bindTexImage()
242 {
243     const FunctionsGL *gl = mDisplay->getRenderer()->getFunctions();
244     gl->eGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
245 }
246 
getTexture()247 GLuint DisplayGbm::Buffer::getTexture()
248 {
249     // TODO(fjhenigman) Try not to create a new texture every time.  That already works on Intel
250     // and should work on Mali with proper fences.
251     const FunctionsGL *gl = mDisplay->getRenderer()->getFunctions();
252     StateManagerGL *sm    = mDisplay->getRenderer()->getStateManager();
253 
254     gl->genTextures(1, &mTexture);
255     sm->bindTexture(gl::TextureType::_2D, mTexture);
256     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
257     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
258     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
259     gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
260     ASSERT(mImage != EGL_NO_IMAGE_KHR);
261     gl->eGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
262     return mTexture;
263 }
264 
getDRMFB()265 uint32_t DisplayGbm::Buffer::getDRMFB()
266 {
267     if (!mHasDRMFB)
268     {
269         int fd              = gbm_device_get_fd(mDisplay->mGBM);
270         uint32_t handles[4] = {gbm_bo_get_handle(mBO).u32};
271         uint32_t pitches[4] = {gbm_bo_get_stride(mBO)};
272         uint32_t offsets[4] = {0};
273         if (drmModeAddFB2(fd, mWidth, mHeight, mDRMFormatFB, handles, pitches, offsets, &mDRMFB, 0))
274         {
275             WARN() << "drmModeAddFB2 failed: " << errno << " " << strerror(errno);
276         }
277         else
278         {
279             mHasDRMFB = true;
280         }
281     }
282 
283     return mDRMFB;
284 }
285 
createGLFB(const gl::Context * context)286 GLuint DisplayGbm::Buffer::createGLFB(const gl::Context *context)
287 {
288     const FunctionsGL *functions = GetFunctionsGL(context);
289     StateManagerGL *stateManager = GetStateManagerGL(context);
290 
291     GLuint framebuffer = 0;
292     functions->genFramebuffers(1, &framebuffer);
293     stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
294 
295     functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER,
296                                        mColorBuffer);
297 
298     if (mDepthBits)
299     {
300         functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
301                                            mDSBuffer);
302     }
303 
304     if (mStencilBits)
305     {
306         functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
307                                            mDSBuffer);
308     }
309 
310     return framebuffer;
311 }
312 
framebufferGL(const gl::Context * context,const gl::FramebufferState & state)313 FramebufferGL *DisplayGbm::Buffer::framebufferGL(const gl::Context *context,
314                                                  const gl::FramebufferState &state)
315 {
316     return new FramebufferGL(state, createGLFB(context), true, false);
317 }
318 
present(const gl::Context * context)319 void DisplayGbm::Buffer::present(const gl::Context *context)
320 {
321     if (mNative)
322     {
323         if (mNative->visible)
324         {
325             mDisplay->drawBuffer(context, this);
326         }
327         resize(mNative->width, mNative->height);
328     }
329 }
330 
createRenderbuffers()331 bool DisplayGbm::Buffer::createRenderbuffers()
332 {
333     const FunctionsGL *gl = mDisplay->getRenderer()->getFunctions();
334     StateManagerGL *sm    = mDisplay->getRenderer()->getStateManager();
335 
336     gl->genRenderbuffers(1, &mColorBuffer);
337     sm->bindRenderbuffer(GL_RENDERBUFFER, mColorBuffer);
338 
339     if (mDepthBits || mStencilBits)
340     {
341         gl->genRenderbuffers(1, &mDSBuffer);
342         sm->bindRenderbuffer(GL_RENDERBUFFER, mDSBuffer);
343     }
344 
345     return true;
346 }
347 
DisplayGbm(const egl::DisplayState & state)348 DisplayGbm::DisplayGbm(const egl::DisplayState &state)
349     : DisplayEGL(state),
350       mGBM(nullptr),
351       mConnector(nullptr),
352       mMode(nullptr),
353       mCRTC(nullptr),
354       mSetCRTC(true),
355       mWidth(1280),
356       mHeight(1024),
357       mScanning(nullptr),
358       mPending(nullptr),
359       mDrawing(nullptr),
360       mUnused(nullptr),
361       mProgram(0),
362       mVertexShader(0),
363       mFragmentShader(0),
364       mVertexBuffer(0),
365       mIndexBuffer(0),
366       mCenterUniform(0),
367       mWindowSizeUniform(0),
368       mBorderSizeUniform(0),
369       mDepthUniform(0)
370 {}
371 
~DisplayGbm()372 DisplayGbm::~DisplayGbm() {}
373 
hasUsableScreen(int fd)374 bool DisplayGbm::hasUsableScreen(int fd)
375 {
376     drmModeResPtr resources = drmModeGetResources(fd);
377     if (!resources)
378     {
379         return false;
380     }
381     if (resources->count_connectors < 1)
382     {
383         drmModeFreeResources(resources);
384         return false;
385     }
386 
387     mConnector = nullptr;
388     for (int i = 0; i < resources->count_connectors; ++i)
389     {
390         drmModeFreeConnector(mConnector);
391         mConnector = drmModeGetConnector(fd, resources->connectors[i]);
392         if (!mConnector || mConnector->connection != DRM_MODE_CONNECTED)
393         {
394             continue;
395         }
396         mMode = ChooseMode(mConnector);
397         if (!mMode)
398         {
399             continue;
400         }
401         int n = ChooseCRTC(fd, mConnector);
402         if (n < 0)
403         {
404             continue;
405         }
406         mCRTC = drmModeGetCrtc(fd, resources->crtcs[n]);
407         if (mCRTC)
408         {
409             // found a screen
410             mGBM = gbm_create_device(fd);
411             if (mGBM)
412             {
413                 mWidth  = mMode->hdisplay;
414                 mHeight = mMode->vdisplay;
415                 drmModeFreeResources(resources);
416                 return true;
417             }
418             // can't use this screen
419             drmModeFreeCrtc(mCRTC);
420             mCRTC = nullptr;
421         }
422     }
423 
424     drmModeFreeResources(resources);
425     return false;
426 }
427 
initialize(egl::Display * display)428 egl::Error DisplayGbm::initialize(egl::Display *display)
429 {
430     int fd;
431     char deviceName[30];
432 
433     for (int i = 0; i < 64; ++i)
434     {
435         snprintf(deviceName, sizeof(deviceName), "/dev/dri/card%d", i);
436         fd = open(deviceName, O_RDWR | O_CLOEXEC);
437         if (fd >= 0)
438         {
439             if (hasUsableScreen(fd))
440             {
441                 break;
442             }
443             close(fd);
444         }
445     }
446 
447     if (!mGBM)
448     {
449         // there's no usable screen so try to proceed without one
450         for (int i = 128; i < 192; ++i)
451         {
452             snprintf(deviceName, sizeof(deviceName), "/dev/dri/renderD%d", i);
453             fd = open(deviceName, O_RDWR | O_CLOEXEC);
454             if (fd >= 0)
455             {
456                 mGBM = gbm_create_device(fd);
457                 if (mGBM)
458                 {
459                     break;
460                 }
461                 close(fd);
462             }
463         }
464     }
465 
466     if (!mGBM)
467     {
468         return egl::EglNotInitialized() << "Could not open drm device.";
469     }
470 
471     return DisplayEGL::initialize(display);
472 }
473 
pageFlipHandler(int fd,unsigned int sequence,unsigned int tv_sec,unsigned int tv_usec,void * data)474 void DisplayGbm::pageFlipHandler(int fd,
475                                  unsigned int sequence,
476                                  unsigned int tv_sec,
477                                  unsigned int tv_usec,
478                                  void *data)
479 {
480     DisplayGbm *display = reinterpret_cast<DisplayGbm *>(data);
481     uint64_t tv         = tv_sec;
482     display->pageFlipHandler(sequence, tv * 1000000 + tv_usec);
483 }
484 
pageFlipHandler(unsigned int sequence,uint64_t tv)485 void DisplayGbm::pageFlipHandler(unsigned int sequence, uint64_t tv)
486 {
487     ASSERT(mPending);
488     mUnused   = mScanning;
489     mScanning = mPending;
490     mPending  = nullptr;
491 }
492 
presentScreen()493 void DisplayGbm::presentScreen()
494 {
495     if (!mCRTC)
496     {
497         // no monitor
498         return;
499     }
500 
501     // see if pending flip has finished, without blocking
502     int fd = gbm_device_get_fd(mGBM);
503     if (mPending)
504     {
505         pollfd pfd;
506         pfd.fd     = fd;
507         pfd.events = POLLIN;
508         if (poll(&pfd, 1, 0) < 0)
509         {
510             WARN() << "poll failed: " << errno << " " << strerror(errno);
511         }
512         if (pfd.revents & POLLIN)
513         {
514             drmEventContext event;
515             event.version           = DRM_EVENT_CONTEXT_VERSION;
516             event.page_flip_handler = pageFlipHandler;
517             drmHandleEvent(fd, &event);
518         }
519     }
520 
521     // if pending flip has finished, schedule next one
522     if (!mPending && mDrawing)
523     {
524         flushGL();
525         if (mSetCRTC)
526         {
527             if (drmModeSetCrtc(fd, mCRTC->crtc_id, mDrawing->getDRMFB(), 0, 0,
528                                &mConnector->connector_id, 1, mMode))
529             {
530                 WARN() << "set crtc failed: " << errno << " " << strerror(errno);
531             }
532             mSetCRTC = false;
533         }
534         if (drmModePageFlip(fd, mCRTC->crtc_id, mDrawing->getDRMFB(), DRM_MODE_PAGE_FLIP_EVENT,
535                             this))
536         {
537             WARN() << "page flip failed: " << errno << " " << strerror(errno);
538         }
539         mPending = mDrawing;
540         mDrawing = nullptr;
541     }
542 }
543 
makeShader(GLuint type,const char * src)544 GLuint DisplayGbm::makeShader(GLuint type, const char *src)
545 {
546     const FunctionsGL *gl = getRenderer()->getFunctions();
547     GLuint shader         = gl->createShader(type);
548     gl->shaderSource(shader, 1, &src, nullptr);
549     gl->compileShader(shader);
550 
551     GLchar buf[999];
552     GLsizei len;
553     GLint compiled;
554     gl->getShaderInfoLog(shader, sizeof(buf), &len, buf);
555     gl->getShaderiv(shader, GL_COMPILE_STATUS, &compiled);
556     if (compiled != GL_TRUE)
557     {
558         WARN() << "DisplayGbm shader compilation error: " << buf;
559     }
560 
561     return shader;
562 }
563 
drawWithTexture(const gl::Context * context,Buffer * buffer)564 void DisplayGbm::drawWithTexture(const gl::Context *context, Buffer *buffer)
565 {
566     const FunctionsGL *gl = getRenderer()->getFunctions();
567     StateManagerGL *sm    = getRenderer()->getStateManager();
568 
569     if (!mProgram)
570     {
571         const GLchar *vertexSource =
572             "#version 100\n"
573             "attribute vec3 vertex;\n"
574             "uniform vec2 center;\n"
575             "uniform vec2 windowSize;\n"
576             "uniform vec2 borderSize;\n"
577             "uniform float depth;\n"
578             "varying vec3 texCoord;\n"
579             "void main()\n"
580             "{\n"
581             "    vec2 pos = vertex.xy * (windowSize + borderSize * vertex.z);\n"
582             "    gl_Position = vec4(center + pos, depth, 1);\n"
583             "    texCoord = vec3(pos / windowSize * vec2(.5, -.5) + vec2(.5, .5), vertex.z);\n"
584             "}\n";
585 
586         const GLchar *fragmentSource =
587             "#version 100\n"
588             "precision mediump float;\n"
589             "uniform sampler2D tex;\n"
590             "varying vec3 texCoord;\n"
591             "void main()\n"
592             "{\n"
593             "    if (texCoord.z > 0.)\n"
594             "    {\n"
595             "        float c = abs((texCoord.z * 2.) - 1.);\n"
596             "        gl_FragColor = vec4(c, c, c, 1);\n"
597             "    }\n"
598             "    else\n"
599             "    {\n"
600             "        gl_FragColor = texture2D(tex, texCoord.xy);\n"
601             "    }\n"
602             "}\n";
603 
604         mVertexShader   = makeShader(GL_VERTEX_SHADER, vertexSource);
605         mFragmentShader = makeShader(GL_FRAGMENT_SHADER, fragmentSource);
606         mProgram        = gl->createProgram();
607         gl->attachShader(mProgram, mVertexShader);
608         gl->attachShader(mProgram, mFragmentShader);
609         gl->bindAttribLocation(mProgram, 0, "vertex");
610         gl->linkProgram(mProgram);
611         GLint linked;
612         gl->getProgramiv(mProgram, GL_LINK_STATUS, &linked);
613         if (!linked)
614         {
615             WARN() << "shader link failed: cannot display buffer";
616             return;
617         }
618         mCenterUniform     = gl->getUniformLocation(mProgram, "center");
619         mWindowSizeUniform = gl->getUniformLocation(mProgram, "windowSize");
620         mBorderSizeUniform = gl->getUniformLocation(mProgram, "borderSize");
621         mDepthUniform      = gl->getUniformLocation(mProgram, "depth");
622         GLint texUniform   = gl->getUniformLocation(mProgram, "tex");
623         sm->useProgram(mProgram);
624         gl->uniform1i(texUniform, 0);
625 
626         // clang-format off
627         const GLfloat vertices[] =
628         {
629              // window corners, and window border inside corners
630              1, -1, 0,
631             -1, -1, 0,
632              1,  1, 0,
633             -1,  1, 0,
634              // window border outside corners
635              1, -1, 1,
636             -1, -1, 1,
637              1,  1, 1,
638             -1,  1, 1,
639         };
640         // clang-format on
641         gl->genBuffers(1, &mVertexBuffer);
642         sm->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
643         gl->bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
644 
645         // window border triangle strip
646         const GLuint borderStrip[] = {5, 0, 4, 2, 6, 3, 7, 1, 5, 0};
647 
648         gl->genBuffers(1, &mIndexBuffer);
649         sm->bindBuffer(gl::BufferBinding::ElementArray, mIndexBuffer);
650         gl->bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(borderStrip), borderStrip, GL_STATIC_DRAW);
651     }
652     else
653     {
654         sm->useProgram(mProgram);
655         sm->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
656         sm->bindBuffer(gl::BufferBinding::ElementArray, mIndexBuffer);
657     }
658 
659     // convert from pixels to "-1 to 1" space
660     const NativeWindow *n = buffer->getNative();
661     double x              = n->x * 2. / mWidth - 1;
662     double y              = n->y * 2. / mHeight - 1;
663     double halfw          = n->width * 1. / mWidth;
664     double halfh          = n->height * 1. / mHeight;
665     double borderw        = n->borderWidth * 2. / mWidth;
666     double borderh        = n->borderHeight * 2. / mHeight;
667 
668     gl->uniform2f(mCenterUniform, x + halfw, y + halfh);
669     gl->uniform2f(mWindowSizeUniform, halfw, halfh);
670     gl->uniform2f(mBorderSizeUniform, borderw, borderh);
671     gl->uniform1f(mDepthUniform, n->depth / 1e6);
672 
673     sm->setBlendEnabled(false);
674     sm->setCullFaceEnabled(false);
675     sm->setStencilTestEnabled(false);
676     sm->setScissorTestEnabled(false);
677     sm->setDepthTestEnabled(true);
678     sm->setColorMask(true, true, true, true);
679     sm->setDepthMask(true);
680     sm->setDepthRange(0, 1);
681     sm->setDepthFunc(GL_LESS);
682     sm->setViewport(gl::Rectangle(0, 0, mWidth, mHeight));
683     sm->activeTexture(0);
684     GLuint tex = buffer->getTexture();
685     sm->bindTexture(gl::TextureType::_2D, tex);
686     gl->vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
687     gl->enableVertexAttribArray(0);
688     GLuint fbo = mDrawing->createGLFB(context);
689     sm->bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
690     gl->drawArrays(GL_TRIANGLE_STRIP, 0, 4);
691     gl->drawElements(GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, 0);
692     sm->deleteTexture(tex);
693     sm->deleteFramebuffer(fbo);
694 }
695 
drawBuffer(const gl::Context * context,Buffer * buffer)696 void DisplayGbm::drawBuffer(const gl::Context *context, Buffer *buffer)
697 {
698     if (!mDrawing)
699     {
700         // get buffer on which to draw window
701         if (mUnused)
702         {
703             mDrawing = mUnused;
704             mUnused  = nullptr;
705         }
706         else
707         {
708             mDrawing = new Buffer(this, GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT,
709                                   GBM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888,
710                                   true, true);  // XXX shouldn't need stencil
711             if (!mDrawing || !mDrawing->initialize(mWidth, mHeight))
712             {
713                 return;
714             }
715         }
716 
717         const FunctionsGL *gl = getRenderer()->getFunctions();
718         StateManagerGL *sm    = getRenderer()->getStateManager();
719 
720         GLuint fbo = mDrawing->createGLFB(context);
721         sm->bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
722         sm->setClearColor(gl::ColorF(0, 0, 0, 1));
723         sm->setClearDepth(1);
724         sm->setScissorTestEnabled(false);
725         sm->setColorMask(true, true, true, true);
726         sm->setDepthMask(true);
727         gl->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
728         sm->deleteFramebuffer(fbo);
729     }
730 
731     drawWithTexture(context, buffer);
732     presentScreen();
733 }
734 
flushGL()735 void DisplayGbm::flushGL()
736 {
737     const FunctionsGL *gl = getRenderer()->getFunctions();
738     gl->flush();
739     if (getFunctionsEGL()->hasExtension("EGL_KHR_fence_sync"))
740     {
741         const EGLint attrib[] = {EGL_SYNC_CONDITION_KHR,
742                                  EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, EGL_NONE};
743         EGLSyncKHR fence      = getFunctionsEGL()->createSyncKHR(EGL_SYNC_FENCE_KHR, attrib);
744         if (fence)
745         {
746             // TODO(fjhenigman) Figure out the right way to use fences on Mali GPU
747             // to maximize throughput and avoid hangs when a program is interrupted.
748             // This busy wait was an attempt to reduce hangs when interrupted by SIGINT,
749             // but we still get some.
750             for (;;)
751             {
752                 EGLint r =
753                     getFunctionsEGL()->clientWaitSyncKHR(fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 0);
754                 if (r != EGL_TIMEOUT_EXPIRED_KHR)
755                 {
756                     break;
757                 }
758                 usleep(99);
759             }
760             getFunctionsEGL()->destroySyncKHR(fence);
761             return;
762         }
763     }
764 }
765 
terminate()766 void DisplayGbm::terminate()
767 {
768     SafeDelete(mScanning);
769     SafeDelete(mPending);
770     SafeDelete(mDrawing);
771     SafeDelete(mUnused);
772 
773     if (mProgram)
774     {
775         const FunctionsGL *gl = getRenderer()->getFunctions();
776         gl->deleteProgram(mProgram);
777         gl->deleteShader(mVertexShader);
778         gl->deleteShader(mFragmentShader);
779         gl->deleteBuffers(1, &mVertexBuffer);
780         gl->deleteBuffers(1, &mIndexBuffer);
781         mProgram = 0;
782     }
783 
784     DisplayEGL::terminate();
785 
786     drmModeFreeConnector(mConnector);
787     mConnector = nullptr;
788     mMode      = nullptr;
789     drmModeFreeCrtc(mCRTC);
790     mCRTC = nullptr;
791 
792     if (mGBM)
793     {
794         int fd = gbm_device_get_fd(mGBM);
795         gbm_device_destroy(mGBM);
796         mGBM = nullptr;
797         close(fd);
798     }
799 }
800 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)801 SurfaceImpl *DisplayGbm::createWindowSurface(const egl::SurfaceState &state,
802                                              EGLNativeWindowType window,
803                                              const egl::AttributeMap &attribs)
804 {
805     Buffer *buffer = new Buffer(this, GBM_BO_USE_RENDERING, GBM_FORMAT_ARGB8888,
806                                 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, true, true);
807     if (!buffer || !buffer->initialize(reinterpret_cast<const NativeWindow *>(window)))
808     {
809         return nullptr;
810     }
811     return new SurfaceGbm(state, buffer);
812 }
813 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)814 SurfaceImpl *DisplayGbm::createPbufferSurface(const egl::SurfaceState &state,
815                                               const egl::AttributeMap &attribs)
816 {
817     EGLAttrib width  = attribs.get(EGL_WIDTH, 0);
818     EGLAttrib height = attribs.get(EGL_HEIGHT, 0);
819     Buffer *buffer   = new Buffer(this, GBM_BO_USE_RENDERING, GBM_FORMAT_ARGB8888,
820                                 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, true, true);
821     if (!buffer || !buffer->initialize(static_cast<int>(width), static_cast<int>(height)))
822     {
823         return nullptr;
824     }
825     return new SurfaceGbm(state, buffer);
826 }
827 
isValidNativeWindow(EGLNativeWindowType window) const828 bool DisplayGbm::isValidNativeWindow(EGLNativeWindowType window) const
829 {
830     return true;
831 }
832 
setSwapInterval(EGLSurface drawable,SwapControlData * data)833 void DisplayGbm::setSwapInterval(EGLSurface drawable, SwapControlData *data)
834 {
835     ASSERT(data != nullptr);
836 }
837 
fixSurfaceType(EGLint surfaceType) const838 EGLint DisplayGbm::fixSurfaceType(EGLint surfaceType) const
839 {
840     EGLint type = DisplayEGL::fixSurfaceType(surfaceType);
841     // Ozone native surfaces don't support EGL_WINDOW_BIT,
842     // but ANGLE uses renderbuffers to emulate windows
843     return type | EGL_WINDOW_BIT;
844 }
845 
846 }  // namespace rx
847