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