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