40 ****************************************************************************/ |
40 ****************************************************************************/ |
41 |
41 |
42 #include <QtGui/qpaintdevice.h> |
42 #include <QtGui/qpaintdevice.h> |
43 #include <QtGui/qpixmap.h> |
43 #include <QtGui/qpixmap.h> |
44 #include <QtGui/qwidget.h> |
44 #include <QtGui/qwidget.h> |
|
45 #include <QtCore/qatomic.h> |
45 #include <QtCore/qdebug.h> |
46 #include <QtCore/qdebug.h> |
46 |
47 |
47 #include "qegl_p.h" |
48 #include "qegl_p.h" |
48 #include "qeglcontext_p.h" |
49 #include "qeglcontext_p.h" |
49 |
50 |
50 |
51 |
51 QT_BEGIN_NAMESPACE |
52 QT_BEGIN_NAMESPACE |
|
53 |
|
54 |
|
55 /* |
|
56 QEglContextTracker is used to track the EGL contexts that we |
|
57 create internally in Qt, so that we can call eglTerminate() to |
|
58 free additional EGL resources when the last context is destroyed. |
|
59 */ |
|
60 |
|
61 class QEglContextTracker |
|
62 { |
|
63 public: |
|
64 static void ref() { contexts.ref(); } |
|
65 static void deref() { |
|
66 if (!contexts.deref()) { |
|
67 eglTerminate(QEgl::display()); |
|
68 displayOpen = 0; |
|
69 } |
|
70 } |
|
71 static void setDisplayOpened() { displayOpen = 1; } |
|
72 static bool displayOpened() { return displayOpen; } |
|
73 |
|
74 private: |
|
75 static QBasicAtomicInt contexts; |
|
76 static QBasicAtomicInt displayOpen; |
|
77 }; |
|
78 |
|
79 QBasicAtomicInt QEglContextTracker::contexts = Q_BASIC_ATOMIC_INITIALIZER(0); |
|
80 QBasicAtomicInt QEglContextTracker::displayOpen = Q_BASIC_ATOMIC_INITIALIZER(0); |
52 |
81 |
53 // Current GL and VG contexts. These are used to determine if |
82 // Current GL and VG contexts. These are used to determine if |
54 // we can avoid an eglMakeCurrent() after a call to lazyDoneCurrent(). |
83 // we can avoid an eglMakeCurrent() after a call to lazyDoneCurrent(). |
55 // If a background thread modifies the value, the worst that will |
84 // If a background thread modifies the value, the worst that will |
56 // happen is a redundant eglMakeCurrent() in the foreground thread. |
85 // happen is a redundant eglMakeCurrent() in the foreground thread. |
64 , currentSurface(EGL_NO_SURFACE) |
93 , currentSurface(EGL_NO_SURFACE) |
65 , current(false) |
94 , current(false) |
66 , ownsContext(true) |
95 , ownsContext(true) |
67 , sharing(false) |
96 , sharing(false) |
68 { |
97 { |
|
98 QEglContextTracker::ref(); |
69 } |
99 } |
70 |
100 |
71 QEglContext::~QEglContext() |
101 QEglContext::~QEglContext() |
72 { |
102 { |
73 destroyContext(); |
103 destroyContext(); |
74 |
104 |
75 if (currentGLContext == this) |
105 if (currentGLContext == this) |
76 currentGLContext = 0; |
106 currentGLContext = 0; |
77 if (currentVGContext == this) |
107 if (currentVGContext == this) |
78 currentVGContext = 0; |
108 currentVGContext = 0; |
|
109 QEglContextTracker::deref(); |
79 } |
110 } |
80 |
111 |
81 bool QEglContext::isValid() const |
112 bool QEglContext::isValid() const |
82 { |
113 { |
83 return (ctx != EGL_NO_CONTEXT); |
114 return (ctx != EGL_NO_CONTEXT); |
482 if (!ok) |
513 if (!ok) |
483 qWarning() << "QEglContext::swapBuffers():" << QEgl::errorString(); |
514 qWarning() << "QEglContext::swapBuffers():" << QEgl::errorString(); |
484 return ok; |
515 return ok; |
485 } |
516 } |
486 |
517 |
|
518 bool QEglContext::swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region) { |
|
519 QVector<QRect> qrects = region->rects(); |
|
520 EGLint *gl_rects; |
|
521 uint count; |
|
522 uint i; |
|
523 |
|
524 count = qrects.size(); |
|
525 QVarLengthArray <EGLint> arr(4 * count); |
|
526 gl_rects = arr.data(); |
|
527 for (i = 0; i < count; i++) { |
|
528 QRect qrect = qrects[i]; |
|
529 |
|
530 gl_rects[4 * i + 0] = qrect.x(); |
|
531 gl_rects[4 * i + 1] = qrect.y(); |
|
532 gl_rects[4 * i + 2] = qrect.width(); |
|
533 gl_rects[4 * i + 3] = qrect.height(); |
|
534 } |
|
535 |
|
536 bool ok = QEgl::eglSwapBuffersRegion2NOK(QEgl::display(), surface, count, gl_rects); |
|
537 |
|
538 if (!ok) |
|
539 qWarning() << "QEglContext::swapBuffersRegion2NOK():" << QEgl::errorString(); |
|
540 return ok; |
|
541 } |
|
542 |
487 int QEglContext::configAttrib(int name) const |
543 int QEglContext::configAttrib(int name) const |
488 { |
544 { |
489 EGLint value; |
545 EGLint value; |
490 EGLBoolean success = eglGetConfigAttrib(QEgl::display(), cfg, name, &value); |
546 EGLBoolean success = eglGetConfigAttrib(QEgl::display(), cfg, name, &value); |
491 if (success) |
547 if (success) |
499 |
555 |
500 // Defined in qegl.cpp: |
556 // Defined in qegl.cpp: |
501 static _eglCreateImageKHR qt_eglCreateImageKHR = 0; |
557 static _eglCreateImageKHR qt_eglCreateImageKHR = 0; |
502 static _eglDestroyImageKHR qt_eglDestroyImageKHR = 0; |
558 static _eglDestroyImageKHR qt_eglDestroyImageKHR = 0; |
503 |
559 |
|
560 typedef EGLBoolean (EGLAPIENTRY *_eglSwapBuffersRegion2NOK)(EGLDisplay, EGLSurface, EGLint, const EGLint*); |
|
561 |
|
562 static _eglSwapBuffersRegion2NOK qt_eglSwapBuffersRegion2NOK = 0; |
504 |
563 |
505 EGLDisplay QEgl::display() |
564 EGLDisplay QEgl::display() |
506 { |
565 { |
507 static EGLDisplay dpy = EGL_NO_DISPLAY; |
566 static EGLDisplay dpy = EGL_NO_DISPLAY; |
508 static bool openedDisplay = false; |
567 if (!QEglContextTracker::displayOpened()) { |
509 |
|
510 if (!openedDisplay) { |
|
511 dpy = eglGetDisplay(nativeDisplay()); |
568 dpy = eglGetDisplay(nativeDisplay()); |
512 openedDisplay = true; |
569 QEglContextTracker::setDisplayOpened(); |
513 if (dpy == EGL_NO_DISPLAY) { |
570 if (dpy == EGL_NO_DISPLAY) { |
514 qWarning("QEgl::display(): Falling back to EGL_DEFAULT_DISPLAY"); |
571 qWarning("QEgl::display(): Falling back to EGL_DEFAULT_DISPLAY"); |
515 dpy = eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); |
572 dpy = eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); |
516 } |
573 } |
517 if (dpy == EGL_NO_DISPLAY) { |
574 if (dpy == EGL_NO_DISPLAY) { |
529 if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_base")) { |
586 if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_base")) { |
530 qt_eglCreateImageKHR = (_eglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); |
587 qt_eglCreateImageKHR = (_eglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); |
531 qt_eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); |
588 qt_eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); |
532 } |
589 } |
533 #endif |
590 #endif |
|
591 |
|
592 if (QEgl::hasExtension("EGL_NOK_swap_region2")) { |
|
593 qt_eglSwapBuffersRegion2NOK = (_eglSwapBuffersRegion2NOK) eglGetProcAddress("eglSwapBuffersRegion2NOK"); |
|
594 } |
534 } |
595 } |
535 |
596 |
536 return dpy; |
597 return dpy; |
537 } |
598 } |
538 |
599 |
560 |
621 |
561 qWarning("QEgl::eglDestroyImageKHR() called but EGL_KHR_image(_base) extension not present"); |
622 qWarning("QEgl::eglDestroyImageKHR() called but EGL_KHR_image(_base) extension not present"); |
562 return 0; |
623 return 0; |
563 } |
624 } |
564 |
625 |
|
626 EGLBoolean QEgl::eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects) |
|
627 { |
|
628 if (qt_eglSwapBuffersRegion2NOK) |
|
629 return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects); |
|
630 |
|
631 QEgl::display(); // Initialises function pointers |
|
632 if (qt_eglSwapBuffersRegion2NOK) |
|
633 return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects); |
|
634 |
|
635 qWarning("QEgl::eglSwapBuffersRegion2NOK() called but EGL_NOK_swap_region2 extension not present"); |
|
636 return 0; |
|
637 } |
565 |
638 |
566 #ifndef Q_WS_X11 |
639 #ifndef Q_WS_X11 |
567 EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties) |
640 EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties) |
568 { |
641 { |
569 // Create the native drawable for the paint device. |
642 // Create the native drawable for the paint device. |