From dbb2581af5cd1e891cb4202ff8a8caa68cd74b6a Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 16 Oct 2012 07:20:23 +0300 Subject: Remove Qt3 compat leftovers Change-Id: I91c3d26125168998d6279bddb0671cfb68eac2f4 Reviewed-by: Lars Knoll --- src/gui/text/qtextengine_p.h | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index bef461f448..82467229eb 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -540,24 +540,14 @@ public: int findItem(int strPos) const; inline QTextFormatCollection *formats() const { -#ifdef QT_BUILD_COMPAT_LIB - return 0; // Compat should never reference this symbol -#else if (block.docHandle()) return block.docHandle()->formatCollection(); - else if (specialData) - return specialData->formats.data(); - - return 0; -#endif + return specialData ? specialData->formats.data() : 0; } QTextCharFormat format(const QScriptItem *si) const; inline QAbstractTextDocumentLayout *docLayout() const { -#ifdef QT_BUILD_COMPAT_LIB - return 0; // Compat should never reference this symbol -#else + Q_ASSERT(block.docHandle()); return block.docHandle()->document()->documentLayout(); -#endif } int formatIndex(const QScriptItem *si) const; -- cgit v1.2.3 From bdc0eaae6b47eebbf99bea1034857287fb75aa46 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 18 Oct 2012 14:15:38 +0300 Subject: Fix excess enter/leave event generation for native widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Native widgets have a native window each, so QPA plugin sends enter and leave events for associated QWindow whenever mouse cursor moves from one widget to another. QWidgetWindow had no context to interpret these events as moves from one widget to another, since they were sent separately. This resulted in leaves and enters for each widget in parent chain, when only the bottom child should have gotten them. Fixed by peeking into window system message queue when handling leave in QWidgetWindow and retrieving the entered window from queued enter event. Also provided a convenience function that QPA plugin can use to ensure both leave and enter events are in the event queue when moving from one QWindow to another. Task-number: QTBUG-27550 Change-Id: I74fec0ac90f6848495c2392c5f7e41624ad8aea2 Reviewed-by: Morten Johan Sørvig Reviewed-by: Samuel Rødal --- src/gui/kernel/qwindowsysteminterface.cpp | 30 ++++++++++++++++++++++++++++++ src/gui/kernel/qwindowsysteminterface.h | 1 + src/gui/kernel/qwindowsysteminterface_p.h | 25 +++++++++++++++++++++++-- src/widgets/kernel/qwidgetwindow.cpp | 27 +++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index d05dc8cbdc..82e0e44ac7 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -89,6 +89,26 @@ void QWindowSystemInterface::handleLeaveEvent(QWindow *tlw) QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } +/*! + This method can be used to ensure leave and enter events are both in queue when moving from + one QWindow to another. This allows QWindow subclasses to check for a queued enter event + when handling the leave event (\c QWindowSystemInterfacePrivate::peekWindowSystemEvent) to + determine where mouse went and act accordingly. E.g. QWidgetWindow needs to know if mouse + cursor moves between windows in same window hierarchy. +*/ +void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leave) +{ + bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowsSystemEvents; + if (wasSynchronous) + setSynchronousWindowsSystemEvents(false); + handleLeaveEvent(leave); + handleEnterEvent(enter); + if (wasSynchronous) { + flushWindowSystemEvents(); + setSynchronousWindowsSystemEvents(true); + } +} + void QWindowSystemInterface::handleWindowActivated(QWindow *tlw) { QWindowSystemInterfacePrivate::ActivatedWindowEvent *e = new QWindowSystemInterfacePrivate::ActivatedWindowEvent(tlw); @@ -324,6 +344,16 @@ QWindowSystemInterfacePrivate::WindowSystemEvent * QWindowSystemInterfacePrivate return windowSystemEventQueue.takeFirstOrReturnNull(); } +QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::peekWindowSystemEvent(EventType t) +{ + return windowSystemEventQueue.peekAtFirstOfType(t); +} + +void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *event) +{ + windowSystemEventQueue.remove(event); +} + void QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev) { if (synchronousWindowsSystemEvents) { diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index cf5d22edbd..74b5a136f4 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -136,6 +136,7 @@ public: static void handleCloseEvent(QWindow *w); static void handleEnterEvent(QWindow *w); static void handleLeaveEvent(QWindow *w); + static void handleEnterLeaveEvent(QWindow *enter, QWindow *leave); static void handleWindowActivated(QWindow *w); static void handleWindowStateChanged(QWindow *w, Qt::WindowState newState); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index e9d2fadc84..4e907f3f51 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -52,7 +52,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QWindowSystemInterfacePrivate { +class Q_GUI_EXPORT QWindowSystemInterfacePrivate { public: enum EventType { Close, @@ -349,6 +349,25 @@ public: { const QMutexLocker locker(&mutex); impl.append(e); } int count() const { const QMutexLocker locker(&mutex); return impl.count(); } + WindowSystemEvent *peekAtFirstOfType(EventType t) const + { + const QMutexLocker locker(&mutex); + for (int i = 0; i < impl.size(); ++i) { + if (impl.at(i)->type == t) + return impl.at(i); + } + return 0; + } + void remove(const WindowSystemEvent *e) + { + const QMutexLocker locker(&mutex); + for (int i = 0; i < impl.size(); ++i) { + if (impl.at(i) == e) { + impl.removeAt(i); + break; + } + } + } private: Q_DISABLE_COPY(WindowSystemEventList); }; @@ -356,7 +375,9 @@ public: static WindowSystemEventList windowSystemEventQueue; static int windowSystemEventsQueued(); - static WindowSystemEvent * getWindowSystemEvent(); + static WindowSystemEvent *getWindowSystemEvent(); + static WindowSystemEvent *peekWindowSystemEvent(EventType t); + static void removeWindowSystemEvent(WindowSystemEvent *event); static void handleWindowSystemEvent(WindowSystemEvent *ev); static QElapsedTimer eventTime; diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 10ec4d3745..5f25e1274e 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -47,6 +47,7 @@ #include #endif #include +#include QT_BEGIN_NAMESPACE @@ -212,9 +213,31 @@ QPointer qt_last_mouse_receiver = 0; void QWidgetWindow::handleEnterLeaveEvent(QEvent *event) { if (event->type() == QEvent::Leave) { + QWidget *enter = 0; + // Check from window system event queue if the next queued enter targets a window + // in the same window hierarchy (e.g. enter a child of this window). If so, + // remove the enter event from queue and handle both in single dispatch. + QWindowSystemInterfacePrivate::EnterEvent *systemEvent = + static_cast + (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::Enter)); + if (systemEvent) { + if (QWidgetWindow *enterWindow = qobject_cast(systemEvent->enter)) + { + QWindow *thisParent = this; + QWindow *enterParent = enterWindow; + while (thisParent->parent()) + thisParent = thisParent->parent(); + while (enterParent->parent()) + enterParent = enterParent->parent(); + if (thisParent == enterParent) { + enter = enterWindow->widget(); + QWindowSystemInterfacePrivate::removeWindowSystemEvent(systemEvent); + } + } + } QWidget *leave = qt_last_mouse_receiver ? qt_last_mouse_receiver.data() : m_widget; - QApplicationPrivate::dispatchEnterLeave(0, leave); - qt_last_mouse_receiver = 0; + QApplicationPrivate::dispatchEnterLeave(enter, leave); + qt_last_mouse_receiver = enter; } else { QApplicationPrivate::dispatchEnterLeave(m_widget, 0); qt_last_mouse_receiver = m_widget; -- cgit v1.2.3 From 1e68ec7e6756baa62353ad9f017b48bf031a7354 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 3 Sep 2012 11:38:00 +0200 Subject: remove explicit load(qt_build_config)s from the libraries .qmake.conf (and previously .qmake.cache) already does that for us. Change-Id: I06cc01fa45921d7bd66dda7a0f88729faeff37bd Reviewed-by: Joerg Bornemann --- src/concurrent/concurrent.pro | 2 -- src/corelib/corelib.pro | 2 -- src/dbus/dbus.pro | 2 -- src/gui/gui.pro | 2 -- src/network/network.pro | 2 -- src/opengl/opengl.pro | 2 -- src/platformsupport/platformsupport.pro | 1 - src/printsupport/printsupport.pro | 2 -- src/sql/sql.pro | 2 -- src/testlib/testlib.pro | 2 -- src/widgets/widgets.pro | 2 -- src/winmain/winmain.pro | 2 -- src/xml/xml.pro | 2 -- 13 files changed, 25 deletions(-) (limited to 'src') diff --git a/src/concurrent/concurrent.pro b/src/concurrent/concurrent.pro index cfa76ff130..375de00344 100644 --- a/src/concurrent/concurrent.pro +++ b/src/concurrent/concurrent.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtConcurrent QT = core-private CONFIG += exceptions diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index b83b2bac1e..ba9488cbff 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtCore QT = CONFIG += exceptions diff --git a/src/dbus/dbus.pro b/src/dbus/dbus.pro index 1793871de6..5ad77ddf95 100644 --- a/src/dbus/dbus.pro +++ b/src/dbus/dbus.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtDBus QT = core-private CONFIG += link_pkgconfig diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 8b7bb13a26..301d704e2e 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtGui QT = core-private MODULE_CONFIG = opengl diff --git a/src/network/network.pro b/src/network/network.pro index 09791d7f6d..d2b2447611 100644 --- a/src/network/network.pro +++ b/src/network/network.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtNetwork QT = core-private diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index dfc342c5dd..57892c7300 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtOpenGL QT = core-private gui-private widgets-private diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 5cb883355b..57d9b422f4 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -1,4 +1,3 @@ -load(qt_build_config) TARGET = QtPlatformSupport QT = core-private gui-private diff --git a/src/printsupport/printsupport.pro b/src/printsupport/printsupport.pro index bc8b3936ce..ee4f9f72df 100644 --- a/src/printsupport/printsupport.pro +++ b/src/printsupport/printsupport.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtPrintSupport QT = core-private gui-private widgets-private diff --git a/src/sql/sql.pro b/src/sql/sql.pro index 42d3364192..4f5af51c52 100644 --- a/src/sql/sql.pro +++ b/src/sql/sql.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtSql QT = core-private diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index c14f6e0687..06d7612185 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtTest QT = core-private CONFIG += exceptions diff --git a/src/widgets/widgets.pro b/src/widgets/widgets.pro index f294934269..f8f00af69b 100644 --- a/src/widgets/widgets.pro +++ b/src/widgets/widgets.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtWidgets QT = core-private gui-private MODULE_CONFIG = uic diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro index 0fa4dca8d7..843a15989e 100644 --- a/src/winmain/winmain.pro +++ b/src/winmain/winmain.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - # Additional Qt project file for qtmain lib on Windows !win32:error("$$_FILE_ is intended only for Windows!") diff --git a/src/xml/xml.pro b/src/xml/xml.pro index 80fe3a9ba2..c4b8b5b229 100644 --- a/src/xml/xml.pro +++ b/src/xml/xml.pro @@ -1,5 +1,3 @@ -load(qt_build_config) - TARGET = QtXml QT = core-private -- cgit v1.2.3 From b206fba8b1f6c8b03c7d23bccdaf0888727ce6b6 Mon Sep 17 00:00:00 2001 From: Jerome Pasion Date: Thu, 18 Oct 2012 15:15:04 +0200 Subject: Doc: Adding Event System documentation. Previously in qtdoc repository. Change-Id: I9f5cc876f2b49e86520097c0d8efe7e21eabc04e Reviewed-by: Martin Smith --- .../doc/snippets/eventfilters/filterobject.cpp | 74 +++++++ .../doc/snippets/eventfilters/filterobject.h | 59 ++++++ src/corelib/doc/snippets/eventfilters/main.cpp | 54 +++++ src/corelib/doc/snippets/events/events.cpp | 97 +++++++++ src/corelib/doc/src/eventsandfilters.qdoc | 220 +++++++++++++++++++++ 5 files changed, 504 insertions(+) create mode 100644 src/corelib/doc/snippets/eventfilters/filterobject.cpp create mode 100644 src/corelib/doc/snippets/eventfilters/filterobject.h create mode 100644 src/corelib/doc/snippets/eventfilters/main.cpp create mode 100644 src/corelib/doc/snippets/events/events.cpp create mode 100644 src/corelib/doc/src/eventsandfilters.qdoc (limited to 'src') diff --git a/src/corelib/doc/snippets/eventfilters/filterobject.cpp b/src/corelib/doc/snippets/eventfilters/filterobject.cpp new file mode 100644 index 0000000000..81591f4f3d --- /dev/null +++ b/src/corelib/doc/snippets/eventfilters/filterobject.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "filterobject.h" + +FilterObject::FilterObject(QObject *parent) + : QObject(parent), target(0) +{ +} + +//! [0] +bool FilterObject::eventFilter(QObject *object, QEvent *event) +{ + if (object == target && event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Tab) { + // Special tab handling + return true; + } else + return false; + } + return false; +} +//! [0] + +void FilterObject::setFilteredObject(QObject *object) +{ + if (target) + target->removeEventFilter(this); + + target = object; + + if (target) + target->installEventFilter(this); +} diff --git a/src/corelib/doc/snippets/eventfilters/filterobject.h b/src/corelib/doc/snippets/eventfilters/filterobject.h new file mode 100644 index 0000000000..8c9d2e72cd --- /dev/null +++ b/src/corelib/doc/snippets/eventfilters/filterobject.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FILTEROBJECT_H +#define FILTEROBJECT_H + +#include + +class FilterObject : public QObject +{ + Q_OBJECT + +public: + FilterObject(QObject *parent = 0); + bool eventFilter(QObject *object, QEvent *event); + void setFilteredObject(QObject *object); + +private: + QObject *target; +}; + +#endif diff --git a/src/corelib/doc/snippets/eventfilters/main.cpp b/src/corelib/doc/snippets/eventfilters/main.cpp new file mode 100644 index 0000000000..7f6bde4987 --- /dev/null +++ b/src/corelib/doc/snippets/eventfilters/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "filterobject.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QTextEdit editor; + FilterObject filter; + filter.setFilteredObject(&editor); + editor.show(); + return app.exec(); +} diff --git a/src/corelib/doc/snippets/events/events.cpp b/src/corelib/doc/snippets/events/events.cpp new file mode 100644 index 0000000000..a3a95d6935 --- /dev/null +++ b/src/corelib/doc/snippets/events/events.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +class MyCheckBox : public QCheckBox +{ +public: + void mousePressEvent(QMouseEvent *event); +}; + +//! [0] +void MyCheckBox::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + // handle left mouse button here + } else { + // pass on other buttons to base class + QCheckBox::mousePressEvent(event); + } +} +//! [0] + +class MyWidget : public QWidget +{ +public: + bool event(QEvent *event); +}; + +static const int MyCustomEventType = 1099; + +class MyCustomEvent : public QEvent +{ +public: + MyCustomEvent() : QEvent((QEvent::Type)MyCustomEventType) {} +}; + +//! [1] +bool MyWidget::event(QEvent *event) +{ + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_Tab) { + // special tab handling here + return true; + } + } else if (event->type() == MyCustomEventType) { + MyCustomEvent *myEvent = static_cast(event); + // custom event handling here + return true; + } + + return QWidget::event(event); +} +//! [1] + +int main() +{ +} diff --git a/src/corelib/doc/src/eventsandfilters.qdoc b/src/corelib/doc/src/eventsandfilters.qdoc new file mode 100644 index 0000000000..5fe444538d --- /dev/null +++ b/src/corelib/doc/src/eventsandfilters.qdoc @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \group events + \title Event Classes + \ingroup groups + + \brief Classes used to create and handle events. + + These classes are used to create and handle events. + + For more information see the \link object.html Object model\endlink + and \link signalsandslots.html Signals and Slots\endlink. +*/ + +/*! + \page eventsandfilters.html + \title The Event System + \ingroup qt-basic-concepts + \brief A guide to event handling in Qt. + + \ingroup frameworks-technologies + + In Qt, events are objects, derived from the abstract QEvent class, + that represent things that have happened either within an application + or as a result of outside activity that the application needs to know + about. Events can be received and handled by any instance of a + QObject subclass, but they are especially relevant to widgets. This + document describes how events are delivered and handled in a typical + application. + + \section1 How Events are Delivered + + When an event occurs, Qt creates an event object to represent it by + constructing an instance of the appropriate QEvent subclass, and + delivers it to a particular instance of QObject (or one of its + subclasses) by calling its \l{QObject::}{event()} function. + + This function does not handle the event itself; based on the type + of event delivered, it calls an event handler for that specific + type of event, and sends a response based on whether the event + was accepted or ignored. + + \omit + Event delivery means that an + event has occurred, the QEvent indicates precisely what, and the + QObject needs to respond. Most events are specific to QWidget and its + subclasses, but there are important events that aren't related to + graphics (e.g., \l{QTimer}{timer events}). + \endomit + + Some events, such as QMouseEvent and QKeyEvent, come from the + window system; some, such as QTimerEvent, come from other sources; + some come from the application itself. + + \section1 Event Types + + Most events types have special classes, notably QResizeEvent, + QPaintEvent, QMouseEvent, QKeyEvent, and QCloseEvent. Each class + subclasses QEvent and adds event-specific functions. For example, + QResizeEvent adds \l{QResizeEvent::}{size()} and + \l{QResizeEvent::}{oldSize()} to enable widgets to discover how + their dimensions have been changed. + + Some classes support more than one actual event type. QMouseEvent + supports mouse button presses, double-clicks, moves, and other + related operations. + + Each event has an associated type, defined in QEvent::Type, and this + can be used as a convenient source of run-time type information to + quickly determine which subclass a given event object was constructed + from. + + Since programs need to react in varied and complex ways, Qt's + event delivery mechanisms are flexible. The documentation for + QCoreApplication::notify() concisely tells the whole story; the + \e{Qt Quarterly} article + \l{http://doc.qt.nokia.com/qq/qq11-events.html}{Another Look at Events} + rehashes it less concisely. Here we will explain enough for 95% + of applications. + + \section1 Event Handlers + + The normal way for an event to be delivered is by calling a virtual + function. For example, QPaintEvent is delivered by calling + QWidget::paintEvent(). This virtual function is responsible for + reacting appropriately, normally by repainting the widget. If you + do not perform all the necessary work in your implementation of the + virtual function, you may need to call the base class's implementation. + + For example, the following code handles left mouse button clicks on + a custom checkbox widget while passing all other button clicks to the + base QCheckBox class: + + \snippet events/events.cpp 0 + + If you want to replace the base class's function, you must + implement everything yourself. However, if you only want to extend + the base class's functionality, then you implement what you want and + call the base class to obtain the default behavior for any cases you + do not want to handle. + + Occasionally, there isn't such an event-specific function, or the + event-specific function isn't sufficient. The most common example + involves Tab key presses. Normally, QWidget intercepts these to + move the keyboard focus, but a few widgets need the Tab key for + themselves. + + These objects can reimplement QObject::event(), the general event + handler, and either do their event handling before or after the usual + handling, or they can replace the function completely. A very unusual + widget that both interprets Tab and has an application-specific + custom event might contain the following \l{QObject::event()}{event()} + function: + + \snippet events/events.cpp 1 + + Note that QWidget::event() is still called for all of the cases not + handled, and that the return value indicates whether an event was + dealt with; a \c true value prevents the event from being sent on + to other objects. + + \section1 Event Filters + + Sometimes an object needs to look at, and possibly intercept, the + events that are delivered to another object. For example, dialogs + commonly want to filter key presses for some widgets; for example, + to modify Return-key handling. + + The QObject::installEventFilter() function enables this by setting + up an \e{event filter}, causing a nominated filter object to receive + the events for a target object in its QObject::eventFilter() + function. An event filter gets to process events before the target + object does, allowing it to inspect and discard the events as + required. An existing event filter can be removed using the + QObject::removeEventFilter() function. + + When the filter object's \l{QObject::}{eventFilter()} implementation + is called, it can accept or reject the event, and allow or deny + further processing of the event. If all the event filters allow + further processing of an event (by each returning \c false), the event + is sent to the target object itself. If one of them stops processing + (by returning \c true), the target and any later event filters do not + get to see the event at all. + + \snippet eventfilters/filterobject.cpp 0 + + The above code shows another way to intercept Tab key press + events sent to a particular target widget. In this case, the filter + handles the relevant events and returns \c true to stop them from + being processed any further. All other events are ignored, and the + filter returns \c false to allow them to be sent on to the target + widget, via any other event filters that are installed on it. + + It is also possible to filter \e all events for the entire application, + by installing an event filter on the QApplication or QCoreApplication + object. Such global event filters are called before the object-specific + filters. This is very powerful, but it also slows down event delivery + of every single event in the entire application; the other techniques + discussed should generally be used instead. + + \section1 Sending Events + + Many applications want to create and send their own events. You can + send events in exactly the same ways as Qt's own event loop by + constructing suitable event objects and sending them with + QCoreApplication::sendEvent() and QCoreApplication::postEvent(). + + \l{QCoreApplication::}{sendEvent()} processes the event immediately. + When it returns, the event filters and/or the object itself have + already processed the event. For many event classes there is a function + called isAccepted() that tells you whether the event was accepted + or rejected by the last handler that was called. + + \l{QCoreApplication::}{postEvent()} posts the event on a queue for + later dispatch. The next time Qt's main event loop runs, it dispatches + all posted events, with some optimization. For example, if there are + several resize events, they are compressed into one. The same + applies to paint events: QWidget::update() calls + \l{QCoreApplication::}{postEvent()}, which eliminates flickering and + increases speed by avoiding multiple repaints. + + \l{QCoreApplication::}{postEvent()} is also used during object + initialization, since the posted event will typically be dispatched + very soon after the initialization of the object is complete. + When implementing a widget, it is important to realise that events + can be delivered very early in its lifetime so, in its constructor, + be sure to initialize member variables early on, before there's any + chance that it might receive an event. + + To create events of a custom type, you need to define an event + number, which must be greater than QEvent::User, and you may need to + subclass QEvent in order to pass specific information about your + custom event. See the QEvent documentation for further details. +*/ -- cgit v1.2.3 From 391d2e37f3b301097cd23fdaf99dc34ed6a114a5 Mon Sep 17 00:00:00 2001 From: Thomas McGuire Date: Wed, 26 Sep 2012 17:57:14 +0200 Subject: QNX: Use extra information in dirent to avoid stat() calls This improves iterating over /usr/bin with QDirIterator by more than half, from 36 to 13 milliseconds. Change-Id: Ib3a9271c3a6f81c1ea3c21d012c875c7e9bad2ad Reviewed-by: Giuseppe D'Angelo Reviewed-by: Kevin Krammer Reviewed-by: Sean Harmer Reviewed-by: Rafael Roquetto Reviewed-by: Stephen Kelly --- src/corelib/io/qfilesystemengine.cpp | 49 ++++++++++++++++++++++++++++- src/corelib/io/qfilesystemiterator_p.h | 4 +++ src/corelib/io/qfilesystemiterator_unix.cpp | 18 ++++++++++- 3 files changed, 69 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp index 74ceeb11c1..fe06210fb9 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -224,6 +224,19 @@ bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) return false; } +#if defined(Q_OS_QNX) +static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32) +{ + statBuf64->st_mode = statBuf32.st_mode; + statBuf64->st_size = statBuf32.st_size; + statBuf64->st_ctime = statBuf32.st_ctime; + statBuf64->st_mtime = statBuf32.st_mtime; + statBuf64->st_atime = statBuf32.st_atime; + statBuf64->st_uid = statBuf32.st_uid; + statBuf64->st_gid = statBuf32.st_gid; +} +#endif + void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer) { // Permissions @@ -277,7 +290,41 @@ void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer) void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry) { -#if defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4) +#if defined(Q_OS_QNX) + knownFlagsMask = 0; + entryFlags = 0; + for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry); + extra = _DEXTRA_NEXT(extra)) { + if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) { + + const struct dirent_extra_stat * const extra_stat = + reinterpret_cast(extra); + + // For symlinks, the extra type _DTYPE_LSTAT doesn't work for filling out the meta data, + // as we need the stat() information there, not the lstat() information. + // In this case, don't use the extra information. + // Unfortunately, readdir() never seems to return extra info of type _DTYPE_STAT, so for + // symlinks, we always incur the cost of an extra stat() call later. + if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT) + continue; + +#if defined(__EXT_LF64SRC) + // Even with large file support, d_stat is always of type struct stat, not struct stat64, + // so it needs to be converted + struct stat64 statBuf; + fillStat64fromStat32(&statBuf, extra_stat->d_stat); + fillFromStatBuf(statBuf); +#else + fillFromStatBuf(extra_stat->d_stat); +#endif + knownFlagsMask |= QFileSystemMetaData::PosixStatFlags; + if (!S_ISLNK(extra_stat->d_stat.st_mode)) { + knownFlagsMask |= QFileSystemMetaData::ExistsAttribute; + entryFlags |= QFileSystemMetaData::ExistsAttribute; + } + } + } +#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4) // BSD4 includes Mac OS X // ### This will clear all entry flags and knownFlagsMask diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h index 87395ec2cf..a68615ca05 100644 --- a/src/corelib/io/qfilesystemiterator_p.h +++ b/src/corelib/io/qfilesystemiterator_p.h @@ -98,6 +98,10 @@ private: #if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) // for readdir_r QScopedPointer mt_file; +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + // for _readdir_r + size_t direntSize; +#endif #endif int lastError; #endif diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp index 9ab186d119..28f5e36bb8 100644 --- a/src/corelib/io/qfilesystemiterator_unix.cpp +++ b/src/corelib/io/qfilesystemiterator_unix.cpp @@ -54,6 +54,9 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi : nativePath(entry.nativeFilePath()) , dir(0) , dirEntry(0) +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + , direntSize(0) +#endif , lastError(0) { Q_UNUSED(filters) @@ -78,6 +81,15 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi Q_CHECK_PTR(p); mt_file.reset(p); +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + direntSize = maxPathName; + + // Include extra stat information in the readdir() call (d_stat member of dirent_extra_stat). + // This is used in QFileSystemMetaData::fillFromDirEnt() to avoid extra stat() calls when iterating + // over directories + if (dircntl(dir, D_SETFLAG, D_FLAG_STAT) == -1) + lastError = errno; +#endif #endif } } @@ -93,7 +105,11 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa if (!dir) return false; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) + lastError = _readdir_r(dir, mt_file.data(), &dirEntry, direntSize); + if (lastError) + return false; +#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) lastError = QT_READDIR_R(dir, mt_file.data(), &dirEntry); if (lastError) return false; -- cgit v1.2.3 From 59009cfd0c0ac36bab5864c2a48dfc052ea29191 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 19 Oct 2012 14:34:37 +0200 Subject: QStyleSheetStyle: kill more dependencies to QWidget Change-Id: I5e58ec68c5d20fd7b201c83743f9d284e7c4dc52 Reviewed-by: J-P Nurmi Reviewed-by: Jens Bache-Wiig --- src/widgets/styles/qstylesheetstyle.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 857750b466..4abedb07c8 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -1408,7 +1408,7 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const Q /////////////////////////////////////////////////////////////////////////////// // Style rules -#define WIDGET(x) (static_cast(x.ptr)) +#define OBJECT_PTR(x) (static_cast(x.ptr)) static inline QObject *parentObject(const QObject *obj) { @@ -1429,7 +1429,7 @@ public: { if (isNullNode(node)) return QStringList(); - const QMetaObject *metaObject = WIDGET(node)->metaObject(); + const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject(); #ifndef QT_NO_TOOLTIP if (qstrcmp(metaObject->className(), "QTipLabel") == 0) return QStringList(QLatin1String("QToolTip")); @@ -1446,21 +1446,23 @@ public: if (isNullNode(node)) return QString(); - QHash &cache = m_attributeCache[WIDGET(node)]; + QHash &cache = m_attributeCache[OBJECT_PTR(node)]; QHash::const_iterator cacheIt = cache.constFind(name); if (cacheIt != cache.constEnd()) return cacheIt.value(); - QVariant value = WIDGET(node)->property(name.toLatin1()); + QObject *obj = OBJECT_PTR(node); + QVariant value = obj->property(name.toLatin1()); if (!value.isValid()) { if (name == QLatin1String("class")) { - QString className = QString::fromLatin1(WIDGET(node)->metaObject()->className()); + QString className = QString::fromLatin1(obj->metaObject()->className()); if (className.contains(QLatin1Char(':'))) className.replace(QLatin1Char(':'), QLatin1Char('-')); cache[name] = className; return className; } else if (name == QLatin1String("style")) { - QStyleSheetStyle *proxy = qobject_cast(WIDGET(node)->style()); + QWidget *w = qobject_cast(obj); + QStyleSheetStyle *proxy = w ? qobject_cast(w->style()) : 0; if (proxy) { QString styleName = QString::fromLatin1(proxy->baseStyle()->metaObject()->className()); cache[name] = styleName; @@ -1480,7 +1482,7 @@ public: { if (isNullNode(node)) return false; - const QMetaObject *metaObject = WIDGET(node)->metaObject(); + const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject(); #ifndef QT_NO_TOOLTIP if (qstrcmp(metaObject->className(), "QTipLabel") == 0) return nodeName == QLatin1String("QToolTip"); @@ -1502,11 +1504,11 @@ public: bool hasAttributes(NodePtr) const { return true; } QStringList nodeIds(NodePtr node) const - { return isNullNode(node) ? QStringList() : QStringList(WIDGET(node)->objectName()); } + { return isNullNode(node) ? QStringList() : QStringList(OBJECT_PTR(node)->objectName()); } bool isNullNode(NodePtr node) const { return node.ptr == 0; } NodePtr parentNode(NodePtr node) const - { NodePtr n; n.ptr = isNullNode(node) ? 0 : parentObject(WIDGET(node)); return n; } + { NodePtr n; n.ptr = isNullNode(node) ? 0 : parentObject(OBJECT_PTR(node)); return n; } NodePtr previousSiblingNode(NodePtr) const { NodePtr n; n.ptr = 0; return n; } NodePtr duplicateNode(NodePtr node) const @@ -1515,7 +1517,7 @@ public: { } private: - mutable QHash > m_attributeCache; + mutable QHash > m_attributeCache; }; QVector QStyleSheetStyle::styleRules(const QObject *obj) const -- cgit v1.2.3 From 4c41cb48d0356a28190c300fd4cc5e03f824b870 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 16 Oct 2012 18:11:42 +0200 Subject: Modularize drag and drop documentation - Move dnd docs and examples out of QtDoc module to gui library in QtBase - Remove info related to Motif dnd since Qt5 doesn't implement it Change-Id: Id7eb4eb422f4294a36dd92709ce3007903371f03 Reviewed-by: Jerome Pasion --- src/gui/doc/qtgui.qdocconf | 9 +- src/gui/doc/snippets/clipboard/clipboard.pro | 3 + src/gui/doc/snippets/clipboard/clipwindow.cpp | 103 ++++++ src/gui/doc/snippets/clipboard/clipwindow.h | 72 ++++ src/gui/doc/snippets/clipboard/main.cpp | 52 +++ src/gui/doc/snippets/draganddrop/draganddrop.pro | 5 + src/gui/doc/snippets/draganddrop/dragwidget.cpp | 153 ++++++++ src/gui/doc/snippets/draganddrop/dragwidget.h | 79 ++++ src/gui/doc/snippets/draganddrop/main.cpp | 53 +++ src/gui/doc/snippets/draganddrop/mainwindow.cpp | 84 +++++ src/gui/doc/snippets/draganddrop/mainwindow.h | 71 ++++ src/gui/doc/snippets/dragging/dragging.pro | 5 + src/gui/doc/snippets/dragging/images.qrc | 5 + src/gui/doc/snippets/dragging/images/file.png | Bin 0 -> 313 bytes src/gui/doc/snippets/dragging/main.cpp | 51 +++ src/gui/doc/snippets/dragging/mainwindow.h | 71 ++++ src/gui/doc/snippets/dropevents/dropevents.pro | 3 + src/gui/doc/snippets/dropevents/main.cpp | 52 +++ src/gui/doc/snippets/dropevents/window.cpp | 87 +++++ src/gui/doc/snippets/dropevents/window.h | 71 ++++ .../doc/snippets/droprectangle/droprectangle.pro | 3 + src/gui/doc/snippets/droprectangle/main.cpp | 51 +++ src/gui/doc/snippets/droprectangle/window.cpp | 96 +++++ src/gui/doc/snippets/droprectangle/window.h | 71 ++++ src/gui/doc/snippets/separations/finalwidget.h | 77 ++++ src/gui/doc/snippets/separations/main.cpp | 50 +++ src/gui/doc/snippets/separations/screenwidget.cpp | 217 +++++++++++ src/gui/doc/snippets/separations/screenwidget.h | 86 +++++ src/gui/doc/snippets/separations/separations.pro | 7 + src/gui/doc/snippets/separations/separations.qdoc | 54 +++ src/gui/doc/snippets/separations/viewer.cpp | 328 +++++++++++++++++ src/gui/doc/snippets/separations/viewer.h | 89 +++++ src/gui/doc/src/dnd.qdoc | 401 +++++++++++++++++++++ src/gui/doc/src/qtgui.qdoc | 2 + src/plugins/platforms/xcb/qxcbdrag.cpp | 25 +- 35 files changed, 2560 insertions(+), 26 deletions(-) create mode 100644 src/gui/doc/snippets/clipboard/clipboard.pro create mode 100644 src/gui/doc/snippets/clipboard/clipwindow.cpp create mode 100644 src/gui/doc/snippets/clipboard/clipwindow.h create mode 100644 src/gui/doc/snippets/clipboard/main.cpp create mode 100644 src/gui/doc/snippets/draganddrop/draganddrop.pro create mode 100644 src/gui/doc/snippets/draganddrop/dragwidget.cpp create mode 100644 src/gui/doc/snippets/draganddrop/dragwidget.h create mode 100644 src/gui/doc/snippets/draganddrop/main.cpp create mode 100644 src/gui/doc/snippets/draganddrop/mainwindow.cpp create mode 100644 src/gui/doc/snippets/draganddrop/mainwindow.h create mode 100644 src/gui/doc/snippets/dragging/dragging.pro create mode 100644 src/gui/doc/snippets/dragging/images.qrc create mode 100644 src/gui/doc/snippets/dragging/images/file.png create mode 100644 src/gui/doc/snippets/dragging/main.cpp create mode 100644 src/gui/doc/snippets/dragging/mainwindow.h create mode 100644 src/gui/doc/snippets/dropevents/dropevents.pro create mode 100644 src/gui/doc/snippets/dropevents/main.cpp create mode 100644 src/gui/doc/snippets/dropevents/window.cpp create mode 100644 src/gui/doc/snippets/dropevents/window.h create mode 100644 src/gui/doc/snippets/droprectangle/droprectangle.pro create mode 100644 src/gui/doc/snippets/droprectangle/main.cpp create mode 100644 src/gui/doc/snippets/droprectangle/window.cpp create mode 100644 src/gui/doc/snippets/droprectangle/window.h create mode 100644 src/gui/doc/snippets/separations/finalwidget.h create mode 100644 src/gui/doc/snippets/separations/main.cpp create mode 100644 src/gui/doc/snippets/separations/screenwidget.cpp create mode 100644 src/gui/doc/snippets/separations/screenwidget.h create mode 100644 src/gui/doc/snippets/separations/separations.pro create mode 100644 src/gui/doc/snippets/separations/separations.qdoc create mode 100644 src/gui/doc/snippets/separations/viewer.cpp create mode 100644 src/gui/doc/snippets/separations/viewer.h create mode 100644 src/gui/doc/src/dnd.qdoc (limited to 'src') diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf index 958f592cc6..cdf37e29f2 100644 --- a/src/gui/doc/qtgui.qdocconf +++ b/src/gui/doc/qtgui.qdocconf @@ -39,12 +39,7 @@ sourcedirs += .. \ ../../../examples/gui/doc exampledirs += ../../../examples/gui \ - ../../../doc/src/snippets \ - ../ \ + ../../../examples/widgets \ snippets -excludedirs += snippets - -imagedirs += images \ - ../../../doc/src/images \ - ../../../examples/gui/doc/images +imagedirs += images diff --git a/src/gui/doc/snippets/clipboard/clipboard.pro b/src/gui/doc/snippets/clipboard/clipboard.pro new file mode 100644 index 0000000000..a26fea6b57 --- /dev/null +++ b/src/gui/doc/snippets/clipboard/clipboard.pro @@ -0,0 +1,3 @@ +HEADERS = clipwindow.h +SOURCES = clipwindow.cpp \ + main.cpp diff --git a/src/gui/doc/snippets/clipboard/clipwindow.cpp b/src/gui/doc/snippets/clipboard/clipwindow.cpp new file mode 100644 index 0000000000..376d92afac --- /dev/null +++ b/src/gui/doc/snippets/clipboard/clipwindow.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "clipwindow.h" + +ClipWindow::ClipWindow(QWidget *parent) + : QMainWindow(parent) +{ + clipboard = QApplication::clipboard(); + + QWidget *centralWidget = new QWidget(this); + QWidget *currentItem = new QWidget(centralWidget); + QLabel *mimeTypeLabel = new QLabel(tr("MIME types:"), currentItem); + mimeTypeCombo = new QComboBox(currentItem); + QLabel *dataLabel = new QLabel(tr("Data:"), currentItem); + dataInfoLabel = new QLabel("", currentItem); + + previousItems = new QListWidget(centralWidget); + +//! [0] + connect(clipboard, SIGNAL(dataChanged()), this, SLOT(updateClipboard())); +//! [0] + connect(mimeTypeCombo, SIGNAL(activated(const QString &)), + this, SLOT(updateData(const QString &))); + + QVBoxLayout *currentLayout = new QVBoxLayout(currentItem); + currentLayout->addWidget(mimeTypeLabel); + currentLayout->addWidget(mimeTypeCombo); + currentLayout->addWidget(dataLabel); + currentLayout->addWidget(dataInfoLabel); + currentLayout->addStretch(1); + + QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget); + mainLayout->addWidget(currentItem, 1); + mainLayout->addWidget(previousItems); + + setCentralWidget(centralWidget); + setWindowTitle(tr("Clipboard")); +} + +//! [1] +void ClipWindow::updateClipboard() +{ + QStringList formats = clipboard->mimeData()->formats(); + QByteArray data = clipboard->mimeData()->data(format); +//! [1] + + mimeTypeCombo->clear(); + mimeTypeCombo->insertStringList(formats); + + int size = clipboard->mimeData()->data(formats[0]).size(); + QListWidgetItem *newItem = new QListWidgetItem(previousItems); + newItem->setText(tr("%1 (%2 bytes)").arg(formats[0]).arg(size)); + + updateData(formats[0]); +//! [2] +} +//! [2] + +void ClipWindow::updateData(const QString &format) +{ + QByteArray data = clipboard->mimeData()->data(format); + dataInfoLabel->setText(tr("%1 bytes").arg(data.size())); +} diff --git a/src/gui/doc/snippets/clipboard/clipwindow.h b/src/gui/doc/snippets/clipboard/clipwindow.h new file mode 100644 index 0000000000..2ab42c9174 --- /dev/null +++ b/src/gui/doc/snippets/clipboard/clipwindow.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIPWINDOW_H +#define CLIPWINDOW_H + +#include + +class QClipboard; +class QComboBox; +class QLabel; +class QListWidget; +class QMimeData; +class QWidget; + +class ClipWindow : public QMainWindow +{ + Q_OBJECT + +public: + ClipWindow(QWidget *parent = 0); + +public slots: + void updateClipboard(); + void updateData(const QString &format); + +private: + int currentItem; + QClipboard *clipboard; + QComboBox *mimeTypeCombo; + QLabel *dataInfoLabel; + QListWidget *previousItems; +}; + +#endif diff --git a/src/gui/doc/snippets/clipboard/main.cpp b/src/gui/doc/snippets/clipboard/main.cpp new file mode 100644 index 0000000000..f94fe4994a --- /dev/null +++ b/src/gui/doc/snippets/clipboard/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "clipwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + ClipWindow *window = new ClipWindow; + window->resize(640, 480); + window->show(); + return app.exec(); +} diff --git a/src/gui/doc/snippets/draganddrop/draganddrop.pro b/src/gui/doc/snippets/draganddrop/draganddrop.pro new file mode 100644 index 0000000000..67bc32bd10 --- /dev/null +++ b/src/gui/doc/snippets/draganddrop/draganddrop.pro @@ -0,0 +1,5 @@ +HEADERS = dragwidget.h \ + mainwindow.h +SOURCES = dragwidget.cpp \ + main.cpp \ + mainwindow.cpp diff --git a/src/gui/doc/snippets/draganddrop/dragwidget.cpp b/src/gui/doc/snippets/draganddrop/dragwidget.cpp new file mode 100644 index 0000000000..aa2075a977 --- /dev/null +++ b/src/gui/doc/snippets/draganddrop/dragwidget.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "dragwidget.h" + +DragWidget::DragWidget(QWidget *parent) + : QFrame(parent) +{ + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + dragDropLabel = new QLabel("", this); + dragDropLabel->setAlignment(Qt::AlignHCenter); + + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addStretch(0); + layout->addWidget(dragDropLabel); + layout->addStretch(0); + + setAcceptDrops(true); +} + +// Accept all actions, but deal with them separately later. +//! [0] +void DragWidget::dragEnterEvent(QDragEnterEvent *event) +{ + event->acceptProposedAction(); +} +//! [0] + +//! [1] +void DragWidget::dropEvent(QDropEvent *event) +{ + if (event->source() == this && event->possibleActions() & Qt::MoveAction) + return; +//! [1] + +//! [2] + if (event->proposedAction() == Qt::MoveAction) { + event->acceptProposedAction(); + // Process the data from the event. +//! [2] + emit dragResult(tr("The data was moved here.")); +//! [3] + } else if (event->proposedAction() == Qt::CopyAction) { + event->acceptProposedAction(); + // Process the data from the event. +//! [3] + emit dragResult(tr("The data was copied here.")); +//! [4] + } else { + // Ignore the drop. + return; + } +//! [4] + // End of quote + + emit mimeTypes(event->mimeData()->formats()); + setData(event->mimeData()->formats()[0], + event->mimeData()->data(event->mimeData()->formats()[0])); +//! [5] +} +//! [5] + +//! [6] +void DragWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + dragStartPosition = event->pos(); +} +//! [6] + +//! [7] +void DragWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (!(event->buttons() & Qt::LeftButton)) + return; + if ((event->pos() - dragStartPosition).manhattanLength() + < QApplication::startDragDistance()) + return; + + QDrag *drag = new QDrag(this); + QMimeData *mimeData = new QMimeData; + + mimeData->setData(mimeType, data); + drag->setMimeData(mimeData); + + Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction); +//! [7] + + switch (dropAction) { + case Qt::CopyAction: + emit dragResult(tr("The text was copied.")); + break; + case Qt::MoveAction: + emit dragResult(tr("The text was moved.")); + break; + default: + emit dragResult(tr("Unknown action.")); + break; + } +//! [8] +} +//! [8] + +void DragWidget::setData(const QString &mimetype, const QByteArray &newData) +{ + mimeType = mimetype; + data = QByteArray(newData); + + dragDropLabel->setText(tr("%1 bytes").arg(data.size())); + + QStringList formats; + formats << mimetype; + emit mimeTypes(formats); +} diff --git a/src/gui/doc/snippets/draganddrop/dragwidget.h b/src/gui/doc/snippets/draganddrop/dragwidget.h new file mode 100644 index 0000000000..cd12c08884 --- /dev/null +++ b/src/gui/doc/snippets/draganddrop/dragwidget.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DRAGWIDGET_H +#define DRAGWIDGET_H + +#include +#include +#include +#include + +class QComboBox; +class QFrame; +class QLabel; +class QTextBrowser; + +class DragWidget : public QFrame +{ + Q_OBJECT + +public: + DragWidget(QWidget *parent); + void setData(const QString &mimetype, const QByteArray &newData); + +signals: + void dragResult(const QString &actionText); + void mimeTypes(const QStringList &types); + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + +private: + QByteArray data; + QLabel *dragDropLabel; + QPoint dragStartPosition; + QString mimeType; +}; + +#endif diff --git a/src/gui/doc/snippets/draganddrop/main.cpp b/src/gui/doc/snippets/draganddrop/main.cpp new file mode 100644 index 0000000000..c15b641249 --- /dev/null +++ b/src/gui/doc/snippets/draganddrop/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow *window1 = new MainWindow; + MainWindow *window2 = new MainWindow; + window1->show(); + window2->show(); + return app.exec(); +} diff --git a/src/gui/doc/snippets/draganddrop/mainwindow.cpp b/src/gui/doc/snippets/draganddrop/mainwindow.cpp new file mode 100644 index 0000000000..4c443bbc09 --- /dev/null +++ b/src/gui/doc/snippets/draganddrop/mainwindow.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "dragwidget.h" +#include "mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ + QFrame *centralWidget = new QFrame(this); + + QLabel *mimeTypeLabel = new QLabel(tr("MIME types:"), centralWidget); + mimeTypeCombo = new QComboBox(centralWidget); + + QLabel *dataLabel = new QLabel(tr("Amount of data (bytes):"), centralWidget); + dragWidget = new DragWidget(centralWidget); + + connect(dragWidget, SIGNAL(mimeTypes(const QStringList &)), + this, SLOT(setMimeTypes(const QStringList &))); + connect(dragWidget, SIGNAL(dragResult(const QString &)), + this, SLOT(setDragResult(const QString &))); + + QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget); + mainLayout->addWidget(mimeTypeLabel); + mainLayout->addWidget(mimeTypeCombo); + mainLayout->addSpacing(32); + mainLayout->addWidget(dataLabel); + mainLayout->addWidget(dragWidget); + + statusBar(); + dragWidget->setData(QString("text/plain"), QByteArray("Hello world")); + setCentralWidget(centralWidget); + setWindowTitle(tr("Drag and Drop")); +} + +void MainWindow::setDragResult(const QString &actionText) +{ + statusBar()->showMessage(actionText); +} + +void MainWindow::setMimeTypes(const QStringList &types) +{ + mimeTypeCombo->clear(); + mimeTypeCombo->addItems(types); +} diff --git a/src/gui/doc/snippets/draganddrop/mainwindow.h b/src/gui/doc/snippets/draganddrop/mainwindow.h new file mode 100644 index 0000000000..5b9018e1a2 --- /dev/null +++ b/src/gui/doc/snippets/draganddrop/mainwindow.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +class QComboBox; +class QLabel; +class QLineEdit; +class QMouseEvent; +class QTextEdit; +class DragWidget; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = 0); + +public slots: + void setDragResult(const QString &actionText); + void setMimeTypes(const QStringList &types); + +private: + QComboBox *mimeTypeCombo; + DragWidget *dragWidget; +}; + +#endif diff --git a/src/gui/doc/snippets/dragging/dragging.pro b/src/gui/doc/snippets/dragging/dragging.pro new file mode 100644 index 0000000000..0a16eb19bf --- /dev/null +++ b/src/gui/doc/snippets/dragging/dragging.pro @@ -0,0 +1,5 @@ +QT += widgets +HEADERS += mainwindow.h +RESOURCES += images.qrc +SOURCES += main.cpp \ + mainwindow.cpp diff --git a/src/gui/doc/snippets/dragging/images.qrc b/src/gui/doc/snippets/dragging/images.qrc new file mode 100644 index 0000000000..30b8a2986e --- /dev/null +++ b/src/gui/doc/snippets/dragging/images.qrc @@ -0,0 +1,5 @@ + + + images/file.png + + diff --git a/src/gui/doc/snippets/dragging/images/file.png b/src/gui/doc/snippets/dragging/images/file.png new file mode 100644 index 0000000000..9520080ed0 Binary files /dev/null and b/src/gui/doc/snippets/dragging/images/file.png differ diff --git a/src/gui/doc/snippets/dragging/main.cpp b/src/gui/doc/snippets/dragging/main.cpp new file mode 100644 index 0000000000..1eb4112e60 --- /dev/null +++ b/src/gui/doc/snippets/dragging/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow *window = new MainWindow; + window->show(); + return app.exec(); +} diff --git a/src/gui/doc/snippets/dragging/mainwindow.h b/src/gui/doc/snippets/dragging/mainwindow.h new file mode 100644 index 0000000000..216afbc6db --- /dev/null +++ b/src/gui/doc/snippets/dragging/mainwindow.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +class QLabel; +class QLineEdit; +class QMouseEvent; +class QTextEdit; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = 0); + +protected: + void mousePressEvent(QMouseEvent *event); + +private: + QLabel *iconLabel; + QLineEdit *nameEdit; + QPixmap iconPixmap; + QPoint dragStartPosition; + QTextEdit *commentEdit; +}; + +#endif diff --git a/src/gui/doc/snippets/dropevents/dropevents.pro b/src/gui/doc/snippets/dropevents/dropevents.pro new file mode 100644 index 0000000000..6283406f25 --- /dev/null +++ b/src/gui/doc/snippets/dropevents/dropevents.pro @@ -0,0 +1,3 @@ +HEADERS = window.h +SOURCES = main.cpp \ + window.cpp diff --git a/src/gui/doc/snippets/dropevents/main.cpp b/src/gui/doc/snippets/dropevents/main.cpp new file mode 100644 index 0000000000..1337f7f921 --- /dev/null +++ b/src/gui/doc/snippets/dropevents/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "window.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + Window *window = new Window; + window->show(); + return app.exec(); +} diff --git a/src/gui/doc/snippets/dropevents/window.cpp b/src/gui/doc/snippets/dropevents/window.cpp new file mode 100644 index 0000000000..f3c4a0c610 --- /dev/null +++ b/src/gui/doc/snippets/dropevents/window.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "window.h" + +//! [0] +Window::Window(QWidget *parent) + : QWidget(parent) +{ +//! [0] + QLabel *textLabel = new QLabel(tr("Data:"), this); + textBrowser = new QTextBrowser(this); + + QLabel *mimeTypeLabel = new QLabel(tr("MIME types:"), this); + mimeTypeCombo = new QComboBox(this); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(textLabel); + layout->addWidget(textBrowser); + layout->addWidget(mimeTypeLabel); + layout->addWidget(mimeTypeCombo); + +//! [1] + setAcceptDrops(true); +//! [1] + setWindowTitle(tr("Drop Events")); +//! [2] +} +//! [2] + +//! [3] +void Window::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasFormat("text/plain")) + event->acceptProposedAction(); +} +//! [3] + +//! [4] +void Window::dropEvent(QDropEvent *event) +{ + textBrowser->setPlainText(event->mimeData()->text()); + mimeTypeCombo->clear(); + mimeTypeCombo->addItems(event->mimeData()->formats()); + + event->acceptProposedAction(); +} +//! [4] diff --git a/src/gui/doc/snippets/dropevents/window.h b/src/gui/doc/snippets/dropevents/window.h new file mode 100644 index 0000000000..dd5487a7e2 --- /dev/null +++ b/src/gui/doc/snippets/dropevents/window.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include +#include + +class QComboBox; +class QFrame; +class QTextBrowser; + +class Window : public QWidget +{ + Q_OBJECT + +public: + Window(QWidget *parent = 0); + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + +private: + QComboBox *mimeTypeCombo; + QFrame *dropFrame; + QTextBrowser *textBrowser; + QString oldText; + QStringList oldMimeTypes; +}; + +#endif diff --git a/src/gui/doc/snippets/droprectangle/droprectangle.pro b/src/gui/doc/snippets/droprectangle/droprectangle.pro new file mode 100644 index 0000000000..6283406f25 --- /dev/null +++ b/src/gui/doc/snippets/droprectangle/droprectangle.pro @@ -0,0 +1,3 @@ +HEADERS = window.h +SOURCES = main.cpp \ + window.cpp diff --git a/src/gui/doc/snippets/droprectangle/main.cpp b/src/gui/doc/snippets/droprectangle/main.cpp new file mode 100644 index 0000000000..e436e24e97 --- /dev/null +++ b/src/gui/doc/snippets/droprectangle/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "window.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + Window *window = new Window; + window->show(); + return app.exec(); +} diff --git a/src/gui/doc/snippets/droprectangle/window.cpp b/src/gui/doc/snippets/droprectangle/window.cpp new file mode 100644 index 0000000000..d488a8742b --- /dev/null +++ b/src/gui/doc/snippets/droprectangle/window.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "window.h" + +Window::Window(QWidget *parent) + : QWidget(parent) +{ + QLabel *textLabel = new QLabel(tr("Data:"), this); + textBrowser = new QTextBrowser(this); + + QLabel *mimeTypeLabel = new QLabel(tr("MIME types:"), this); + mimeTypeCombo = new QComboBox(this); + + dropFrame = new QFrame(this); + dropFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + QLabel *dropLabel = new QLabel(tr("Drop items here"), dropFrame); + dropLabel->setAlignment(Qt::AlignHCenter); + + QVBoxLayout *dropFrameLayout = new QVBoxLayout(dropFrame); + dropFrameLayout->addWidget(dropLabel); + + QHBoxLayout *dropLayout = new QHBoxLayout; + dropLayout->addStretch(0); + dropLayout->addWidget(dropFrame); + dropLayout->addStretch(0); + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(textLabel); + mainLayout->addWidget(textBrowser); + mainLayout->addWidget(mimeTypeLabel); + mainLayout->addWidget(mimeTypeCombo); + mainLayout->addSpacing(32); + mainLayout->addLayout(dropLayout); + + setAcceptDrops(true); + setWindowTitle(tr("Drop Rectangle")); +} + +//! [0] +void Window::dragMoveEvent(QDragMoveEvent *event) +{ + if (event->mimeData()->hasFormat("text/plain") + && event->answerRect().intersects(dropFrame->geometry())) + + event->acceptProposedAction(); +} +//! [0] + +void Window::dropEvent(QDropEvent *event) +{ + textBrowser->setPlainText(event->mimeData()->text()); + mimeTypeCombo->clear(); + mimeTypeCombo->addItems(event->mimeData()->formats()); + + event->acceptProposedAction(); +} diff --git a/src/gui/doc/snippets/droprectangle/window.h b/src/gui/doc/snippets/droprectangle/window.h new file mode 100644 index 0000000000..b07d030d13 --- /dev/null +++ b/src/gui/doc/snippets/droprectangle/window.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include +#include + +class QComboBox; +class QFrame; +class QTextBrowser; + +class Window : public QWidget +{ + Q_OBJECT + +public: + Window(QWidget *parent = 0); + +protected: + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent *event); + +private: + QComboBox *mimeTypeCombo; + QFrame *dropFrame; + QTextBrowser *textBrowser; + QString oldText; + QStringList oldMimeTypes; +}; + +#endif diff --git a/src/gui/doc/snippets/separations/finalwidget.h b/src/gui/doc/snippets/separations/finalwidget.h new file mode 100644 index 0000000000..e7247d31c0 --- /dev/null +++ b/src/gui/doc/snippets/separations/finalwidget.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FINALWIDGET_H +#define FINALWIDGET_H + +#include +#include +#include +#include + +class QGridLayout; +class QLabel; +class QMouseEvent; +class QWidget; + +class FinalWidget : public QFrame +{ + Q_OBJECT + +public: + FinalWidget(QWidget *parent, const QString &name, const QSize &labelSize); + void setPixmap(const QPixmap &pixmap); + const QPixmap *pixmap() const; + +protected: + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + +private: + void createImage(); + + bool hasImage; + QImage originalImage; + QLabel *imageLabel; + QLabel *nameLabel; + QPoint dragStartPosition; +}; + +#endif diff --git a/src/gui/doc/snippets/separations/main.cpp b/src/gui/doc/snippets/separations/main.cpp new file mode 100644 index 0000000000..963dab3635 --- /dev/null +++ b/src/gui/doc/snippets/separations/main.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "viewer.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + Viewer viewer; + viewer.show(); + return app.exec(); +} diff --git a/src/gui/doc/snippets/separations/screenwidget.cpp b/src/gui/doc/snippets/separations/screenwidget.cpp new file mode 100644 index 0000000000..328b1d0624 --- /dev/null +++ b/src/gui/doc/snippets/separations/screenwidget.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +screenwidget.cpp + +A widget to display colour components from an image using independently +selected colors. Controls are provided to allow the image to be inverted, and +the color to be selection via a standard dialog. The image is displayed in a +label widget. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "screenwidget.h" + +/*! +Initializes the paint color, the mask color (cyan, magenta, +or yellow), connects the color selector and invert checkbox to functions, +and creates a two-by-two grid layout. +*/ + +ScreenWidget::ScreenWidget(QWidget *parent, QColor initialColor, + const QString &name, Separation mask, + const QSize &labelSize) + : QFrame(parent) +{ + paintColor = initialColor; + maskColor = mask; + inverted = false; + + imageLabel = new QLabel; + imageLabel->setFrameShadow(QFrame::Sunken); + imageLabel->setFrameShape(QFrame::StyledPanel); + imageLabel->setMinimumSize(labelSize); + + nameLabel = new QLabel(name); + colorButton = new QPushButton(tr("Modify...")); + colorButton->setBackgroundRole(QPalette::Button); + colorButton->setMinimumSize(32, 32); + + QPalette palette(colorButton->palette()); + palette.setColor(QPalette::Button, initialColor); + colorButton->setPalette(palette); + + invertButton = new QPushButton(tr("Invert")); + //invertButton->setToggleButton(true); + //invertButton->setOn(inverted); + invertButton->setEnabled(false); + + connect(colorButton, SIGNAL(clicked()), this, SLOT(setColor())); + connect(invertButton, SIGNAL(clicked()), this, SLOT(invertImage())); + + QGridLayout *gridLayout = new QGridLayout; + gridLayout->addWidget(imageLabel, 0, 0, 1, 2); + gridLayout->addWidget(nameLabel, 1, 0); + gridLayout->addWidget(colorButton, 1, 1); + gridLayout->addWidget(invertButton, 2, 1, 1, 1); + setLayout(gridLayout); +} + +/*! + Creates a new image by separating out the cyan, magenta, or yellow + component, depending on the mask color specified in the constructor. + + The amount of the component found in each pixel of the image is used + to determine how much of a user-selected ink is used for each pixel + in the new image for the label widget. +*/ + +void ScreenWidget::createImage() +{ + newImage = originalImage.copy(); + + // Create CMY components for the ink being used. + float cyanInk = (255 - paintColor.red())/255.0; + float magentaInk = (255 - paintColor.green())/255.0; + float yellowInk = (255 - paintColor.blue())/255.0; + + int (*convert)(QRgb); + + switch (maskColor) { + case Cyan: + convert = qRed; + break; + case Magenta: + convert = qGreen; + break; + case Yellow: + convert = qBlue; + break; + } + + for (int y = 0; y < newImage.height(); ++y) { + for (int x = 0; x < newImage.width(); ++x) { + QRgb p(originalImage.pixel(x, y)); + + // Separate the source pixel into its cyan component. + int amount; + + if (inverted) + amount = convert(p); + else + amount = 255 - convert(p); + + QColor newColor( + 255 - qMin(int(amount * cyanInk), 255), + 255 - qMin(int(amount * magentaInk), 255), + 255 - qMin(int(amount * yellowInk), 255)); + + newImage.setPixel(x, y, newColor.rgb()); + } + } + + imageLabel->setPixmap(QPixmap::fromImage(newImage)); +} + +/*! + Returns a pointer to the modified image. +*/ + +QImage* ScreenWidget::image() +{ + return &newImage; +} + +/*! + Sets whether the amount of ink applied to the canvas is to be inverted + (subtracted from the maximum value) before the ink is applied. +*/ + +void ScreenWidget::invertImage() +{ + //inverted = invertButton->isOn(); + inverted = !inverted; + createImage(); + emit imageChanged(); +} + +/*! + Separate the current image into cyan, magenta, and yellow components. + Create a representation of how each component might appear when applied + to a blank white piece of paper. +*/ + +void ScreenWidget::setColor() +{ + QColor newColor = QColorDialog::getColor(paintColor); + + if (newColor.isValid()) { + paintColor = newColor; + QPalette palette(colorButton->palette()); + palette.setColor(QPalette::Button, paintColor); + colorButton->setPalette(palette); + createImage(); + emit imageChanged(); + } +} + +/*! + Records the original image selected by the user, creates a color + separation, and enables the invert image checkbox. +*/ + +void ScreenWidget::setImage(QImage &image) +{ + originalImage = image; + createImage(); + invertButton->setEnabled(true); +} diff --git a/src/gui/doc/snippets/separations/screenwidget.h b/src/gui/doc/snippets/separations/screenwidget.h new file mode 100644 index 0000000000..82d079f533 --- /dev/null +++ b/src/gui/doc/snippets/separations/screenwidget.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCREENWIDGET_H +#define SCREENWIDGET_H + +#include +#include +#include +#include + +class QGridLayout; +class QLabel; +class QPushButton; +class QWidget; + +class ScreenWidget : public QFrame +{ + Q_OBJECT +public: + enum Separation { Cyan, Magenta, Yellow }; + + ScreenWidget(QWidget *parent, QColor initialColor, const QString &name, + Separation mask, const QSize &labelSize); + void setImage(QImage &image); + QImage* image(); + +signals: + void imageChanged(); + +public slots: + void setColor(); + void invertImage(); + +private: + void createImage(); + + bool inverted; + QColor paintColor; + QImage newImage; + QImage originalImage; + QLabel *imageLabel; + QLabel *nameLabel; + QPushButton *colorButton; + QPushButton *invertButton; + Separation maskColor; +}; + +#endif diff --git a/src/gui/doc/snippets/separations/separations.pro b/src/gui/doc/snippets/separations/separations.pro new file mode 100644 index 0000000000..48af2c8472 --- /dev/null +++ b/src/gui/doc/snippets/separations/separations.pro @@ -0,0 +1,7 @@ +HEADERS = finalwidget.h \ + screenwidget.h \ + viewer.h +SOURCES = finalwidget.cpp \ + main.cpp \ + screenwidget.cpp \ + viewer.cpp diff --git a/src/gui/doc/snippets/separations/separations.qdoc b/src/gui/doc/snippets/separations/separations.qdoc new file mode 100644 index 0000000000..005ee7be22 --- /dev/null +++ b/src/gui/doc/snippets/separations/separations.qdoc @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + \example painting/separations + \title Color Separations Example + + This example enables simple color manipulation of images and demonstrates a + number of image-related features of Qt, from per-pixel image manipulation to + drag and drop handling of images. + + \image separations-example.png + + The application allows the user to load an image, shown in the top-left + part of the main window, and to adjust its color balance by replacing its + initial cyan, magenta, and yellow components with different colors. +*/ diff --git a/src/gui/doc/snippets/separations/viewer.cpp b/src/gui/doc/snippets/separations/viewer.cpp new file mode 100644 index 0000000000..1cb7d2d0d5 --- /dev/null +++ b/src/gui/doc/snippets/separations/viewer.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +viewer.cpp + +Provides a main window for displaying a user-specified original image +with three color separations in a grid layout. + +A main menu provides entries for selecting files, and adjusting the +brightness of the separations. +*/ + +#include + +#include "finalwidget.h" +#include "screenwidget.h" +#include "viewer.h" + +/* + Constructor: initializes a default value for the brightness, creates + the main menu entries, and constructs a central widget that contains + enough space for images to be displayed. +*/ + +Viewer::Viewer() +{ + setWindowTitle(tr("QImage Color Separations")); + + brightness = 255; + + createMenus(); + setCentralWidget(createCentralWidget()); +} + +/* + Creates a main menu with two entries: a File menu, to allow the image + to be selected, and a Brightness menu to allow the brightness of the + separations to be changed. + + Initially, the Brightness menu items are disabled, but the first entry in + the menu is checked to reflect the default brightness. +*/ + +void Viewer::createMenus() +{ + fileMenu = new QMenu(tr("&File"), this); + brightnessMenu = new QMenu(tr("&Brightness"), this); + + QAction *openAction = fileMenu->addAction(tr("&Open...")); + openAction->setShortcut(QKeySequence("Ctrl+O")); + saveAction = fileMenu->addAction(tr("&Save...")); + saveAction->setShortcut(QKeySequence("Ctrl+S")); + saveAction->setEnabled(false); + QAction *quitAction = fileMenu->addAction(tr("E&xit")); + quitAction->setShortcut(QKeySequence("Ctrl+Q")); + + QAction *noBrightness = brightnessMenu->addAction(tr("&0%")); + noBrightness->setCheckable(true); + QAction *quarterBrightness = brightnessMenu->addAction(tr("&25%")); + quarterBrightness->setCheckable(true); + QAction *halfBrightness = brightnessMenu->addAction(tr("&50%")); + halfBrightness->setCheckable(true); + QAction *threeQuartersBrightness = brightnessMenu->addAction(tr("&75%")); + threeQuartersBrightness->setCheckable(true); + QAction *fullBrightness = brightnessMenu->addAction(tr("&100%")); + fullBrightness->setCheckable(true); + + menuMap[noBrightness] = None; + menuMap[quarterBrightness] = Quarter; + menuMap[halfBrightness] = Half; + menuMap[threeQuartersBrightness] = ThreeQuarters; + menuMap[fullBrightness] = Full; + + currentBrightness = fullBrightness; + currentBrightness->setChecked(true); + brightnessMenu->setEnabled(false); + + menuBar()->addMenu(fileMenu); + menuBar()->addMenu(brightnessMenu); + + connect(openAction, SIGNAL(triggered()), this, SLOT(chooseFile())); + connect(saveAction, SIGNAL(triggered()), this, SLOT(saveImage())); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(brightnessMenu, SIGNAL(triggered(QAction *)), this, + SLOT(setBrightness(QAction *))); +} + +/* + Constructs a central widget for the window consisting of a two-by-two + grid of labels, each of which will contain an image. We restrict the + size of the labels to 256 pixels, and ensure that the window cannot + be resized. +*/ + +QFrame* Viewer::createCentralWidget() +{ + QFrame* frame = new QFrame(this); + grid = new QGridLayout(frame); + grid->setSpacing(8); + grid->setMargin(4); + + layout()->setSizeConstraint(QLayout::SetFixedSize); + + QSize labelSize(256, 256); + + finalWidget = new FinalWidget(frame, tr("Final image"), labelSize); + + cyanWidget = new ScreenWidget(frame, Qt::cyan, tr("Cyan"), + ScreenWidget::Cyan, labelSize); + magentaWidget = new ScreenWidget(frame, Qt::magenta, tr("Magenta"), + ScreenWidget::Magenta, labelSize); + yellowWidget = new ScreenWidget(frame, Qt::yellow, tr("Yellow"), + ScreenWidget::Yellow, labelSize); + + connect(cyanWidget, SIGNAL(imageChanged()), this, SLOT(createImage())); + connect(magentaWidget, SIGNAL(imageChanged()), this, SLOT(createImage())); + connect(yellowWidget, SIGNAL(imageChanged()), this, SLOT(createImage())); + + grid->addWidget(finalWidget, 0, 0, Qt::AlignTop | Qt::AlignHCenter); + grid->addWidget(cyanWidget, 0, 1, Qt::AlignTop | Qt::AlignHCenter); + grid->addWidget(magentaWidget, 1, 0, Qt::AlignTop | Qt::AlignHCenter); + grid->addWidget(yellowWidget, 1, 1, Qt::AlignTop | Qt::AlignHCenter); + + return frame; +} + +/* + Provides a dialog window to allow the user to specify an image file. + If a file is selected, the appropriate function is called to process + and display it. +*/ + +void Viewer::chooseFile() +{ + QString imageFile = QFileDialog::getOpenFileName(this, + tr("Choose an image file to open"), path, tr("Images (*.*)")); + + if (!imageFile.isEmpty()) { + openImageFile(imageFile); + path = imageFile; + } +} + +/* + Changes the value of the brightness according to the entry selected in the + Brightness menu. The selected entry is checked, and the previously selected + entry is unchecked. + + The color separations are updated to use the new value for the brightness. +*/ + +void Viewer::setBrightness(QAction *action) +{ + if (!menuMap.contains(action) || scaledImage.isNull()) + return; + + Brightness amount = menuMap[action]; + + switch (amount) { + case None: + brightness = 0; break; + case Quarter: + brightness = 64; break; + case Half: + brightness = 128; break; + case ThreeQuarters: + brightness = 191; break; + case Full: + brightness = 255; break; + default: return; + } + + currentBrightness->setChecked(false); + currentBrightness = action; + currentBrightness->setChecked(true); + + createImage(); +} + +/* + Load the image from the file given, and create four pixmaps based + on the original image. + + The window caption is set, and the Brightness menu enabled if the image file + can be loaded. +*/ + +void Viewer::openImageFile(QString &imageFile) +{ + QImage originalImage; + + if (originalImage.load(imageFile)) { + setWindowTitle(imageFile); + //menuBar()->setItemEnabled(brightnessMenuId, true); + saveAction->setEnabled(true); + brightnessMenu->setEnabled(true); + + /* Note: the ScaleMin value may be different for Qt 4. */ + scaledImage = originalImage.scaled(256, 256, Qt::KeepAspectRatio); + + cyanWidget->setImage(scaledImage); + magentaWidget->setImage(scaledImage); + yellowWidget->setImage(scaledImage); + createImage(); + } + else + (void) QMessageBox::warning(this, tr("Cannot open file"), + tr("The selected file could not be opened."), + QMessageBox::Cancel, QMessageBox::NoButton, QMessageBox::NoButton); +} + +/* + Creates an image by combining the contents of the three screens + to present a page preview. + + The image associated with each screen is separated into cyan, + magenta, and yellow components. We add up the values for each + component from the three screen images, and subtract the totals + from the maximum value for each corresponding primary color. +*/ + +void Viewer::createImage() +{ + QImage newImage = scaledImage.copy(); + + QImage *image1 = cyanWidget->image(); + QImage *image2 = magentaWidget->image(); + QImage *image3 = yellowWidget->image(); + int darkness = 255 - brightness; + + for (int y = 0; y < newImage.height(); ++y) { + for (int x = 0; x < newImage.width(); ++x) { + + // Create three screens, using the quantities of the source + // CMY components to determine how much of each of the + // inks are to be put on each screen. + QRgb p1(image1->pixel(x, y)); + float cyan1 = 255 - qRed(p1); + float magenta1 = 255 - qGreen(p1); + float yellow1 = 255 - qBlue(p1); + + QRgb p2(image2->pixel(x, y)); + float cyan2 = 255 - qRed(p2); + float magenta2 = 255 - qGreen(p2); + float yellow2 = 255 - qBlue(p2); + + QRgb p3(image3->pixel(x, y)); + float cyan3 = 255 - qRed(p3); + float magenta3 = 255 - qGreen(p3); + float yellow3 = 255 - qBlue(p3); + + QColor newColor( + qMax(255 - int(cyan1+cyan2+cyan3) - darkness, 0), + qMax(255 - int(magenta1+magenta2+magenta3) - darkness, 0), + qMax(255 - int(yellow1+yellow2+yellow3) - darkness, 0)); + + newImage.setPixel(x, y, newColor.rgb()); + } + } + + finalWidget->setPixmap(QPixmap::fromImage(newImage)); +} + +/* + Provides a dialog window to allow the user to save the image file. +*/ + +void Viewer::saveImage() +{ + QString imageFile = QFileDialog::getSaveFileName(this, + tr("Choose a filename to save the image"), "", tr("Images (*.png)")); + + QFileInfo info(imageFile); + + if (!info.baseName().isEmpty()) { + QString newImageFile = QFileInfo(info.absoluteDir(), + info.baseName() + ".png").absoluteFilePath(); + + if (!finalWidget->pixmap()->save(newImageFile, "PNG")) + (void) QMessageBox::warning(this, tr("Cannot save file"), + tr("The file could not be saved."), + QMessageBox::Cancel, QMessageBox::NoButton, + QMessageBox::NoButton); + } + else + (void) QMessageBox::warning(this, tr("Cannot save file"), + tr("Please enter a valid filename."), + QMessageBox::Cancel, QMessageBox::NoButton, + QMessageBox::NoButton); +} diff --git a/src/gui/doc/snippets/separations/viewer.h b/src/gui/doc/snippets/separations/viewer.h new file mode 100644 index 0000000000..c1e3725895 --- /dev/null +++ b/src/gui/doc/snippets/separations/viewer.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIEWER_H +#define VIEWER_H + +#include +#include +#include + +class QAction; +class QFrame; +class QGridLayout; +class QLabel; +class QMenu; +class FinalWidget; +class ScreenWidget; + +class Viewer : public QMainWindow +{ + Q_OBJECT +public: + enum Brightness { None, Quarter, Half, ThreeQuarters, Full }; + Viewer(); + +public slots: + void chooseFile(); + void setBrightness(QAction *action); + void createImage(); + void saveImage(); + +private: + void createMenus(); + QFrame *createCentralWidget(); + void openImageFile(QString &filePath); + + FinalWidget *finalWidget; + int brightness; + QAction *currentBrightness; + QAction *saveAction; + QGridLayout *grid; + QImage scaledImage; + QMap menuMap; + QMenu *brightnessMenu; + QMenu *fileMenu; + QString path; + ScreenWidget *cyanWidget; + ScreenWidget *magentaWidget; + ScreenWidget *yellowWidget; +}; + +#endif diff --git a/src/gui/doc/src/dnd.qdoc b/src/gui/doc/src/dnd.qdoc new file mode 100644 index 0000000000..a4eb77469b --- /dev/null +++ b/src/gui/doc/src/dnd.qdoc @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page dnd.html + \title Drag and Drop + \brief An overview of the drag and drop system provided by Qt. + + \ingroup qt-gui-concepts + + Drag and drop provides a simple visual mechanism which users can use + to transfer information between and within applications. (In the + literature this is referred to as a "direct manipulation model".) Drag + and drop is similar in function to the clipboard's cut and paste + mechanism. + + \tableofcontents + + This document describes the basic drag and drop mechanism and + outlines the approach used to enable it in custom widgets. Drag + and drop operations are also supported by Qt's item views and by + the graphics view framework. More information is available in + \l{Using drag and drop with item views} and \l{Graphics View + Framework}. + + \section1 Drag and Drop Classes + + These classes deal with drag and drop and the necessary mime type + encoding and decoding. + + \annotatedlist draganddrop + + \section1 Configuration + + The QApplication object provides some properties that are related + to drag and drop operations: + + \list + \li \l{QApplication::startDragTime} describes the amount of time in + milliseconds that the user must hold down a mouse button over an + object before a drag will begin. + \li \l{QApplication::startDragDistance} indicates how far the user has to + move the mouse while holding down a mouse button before the movement + will be interpreted as dragging. Use of high values for this quantity + prevents accidental dragging when the user only meant to click on an + object. + \endlist + + These quantities provide sensible default values for you to use if you + provide drag and drop support in your widgets. + + \section1 Dragging + + To start a drag, create a QDrag object, and call its + exec() function. In most applications, it is a good idea to begin a drag + and drop operation only after a mouse button has been pressed and the + cursor has been moved a certain distance. However, the simplest way to + enable dragging from a widget is to reimplement the widget's + \l{QWidget::mousePressEvent()}{mousePressEvent()} and start a drag + and drop operation: + + \snippet dragging/mainwindow.cpp 0 + \dots 8 + \snippet dragging/mainwindow.cpp 2 + + Although the user may take some time to complete the dragging operation, + as far as the application is concerned the exec() function is a blocking + function that returns with \l{Qt::DropActions}{one of several values}. + These indicate how the operation ended, and are described in more detail + below. + + Note that the exec() function does not block the main event loop. + + For widgets that need to distinguish between mouse clicks and drags, it + is useful to reimplement the widget's + \l{QWidget::mousePressEvent()}{mousePressEvent()} function to record to + start position of the drag: + + \snippet draganddrop/dragwidget.cpp 6 + + Later, in \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()}, we can determine + whether a drag should begin, and construct a drag object to handle the + operation: + + \snippet draganddrop/dragwidget.cpp 7 + \dots + \snippet draganddrop/dragwidget.cpp 8 + + This particular approach uses the \l QPoint::manhattanLength() function + to get a rough estimate of the distance between where the mouse click + occurred and the current cursor position. This function trades accuracy + for speed, and is usually suitable for this purpose. + + \section1 Dropping + + To be able to receive media dropped on a widget, call + \l{QWidget::setAcceptDrops()}{setAcceptDrops(true)} for the widget, + and reimplement the \l{QWidget::dragEnterEvent()}{dragEnterEvent()} and + \l{QWidget::dropEvent()}{dropEvent()} event handler functions. + + For example, the following code enables drop events in the constructor of + a QWidget subclass, making it possible to usefully implement drop event + handlers: + + \snippet dropevents/window.cpp 0 + \dots + \snippet dropevents/window.cpp 1 + \snippet dropevents/window.cpp 2 + + The dragEnterEvent() function is typically used to inform Qt about the + types of data that the widget accepts. + You must reimplement this function if you want to receive either + QDragMoveEvent or QDropEvent in your reimplementations of + \l{QWidget::dragMoveEvent()}{dragMoveEvent()} and + \l{QWidget::dropEvent()}{dropEvent()}. + + The following code shows how \l{QWidget::dragEnterEvent()}{dragEnterEvent()} + can be reimplemented to + tell the drag and drop system that we can only handle plain text: + + \snippet dropevents/window.cpp 3 + + The \l{QWidget::dropEvent()}{dropEvent()} is used to unpack dropped data + and handle it in way that is suitable for your application. + + In the following code, the text supplied in the event is passed to a + QTextBrowser and a QComboBox is filled with the list of MIME types that + are used to describe the data: + + \snippet dropevents/window.cpp 4 + + In this case, we accept the proposed action without checking what it is. + In a real world application, it may be necessary to return from the + \l{QWidget::dropEvent()}{dropEvent()} function without accepting the + proposed action or handling + the data if the action is not relevant. For example, we may choose to + ignore Qt::LinkAction actions if we do not support + links to external sources in our application. + + \section2 Overriding Proposed Actions + + We may also ignore the proposed action, and perform some other action on + the data. To do this, we would call the event object's + \l{QDropEvent::setDropAction()}{setDropAction()} with the preferred + action from Qt::DropAction before calling \l{QEvent::}{accept()}. + This ensures that the replacement drop action is used instead of the + proposed action. + + For more sophisticated applications, reimplementing + \l{QWidget::dragMoveEvent()}{dragMoveEvent()} and + \l{QWidget::dragLeaveEvent()}{dragLeaveEvent()} will let you make + certain parts of your widgets sensitive to drop events, and give you more + control over drag and drop in your application. + + \section2 Subclassing Complex Widgets + + Certain standard Qt widgets provide their own support for drag and drop. + When subclassing these widgets, it may be necessary to reimplement + \l{QWidget::dragMoveEvent()}{dragMoveEvent()} in addition to + \l{QWidget::dragEnterEvent()}{dragEnterEvent()} and + \l{QWidget::dropEvent()}{dropEvent()} to prevent the base class from + providing default drag and drop handling, and to handle any special + cases you are interested in. + + \section1 Drag and Drop Actions + + In the simplest case, the target of a drag and drop action receives a + copy of the data being dragged, and the source decides whether to + delete the original. This is described by the \c CopyAction action. + The target may also choose to handle other actions, specifically the + \c MoveAction and \c LinkAction actions. If the source calls + QDrag::exec(), and it returns \c MoveAction, the source is responsible + for deleting any original data if it chooses to do so. The QMimeData + and QDrag objects created by the source widget \e{should not be deleted} + - they will be destroyed by Qt. The target is responsible for taking + ownership of the data sent in the drag and drop operation; this is + usually done by keeping references to the data. + + If the target understands the \c LinkAction action, it should + store its own reference to the original information; the source + does not need to perform any further processing on the data. The + most common use of drag and drop actions is when performing a + Move within the same widget; see the section on \l{Drop Actions} + for more information about this feature. + + The other major use of drag actions is when using a reference type + such as text/uri-list, where the dragged data are actually references + to files or objects. + + \section1 Adding New Drag and Drop Types + + Drag and drop is not limited to text and images. Any type of information + can be transferred in a drag and drop operation. To drag information + between applications, the applications must be able to indicate to each + other which data formats they can accept and which they can produce. + This is achieved using + \l{http://www.rfc-editor.org/rfc/rfc1341.txt}{MIME types}. The QDrag + object constructed by the source contains a list of MIME types that it + uses to represent the data (ordered from most appropriate to least + appropriate), and the drop target uses one of these to access the data. + For common data types, the convenience functions handle the MIME types + used transparently but, for custom data types, it is necessary to + state them explicitly. + + To implement drag and drop actions for a type of information that is + not covered by the QDrag convenience functions, the first and most + important step is to look for existing formats that are appropriate: + The Internet Assigned Numbers Authority (\l{http://www.iana.org}{IANA}) + provides a + \l{http://www.iana.org/assignments/media-types/}{hierarchical + list of MIME media types} at the Information Sciences Institute + (\l{http://www.isi.edu}{ISI}). + Using standard MIME types maximizes the interoperability of + your application with other software now and in the future. + + To support an additional media type, simply set the data in the QMimeData + object with the \l{QMimeData::setData()}{setData()} function, supplying + the full MIME type and a QByteArray containing the data in the appropriate + format. The following code takes a pixmap from a label and stores it + as a Portable Network Graphics (PNG) file in a QMimeData object: + + \snippet separations/finalwidget.cpp 0 + + Of course, for this case we could have simply used + \l{QMimeData::setImageData()}{setImageData()} instead to supply image data + in a variety of formats: + + \snippet separations/finalwidget.cpp 1 + + The QByteArray approach is still useful in this case because it provides + greater control over the amount of data stored in the QMimeData object. + + Note that custom datatypes used in item views must be declared as + \l{QMetaObject}{meta objects} and that stream operators for them + must be implemented. + + \section1 Drop Actions + + In the clipboard model, the user can \e cut or \e copy the source + information, then later paste it. Similarly in the drag and drop + model, the user can drag a \e copy of the information or they can drag + the information itself to a new place (\e moving it). The + drag and drop model has an additional complication for the programmer: + The program doesn't know whether the user wants to cut or copy the + information until the operation is complete. This often makes no + difference when dragging information between applications, but within + an application it is important to check which drop action was used. + + We can reimplement the mouseMoveEvent() for a widget, and start a drag + and drop operation with a combination of possible drop actions. For + example, we may want to ensure that dragging always moves objects in + the widget: + + \snippet draganddrop/dragwidget.cpp 7 + \dots + \snippet draganddrop/dragwidget.cpp 8 + + The action returned by the exec() function may default to a + \c CopyAction if the information is dropped into another application + but, if it is dropped in another widget in the same application, we + may obtain a different drop action. + + The proposed drop actions can be filtered in a widget's dragMoveEvent() + function. However, it is possible to accept all proposed actions in + the dragEnterEvent() and let the user decide which they want to accept + later: + + \snippet draganddrop/dragwidget.cpp 0 + + When a drop occurs in the widget, the dropEvent() handler function is + called, and we can deal with each possible action in turn. First, we + deal with drag and drop operations within the same widget: + + \snippet draganddrop/dragwidget.cpp 1 + + In this case, we refuse to deal with move operations. Each type of drop + action that we accept is checked and dealt with accordingly: + + \snippet draganddrop/dragwidget.cpp 2 + \snippet draganddrop/dragwidget.cpp 3 + \snippet draganddrop/dragwidget.cpp 4 + \dots + \snippet draganddrop/dragwidget.cpp 5 + + Note that we checked for individual drop actions in the above code. + As mentioned above in the section on + \l{#Overriding Proposed Actions}{Overriding Proposed Actions}, it is + sometimes necessary to override the proposed drop action and choose a + different one from the selection of possible drop actions. + To do this, you need to check for the presence of each action in the value + supplied by the event's \l{QDropEvent::}{possibleActions()}, set the drop + action with \l{QDropEvent::}{setDropAction()}, and call + \l{QEvent::}{accept()}. + + \section1 Drop Rectangles + + The widget's dragMoveEvent() can be used to restrict drops to certain parts + of the widget by only accepting the proposed drop actions when the cursor + is within those areas. For example, the following code accepts any proposed + drop actions when the cursor is over a child widget (\c dropFrame): + + \snippet droprectangle/window.cpp 0 + + The dragMoveEvent() can also be used if you need to give visual + feedback during a drag and drop operation, to scroll the window, or + whatever is appropriate. + + \section1 The Clipboard + + Applications can also communicate with each other by putting data on + the clipboard. To access this, you need to obtain a QClipboard object + from the QApplication object: + + \snippet widgets/charactermap/mainwindow.cpp 3 + + The QMimeData class is used to represent data that is transferred to and + from the clipboard. To put data on the clipboard, you can use the + setText(), setImage(), and setPixmap() convenience functions for common + data types. These functions are similar to those found in the QMimeData + class, except that they also take an additional argument that controls + where the data is stored: If \l{QClipboard::Mode}{Clipboard} is + specified, the data is placed on the clipboard; if + \l{QClipboard::Mode}{Selection} is specified, the data is placed in the + mouse selection (on X11 only). By default, data is put on the clipboard. + + For example, we can copy the contents of a QLineEdit to the clipboard + with the following code: + + \snippet widgets/charactermap/mainwindow.cpp 11 + + Data with different MIME types can also be put on the clipboard. + Construct a QMimeData object and set data with setData() function in + the way described in the previous section; this object can then be + put on the clipboard with the + \l{QClipboard::setMimeData()}{setMimeData()} function. + + The QClipboard class can notify the application about changes to the + data it contains via its \l{QClipboard::dataChanged()}{dataChanged()} + signal. For example, we can monitor the clipboard by connecting this + signal to a slot in a widget: + + \snippet clipboard/clipwindow.cpp 0 + + The slot connected to this signal can read the data on the clipboard + using one of the MIME types that can be used to represent it: + + \snippet clipboard/clipwindow.cpp 1 + \dots + \snippet clipboard/clipwindow.cpp 2 + + The \l{QClipboard::selectionChanged()}{selectionChanged()} signal can + be used on X11 to monitor the mouse selection. + + \section1 Examples + + \list + \li \l{draganddrop/draggableicons}{Draggable Icons} + \li \l{draganddrop/draggabletext}{Draggable Text} + \li \l{draganddrop/dropsite}{Drop Site} + \li \l{draganddrop/fridgemagnets}{Fridge Magnets} + \li \l{draganddrop/puzzle}{Drag and Drop Puzzle} + \endlist + + \section1 Interoperating with Other Applications + + On X11, the public \l{http://www.newplanetsoftware.com/xdnd/}{XDND + protocol} is used, while on Windows Qt uses the OLE standard, and + Qt for Mac OS X uses the Cocoa Drag Manager. On X11, XDND uses MIME, + so no translation is necessary. The Qt API is the same regardless of + the platform. On Windows, MIME-aware applications can communicate by + using clipboard format names that are MIME types. Already some + Windows applications use MIME naming conventions for their + clipboard formats. Internally, Qt uses QWindowsMime and + QMacPasteboardMime for translating proprietary clipboard formats + to and from MIME types. + +*/ diff --git a/src/gui/doc/src/qtgui.qdoc b/src/gui/doc/src/qtgui.qdoc index c08ee657bb..f68ccbb6a8 100644 --- a/src/gui/doc/src/qtgui.qdoc +++ b/src/gui/doc/src/qtgui.qdoc @@ -158,7 +158,9 @@ QtGui now contains only a small set of enablers, which are generally useful for all graphical applications. + \section1 Drag and Drop + More info in \l{Drag and Drop} \section1 Reference \list diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 5d887cd06d..27a926eca2 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -680,8 +680,6 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev DEBUG() << "handleEnter" << window; xdnd_types.clear(); -// motifdnd_active = false; -// last_enter_event.xclient = xe->xclient; int version = (int)(event->data.data32[1] >> 24); if (version > xdnd_version) @@ -1217,9 +1215,7 @@ QXcbDropData::~QXcbDropData() QVariant QXcbDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const { QByteArray mime = mimetype.toLatin1(); - QVariant data = /*X11->motifdnd_active - ? X11->motifdndObtainData(mime) - :*/ xdndObtainData(mime, requestedType); + QVariant data = xdndObtainData(mime, requestedType); return data; } @@ -1260,20 +1256,11 @@ bool QXcbDropData::hasFormat_sys(const QString &format) const QStringList QXcbDropData::formats_sys() const { QStringList formats; -// if (X11->motifdnd_active) { -// int i = 0; -// QByteArray fmt; -// while (!(fmt = X11->motifdndFormat(i)).isEmpty()) { -// formats.append(QLatin1String(fmt)); -// ++i; -// } -// } else { - for (int i = 0; i < drag->xdnd_types.size(); ++i) { - QString f = mimeAtomToString(drag->connection(), drag->xdnd_types.at(i)); - if (!formats.contains(f)) - formats.append(f); - } -// } + for (int i = 0; i < drag->xdnd_types.size(); ++i) { + QString f = mimeAtomToString(drag->connection(), drag->xdnd_types.at(i)); + if (!formats.contains(f)) + formats.append(f); + } return formats; } -- cgit v1.2.3 From c4ff5c53efc213d9ce4fe0cfe9ab3d6c13cd8716 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 19 Oct 2012 16:35:54 +0200 Subject: Mac: Adapt scrollbar fadeout animation for QStyleAnimation Change-Id: I39f1089e8d6ba1bb412d33aa4ebc0971aba52681 Reviewed-by: Jens Bache-Wiig --- src/widgets/styles/qmacstyle_mac.mm | 9 ++++++++- src/widgets/styles/qmacstyle_mac_p.h | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 38f4dc3abc..2b6f271a40 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1739,7 +1739,6 @@ bool QMacStylePrivate::addWidget(QWidget *w) bool isScrollBar = (qobject_cast(w)); if (isScrollBar) { w->installEventFilter(q); - startAnimate(AquaScrollBar, w); return true; } } @@ -5106,6 +5105,14 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex QMacStylePrivate::ScrollBarFadeOutDuration); info.cleared = opacity <= 0.0; + if (info.animating && info.cleared) { + d->stopAnimation(slider->styleObject); + info.animating = false; + } else if (!info.animating && !info.cleared) { + d->startAnimation(new QStyleAnimation(slider->styleObject)); + info.animating = true; + } + CGContextBeginTransparencyLayerWithRect(cg, qt_hirectForQRect(slider->rect), NULL); CGContextSetAlpha(cg, opacity); diff --git a/src/widgets/styles/qmacstyle_mac_p.h b/src/widgets/styles/qmacstyle_mac_p.h index 812c79e158..66691c63f7 100644 --- a/src/widgets/styles/qmacstyle_mac_p.h +++ b/src/widgets/styles/qmacstyle_mac_p.h @@ -211,7 +211,8 @@ public: lastUpdate(QDateTime::currentMSecsSinceEpoch()), hovered(false), lastHovered(0), - cleared(false) + cleared(false), + animating(false) {} int lastValue; int lastMinimum; @@ -221,6 +222,7 @@ public: bool hovered; qint64 lastHovered; bool cleared; + bool animating; }; mutable QMap scrollBarInfos; -- cgit v1.2.3 From bdc115d9698d4f3cf5ce089dbddca75e425d3eeb Mon Sep 17 00:00:00 2001 From: Andreas Hartmetz Date: Sun, 14 Oct 2012 04:28:51 +0200 Subject: detach() safely in QVector::erase(), and update callers to not detach. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit remove() can use non-detaching iterators internally before calling erase(), which hasn't been exploited so far, so that the detach() in erase() never actually detached. When using erase() from outside, you can't do it legally without calling begin() or end() that detach() before erase() is called. Now remove() doesn't detach anymore, and detaching in erase() works. With new tests that fail after changing only the erase() callers and pass again after fixing erase(). Change-Id: I47c0a9e362dce8628ec566f5437d951755de96c8 Reviewed-by: Thorbjørn Lund Martsum Reviewed-by: Olivier Goffart Reviewed-by: Konstantin Ritt --- src/corelib/tools/qvector.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 925ad17110..94733f77da 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -200,8 +200,8 @@ public: typedef int size_type; inline void push_back(const T &t) { append(t); } inline void push_front(const T &t) { prepend(t); } - void pop_back() { Q_ASSERT(!isEmpty()); erase(end()-1); } - void pop_front() { Q_ASSERT(!isEmpty()); erase(begin()); } + void pop_back() { Q_ASSERT(!isEmpty()); erase(d->end() - 1); } + void pop_front() { Q_ASSERT(!isEmpty()); erase(d->begin()); } inline bool empty() const { return d->size == 0; } inline T& front() { return first(); } @@ -366,11 +366,11 @@ inline void QVector::insert(int i, int n, const T &t) template inline void QVector::remove(int i, int n) { Q_ASSERT_X(i >= 0 && n >= 0 && i + n <= d->size, "QVector::remove", "index out of range"); - erase(begin() + i, begin() + i + n); } + erase(d->begin() + i, d->begin() + i + n); } template inline void QVector::remove(int i) { Q_ASSERT_X(i >= 0 && i < d->size, "QVector::remove", "index out of range"); - erase(begin() + i, begin() + i + 1); } + erase(d->begin() + i, d->begin() + i + 1); } template inline void QVector::prepend(const T &t) { insert(begin(), 1, t); } @@ -607,6 +607,8 @@ typename QVector::iterator QVector::erase(iterator abegin, iterator aend) // FIXME we ara about to delete data maybe it is good time to shrink? if (d->alloc) { detach(); + abegin = d->begin() + itemsUntouched; + aend = abegin + itemsToErase; if (QTypeInfo::isStatic) { iterator moveBegin = abegin + itemsToErase; iterator moveEnd = d->end(); -- cgit v1.2.3 From 9690548113e03614c770cec44a527e6c1edce6ab Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Wed, 17 Oct 2012 14:31:33 +0300 Subject: QFont: Don't invalidate engine unless request has been changed This makes QFont do a "light" detach when the font attributes data has been changed. The new test clearly shows that the engine is now shared between two font instances after changing the kerning attribute. Change-Id: I59db822f459f02d111686dba7101b98e361fada9 Reviewed-by: Marc Mutz Reviewed-by: Lars Knoll --- src/gui/text/qfont.cpp | 33 ++++++++++++++++++++++++++------- src/gui/text/qfont_p.h | 3 +++ 2 files changed, 29 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 995d48d450..2bc63cbd10 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -648,6 +648,24 @@ void QFont::detach() d.detach(); } +/*! + \internal + Detaches the font object from common font attributes data. + Call this instead of QFont::detach() if the only font attributes data + has been changed (underline, letterSpacing, kerning, etc.). +*/ +void QFontPrivate::detachButKeepEngineData(QFont *font) +{ + if (font->d->ref.load() == 1) + return; + + QFontEngineData *engineData = font->d->engineData; + if (engineData) + engineData->ref.ref(); + font->d.detach(); + font->d->engineData = engineData; +} + /*! Constructs a font object that uses the application's default font. @@ -1149,7 +1167,7 @@ void QFont::setUnderline(bool enable) if ((resolve_mask & QFont::UnderlineResolved) && d->underline == enable) return; - detach(); + QFontPrivate::detachButKeepEngineData(this); d->underline = enable; resolve_mask |= QFont::UnderlineResolved; @@ -1175,7 +1193,7 @@ void QFont::setOverline(bool enable) if ((resolve_mask & QFont::OverlineResolved) && d->overline == enable) return; - detach(); + QFontPrivate::detachButKeepEngineData(this); d->overline = enable; resolve_mask |= QFont::OverlineResolved; @@ -1202,7 +1220,7 @@ void QFont::setStrikeOut(bool enable) if ((resolve_mask & QFont::StrikeOutResolved) && d->strikeOut == enable) return; - detach(); + QFontPrivate::detachButKeepEngineData(this); d->strikeOut = enable; resolve_mask |= QFont::StrikeOutResolved; @@ -1262,7 +1280,7 @@ void QFont::setKerning(bool enable) if ((resolve_mask & QFont::KerningResolved) && d->kerning == enable) return; - detach(); + QFontPrivate::detachButKeepEngineData(this); d->kerning = enable; resolve_mask |= QFont::KerningResolved; @@ -1512,7 +1530,7 @@ void QFont::setLetterSpacing(SpacingType type, qreal spacing) d->letterSpacing == newSpacing) return; - detach(); + QFontPrivate::detachButKeepEngineData(this); d->letterSpacing = newSpacing; d->letterSpacingIsAbsolute = absoluteSpacing; @@ -1562,7 +1580,7 @@ void QFont::setWordSpacing(qreal spacing) d->wordSpacing == newSpacing) return; - detach(); + QFontPrivate::detachButKeepEngineData(this); d->wordSpacing = newSpacing; resolve_mask |= QFont::WordSpacingResolved; @@ -1596,7 +1614,7 @@ void QFont::setCapitalization(Capitalization caps) capitalization() == caps) return; - detach(); + QFontPrivate::detachButKeepEngineData(this); d->capital = caps; resolve_mask |= QFont::CapitalizationResolved; @@ -1635,6 +1653,7 @@ void QFont::setRawMode(bool enable) { if ((bool) d->rawMode == enable) return; + // might change behavior, thus destroy engine data detach(); d->rawMode = enable; diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index f32b6e72a4..2a37b56d87 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -185,6 +185,9 @@ public: } void resolve(uint mask, const QFontPrivate *other); + + static void detachButKeepEngineData(QFont *font); + private: QFontPrivate &operator=(const QFontPrivate &) { return *this; } }; -- cgit v1.2.3 From 7d7f09650c3b3b2990f16ff4a6401a8c74e1f868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 17 Oct 2012 14:34:32 +0200 Subject: Fixed GCC 3.4 build with sse2 enabled. With minimal effort we can keep the GCC 3.4 build working. Task-number: QTBUG-19803 Change-Id: I31611a27b97d5ac426ea857d8f1b656dc6f5377a Reviewed-by: Thiago Macieira --- src/gui/painting/qdrawhelper_sse2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index e72b9ba968..a29d2037db 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -535,7 +535,8 @@ public: static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); } // pre-VS 2008 doesn't have cast intrinsics, whereas 2008 and later requires it -#if defined(Q_CC_MSVC) && _MSC_VER < 1500 + // (same deal with gcc prior to 4.0) +#if (defined(Q_CC_MSVC) && _MSC_VER < 1500) || (defined(Q_CC_GNU) && __GNUC__ < 4) static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { union Convert { Int32x4 vi; Float32x4 vf; } convert; -- cgit v1.2.3 From cdc2161b6f87deaac6a256885fd6ecdccad6eb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 1 Oct 2012 10:17:21 +0200 Subject: Made xcb plugin work when the GLX extension is not present. Change-Id: I9285d7524586ff404206c088019ece33335137d9 Reviewed-by: Lars Knoll --- src/plugins/platforms/xcb/README | 6 ++--- src/plugins/platforms/xcb/qxcbconnection.cpp | 33 +++++++++++++++++++++++++++ src/plugins/platforms/xcb/qxcbconnection.h | 3 +++ src/plugins/platforms/xcb/qxcbintegration.cpp | 10 +++++++- src/plugins/platforms/xcb/qxcbwindow.cpp | 4 +--- src/plugins/platforms/xcb/xcb.pro | 4 ++++ 6 files changed, 53 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index 264d28c6b4..59d9ffe39b 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -1,14 +1,14 @@ Requires libxcb >= 1.5. Required packages: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev On Ubuntu 11.10 icccm1 is replaced by icccm4 and xcb-render-util is not available: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev The packages for xcb-render-util can be installed manually from http://packages.ubuntu.com/natty/libxcb-render-util0 and http://packages.ubuntu.com/natty/libxcb-render-util0-dev On Ubuntu 12.04 icccm1 is replaced by icccm4 and xcb-render-util can be installed automatically: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0 libxcb-render-util0-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-glx0-dev On Fedora, the following packages are required: diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index ad9fb1d19c..bb5f301fea 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -72,6 +72,10 @@ #include #endif +#if defined(XCB_HAS_XCB_GLX) +#include +#endif + #ifdef XCB_USE_EGL //don't pull in eglext prototypes #include #endif @@ -263,6 +267,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char #endif , xfixes_first_event(0) , xrandr_first_event(0) + , has_glx_extension(false) , has_shape_extension(false) , has_randr_extension(false) , has_input_shape(false) @@ -320,6 +325,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, m_screens.at(0)->screen()->root_visual, 0, 0); + initializeGLX(); initializeXFixes(); initializeXRender(); m_xi2Enabled = false; @@ -1312,6 +1318,33 @@ void QXcbConnection::initializeXRender() #endif } +void QXcbConnection::initializeGLX() +{ +#ifdef XCB_HAS_XCB_GLX + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_glx_id); + if (!reply || !reply->present) + return; + + has_glx_extension = true; + + xcb_generic_error_t *error = 0; + xcb_glx_query_version_cookie_t xglx_query_cookie = xcb_glx_query_version(m_connection, + XCB_GLX_MAJOR_VERSION, + XCB_GLX_MINOR_VERSION); + xcb_glx_query_version_reply_t *xglx_query = xcb_glx_query_version_reply(m_connection, + xglx_query_cookie, &error); + if (!xglx_query || error) { + qWarning("QXcbConnection: Failed to initialize GLX"); + free(error); + has_glx_extension = false; + } + free(xglx_query); +#else + // no way to check, assume GLX is present + has_glx_extension = true; +#endif +} + void QXcbConnection::initializeXRandr() { const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_randr_id); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 8a6c418788..cbfdd803f2 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -374,6 +374,7 @@ public: inline xcb_timestamp_t time() const { return m_time; } inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; } + bool hasGLX() const { return has_glx_extension; } bool hasXFixes() const { return xfixes_first_event > 0; } bool hasXShape() const { return has_shape_extension; } bool hasXRandr() const { return has_randr_extension; } @@ -387,6 +388,7 @@ private slots: private: void initializeAllAtoms(); void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); + void initializeGLX(); void initializeXFixes(); void initializeXRender(); void initializeXRandr(); @@ -507,6 +509,7 @@ private: uint32_t xfixes_first_event; uint32_t xrandr_first_event; + bool has_glx_extension; bool has_shape_extension; bool has_randr_extension; bool has_input_shape; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 2ace68036b..f6077316e6 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -192,9 +192,11 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont screen->connection()->egl_display(), screen->connection()); #elif defined(XCB_USE_DRI2) return new QDri2Context(context->format(), context->shareHandle()); -#endif +#else + Q_UNUSED(screen); qWarning("QXcbIntegration: Cannot create platform OpenGL context, none of GLX, EGL, or DRI2 are enabled"); return 0; +#endif } #endif @@ -207,7 +209,13 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { case ThreadedPixmaps: return true; +#if defined(XCB_USE_GLX) + case OpenGL: return m_connections.at(0)->hasGLX(); +#elif defined(XCB_USE_EGL) || defined(XCB_USE_DRI2) case OpenGL: return true; +#else + case OpenGL: return false; +#endif case ThreadedOpenGL: return false; case WindowMasks: return true; default: return QPlatformIntegration::hasCapability(cap); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index bab1884a9a..30f833012c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -233,9 +233,7 @@ void QXcbWindow::create() m_format = window()->requestedFormat(); #if (defined(XCB_USE_GLX) || defined(XCB_USE_EGL)) && defined(XCB_USE_XLIB) - if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) - || m_format.hasAlpha()) - { + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { #if defined(XCB_USE_GLX) XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format); if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface) diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 116951d36d..617f2e685c 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -98,6 +98,10 @@ contains(DEFINES, XCB_USE_DRI2) { HEADERS += qglxintegration.h SOURCES += qglxintegration.cpp LIBS += $$QMAKE_LIBS_DYNLOAD + contains(QT_CONFIG, xcb-glx) { + DEFINES += XCB_HAS_XCB_GLX + LIBS += -lxcb-glx + } } } -- cgit v1.2.3 From 9b2e4cd5a8cac007aa702ce5f822e78e54707a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 2 Oct 2012 09:30:18 +0200 Subject: Small xcb startup performance optimization. Prefetch all the extensions, to avoid having to do blocking calls later. Change-Id: I1527dbf03d76372ec88bc0d5d9f7af18a4cc2a26 Reviewed-by: Lars Knoll Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbconnection.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index bb5f301fea..3261bd189d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -60,6 +60,8 @@ #include #include +#include +#include #include #ifdef XCB_USE_XLIB @@ -308,7 +310,19 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents())); #endif - xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id); + xcb_extension_t *extensions[] = { + &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, +#ifdef XCB_USE_RENDER + &xcb_render_id, +#endif +#ifdef XCB_HAS_XCB_GLX + &xcb_glx_id, +#endif + 0 + }; + + for (xcb_extension_t **ext_it = extensions; *ext_it; ++ext_it) + xcb_prefetch_extension_data (m_connection, *ext_it); m_setup = xcb_get_setup(xcb_connection()); -- cgit v1.2.3 From 39eaff6773fc4f05fc95473b769b3a2f0301e12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 8 Oct 2012 12:53:56 +0200 Subject: Remove DRI2/OpenGL code paths from xcb plugin. These were used to test QtWayland, but there are other options available for that now. The DRI2 code hasn't been maintained and doesn't even compile at the moment, so let's just remove it to de-clutter the source. Change-Id: I7db0f4db82348497b9f4d6c2dcf2e13f3ab14a76 Reviewed-by: Uli Schlachter Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira --- src/plugins/platforms/xcb/qdri2context.cpp | 273 ---------------------- src/plugins/platforms/xcb/qdri2context.h | 81 ------- src/plugins/platforms/xcb/qxcbconnection.cpp | 108 --------- src/plugins/platforms/xcb/qxcbconnection.h | 22 +- src/plugins/platforms/xcb/qxcbintegration.cpp | 6 +- src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 42 +--- src/plugins/platforms/xcb/qxcbwindow.cpp | 9 - src/plugins/platforms/xcb/xcb.pro | 12 +- 8 files changed, 8 insertions(+), 545 deletions(-) delete mode 100644 src/plugins/platforms/xcb/qdri2context.cpp delete mode 100644 src/plugins/platforms/xcb/qdri2context.h (limited to 'src') diff --git a/src/plugins/platforms/xcb/qdri2context.cpp b/src/plugins/platforms/xcb/qdri2context.cpp deleted file mode 100644 index 5f116fe0f6..0000000000 --- a/src/plugins/platforms/xcb/qdri2context.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdri2context.h" - -#include "qxcbwindow.h" -#include "qxcbconnection.h" - -#include -#include - -#include -#include - -#define MESA_EGL_NO_X11_HEADERS -#define EGL_EGLEXT_PROTOTYPES -#include -#include - -#define GL_GLEXT_PROTOTYPES -#include -#include - -QT_BEGIN_NAMESPACE - -class QDri2ContextPrivate -{ -public: - QDri2ContextPrivate(QXcbWindow *window) - : qXcbWindow(window) - , windowFormat(window->widget()->platformWindowFormat()) - , image(0) - { - } - - xcb_window_t xcbWindow() { return qXcbWindow->window(); } - xcb_connection_t *xcbConnection() { return qXcbWindow->xcb_connection(); } - - QXcbWindow *qXcbWindow; - QPlatformWindowFormat windowFormat; - - EGLContext eglContext; - - EGLImageKHR image; - - GLuint fbo; - GLuint rbo; - GLuint depth; - - QSize size; -}; - -QDri2Context::QDri2Context(QXcbWindow *window) - : d_ptr(new QDri2ContextPrivate(window)) -{ - Q_D(QDri2Context); - - static const EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - eglBindAPI(EGL_OPENGL_ES_API); - - EGLContext shareContext = EGL_NO_CONTEXT; - if (window->widget()->platformWindowFormat().sharedGLContext()) { - QDri2Context *context = static_cast(window->widget()->platformWindowFormat().sharedGLContext()); - shareContext = context->d_func()->eglContext; - } - d->eglContext = eglCreateContext(EGL_DISPLAY_FROM_XCB(d->qXcbWindow), NULL, - shareContext, contextAttribs); - - if (d->eglContext == EGL_NO_CONTEXT) { - qDebug() << "No eglContext!" << eglGetError(); - } - - EGLBoolean makeCurrentSuccess = eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,d->eglContext); - if (!makeCurrentSuccess) { - qDebug() << "eglMakeCurrent failed!" << eglGetError(); - } - - xcb_dri2_create_drawable (d->xcbConnection(), d->xcbWindow()); - - glGenFramebuffers(1,&d->fbo); - glBindFramebuffer(GL_FRAMEBUFFER,d->fbo); - glActiveTexture(GL_TEXTURE0); - - glGenRenderbuffers(1, &d->rbo); - glBindRenderbuffer(GL_RENDERBUFFER, d->rbo); - - glGenRenderbuffers(1,&d->depth); - glBindRenderbuffer(GL_RENDERBUFFER, d->depth); - - resize(d->qXcbWindow->widget()->geometry().size()); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, d->rbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERER,d->depth); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERER,d->depth); - - //restore the old current context - const QPlatformOpenGLContext *currentContext = QPlatformOpenGLContext::currentContext(); - if (currentContext) - const_cast(currentContext)->makeCurrent(); -} - -QDri2Context::~QDri2Context() -{ - //cleanup -} - -void QDri2Context::makeCurrent() -{ - Q_D(QDri2Context); - - eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,d->eglContext); - glBindFramebuffer(GL_FRAMEBUFFER,d->fbo); - -} - -void QDri2Context::doneCurrent() -{ - Q_D(QDri2Context); - eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); -} - -void QDri2Context::swapBuffers() -{ - Q_D(QDri2Context); - xcb_rectangle_t rectangle; - rectangle.x = 0; - rectangle.y = 0; - rectangle.width = d->qXcbWindow->widget()->geometry().width(); - rectangle.height = d->qXcbWindow->widget()->geometry().height(); - - xcb_xfixes_region_t xfixesRegion = xcb_generate_id(d->xcbConnection()); - xcb_xfixes_create_region(d->xcbConnection(), xfixesRegion, - 1, &rectangle); - - xcb_dri2_copy_region_cookie_t cookie = xcb_dri2_copy_region_unchecked(d->xcbConnection(), - d->qXcbWindow->window(), - xfixesRegion, - XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT, - XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT); - - xcb_dri2_copy_region_reply_t *reply = xcb_dri2_copy_region_reply(d->xcbConnection(),cookie,NULL); - - //cleanup - delete reply; - xcb_xfixes_destroy_region(d->xcbConnection(), xfixesRegion); - -} - -void * QDri2Context::getProcAddress(const QString &procName) -{ - return (void *)eglGetProcAddress(qPrintable(procName)); -} - -void QDri2Context::resize(const QSize &size) -{ - Q_D(QDri2Context); - d->size= size; - - glBindFramebuffer(GL_FRAMEBUFFER,d->fbo); - - xcb_dri2_dri2_buffer_t *backBfr = backBuffer(); - - if (d->image) { - qDebug() << "destroing image"; - eglDestroyImageKHR(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),d->image); - } - - EGLint imgAttribs[] = { - EGL_WIDTH, d->size.width(), - EGL_HEIGHT, d->size.height(), - EGL_DRM_BUFFER_STRIDE_MESA, backBfr->pitch /4, - EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, - EGL_NONE - }; - - d->image = eglCreateImageKHR(EGL_DISPLAY_FROM_XCB(d->qXcbWindow), - EGL_NO_CONTEXT, - EGL_DRM_BUFFER_MESA, - (EGLClientBuffer) backBfr->name, - imgAttribs); - - glBindRenderbuffer(GL_RENDERBUFFER, d->rbo); - glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, - d->image); - - glBindRenderbuffer(GL_RENDERBUFFER, d->depth); - glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH24_STENCIL8_OES,d->size.width(), d->size.height()); - -} - -QPlatformWindowFormat QDri2Context::platformWindowFormat() const -{ - Q_D(const QDri2Context); - return d->windowFormat; -} - -xcb_dri2_dri2_buffer_t * QDri2Context::backBuffer() -{ - Q_D(QDri2Context); - - unsigned int backBufferAttachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT; - xcb_dri2_get_buffers_cookie_t cookie = xcb_dri2_get_buffers_unchecked (d->xcbConnection(), - d->xcbWindow(), - 1, 1, &backBufferAttachment); - - xcb_dri2_get_buffers_reply_t *reply = xcb_dri2_get_buffers_reply (d->xcbConnection(), cookie, NULL); - if (!reply) { - qDebug() << "failed to get buffers reply"; - return 0; - } - - xcb_dri2_dri2_buffer_t *buffers = xcb_dri2_get_buffers_buffers (reply); - if (!buffers) { - qDebug() << "failed to get buffers"; - return 0; - } - - Q_ASSERT(reply->count == 1); - - delete reply; - - return buffers; -} - -void * QDri2Context::eglContext() const -{ - Q_D(const QDri2Context); - return d->eglContext; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qdri2context.h b/src/plugins/platforms/xcb/qdri2context.h deleted file mode 100644 index e355eb5c28..0000000000 --- a/src/plugins/platforms/xcb/qdri2context.h +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDRI2CONTEXT_H -#define QDRI2CONTEXT_H - -#include - -struct xcb_dri2_dri2_buffer_t; - -QT_BEGIN_NAMESPACE - -class QXcbWindow; -class QDri2ContextPrivate; - -class QDri2Context : public QPlatformOpenGLContext -{ - Q_DECLARE_PRIVATE(QDri2Context); -public: - QDri2Context(QXcbWindow *window); - ~QDri2Context(); - - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); - - void resize(const QSize &size); - - QPlatformWindowFormat platformWindowFormat() const; - - void *eglContext() const; - -protected: - xcb_dri2_dri2_buffer_t *backBuffer(); - QScopedPointer d_ptr; -private: - Q_DISABLE_COPY(QDri2Context) -}; - -QT_END_NAMESPACE - -#endif // QDRI2CONTEXT_H diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 3261bd189d..85f6fc9213 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -82,17 +82,6 @@ #include #endif -#ifdef XCB_USE_DRI2 -#include -extern "C" { -#include -} -#define MESA_EGL_NO_X11_HEADERS -#define EGL_EGLEXT_PROTOTYPES -#include -#include -#endif - #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) #include #include @@ -260,12 +249,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char , m_nativeInterface(nativeInterface) #ifdef XCB_USE_XINPUT2_MAEMO , m_xinputData(0) -#endif -#ifdef XCB_USE_DRI2 - , m_dri2_major(0) - , m_dri2_minor(0) - , m_dri2_support_probed(false) - , m_has_support_for_dri2(false) #endif , xfixes_first_event(0) , xrandr_first_event(0) @@ -359,9 +342,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char m_drag = new QXcbDrag(this); #endif -#ifdef XCB_USE_DRI2 - initializeDri2(); -#endif sync(); } @@ -1410,94 +1390,6 @@ bool QXcbConnection::hasEgl() const } #endif // defined(XCB_USE_EGL) -#ifdef XCB_USE_DRI2 -void QXcbConnection::initializeDri2() -{ - xcb_dri2_connect_cookie_t connect_cookie = xcb_dri2_connect_unchecked (m_connection, - m_screens[0]->root(), - XCB_DRI2_DRIVER_TYPE_DRI); - - xcb_dri2_connect_reply_t *connect = xcb_dri2_connect_reply (m_connection, - connect_cookie, NULL); - - if (! connect || connect->driver_name_length + connect->device_name_length == 0) { - qWarning("QXcbConnection: Failed to connect to DRI2"); - return; - } - - m_dri2_device_name = QByteArray(xcb_dri2_connect_device_name (connect), - xcb_dri2_connect_device_name_length (connect)); - delete connect; - - int fd = open(m_dri2_device_name.constData(), O_RDWR); - if (fd < 0) { - qWarning() << "QXcbConnection: Couldn't open DRI2 device" << m_dri2_device_name; - m_dri2_device_name = QByteArray(); - return; - } - - drm_magic_t magic; - if (drmGetMagic(fd, &magic)) { - qWarning("QXcbConnection: Failed to get drmMagic"); - return; - } - - xcb_dri2_authenticate_cookie_t authenticate_cookie = xcb_dri2_authenticate_unchecked(m_connection, - m_screens[0]->root(), magic); - xcb_dri2_authenticate_reply_t *authenticate = xcb_dri2_authenticate_reply(m_connection, - authenticate_cookie, NULL); - if (authenticate == NULL || !authenticate->authenticated) { - qWarning("QXcbConnection: DRI2: failed to authenticate"); - free(authenticate); - return; - } - - delete authenticate; - - EGLDisplay display = eglGetDRMDisplayMESA(fd); - if (!display) { - qWarning("QXcbConnection: Failed to create EGL display using DRI2"); - return; - } - - m_egl_display = display; - EGLint major,minor; - if (!eglInitialize(display, &major, &minor)) { - qWarning("QXcbConnection: Failed to initialize EGL display using DRI2"); - return; - } -} - -bool QXcbConnection::hasSupportForDri2() const -{ - if (!m_dri2_support_probed) { - xcb_generic_error_t *error = 0; - - xcb_prefetch_extension_data (m_connection, &xcb_dri2_id); - - xcb_dri2_query_version_cookie_t dri2_query_cookie = xcb_dri2_query_version (m_connection, - XCB_DRI2_MAJOR_VERSION, - XCB_DRI2_MINOR_VERSION); - - xcb_dri2_query_version_reply_t *dri2_query = xcb_dri2_query_version_reply (m_connection, - dri2_query_cookie, &error); - if (!dri2_query || error) { - delete error; - delete dri2_query; - return false; - } - - QXcbConnection *that = const_cast(this); - that->m_dri2_major = dri2_query->major_version; - that->m_dri2_minor = dri2_query->minor_version; - - that->m_has_support_for_dri2 = true; - that->m_dri2_support_probed = true; - } - return m_has_support_for_dri2; -} -#endif //XCB_USE_DRI2 - #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) // Borrowed from libXi. int QXcbConnection::xi2CountBits(unsigned char *ptr, int len) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index cbfdd803f2..8b2315c67e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -338,14 +338,10 @@ public: void *xlib_display() const { return m_xlib_display; } #endif -#ifdef XCB_USE_DRI2 - bool hasSupportForDri2() const; - QByteArray dri2DeviceName() const { return m_dri2_device_name; } -#endif #ifdef XCB_USE_EGL bool hasEgl() const; #endif -#if defined(XCB_USE_EGL) || defined(XCB_USE_DRI2) +#if defined(XCB_USE_EGL) void *egl_display() const { return m_egl_display; } #endif #ifdef XCB_USE_XINPUT2_MAEMO @@ -393,9 +389,6 @@ private: void initializeXRender(); void initializeXRandr(); void initializeXShape(); -#ifdef XCB_USE_DRI2 - void initializeDri2(); -#endif #ifdef XCB_USE_XINPUT2_MAEMO void initializeXInput2Maemo(); void finalizeXInput2Maemo(); @@ -478,14 +471,7 @@ private: QHash m_touchPoints; QHash m_touchDevices; #endif -#ifdef XCB_USE_DRI2 - uint32_t m_dri2_major; - uint32_t m_dri2_minor; - bool m_dri2_support_probed; - bool m_has_support_for_dri2; - QByteArray m_dri2_device_name; -#endif -#if defined(XCB_USE_EGL) || defined(XCB_USE_DRI2) +#if defined(XCB_USE_EGL) void *m_egl_display; bool m_has_egl; #endif @@ -552,9 +538,9 @@ cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, #endif -#if defined(XCB_USE_DRI2) || defined(XCB_USE_EGL) +#if defined(XCB_USE_EGL) #define EGL_DISPLAY_FROM_XCB(object) ((EGLDisplay)(object->connection()->egl_display())) -#endif //endifXCB_USE_DRI2 +#endif QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index f6077316e6..5170ff9e10 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -190,11 +190,9 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont #elif defined(XCB_USE_EGL) return new QEGLXcbPlatformContext(context->format(), context->shareHandle(), screen->connection()->egl_display(), screen->connection()); -#elif defined(XCB_USE_DRI2) - return new QDri2Context(context->format(), context->shareHandle()); #else Q_UNUSED(screen); - qWarning("QXcbIntegration: Cannot create platform OpenGL context, none of GLX, EGL, or DRI2 are enabled"); + qWarning("QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled"); return 0; #endif } @@ -211,7 +209,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const case ThreadedPixmaps: return true; #if defined(XCB_USE_GLX) case OpenGL: return m_connections.at(0)->hasGLX(); -#elif defined(XCB_USE_EGL) || defined(XCB_USE_DRI2) +#elif defined(XCB_USE_EGL) case OpenGL: return true; #else case OpenGL: return false; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 335866dc9d..40f39843e5 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -53,8 +53,6 @@ #if defined(XCB_USE_EGL) #include "QtPlatformSupport/private/qeglplatformcontext_p.h" -#elif defined (XCB_USE_DRI2) -#include "qdri2context.h" #endif QT_BEGIN_NAMESPACE @@ -69,7 +67,6 @@ public: insert("egldisplay",QXcbNativeInterface::EglDisplay); insert("connection",QXcbNativeInterface::Connection); insert("screen",QXcbNativeInterface::Screen); - insert("graphicsdevice",QXcbNativeInterface::GraphicsDevice); insert("eglcontext",QXcbNativeInterface::EglContext); } }; @@ -122,9 +119,6 @@ void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceStr case Screen: result = qPlatformScreenForWindow(window); break; - case GraphicsDevice: - result = graphicsDeviceForWindow(window); - break; default: break; } @@ -165,7 +159,7 @@ void *QXcbNativeInterface::displayForWindow(QWindow *window) void *QXcbNativeInterface::eglDisplayForWindow(QWindow *window) { -#if defined(XCB_USE_DRI2) || defined(XCB_USE_EGL) +#if defined(XCB_USE_EGL) QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->connection()->egl_display(); #else @@ -186,19 +180,6 @@ void *QXcbNativeInterface::screenForWindow(QWindow *window) return screen->screen(); } -void *QXcbNativeInterface::graphicsDeviceForWindow(QWindow *window) -{ -#if defined(XCB_USE_DRI2) - QXcbScreen *screen = qPlatformScreenForWindow(window); - QByteArray deviceName = screen->connection()->dri2DeviceName(); - return deviceName.data(); -#else - Q_UNUSED(window); - return 0; -#endif - -} - void * QXcbNativeInterface::eglContextForContext(QOpenGLContext *context) { Q_ASSERT(context); @@ -206,27 +187,6 @@ void * QXcbNativeInterface::eglContextForContext(QOpenGLContext *context) QEGLPlatformContext *eglPlatformContext = static_cast(context->handle()); return eglPlatformContext->eglContext(); #endif -#if 0 - Q_ASSERT(window); - QPlatformOpenGLContext *platformContext = window->glContext()->handle(); - if (!platformContext) { - qDebug() << "QWindow" << window << "does not have a glContext" - << "cannot return EGLContext"; - return 0; - } -#if defined(XCB_USE_EGL) - QEGLPlatformContext *eglPlatformContext = static_cast(platformContext); - return eglPlatformContext->eglContext(); -#elif defined (XCB_USE_DRI2) - QDri2Context *dri2Context = static_cast(platformContext); - return dri2Context->eglContext(); -#else - return 0; -#endif -#else - Q_UNUSED(context) - return 0; -#endif } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 30f833012c..48754b0a60 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -55,10 +55,6 @@ #include -#ifdef XCB_USE_DRI2 -#include "qdri2context.h" -#endif - // FIXME This workaround can be removed for xcb-icccm > 3.8 #define class class_name #include @@ -1391,11 +1387,6 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } m_dirtyFrameMargins = true; - -#if XCB_USE_DRI2 - if (m_context) - static_cast(m_context)->resize(rect.size()); -#endif } bool QXcbWindow::isExposed() const diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 617f2e685c..58521686aa 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -74,17 +74,7 @@ contains(QT_CONFIG, xcb-render) { !contains(DEFINES, QT_NO_SHAPE):LIBS += -lxcb-shape -# DEFINES += XCB_USE_DRI2 -contains(DEFINES, XCB_USE_DRI2) { - LIBS += -lxcb-dri2 -lEGL - - CONFIG += link_pkgconfig - PKGCONFIG += libdrm - - HEADERS += qdri2context.h - SOURCES += qdri2context.cpp - -} else:contains(QT_CONFIG, opengl) { +contains(QT_CONFIG, opengl) { contains(QT_CONFIG, opengles2) { DEFINES += XCB_USE_EGL LIBS += -lEGL -- cgit v1.2.3 From d7e8b57d0a98696a05cfb0eb15236a34301d9d0a Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Fri, 19 Oct 2012 00:33:03 +0800 Subject: Remove the QThread::terminated() signal The signal is removed from the API; all references to it are removed from documentation; the unit test that checks for its emission is modified to listen for QThread::finished() instead. The QThreadPrivate::terminated flag is also removed, as it served no purpose other than to trigger the emission of QThread::terminated() As discussed at http://lists.qt-project.org/pipermail/development/2012-October/007216.html the signal is not guaranteed to be emitted after every termination, rendering it useless. Change-Id: I7b0c45d7889da0d33875545331606f2208ee56fc Reviewed-by: Lars Knoll Reviewed-by: Olivier Goffart --- src/corelib/thread/qthread.cpp | 27 ++++++++------------------- src/corelib/thread/qthread.h | 1 - src/corelib/thread/qthread_p.h | 1 - src/corelib/thread/qthread_unix.cpp | 7 ------- src/corelib/thread/qthread_win.cpp | 10 +--------- 5 files changed, 9 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 72bae48eba..465f2befbc 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -144,7 +144,7 @@ void QAdoptedThread::run() */ QThreadPrivate::QThreadPrivate(QThreadData *d) - : QObjectPrivate(), running(false), finished(false), terminated(false), + : QObjectPrivate(), running(false), finished(false), isInFinish(false), exited(false), returnCode(-1), stackSize(0), priority(QThread::InheritPriority), data(d) { @@ -203,10 +203,9 @@ QThreadPrivate::~QThreadPrivate() \section1 Managing threads - QThread will notifiy you via a signal - when the thread is started(), finished(), and terminated(), or - you can use isFinished() and isRunning() to query the state of - the thread. + QThread will notifiy you via a signal when the thread is + started() and finished(), or you can use isFinished() and + isRunning() to query the state of the thread. You can stop the thread by calling exit() or quit(). In extreme cases, you may want to forcibly terminate() an executing thread. @@ -326,7 +325,7 @@ QThreadPrivate::~QThreadPrivate() This signal is emitted from the associated thread when it starts executing, before the run() function is called. - \sa finished(), terminated() + \sa finished() */ /*! @@ -341,17 +340,7 @@ QThreadPrivate::~QThreadPrivate() \note If the associated thread was terminated using terminate(), it is undefined from which thread this signal is emitted. - \sa started(), terminated() -*/ - -/*! - \fn void QThread::terminated() - - This signal is emitted when the thread is terminated. - - It is undefined from which thread this signal is emitted. - - \sa started(), finished() + \sa started() */ /*! @@ -656,8 +645,8 @@ QThread::Priority QThread::priority() const Terminates the execution of the thread. The thread may or may not be terminated immediately, depending on the operating system's - scheduling policies. Listen for the terminated() signal, or use - QThread::wait() after terminate(), to be sure. + scheduling policies. Use QThread::wait() after terminate(), to be + sure. When the thread is terminated, all threads waiting for the thread to finish will be woken up. diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index 0fab71d5c1..8fda4513e6 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -113,7 +113,6 @@ public: Q_SIGNALS: void started(); void finished(); - void terminated(); protected: virtual void run(); diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 268891d5e8..ec89eed098 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -147,7 +147,6 @@ public: bool running; bool finished; - bool terminated; bool isInFinish; //when in QThreadPrivate::finish bool exited; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 7fd89f4bca..2213b8f71a 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -346,16 +346,12 @@ void QThreadPrivate::finish(void *arg) d->isInFinish = true; d->priority = QThread::InheritPriority; - bool terminated = d->terminated; void *data = &d->data->tls; locker.unlock(); - if (terminated) - emit thr->terminated(); emit thr->finished(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); QThreadStorageData::finish((void **)data); locker.relock(); - d->terminated = false; QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; if (eventDispatcher) { @@ -523,7 +519,6 @@ void QThread::start(Priority priority) d->running = true; d->finished = false; - d->terminated = false; d->returnCode = 0; d->exited = false; @@ -631,8 +626,6 @@ void QThread::terminate() if (code) { qWarning("QThread::start: Thread termination error: %s", qPrintable(qt_error_string((code)))); - } else { - d->terminated = true; } #endif } diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index b487efffad..56e58fbcc3 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -352,18 +352,13 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) QMutexLocker locker(lockAnyway ? &d->mutex : 0); d->isInFinish = true; d->priority = QThread::InheritPriority; - bool terminated = d->terminated; void **tls_data = reinterpret_cast(&d->data->tls); locker.unlock(); - if (terminated) - emit thr->terminated(); emit thr->finished(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); QThreadStorageData::finish(tls_data); locker.relock(); - d->terminated = false; - QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; if (eventDispatcher) { d->data->eventDispatcher = 0; @@ -443,7 +438,6 @@ void QThread::start(Priority priority) d->running = true; d->finished = false; - d->terminated = false; d->exited = false; d->returnCode = 0; @@ -524,7 +518,6 @@ void QThread::terminate() return; } TerminateThread(d->handle, 0); - d->terminated = true; QThreadPrivate::finish(this, false); } @@ -562,7 +555,7 @@ bool QThread::wait(unsigned long time) if (ret && !d->finished) { // thread was terminated by someone else - d->terminated = true; + QThreadPrivate::finish(this, false); } @@ -583,7 +576,6 @@ void QThread::setTerminationEnabled(bool enabled) QMutexLocker locker(&d->mutex); d->terminationEnabled = enabled; if (enabled && d->terminatePending) { - d->terminated = true; QThreadPrivate::finish(thr, false); locker.unlock(); // don't leave the mutex locked! _endthreadex(0); -- cgit v1.2.3 From 8e82a8e11f00a16c4d6b9703546f943c9ec34276 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 18 Oct 2012 20:58:50 -0700 Subject: Doc: refer to QUrlQuery in QUrl's main doc body As opposed to the deprecated methods. Task-number: QTBUG-25628 Change-Id: Ic1b50b1ac1b974cdd2dd9f0151d567227784e547 Reviewed-by: Stephen Kelly --- src/corelib/io/qurl.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index be87e1f34f..a7a722bc46 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -78,9 +78,10 @@ Call isValid() to check if the URL is valid. This can be done at any point during the constructing of a URL. - Constructing a query is particularly convenient through the use - of setQueryItems(), addQueryItem() and removeQueryItem(). Use - setQueryDelimiters() to customize the delimiters used for + Constructing a query is particularly convenient through the use of the \l + QUrlQuery class and its methods QUrlQuery::setQueryItems(), + QUrlQuery::addQueryItem() and QUrlQuery::removeQueryItem(). Use + QUrlQuery::setQueryDelimiters() to customize the delimiters used for generating the query string. For the convenience of generating encoded URL strings or query -- cgit v1.2.3 From a89eae8cb4675188707a850650f664e7be9fa292 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Sat, 20 Oct 2012 03:19:20 +0300 Subject: Fix crash due to memory access violation The font engine has been re-used without increasing it's reference counter Task-number: QTBUG-27596 Change-Id: Icd4c3ca131446255ad4a27da8aa9a6c69177212e Reviewed-by: Sergio Ahumada --- src/gui/text/qfontengine_qpa.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gui/text/qfontengine_qpa.cpp b/src/gui/text/qfontengine_qpa.cpp index 37195d5f61..c6e8a53284 100644 --- a/src/gui/text/qfontengine_qpa.cpp +++ b/src/gui/text/qfontengine_qpa.cpp @@ -726,6 +726,7 @@ void QFontEngineMultiQPA::setFallbackFamiliesList(const QStringList &fallbacks) // Turns out we lied about having any fallback at all. fallbackFamilies << fe->fontDef.family; engines[1] = fe; + fe->ref.ref(); } fallbacksQueried = true; } -- cgit v1.2.3 From a2b7b42ca4cf1ed682fa777b776673320b53e6ee Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 12 Oct 2012 15:00:23 +0200 Subject: Bring back accessibility for plain text edit. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ports 282951bc6c7ddb607fb7ebf61eb8de9acf3da77f aka Change-Id: If0269a49b9fcd1b3e9fcfd32fac912560df28f21 to Qt 5. Change-Id: I46f1d4947d90688b598993f76330e2e10aeca950 Reviewed-by: Marc Mutz Reviewed-by: Jan Arve Sæther --- src/plugins/accessible/widgets/main.cpp | 2 + .../accessible/widgets/qaccessiblewidgets.cpp | 96 ++++++++++++++++++++-- .../accessible/widgets/qaccessiblewidgets.h | 30 ++++++- src/plugins/accessible/widgets/widgets.json | 1 + src/widgets/widgets/qplaintextedit.cpp | 6 ++ 5 files changed, 125 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp index 2db039f9e5..55b1d375dd 100644 --- a/src/plugins/accessible/widgets/main.cpp +++ b/src/plugins/accessible/widgets/main.cpp @@ -202,6 +202,8 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec #ifndef QT_NO_TEXTEDIT } else if (classname == QLatin1String("QTextEdit")) { iface = new QAccessibleTextEdit(widget); + } else if (classname == QLatin1String("QPlainTextEdit")) { + iface = new QAccessiblePlainTextEdit(widget); #endif } else if (classname == QLatin1String("QTipLabel")) { iface = new QAccessibleDisplay(widget, QAccessible::ToolTip); diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index ad5ef69da4..eac31b8068 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -47,6 +47,7 @@ #include "private/qtextedit_p.h" #include "qtextdocument.h" #include "qtextobject.h" +#include "qplaintextedit.h" #include "qtextboundaryfinder.h" #include "qscrollbar.h" #include "qdebug.h" @@ -100,6 +101,90 @@ QList childWidgets(const QWidget *widget, bool includeTopLevel) #ifndef QT_NO_TEXTEDIT +QAccessiblePlainTextEdit::QAccessiblePlainTextEdit(QWidget* o) + :QAccessibleTextWidget(o) +{ + Q_ASSERT(widget()->inherits("QPlainTextEdit")); +} + +QPlainTextEdit* QAccessiblePlainTextEdit::plainTextEdit() const +{ + return static_cast(widget()); +} + +QString QAccessiblePlainTextEdit::text(QAccessible::Text t) const +{ + if (t == QAccessible::Value) + return plainTextEdit()->toPlainText(); + + return QAccessibleWidget::text(t); +} + +void QAccessiblePlainTextEdit::setText(QAccessible::Text t, const QString &text) +{ + if (t != QAccessible::Value) { + QAccessibleWidget::setText(t, text); + return; + } + if (plainTextEdit()->isReadOnly()) + return; + + plainTextEdit()->setPlainText(text); +} + +QAccessible::State QAccessiblePlainTextEdit::state() const +{ + QAccessible::State st = QAccessibleWidget::state(); + if (plainTextEdit()->isReadOnly()) + st.readOnly = true; + else + st.editable = true; + return st; +} + +void *QAccessiblePlainTextEdit::interface_cast(QAccessible::InterfaceType t) +{ + if (t == QAccessible::TextInterface) + return static_cast(this); + return QAccessibleWidget::interface_cast(t); +} + +QPoint QAccessiblePlainTextEdit::scrollBarPosition() const +{ + QPoint result; + result.setX(plainTextEdit()->horizontalScrollBar() ? plainTextEdit()->horizontalScrollBar()->sliderPosition() : 0); + result.setY(plainTextEdit()->verticalScrollBar() ? plainTextEdit()->verticalScrollBar()->sliderPosition() : 0); + return result; +} + +QTextCursor QAccessiblePlainTextEdit::textCursor() const +{ + return plainTextEdit()->textCursor(); +} + +void QAccessiblePlainTextEdit::setTextCursor(const QTextCursor &textCursor) +{ + plainTextEdit()->setTextCursor(textCursor); +} + +QTextDocument* QAccessiblePlainTextEdit::textDocument() const +{ + return plainTextEdit()->document(); +} + +QWidget* QAccessiblePlainTextEdit::viewport() const +{ + return plainTextEdit()->viewport(); +} + +void QAccessiblePlainTextEdit::scrollToSubstring(int startIndex, int endIndex) +{ + //TODO: Not implemented + Q_UNUSED(startIndex); + Q_UNUSED(endIndex); +} + + /*! \class QAccessibleTextEdit \brief The QAccessibleTextEdit class implements the QAccessibleInterface for richtext editors. @@ -143,9 +228,9 @@ QWidget *QAccessibleTextEdit::viewport() const return textEdit()->viewport(); } -QPoint QAccessibleTextEdit::scrollBarsCurrentPosition() const +QPoint QAccessibleTextEdit::scrollBarPosition() const { - QPoint result(0, 0); + QPoint result; result.setX(textEdit()->horizontalScrollBar() ? textEdit()->horizontalScrollBar()->sliderPosition() : 0); result.setY(textEdit()->verticalScrollBar() ? textEdit()->verticalScrollBar()->sliderPosition() : 0); return result; @@ -750,10 +835,9 @@ QRect QAccessibleTextWidget::characterRect(int offset) const w, h); r.moveTo(viewport()->mapToGlobal(r.topLeft())); } + r.translate(-scrollBarPosition()); } - r.translate(-scrollBarsCurrentPosition()); - return r; } @@ -761,7 +845,7 @@ int QAccessibleTextWidget::offsetAtPoint(const QPoint &point) const { QPoint p = viewport()->mapFromGlobal(point); // convert to document coordinates - p += scrollBarsCurrentPosition(); + p += scrollBarPosition(); return textDocument()->documentLayout()->hitTest(p, Qt::ExactHit); } @@ -907,7 +991,7 @@ QString QAccessibleTextWidget::text(int startOffset, int endOffset) const return cursor.selectedText(); } -QPoint QAccessibleTextWidget::scrollBarsCurrentPosition() const +QPoint QAccessibleTextWidget::scrollBarPosition() const { return QPoint(0, 0); } diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.h b/src/plugins/accessible/widgets/qaccessiblewidgets.h index b740bf7a6d..ec2583235f 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.h +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.h @@ -64,6 +64,7 @@ class QAbstractItemView; class QDockWidget; class QDockWidgetLayout; class QMainWindow; +class QPlainTextEdit; class QTextCursor; class QTextDocument; @@ -111,7 +112,7 @@ public: protected: QTextCursor textCursorForRange(int startOffset, int endOffset) const; QPair getBoundaries(int offset, QAccessible2::BoundaryType boundaryType) const; - virtual QPoint scrollBarsCurrentPosition() const; + virtual QPoint scrollBarPosition() const; virtual QTextCursor textCursor() const = 0; virtual void setTextCursor(const QTextCursor &) = 0; virtual QTextDocument *textDocument() const = 0; @@ -120,6 +121,29 @@ protected: #endif //QT_NO_CURSOR #ifndef QT_NO_TEXTEDIT +class QAccessiblePlainTextEdit : public QAccessibleTextWidget +{ +public: + explicit QAccessiblePlainTextEdit(QWidget *o); + + QString text(QAccessible::Text t) const; + void setText(QAccessible::Text t, const QString &text); + QAccessible::State state() const; + + void *interface_cast(QAccessible::InterfaceType t); + + // QAccessibleTextInterface + void scrollToSubstring(int startIndex, int endIndex); +protected: + QPlainTextEdit *plainTextEdit() const; + + QPoint scrollBarPosition() const; + QTextCursor textCursor() const; + void setTextCursor(const QTextCursor &textCursor); + QTextDocument *textDocument() const; + QWidget *viewport() const; +}; + class QAccessibleTextEdit : public QAccessibleTextWidget { public: @@ -137,13 +161,11 @@ public: protected: QTextEdit *textEdit() const; - QPoint scrollBarsCurrentPosition() const; + QPoint scrollBarPosition() const; QTextCursor textCursor() const; void setTextCursor(const QTextCursor &textCursor); QTextDocument *textDocument() const; QWidget *viewport() const; -private: - int childOffset; }; #endif // QT_NO_TEXTEDIT diff --git a/src/plugins/accessible/widgets/widgets.json b/src/plugins/accessible/widgets/widgets.json index 21c0157144..69584b9bc8 100644 --- a/src/plugins/accessible/widgets/widgets.json +++ b/src/plugins/accessible/widgets/widgets.json @@ -21,6 +21,7 @@ "QGroupBox", "QStatusBar", "QProgressBar", + "QPlainTextEdit", "QMenuBar", "QMenu", "QHeaderView", diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index 397bc677b8..f27ca3921f 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -56,6 +56,7 @@ #include "qtextdocument.h" #include "private/qtextdocument_p.h" #include "qtextlist.h" +#include "qaccessible.h" #include #include @@ -441,6 +442,11 @@ QPlainTextEditControl::QPlainTextEditControl(QPlainTextEdit *parent) void QPlainTextEditPrivate::_q_cursorPositionChanged() { pageUpDownLastCursorYIsValid = false; +#ifndef QT_NO_ACCESSIBILITY + Q_Q(QPlainTextEdit); + QAccessibleTextCursorEvent ev(q, q->textCursor().position()); + QAccessible::updateAccessibility(&ev); +#endif } void QPlainTextEditPrivate::_q_verticalScrollbarActionTriggered(int action) { -- cgit v1.2.3 From fb2d2c4f72428db428898f2d2d55e32abea8d3b0 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 12 Oct 2012 18:42:21 +0200 Subject: Emit cursorPositionChanged in private slot. Since the private slot is already there and used, it might as well emit the signal and save us one connection. Change-Id: I899df74c20f8c2b7875a0f9d0a04465c5dc48bde Reviewed-by: Marc Mutz --- src/widgets/widgets/qplaintextedit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index f27ca3921f..992e613482 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -442,11 +442,12 @@ QPlainTextEditControl::QPlainTextEditControl(QPlainTextEdit *parent) void QPlainTextEditPrivate::_q_cursorPositionChanged() { pageUpDownLastCursorYIsValid = false; -#ifndef QT_NO_ACCESSIBILITY Q_Q(QPlainTextEdit); +#ifndef QT_NO_ACCESSIBILITY QAccessibleTextCursorEvent ev(q, q->textCursor().position()); QAccessible::updateAccessibility(&ev); #endif + emit q->cursorPositionChanged(); } void QPlainTextEditPrivate::_q_verticalScrollbarActionTriggered(int action) { @@ -778,7 +779,6 @@ void QPlainTextEditPrivate::init(const QString &txt) QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool))); QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged())); - QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus())); -- cgit v1.2.3 From 8e62d9acfdfcb4cdd96e9e333360722c5d8a3d30 Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Sun, 21 Oct 2012 00:17:09 +0800 Subject: Doc: Fix small capitalization error for the Qt SQL module header. The header file is named QtSql, not QtSQL. Change-Id: Ia3634c80d73f04fd27256f392cfed2068eeb9bc5 Reviewed-by: Mark Brand --- src/sql/doc/src/qtsql.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sql/doc/src/qtsql.qdoc b/src/sql/doc/src/qtsql.qdoc index f269901906..7ab3cfc127 100644 --- a/src/sql/doc/src/qtsql.qdoc +++ b/src/sql/doc/src/qtsql.qdoc @@ -44,7 +44,7 @@ \section1 Getting Started To enable Qt SQL in a project, add this directive into the C++ files: \code - #include + #include \endcode To link against the Qt SQL module, add this line to the project file: \code -- cgit v1.2.3 From 0693082c95c1833f686accee74024db4eead3003 Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Sun, 21 Oct 2012 20:29:11 +0200 Subject: Pass the correct handle to the Windows EGL context constructor. We should pass the shareHandle here instead of the handle for the context since that's what it expects. Change-Id: If851758817057ecc3c3646cba2354becf5a8a839 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsintegration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 50ffb85b01..f95fbf4b34 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -375,7 +375,7 @@ QPlatformOpenGLContext return 0; d->m_staticEGLContext = QSharedPointer(staticContext); } - return new QWindowsEGLContext(d->m_staticEGLContext, context->format(), context->handle()); + return new QWindowsEGLContext(d->m_staticEGLContext, context->format(), context->shareHandle()); #else // QT_OPENGL_ES_2 if (d->m_staticOpenGLContext.isNull()) d->m_staticOpenGLContext = -- cgit v1.2.3 From d18eb260d70b75376411fe3f69da82bf46fb503f Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 27 Sep 2012 11:36:23 +0200 Subject: Use the layout change hint to speed up QItemSelectionModel. The testcase in the bug report takes 370035 ms to sort the rows with Qt 4, and 5646 ms in Qt 5 (when using the extra hints to layout*Changed). That's an improvement of more than 98%. Task-number: QTBUG-17732 Change-Id: If78f972d80c501e0cb39078228086c4f4ac8a65b Reviewed-by: Marc Mutz --- src/corelib/itemmodels/qitemselectionmodel.cpp | 128 ++++++++++++++++++++----- src/corelib/itemmodels/qitemselectionmodel.h | 4 +- src/corelib/itemmodels/qitemselectionmodel_p.h | 6 +- 3 files changed, 110 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/corelib/itemmodels/qitemselectionmodel.cpp b/src/corelib/itemmodels/qitemselectionmodel.cpp index 4b9391d285..d1cbd7f461 100644 --- a/src/corelib/itemmodels/qitemselectionmodel.cpp +++ b/src/corelib/itemmodels/qitemselectionmodel.cpp @@ -284,12 +284,21 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange & */ -/* - \internal - - utility function for getting the indexes from a range - it avoid concatenating list and works on one - */ +static void rowLengthsFromRange(const QItemSelectionRange &range, QVector > &result) +{ + if (range.isValid() && range.model()) { + const QModelIndex topLeft = range.topLeft(); + const int bottom = range.bottom(); + const uint width = range.width(); + const int column = topLeft.column(); + for (int row = topLeft.row(); row <= bottom; ++row) { + // We don't need to keep track of ItemIsSelectable and ItemIsEnabled here. That is + // required in indexesFromRange() because that method is called from public API + // which requires the limitation. + result.push_back(qMakePair(QPersistentModelIndex(topLeft.sibling(row, column)), width)); + } + } +} template static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContainer &result) @@ -468,6 +477,14 @@ static QVector qSelectionPersistentindexes(const QItemSel return result; } +static QVector > qSelectionPersistentRowLengths(const QItemSelection &sel) +{ + QVector > result; + Q_FOREACH (const QItemSelectionRange &range, sel) + rowLengthsFromRange(range, result); + return result; +} + /*! Merges the \a other selection with this QItemSelection using the \a command given. This method guarantees that no ranges are overlapping. @@ -599,10 +616,10 @@ void QItemSelectionModelPrivate::initModel(QAbstractItemModel *model) q, SLOT(_q_layoutChanged())); QObject::connect(model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), q, SLOT(_q_layoutChanged())); - QObject::connect(model, SIGNAL(layoutAboutToBeChanged()), - q, SLOT(_q_layoutAboutToBeChanged())); - QObject::connect(model, SIGNAL(layoutChanged()), - q, SLOT(_q_layoutChanged())); + QObject::connect(model, SIGNAL(layoutAboutToBeChanged(QList,QAbstractItemModel::LayoutChangeHint)), + q, SLOT(_q_layoutAboutToBeChanged(QList,QAbstractItemModel::LayoutChangeHint))); + QObject::connect(model, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), + q, SLOT(_q_layoutChanged(QList,QAbstractItemModel::LayoutChangeHint))); } } @@ -812,10 +829,12 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &par preparation for the layoutChanged() signal, where the indexes can be merged again. */ -void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged() +void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged(const QList &, QAbstractItemModel::LayoutChangeHint hint) { savedPersistentIndexes.clear(); savedPersistentCurrentIndexes.clear(); + savedPersistentRowLengths.clear(); + savedPersistentCurrentRowLengths.clear(); // optimization for when all indexes are selected // (only if there is lots of items (1000) because this is not entirely correct) @@ -836,8 +855,53 @@ void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged() } tableSelected = false; - savedPersistentIndexes = qSelectionPersistentindexes(ranges); - savedPersistentCurrentIndexes = qSelectionPersistentindexes(currentSelection); + if (hint == QAbstractItemModel::VerticalSortHint) { + // Special case when we know we're sorting vertically. We can assume that all indexes for columns + // are displaced the same way, and therefore we only need to track an index from one column per + // row with a QPersistentModelIndex together with the length of items to the right of it + // which are displaced the same way. + // An algorithm which contains the same assumption is used to process layoutChanged. + savedPersistentRowLengths = qSelectionPersistentRowLengths(ranges); + savedPersistentCurrentRowLengths = qSelectionPersistentRowLengths(currentSelection); + } else { + savedPersistentIndexes = qSelectionPersistentindexes(ranges); + savedPersistentCurrentIndexes = qSelectionPersistentindexes(currentSelection); + } +} +/*! + \internal +*/ +static QItemSelection mergeRowLengths(const QVector > &rowLengths) +{ + if (rowLengths.isEmpty()) + return QItemSelection(); + + QItemSelection result; + int i = 0; + while (i < rowLengths.count()) { + const QPersistentModelIndex &tl = rowLengths.at(i).first; + if (!tl.isValid()) { + ++i; + continue; + } + QPersistentModelIndex br = tl; + const uint length = rowLengths.at(i).second; + while (++i < rowLengths.count()) { + const QPersistentModelIndex &next = rowLengths.at(i).first; + if (!next.isValid()) + continue; + const uint nextLength = rowLengths.at(i).second; + if ((nextLength == length) + && (next.row() == br.row() + 1) + && (next.parent() == br.parent())) { + br = next; + } else { + break; + } + } + result.append(QItemSelectionRange(tl, br.sibling(br.row(), length - 1))); + } + return result; } /*! @@ -913,7 +977,7 @@ static QItemSelection mergeIndexes(const QVector &indexes Merge the selected indexes into selection ranges again. */ -void QItemSelectionModelPrivate::_q_layoutChanged() +void QItemSelectionModelPrivate::_q_layoutChanged(const QList &, QAbstractItemModel::LayoutChangeHint hint) { // special case for when all indexes are selected if (tableSelected && tableColCount == model->columnCount(tableParent) @@ -930,26 +994,42 @@ void QItemSelectionModelPrivate::_q_layoutChanged() return; } - if (savedPersistentCurrentIndexes.isEmpty() && savedPersistentIndexes.isEmpty()) { + if ((hint != QAbstractItemModel::VerticalSortHint && savedPersistentCurrentIndexes.isEmpty() && savedPersistentIndexes.isEmpty()) + || (hint == QAbstractItemModel::VerticalSortHint && savedPersistentRowLengths.isEmpty() && savedPersistentCurrentRowLengths.isEmpty())) { // either the selection was actually empty, or we // didn't get the layoutAboutToBeChanged() signal return; } + // clear the "old" selection ranges.clear(); currentSelection.clear(); - // sort the "new" selection, as preparation for merging - qStableSort(savedPersistentIndexes.begin(), savedPersistentIndexes.end()); - qStableSort(savedPersistentCurrentIndexes.begin(), savedPersistentCurrentIndexes.end()); + if (hint != QAbstractItemModel::VerticalSortHint) { + // sort the "new" selection, as preparation for merging + qStableSort(savedPersistentIndexes.begin(), savedPersistentIndexes.end()); + qStableSort(savedPersistentCurrentIndexes.begin(), savedPersistentCurrentIndexes.end()); - // update the selection by merging the individual indexes - ranges = mergeIndexes(savedPersistentIndexes); - currentSelection = mergeIndexes(savedPersistentCurrentIndexes); + // update the selection by merging the individual indexes + ranges = mergeIndexes(savedPersistentIndexes); + currentSelection = mergeIndexes(savedPersistentCurrentIndexes); - // release the persistent indexes - savedPersistentIndexes.clear(); - savedPersistentCurrentIndexes.clear(); + // release the persistent indexes + savedPersistentIndexes.clear(); + savedPersistentCurrentIndexes.clear(); + } else { + // sort the "new" selection, as preparation for merging + qStableSort(savedPersistentRowLengths.begin(), savedPersistentRowLengths.end()); + qStableSort(savedPersistentCurrentRowLengths.begin(), savedPersistentCurrentRowLengths.end()); + + // update the selection by merging the individual indexes + ranges = mergeRowLengths(savedPersistentRowLengths); + currentSelection = mergeRowLengths(savedPersistentCurrentRowLengths); + + // release the persistent indexes + savedPersistentRowLengths.clear(); + savedPersistentCurrentRowLengths.clear(); + } } /*! diff --git a/src/corelib/itemmodels/qitemselectionmodel.h b/src/corelib/itemmodels/qitemselectionmodel.h index 555401e621..79a8a25470 100644 --- a/src/corelib/itemmodels/qitemselectionmodel.h +++ b/src/corelib/itemmodels/qitemselectionmodel.h @@ -222,8 +222,8 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_rowsAboutToBeRemoved(const QModelIndex&, int, int)) Q_PRIVATE_SLOT(d_func(), void _q_columnsAboutToBeInserted(const QModelIndex&, int, int)) Q_PRIVATE_SLOT(d_func(), void _q_rowsAboutToBeInserted(const QModelIndex&, int, int)) - Q_PRIVATE_SLOT(d_func(), void _q_layoutAboutToBeChanged()) - Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_layoutAboutToBeChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoHint)) + Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoHint)) }; Q_DECLARE_OPERATORS_FOR_FLAGS(QItemSelectionModel::SelectionFlags) diff --git a/src/corelib/itemmodels/qitemselectionmodel_p.h b/src/corelib/itemmodels/qitemselectionmodel_p.h index cc278346ff..9439bb772b 100644 --- a/src/corelib/itemmodels/qitemselectionmodel_p.h +++ b/src/corelib/itemmodels/qitemselectionmodel_p.h @@ -76,8 +76,8 @@ public: void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end); void _q_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end); void _q_columnsAboutToBeInserted(const QModelIndex &parent, int start, int end); - void _q_layoutAboutToBeChanged(); - void _q_layoutChanged(); + void _q_layoutAboutToBeChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); + void _q_layoutChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); inline void remove(QList &r) { @@ -100,6 +100,8 @@ public: QItemSelectionModel::SelectionFlags currentCommand; QVector savedPersistentIndexes; QVector savedPersistentCurrentIndexes; + QVector > savedPersistentRowLengths; + QVector > savedPersistentCurrentRowLengths; // optimization when all indexes are selected bool tableSelected; QPersistentModelIndex tableParent; -- cgit v1.2.3 From efc475a996574364046335e2d66c4a091c5ccc31 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 18 Oct 2012 13:36:02 +0200 Subject: Fix integer overflow in QSpinBox. Change-Id: Ic204d42fbdffc44576f7e76132bc53621e836299 Reviewed-by: Marc Mutz --- src/widgets/widgets/qabstractspinbox.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index f2914025f9..845cb5dbd0 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -1904,7 +1904,20 @@ QVariant operator+(const QVariant &arg1, const QVariant &arg2) qWarning("QAbstractSpinBox: Internal error: Different types (%s vs %s) (%s:%d)", arg1.typeName(), arg2.typeName(), __FILE__, __LINE__); switch (arg1.type()) { - case QVariant::Int: ret = QVariant(arg1.toInt() + arg2.toInt()); break; + case QVariant::Int: { + const int int1 = arg1.toInt(); + const int int2 = arg2.toInt(); + if (int1 > 0 && (int2 >= INT_MAX - int1)) { + // The increment overflows + ret = QVariant(INT_MAX); + } else if (int1 < 0 && (int2 <= INT_MIN - int1)) { + // The increment underflows + ret = QVariant(INT_MIN); + } else { + ret = QVariant(int1 + int2); + } + break; + } case QVariant::Double: ret = QVariant(arg1.toDouble() + arg2.toDouble()); break; case QVariant::DateTime: { QDateTime a2 = arg2.toDateTime(); @@ -1962,7 +1975,9 @@ QVariant operator*(const QVariant &arg1, double multiplier) QVariant ret; switch (arg1.type()) { - case QVariant::Int: ret = QVariant((int)(arg1.toInt() * multiplier)); break; + case QVariant::Int: + ret = static_cast(qBound(INT_MIN, arg1.toInt() * multiplier, INT_MAX)); + break; case QVariant::Double: ret = QVariant(arg1.toDouble() * multiplier); break; case QVariant::DateTime: { double days = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDateTime().date()) * multiplier; -- cgit v1.2.3 From e0ba8fdbcee31966f94bdeef7716a33afc3d9869 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Mon, 22 Oct 2012 11:00:00 +0200 Subject: Trim trailing whitespace. Change-Id: Iee6bb66831f53399e5937eab5704af835979f5c3 Reviewed-by: Lars Knoll --- src/corelib/io/qprocess_win.cpp | 4 +-- src/corelib/statemachine/qstate.cpp | 6 ++-- src/corelib/statemachine/qstatemachine.cpp | 56 +++++++++++++++--------------- src/corelib/statemachine/qstatemachine.h | 2 +- src/corelib/thread/qthread.h | 2 +- 5 files changed, 35 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index dd5cf4819e..d19ab695ea 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -520,8 +520,8 @@ void QProcessPrivate::startProcess() q->setProcessState(QProcess::Running); // User can call kill()/terminate() from the stateChanged() slot - // so check before proceeding - if (!pid) + // so check before proceeding + if (!pid) return; if (threadData->eventDispatcher) { diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 7d4081f2c3..5eb9686f1d 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -279,7 +279,7 @@ void QState::assignProperty(QObject *object, const char *name, #endif // QT_NO_PROPERTIES /*! - Returns this state's error state. + Returns this state's error state. \sa QStateMachine::error() */ @@ -292,7 +292,7 @@ QAbstractState *QState::errorState() const /*! Sets this state's error state to be the given \a state. If the error state is not set, or if it is set to 0, the state will inherit its parent's error - state recursively. If no error state is set for the state itself or any of + state recursively. If no error state is set for the state itself or any of its ancestors, an error will cause the machine to stop executing and an error will be printed to the console. */ @@ -314,7 +314,7 @@ void QState::setErrorState(QAbstractState *state) /*! Adds the given \a transition. The transition has this state as the source. - This state takes ownership of the transition. + This state takes ownership of the transition. */ void QState::addTransition(QAbstractTransition *transition) { diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 4d911cb4a2..c8d2f39525 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -141,8 +141,8 @@ QT_BEGIN_NAMESPACE enter this state. The types of errors possible are described by the \l{QStateMachine::}{Error} enum. After the error state is entered, the type of the error can be retrieved with error(). The execution - of the state graph will not stop when the error state is entered. If - no error state applies to the erroneous state, the machine will stop + of the state graph will not stop when the error state is entered. If + no error state applies to the erroneous state, the machine will stop executing and an error message will be printed to the console. \sa QAbstractState, QAbstractTransition, QState, {The State Machine Framework} @@ -1040,17 +1040,17 @@ QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context) if (errorState == 0) errorState = findErrorState(context->parentState()); } - - return errorState; + + return errorState; } void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext) { Q_Q(QStateMachine); - + error = errorCode; switch (errorCode) { - case QStateMachine::NoInitialStateError: + case QStateMachine::NoInitialStateError: Q_ASSERT(currentContext != 0); errorString = QStateMachine::tr("Missing initial state in compound state '%1'") @@ -1074,23 +1074,23 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta errorString = QStateMachine::tr("Unknown error"); }; - pendingErrorStates.clear(); + pendingErrorStates.clear(); pendingErrorStatesForDefaultEntry.clear(); QAbstractState *currentErrorState = findErrorState(currentContext); // Avoid infinite loop if the error state itself has an error if (currentContext == currentErrorState) - currentErrorState = 0; + currentErrorState = 0; Q_ASSERT(currentErrorState != rootState()); - if (currentErrorState != 0) { + if (currentErrorState != 0) { QState *lca = findLCA(QList() << currentErrorState << currentContext); addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); addAncestorStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); } else { - qWarning("Unrecoverable error detected in running state machine: %s", + qWarning("Unrecoverable error detected in running state machine: %s", qPrintable(errorString)); q->stop(); } @@ -1099,7 +1099,7 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta #ifndef QT_NO_ANIMATION QPair, QList > -QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation, +QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation, const QPropertyAssignment &prop) { QList handledAnimations; @@ -1113,9 +1113,9 @@ QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation, handledAnimations << ret.first; localResetEndValues << ret.second; } - } else { + } else { QPropertyAnimation *animation = qobject_cast(abstractAnimation); - if (animation != 0 + if (animation != 0 && prop.object == animation->targetObject() && prop.propertyName == animation->propertyName()) { @@ -1894,7 +1894,7 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio } void QStateMachinePrivate::handleFilteredEvent(QObject *watched, QEvent *event) -{ +{ if (qobjectEvents.value(watched).contains(event->type())) { postInternalEvent(new QStateMachine::WrappedEvent(watched, handler->cloneEvent(event))); processEvents(DirectProcessing); @@ -1980,24 +1980,24 @@ QStateMachine::~QStateMachine() \value HighPriority The event has high priority. */ -/*! \enum QStateMachine::Error +/*! \enum QStateMachine::Error This enum type defines errors that can occur in the state machine at run time. When the state - machine encounters an unrecoverable error at run time, it will set the error code returned - by error(), the error message returned by errorString(), and enter an error state based on + machine encounters an unrecoverable error at run time, it will set the error code returned + by error(), the error message returned by errorString(), and enter an error state based on the context of the error. \value NoError No error has occurred. \value NoInitialStateError The machine has entered a QState with children which does not have an initial state set. The context of this error is the state which is missing an initial state. - \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have + \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have a default state set. The context of this error is the QHistoryState which is missing a default state. - \value NoCommonAncestorForTransitionError The machine has selected a transition whose source - and targets are not part of the same tree of states, and thus are not part of the same - state machine. Commonly, this could mean that one of the states has not been given - any parent or added to any machine. The context of this error is the source state of + \value NoCommonAncestorForTransitionError The machine has selected a transition whose source + and targets are not part of the same tree of states, and thus are not part of the same + state machine. Commonly, this could mean that one of the states has not been given + any parent or added to any machine. The context of this error is the source state of the transition. \sa setErrorState() @@ -2043,9 +2043,9 @@ QState::RestorePolicy QStateMachine::globalRestorePolicy() const } /*! - Sets the restore policy of the state machine to \a restorePolicy. The default + Sets the restore policy of the state machine to \a restorePolicy. The default restore policy is QState::DontRestoreProperties. - + \sa globalRestorePolicy() */ void QStateMachine::setGlobalRestorePolicy(QState::RestorePolicy restorePolicy) @@ -2437,7 +2437,7 @@ void QStateMachine::onEntry(QEvent *event) /*! \reimp - This function will call stop() to stop the state machine and + This function will call stop() to stop the state machine and subsequently emit the stopped() signal. */ void QStateMachine::onExit(QEvent *event) @@ -2468,7 +2468,7 @@ void QStateMachine::setAnimated(bool enabled) /*! Adds a default \a animation to be considered for any transition. -*/ +*/ void QStateMachine::addDefaultAnimation(QAbstractAnimation *animation) { Q_D(QStateMachine); @@ -2479,13 +2479,13 @@ void QStateMachine::addDefaultAnimation(QAbstractAnimation *animation) Returns the list of default animations that will be considered for any transition. */ QList QStateMachine::defaultAnimations() const -{ +{ Q_D(const QStateMachine); return d->defaultAnimations; } /*! - Removes \a animation from the list of default animations. + Removes \a animation from the list of default animations. */ void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation) { diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index cc1ffff553..d1789e9fcd 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -107,7 +107,7 @@ public: }; enum Error { - NoError, + NoError, NoInitialStateError, NoDefaultStateInHistoryStateError, NoCommonAncestorForTransitionError diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index 8fda4513e6..058091baf4 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -138,7 +138,7 @@ class Q_CORE_EXPORT QThread : public QObject public: static Qt::HANDLE currentThreadId() { return Qt::HANDLE(currentThread()); } static QThread* currentThread(); - + protected: QThread(QThreadPrivate &dd, QObject *parent = 0); -- cgit v1.2.3 From 500ed6b628ee5b58cbf7ce696e60558a0e2f3c4d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 22 Oct 2012 08:32:50 +0200 Subject: QDateTimeEdit: don't throw off auto-indention Reformulate #ifdef'ery involving {}s so as not to throw off auto-indention of code editors due to unbalanced {}s. Change-Id: I0f9858c78d0b6d923de75ca45c7d65ce3fa53e50 Reviewed-by: Stephen Kelly --- src/widgets/widgets/qdatetimeedit.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index 7868690e49..8a23530283 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -990,10 +990,9 @@ QSize QDateTimeEdit::sizeHint() const if (d->calendarPopupEnabled()) { QStyleOptionComboBox opt; d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, hint, this); - } else { -#else - { + } else #endif + { QSize extra(35, 6); QStyleOptionSpinBox opt; initStyleOption(&opt); -- cgit v1.2.3 From 33d9b9f326449341d6a9afd55299e5e1ad7ad037 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 22 Oct 2012 08:20:23 +0200 Subject: Delete QWhatsThis() and QToolTip() These classes are not supposed to be instantiated. QToolTip() already was declared, but not implemented. This patch just adds Q_DECL_EQ_DELETE for better diagnostics on C++11. QWhatsThis() was implemented, but appears to be unused. Since it was private to begin with, successfully compiling QtWidgets is a sufficient test. Change-Id: I698ece8f0eebbcdac7be98456dd42197b758a825 Reviewed-by: Stephen Kelly --- src/widgets/kernel/qtooltip.h | 2 +- src/widgets/kernel/qwhatsthis.cpp | 5 ----- src/widgets/kernel/qwhatsthis.h | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/widgets/kernel/qtooltip.h b/src/widgets/kernel/qtooltip.h index 2b73695a52..860a2ccab0 100644 --- a/src/widgets/kernel/qtooltip.h +++ b/src/widgets/kernel/qtooltip.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE class Q_WIDGETS_EXPORT QToolTip { - QToolTip(); + QToolTip() Q_DECL_EQ_DELETE; public: static void showText(const QPoint &pos, const QString &text, QWidget *w = 0); static void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect); diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp index 95e1683c26..ed2d77021c 100644 --- a/src/widgets/kernel/qwhatsthis.cpp +++ b/src/widgets/kernel/qwhatsthis.cpp @@ -521,11 +521,6 @@ void QWhatsThisAction::actionTriggered() } } -QWhatsThis::QWhatsThis() -{ -} - - /*! This function switches the user interface into "What's This?" mode. The user interface can be switched back into normal mode by diff --git a/src/widgets/kernel/qwhatsthis.h b/src/widgets/kernel/qwhatsthis.h index 2583e3bb62..e901b474fd 100644 --- a/src/widgets/kernel/qwhatsthis.h +++ b/src/widgets/kernel/qwhatsthis.h @@ -56,7 +56,7 @@ class QAction; class Q_WIDGETS_EXPORT QWhatsThis { - QWhatsThis(); + QWhatsThis() Q_DECL_EQ_DELETE; public: static void enterWhatsThisMode(); -- cgit v1.2.3 From 11566de014ed22051a53f1f0c94697fd18a87500 Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Mon, 22 Oct 2012 12:32:25 +0200 Subject: Move some icon code from WindowsStyle to CommonStyle Fusion style only depends on CommonStyle and it seems the autotest for tst_QFileSystemModel:iconProvider assumes an icon will be returned from standardPixmap. Since we dont want the icons to depend on style in this case we should move all this to commonstyle. Change-Id: I3a26367e5c0aefe2a39838f0c2cadc4f7afad89d Reviewed-by: Gabriel de Dietrich Reviewed-by: Jens Bache-Wiig --- src/widgets/styles/qcommonstyle.cpp | 84 ++++++ src/widgets/styles/qcommonstylepixmaps_p.h | 372 ++++++++++++++++++++++- src/widgets/styles/qwindowsstyle.cpp | 456 +---------------------------- 3 files changed, 456 insertions(+), 456 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 4dd92c1a0c..0e22a90a4b 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -5336,6 +5336,41 @@ QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *opti default: break; } + +#ifndef QT_NO_IMAGEFORMAT_XPM + switch (sp) { + case SP_TitleBarMenuButton: + return QPixmap(qt_menu_xpm); + case SP_TitleBarShadeButton: + return QPixmap(qt_shade_xpm); + case SP_TitleBarUnshadeButton: + return QPixmap(qt_unshade_xpm); + case SP_TitleBarNormalButton: + return QPixmap(qt_normalizeup_xpm); + case SP_TitleBarMinButton: + return QPixmap(qt_minimize_xpm); + case SP_TitleBarMaxButton: + return QPixmap(qt_maximize_xpm); + case SP_TitleBarCloseButton: + return QPixmap(qt_close_xpm); + case SP_TitleBarContextHelpButton: + return QPixmap(qt_help_xpm); + case SP_DockWidgetCloseButton: + return QPixmap(dock_widget_close_xpm); + case SP_MessageBoxInformation: + return QPixmap(information_xpm); + case SP_MessageBoxWarning: + return QPixmap(warning_xpm); + case SP_MessageBoxCritical: + return QPixmap(critical_xpm); + case SP_MessageBoxQuestion: + return QPixmap(question_xpm); + default: + break; + } +#endif //QT_NO_IMAGEFORMAT_XPM + + return QPixmap(); } @@ -5346,6 +5381,55 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption const QWidget *widget) const { QIcon icon; +#ifdef Q_OS_WIN + switch (standardIcon) { + case SP_DriveCDIcon: + case SP_DriveDVDIcon: + case SP_DriveNetIcon: + case SP_DriveHDIcon: + case SP_DriveFDIcon: + case SP_FileIcon: + case SP_FileLinkIcon: + case SP_DesktopIcon: + case SP_ComputerIcon: + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + QPlatformTheme::StandardPixmap sp = static_cast(standardIcon); + for (int size = 16 ; size <= 32 ; size += 16) { + QPixmap pixmap = theme->standardPixmap(sp, QSizeF(size, size)); + icon.addPixmap(pixmap, QIcon::Normal); + } + } + break; + case SP_DirIcon: + case SP_DirLinkIcon: + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + QPlatformTheme::StandardPixmap spOff = static_cast(standardIcon); + QPlatformTheme::StandardPixmap spOn = standardIcon == SP_DirIcon ? QPlatformTheme::DirOpenIcon : + QPlatformTheme::DirLinkOpenIcon; + for (int size = 16 ; size <= 32 ; size += 16) { + QSizeF pixSize(size, size); + QPixmap pixmap = theme->standardPixmap(spOff, pixSize); + icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off); + pixmap = theme->standardPixmap(spOn, pixSize); + icon.addPixmap(pixmap, QIcon::Normal, QIcon::On); + } + } + break; + case SP_VistaShield: + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + QPlatformTheme::StandardPixmap sp = static_cast(standardIcon); + QPixmap pixmap = theme->standardPixmap(sp, QSizeF(32, 32)); + icon.addPixmap(pixmap); + } + break; + default: + break; + } + if (!icon.isNull()) + return icon; + +#endif + const bool rtl = (option && option->direction == Qt::RightToLeft) || (!option && QApplication::isRightToLeft()); if (QApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) { switch (standardIcon) { diff --git a/src/widgets/styles/qcommonstylepixmaps_p.h b/src/widgets/styles/qcommonstylepixmaps_p.h index 5e63302f35..d224af3f0f 100644 --- a/src/widgets/styles/qcommonstylepixmaps_p.h +++ b/src/widgets/styles/qcommonstylepixmaps_p.h @@ -156,4 +156,374 @@ static const char * const filedialog_end_xpm[]={ "aaa.............", "aaaaaaaaaaaaaaaa"}; -#endif // QT_NO_IMAGEFORMAT_XPM + +/* XPM */ +static const char * const qt_menu_xpm[] = { +"16 16 72 1", +" c None", +". c #65AF36", +"+ c #66B036", +"@ c #77B94C", +"# c #A7D28C", +"$ c #BADBA4", +"% c #A4D088", +"& c #72B646", +"* c #9ACB7A", +"= c #7FBD56", +"- c #85C05F", +"; c #F4F9F0", +"> c #FFFFFF", +", c #E5F1DC", +"' c #ECF5E7", +") c #7ABA50", +"! c #83BF5C", +"~ c #AED595", +"{ c #D7EACA", +"] c #A9D28D", +"^ c #BCDDA8", +"/ c #C4E0B1", +"( c #81BE59", +"_ c #D0E7C2", +": c #D4E9C6", +"< c #6FB542", +"[ c #6EB440", +"} c #88C162", +"| c #98CA78", +"1 c #F4F9F1", +"2 c #8FC56C", +"3 c #F1F8EC", +"4 c #E8F3E1", +"5 c #D4E9C7", +"6 c #74B748", +"7 c #80BE59", +"8 c #73B747", +"9 c #6DB43F", +"0 c #CBE4BA", +"a c #80BD58", +"b c #6DB33F", +"c c #FEFFFE", +"d c #68B138", +"e c #F9FCF7", +"f c #91C66F", +"g c #E8F3E0", +"h c #DCEDD0", +"i c #91C66E", +"j c #A3CF86", +"k c #C9E3B8", +"l c #B0D697", +"m c #E3F0DA", +"n c #95C873", +"o c #E6F2DE", +"p c #9ECD80", +"q c #BEDEAA", +"r c #C7E2B6", +"s c #79BA4F", +"t c #6EB441", +"u c #BCDCA7", +"v c #FAFCF8", +"w c #F6FAF3", +"x c #84BF5D", +"y c #EDF6E7", +"z c #FAFDF9", +"A c #88C263", +"B c #98CA77", +"C c #CDE5BE", +"D c #67B037", +"E c #D9EBCD", +"F c #6AB23C", +"G c #77B94D", +" .++++++++++++++", +".+++++++++++++++", +"+++@#$%&+++*=+++", +"++-;>,>')+!>~+++", +"++{>]+^>/(_>:~<+", +"+[>>}+|>123>456+", +"+7>>8+->>90>~+++", +"+a>>b+a>c[0>~+++", +"+de>=+f>g+0>~+++", +"++h>i+j>k+0>~+++", +"++l>mno>p+q>rst+", +"++duv>wl++xy>zA+", +"++++B>Cb++++&D++", +"+++++0zE++++++++", +"++++++FG+++++++.", +"++++++++++++++. "}; + +static const char * const qt_close_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +".##....##.", +"..##..##..", +"...####...", +"....##....", +"...####...", +"..##..##..", +".##....##.", +"..........", +".........."}; + +static const char * const qt_maximize_xpm[]={ +"10 10 2 1", +"# c #000000", +". c None", +"#########.", +"#########.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#########.", +".........."}; + +static const char * const qt_minimize_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +"..........", +"..........", +"..........", +"..........", +"..........", +"..........", +".#######..", +".#######..", +".........."}; + +static const char * const qt_normalizeup_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"...######.", +"...######.", +"...#....#.", +".######.#.", +".######.#.", +".#....###.", +".#....#...", +".#....#...", +".######...", +".........."}; + +static const char * const qt_help_xpm[] = { +"10 10 2 1", +". c None", +"# c #000000", +"..........", +"..######..", +".##....##.", +"......##..", +".....##...", +"....##....", +"....##....", +"..........", +"....##....", +".........."}; + +static const char * const qt_shade_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +"..........", +"..........", +"..........", +"....#.....", +"...###....", +"..#####...", +".#######..", +"..........", +".........."}; + +static const char * const qt_unshade_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +"..........", +"..........", +".#######..", +"..#####...", +"...###....", +"....#.....", +"..........", +"..........", +".........."}; + +static const char * dock_widget_close_xpm[] = { +"8 8 2 1", +"# c #000000", +". c None", +"........", +".##..##.", +"..####..", +"...##...", +"..####..", +".##..##.", +"........", +"........"}; + +/* XPM */ +static const char * const information_xpm[]={ +"32 32 5 1", +". c None", +"c c #000000", +"* c #999999", +"a c #ffffff", +"b c #0000ff", +"...........********.............", +"........***aaaaaaaa***..........", +"......**aaaaaaaaaaaaaa**........", +".....*aaaaaaaaaaaaaaaaaa*.......", +"....*aaaaaaaabbbbaaaaaaaac......", +"...*aaaaaaaabbbbbbaaaaaaaac.....", +"..*aaaaaaaaabbbbbbaaaaaaaaac....", +".*aaaaaaaaaaabbbbaaaaaaaaaaac...", +".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..", +"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.", +"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.", +"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", +"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", +"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", +"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", +"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", +".*aaaaaaaaaaabbbbbaaaaaaaaaac***", +".*aaaaaaaaaaabbbbbaaaaaaaaaac***", +"..*aaaaaaaaaabbbbbaaaaaaaaac***.", +"...caaaaaaabbbbbbbbbaaaaaac****.", +"....caaaaaaaaaaaaaaaaaaaac****..", +".....caaaaaaaaaaaaaaaaaac****...", +"......ccaaaaaaaaaaaaaacc****....", +".......*cccaaaaaaaaccc*****.....", +"........***cccaaaac*******......", +"..........****caaac*****........", +".............*caaac**...........", +"...............caac**...........", +"................cac**...........", +".................cc**...........", +"..................***...........", +"...................**..........."}; +/* XPM */ +static const char* const warning_xpm[]={ +"32 32 4 1", +". c None", +"a c #ffff00", +"* c #000000", +"b c #999999", +".............***................", +"............*aaa*...............", +"...........*aaaaa*b.............", +"...........*aaaaa*bb............", +"..........*aaaaaaa*bb...........", +"..........*aaaaaaa*bb...........", +".........*aaaaaaaaa*bb..........", +".........*aaaaaaaaa*bb..........", +"........*aaaaaaaaaaa*bb.........", +"........*aaaa***aaaa*bb.........", +".......*aaaa*****aaaa*bb........", +".......*aaaa*****aaaa*bb........", +"......*aaaaa*****aaaaa*bb.......", +"......*aaaaa*****aaaaa*bb.......", +".....*aaaaaa*****aaaaaa*bb......", +".....*aaaaaa*****aaaaaa*bb......", +"....*aaaaaaaa***aaaaaaaa*bb.....", +"....*aaaaaaaa***aaaaaaaa*bb.....", +"...*aaaaaaaaa***aaaaaaaaa*bb....", +"...*aaaaaaaaaa*aaaaaaaaaa*bb....", +"..*aaaaaaaaaaa*aaaaaaaaaaa*bb...", +"..*aaaaaaaaaaaaaaaaaaaaaaa*bb...", +".*aaaaaaaaaaaa**aaaaaaaaaaa*bb..", +".*aaaaaaaaaaa****aaaaaaaaaa*bb..", +"*aaaaaaaaaaaa****aaaaaaaaaaa*bb.", +"*aaaaaaaaaaaaa**aaaaaaaaaaaa*bb.", +"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb", +"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb", +".*aaaaaaaaaaaaaaaaaaaaaaaaa*bbbb", +"..*************************bbbbb", +"....bbbbbbbbbbbbbbbbbbbbbbbbbbb.", +".....bbbbbbbbbbbbbbbbbbbbbbbbb.."}; +/* XPM */ +static const char* const critical_xpm[]={ +"32 32 4 1", +". c None", +"a c #999999", +"* c #ff0000", +"b c #ffffff", +"...........********.............", +".........************...........", +".......****************.........", +"......******************........", +".....********************a......", +"....**********************a.....", +"...************************a....", +"..*******b**********b*******a...", +"..******bbb********bbb******a...", +".******bbbbb******bbbbb******a..", +".*******bbbbb****bbbbb*******a..", +"*********bbbbb**bbbbb*********a.", +"**********bbbbbbbbbb**********a.", +"***********bbbbbbbb***********aa", +"************bbbbbb************aa", +"************bbbbbb************aa", +"***********bbbbbbbb***********aa", +"**********bbbbbbbbbb**********aa", +"*********bbbbb**bbbbb*********aa", +".*******bbbbb****bbbbb*******aa.", +".******bbbbb******bbbbb******aa.", +"..******bbb********bbb******aaa.", +"..*******b**********b*******aa..", +"...************************aaa..", +"....**********************aaa...", +"....a********************aaa....", +".....a******************aaa.....", +"......a****************aaa......", +".......aa************aaaa.......", +".........aa********aaaaa........", +"...........aaaaaaaaaaa..........", +".............aaaaaaa............"}; +/* XPM */ +static const char *const question_xpm[] = { +"32 32 5 1", +". c None", +"c c #000000", +"* c #999999", +"a c #ffffff", +"b c #0000ff", +"...........********.............", +"........***aaaaaaaa***..........", +"......**aaaaaaaaaaaaaa**........", +".....*aaaaaaaaaaaaaaaaaa*.......", +"....*aaaaaaaaaaaaaaaaaaaac......", +"...*aaaaaaaabbbbbbaaaaaaaac.....", +"..*aaaaaaaabaaabbbbaaaaaaaac....", +".*aaaaaaaabbaaaabbbbaaaaaaaac...", +".*aaaaaaaabbbbaabbbbaaaaaaaac*..", +"*aaaaaaaaabbbbaabbbbaaaaaaaaac*.", +"*aaaaaaaaaabbaabbbbaaaaaaaaaac*.", +"*aaaaaaaaaaaaabbbbaaaaaaaaaaac**", +"*aaaaaaaaaaaaabbbaaaaaaaaaaaac**", +"*aaaaaaaaaaaaabbaaaaaaaaaaaaac**", +"*aaaaaaaaaaaaabbaaaaaaaaaaaaac**", +"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac**", +".*aaaaaaaaaaaabbaaaaaaaaaaaac***", +".*aaaaaaaaaaabbbbaaaaaaaaaaac***", +"..*aaaaaaaaaabbbbaaaaaaaaaac***.", +"...caaaaaaaaaabbaaaaaaaaaac****.", +"....caaaaaaaaaaaaaaaaaaaac****..", +".....caaaaaaaaaaaaaaaaaac****...", +"......ccaaaaaaaaaaaaaacc****....", +".......*cccaaaaaaaaccc*****.....", +"........***cccaaaac*******......", +"..........****caaac*****........", +".............*caaac**...........", +"...............caac**...........", +"................cac**...........", +".................cc**...........", +"..................***...........", +"...................**..........."}; + +#endif //QT_NO_IMAGEFORMAT_XPM diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 9e5e65dcc1..301a7ac9ea 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -470,379 +470,6 @@ int QWindowsStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QW return ret; } -#ifndef QT_NO_IMAGEFORMAT_XPM - -/* XPM */ -static const char * const qt_menu_xpm[] = { -"16 16 72 1", -" c None", -". c #65AF36", -"+ c #66B036", -"@ c #77B94C", -"# c #A7D28C", -"$ c #BADBA4", -"% c #A4D088", -"& c #72B646", -"* c #9ACB7A", -"= c #7FBD56", -"- c #85C05F", -"; c #F4F9F0", -"> c #FFFFFF", -", c #E5F1DC", -"' c #ECF5E7", -") c #7ABA50", -"! c #83BF5C", -"~ c #AED595", -"{ c #D7EACA", -"] c #A9D28D", -"^ c #BCDDA8", -"/ c #C4E0B1", -"( c #81BE59", -"_ c #D0E7C2", -": c #D4E9C6", -"< c #6FB542", -"[ c #6EB440", -"} c #88C162", -"| c #98CA78", -"1 c #F4F9F1", -"2 c #8FC56C", -"3 c #F1F8EC", -"4 c #E8F3E1", -"5 c #D4E9C7", -"6 c #74B748", -"7 c #80BE59", -"8 c #73B747", -"9 c #6DB43F", -"0 c #CBE4BA", -"a c #80BD58", -"b c #6DB33F", -"c c #FEFFFE", -"d c #68B138", -"e c #F9FCF7", -"f c #91C66F", -"g c #E8F3E0", -"h c #DCEDD0", -"i c #91C66E", -"j c #A3CF86", -"k c #C9E3B8", -"l c #B0D697", -"m c #E3F0DA", -"n c #95C873", -"o c #E6F2DE", -"p c #9ECD80", -"q c #BEDEAA", -"r c #C7E2B6", -"s c #79BA4F", -"t c #6EB441", -"u c #BCDCA7", -"v c #FAFCF8", -"w c #F6FAF3", -"x c #84BF5D", -"y c #EDF6E7", -"z c #FAFDF9", -"A c #88C263", -"B c #98CA77", -"C c #CDE5BE", -"D c #67B037", -"E c #D9EBCD", -"F c #6AB23C", -"G c #77B94D", -" .++++++++++++++", -".+++++++++++++++", -"+++@#$%&+++*=+++", -"++-;>,>')+!>~+++", -"++{>]+^>/(_>:~<+", -"+[>>}+|>123>456+", -"+7>>8+->>90>~+++", -"+a>>b+a>c[0>~+++", -"+de>=+f>g+0>~+++", -"++h>i+j>k+0>~+++", -"++l>mno>p+q>rst+", -"++duv>wl++xy>zA+", -"++++B>Cb++++&D++", -"+++++0zE++++++++", -"++++++FG+++++++.", -"++++++++++++++. "}; - -static const char * const qt_close_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"..........", -".##....##.", -"..##..##..", -"...####...", -"....##....", -"...####...", -"..##..##..", -".##....##.", -"..........", -".........."}; - -static const char * const qt_maximize_xpm[]={ -"10 10 2 1", -"# c #000000", -". c None", -"#########.", -"#########.", -"#.......#.", -"#.......#.", -"#.......#.", -"#.......#.", -"#.......#.", -"#.......#.", -"#########.", -".........."}; - -static const char * const qt_minimize_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"..........", -"..........", -"..........", -"..........", -"..........", -"..........", -"..........", -".#######..", -".#######..", -".........."}; - -static const char * const qt_normalizeup_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"...######.", -"...######.", -"...#....#.", -".######.#.", -".######.#.", -".#....###.", -".#....#...", -".#....#...", -".######...", -".........."}; - -static const char * const qt_help_xpm[] = { -"10 10 2 1", -". c None", -"# c #000000", -"..........", -"..######..", -".##....##.", -"......##..", -".....##...", -"....##....", -"....##....", -"..........", -"....##....", -".........."}; - -static const char * const qt_shade_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"..........", -"..........", -"..........", -"..........", -"....#.....", -"...###....", -"..#####...", -".#######..", -"..........", -".........."}; - -static const char * const qt_unshade_xpm[] = { -"10 10 2 1", -"# c #000000", -". c None", -"..........", -"..........", -"..........", -".#######..", -"..#####...", -"...###....", -"....#.....", -"..........", -"..........", -".........."}; - -static const char * dock_widget_close_xpm[] = { -"8 8 2 1", -"# c #000000", -". c None", -"........", -".##..##.", -"..####..", -"...##...", -"..####..", -".##..##.", -"........", -"........"}; - -/* XPM */ -static const char * const information_xpm[]={ -"32 32 5 1", -". c None", -"c c #000000", -"* c #999999", -"a c #ffffff", -"b c #0000ff", -"...........********.............", -"........***aaaaaaaa***..........", -"......**aaaaaaaaaaaaaa**........", -".....*aaaaaaaaaaaaaaaaaa*.......", -"....*aaaaaaaabbbbaaaaaaaac......", -"...*aaaaaaaabbbbbbaaaaaaaac.....", -"..*aaaaaaaaabbbbbbaaaaaaaaac....", -".*aaaaaaaaaaabbbbaaaaaaaaaaac...", -".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..", -"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.", -"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.", -"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", -"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", -"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", -"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", -"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", -".*aaaaaaaaaaabbbbbaaaaaaaaaac***", -".*aaaaaaaaaaabbbbbaaaaaaaaaac***", -"..*aaaaaaaaaabbbbbaaaaaaaaac***.", -"...caaaaaaabbbbbbbbbaaaaaac****.", -"....caaaaaaaaaaaaaaaaaaaac****..", -".....caaaaaaaaaaaaaaaaaac****...", -"......ccaaaaaaaaaaaaaacc****....", -".......*cccaaaaaaaaccc*****.....", -"........***cccaaaac*******......", -"..........****caaac*****........", -".............*caaac**...........", -"...............caac**...........", -"................cac**...........", -".................cc**...........", -"..................***...........", -"...................**..........."}; -/* XPM */ -static const char* const warning_xpm[]={ -"32 32 4 1", -". c None", -"a c #ffff00", -"* c #000000", -"b c #999999", -".............***................", -"............*aaa*...............", -"...........*aaaaa*b.............", -"...........*aaaaa*bb............", -"..........*aaaaaaa*bb...........", -"..........*aaaaaaa*bb...........", -".........*aaaaaaaaa*bb..........", -".........*aaaaaaaaa*bb..........", -"........*aaaaaaaaaaa*bb.........", -"........*aaaa***aaaa*bb.........", -".......*aaaa*****aaaa*bb........", -".......*aaaa*****aaaa*bb........", -"......*aaaaa*****aaaaa*bb.......", -"......*aaaaa*****aaaaa*bb.......", -".....*aaaaaa*****aaaaaa*bb......", -".....*aaaaaa*****aaaaaa*bb......", -"....*aaaaaaaa***aaaaaaaa*bb.....", -"....*aaaaaaaa***aaaaaaaa*bb.....", -"...*aaaaaaaaa***aaaaaaaaa*bb....", -"...*aaaaaaaaaa*aaaaaaaaaa*bb....", -"..*aaaaaaaaaaa*aaaaaaaaaaa*bb...", -"..*aaaaaaaaaaaaaaaaaaaaaaa*bb...", -".*aaaaaaaaaaaa**aaaaaaaaaaa*bb..", -".*aaaaaaaaaaa****aaaaaaaaaa*bb..", -"*aaaaaaaaaaaa****aaaaaaaaaaa*bb.", -"*aaaaaaaaaaaaa**aaaaaaaaaaaa*bb.", -"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb", -"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb", -".*aaaaaaaaaaaaaaaaaaaaaaaaa*bbbb", -"..*************************bbbbb", -"....bbbbbbbbbbbbbbbbbbbbbbbbbbb.", -".....bbbbbbbbbbbbbbbbbbbbbbbbb.."}; -/* XPM */ -static const char* const critical_xpm[]={ -"32 32 4 1", -". c None", -"a c #999999", -"* c #ff0000", -"b c #ffffff", -"...........********.............", -".........************...........", -".......****************.........", -"......******************........", -".....********************a......", -"....**********************a.....", -"...************************a....", -"..*******b**********b*******a...", -"..******bbb********bbb******a...", -".******bbbbb******bbbbb******a..", -".*******bbbbb****bbbbb*******a..", -"*********bbbbb**bbbbb*********a.", -"**********bbbbbbbbbb**********a.", -"***********bbbbbbbb***********aa", -"************bbbbbb************aa", -"************bbbbbb************aa", -"***********bbbbbbbb***********aa", -"**********bbbbbbbbbb**********aa", -"*********bbbbb**bbbbb*********aa", -".*******bbbbb****bbbbb*******aa.", -".******bbbbb******bbbbb******aa.", -"..******bbb********bbb******aaa.", -"..*******b**********b*******aa..", -"...************************aaa..", -"....**********************aaa...", -"....a********************aaa....", -".....a******************aaa.....", -"......a****************aaa......", -".......aa************aaaa.......", -".........aa********aaaaa........", -"...........aaaaaaaaaaa..........", -".............aaaaaaa............"}; -/* XPM */ -static const char *const question_xpm[] = { -"32 32 5 1", -". c None", -"c c #000000", -"* c #999999", -"a c #ffffff", -"b c #0000ff", -"...........********.............", -"........***aaaaaaaa***..........", -"......**aaaaaaaaaaaaaa**........", -".....*aaaaaaaaaaaaaaaaaa*.......", -"....*aaaaaaaaaaaaaaaaaaaac......", -"...*aaaaaaaabbbbbbaaaaaaaac.....", -"..*aaaaaaaabaaabbbbaaaaaaaac....", -".*aaaaaaaabbaaaabbbbaaaaaaaac...", -".*aaaaaaaabbbbaabbbbaaaaaaaac*..", -"*aaaaaaaaabbbbaabbbbaaaaaaaaac*.", -"*aaaaaaaaaabbaabbbbaaaaaaaaaac*.", -"*aaaaaaaaaaaaabbbbaaaaaaaaaaac**", -"*aaaaaaaaaaaaabbbaaaaaaaaaaaac**", -"*aaaaaaaaaaaaabbaaaaaaaaaaaaac**", -"*aaaaaaaaaaaaabbaaaaaaaaaaaaac**", -"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac**", -".*aaaaaaaaaaaabbaaaaaaaaaaaac***", -".*aaaaaaaaaaabbbbaaaaaaaaaaac***", -"..*aaaaaaaaaabbbbaaaaaaaaaac***.", -"...caaaaaaaaaabbaaaaaaaaaac****.", -"....caaaaaaaaaaaaaaaaaaaac****..", -".....caaaaaaaaaaaaaaaaaac****...", -"......ccaaaaaaaaaaaaaacc****....", -".......*cccaaaaaaaaccc*****.....", -"........***cccaaaac*******......", -"..........****caaac*****........", -".............*caaac**...........", -"...............caac**...........", -"................cac**...........", -".................cc**...........", -"..................***...........", -"...................**..........."}; - -#endif //QT_NO_IMAGEFORMAT_XPM - /*! \reimp */ @@ -889,38 +516,6 @@ QPixmap QWindowsStyle::standardPixmap(StandardPixmap standardPixmap, const QStyl return desktopIcon; } #endif -#ifndef QT_NO_IMAGEFORMAT_XPM - switch (standardPixmap) { - case SP_TitleBarMenuButton: - return QPixmap(qt_menu_xpm); - case SP_TitleBarShadeButton: - return QPixmap(qt_shade_xpm); - case SP_TitleBarUnshadeButton: - return QPixmap(qt_unshade_xpm); - case SP_TitleBarNormalButton: - return QPixmap(qt_normalizeup_xpm); - case SP_TitleBarMinButton: - return QPixmap(qt_minimize_xpm); - case SP_TitleBarMaxButton: - return QPixmap(qt_maximize_xpm); - case SP_TitleBarCloseButton: - return QPixmap(qt_close_xpm); - case SP_TitleBarContextHelpButton: - return QPixmap(qt_help_xpm); - case SP_DockWidgetCloseButton: - return QPixmap(dock_widget_close_xpm); - case SP_MessageBoxInformation: - return QPixmap(information_xpm); - case SP_MessageBoxWarning: - return QPixmap(warning_xpm); - case SP_MessageBoxCritical: - return QPixmap(critical_xpm); - case SP_MessageBoxQuestion: - return QPixmap(question_xpm); - default: - break; - } -#endif //QT_NO_IMAGEFORMAT_XPM return QCommonStyle::standardPixmap(standardPixmap, opt, widget); } @@ -2854,56 +2449,7 @@ QSize QWindowsStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, QIcon QWindowsStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { - QIcon icon; -#ifdef Q_OS_WIN - QPixmap pixmap; - switch (standardIcon) { - case SP_DriveCDIcon: - case SP_DriveDVDIcon: - case SP_DriveNetIcon: - case SP_DriveHDIcon: - case SP_DriveFDIcon: - case SP_FileIcon: - case SP_FileLinkIcon: - case SP_DesktopIcon: - case SP_ComputerIcon: - if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { - QPlatformTheme::StandardPixmap sp = static_cast(standardIcon); - for (int size = 16 ; size <= 32 ; size += 16) { - pixmap = theme->standardPixmap(sp, QSizeF(size, size)); - icon.addPixmap(pixmap, QIcon::Normal); - } - } - break; - case SP_DirIcon: - case SP_DirLinkIcon: - if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { - QPlatformTheme::StandardPixmap spOff = static_cast(standardIcon); - QPlatformTheme::StandardPixmap spOn = standardIcon == SP_DirIcon ? QPlatformTheme::DirOpenIcon : - QPlatformTheme::DirLinkOpenIcon; - for (int size = 16 ; size <= 32 ; size += 16) { - QSizeF pixSize(size, size); - pixmap = theme->standardPixmap(spOff, pixSize); - icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off); - pixmap = theme->standardPixmap(spOn, pixSize); - icon.addPixmap(pixmap, QIcon::Normal, QIcon::On); - } - } - break; - case SP_VistaShield: - if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { - QPlatformTheme::StandardPixmap sp = static_cast(standardIcon); - pixmap = theme->standardPixmap(sp, QSizeF(32, 32)); - } - break; - default: - break; - } -#endif - - if (icon.isNull()) - icon = QCommonStyle::standardIcon(standardIcon, option, widget); - return icon; + return QCommonStyle::standardIcon(standardIcon, option, widget); } -- cgit v1.2.3 From b213d5bfa3a8ed81077cd8eaf229764ff2f1b346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 15 Oct 2012 17:06:34 +0200 Subject: Make QPen default to 1-width non-cosmetic. Use the Qt4CompatiblePainting render hint when painting with QPainter to treat default constructed QPens as cosmetic still. The NonCosmeticDefaultPen render hint gets documented as obsolete, since it was in any case not respected by the raster nor OpenGL paint engine. Change-Id: I04d910e9700baf7f13a8aac07a3633014bb9283e Reviewed-by: Jens Bache-Wiig --- src/gui/opengl/qopenglpaintengine.cpp | 13 +++--- src/gui/opengl/qtriangulatingstroker.cpp | 8 ++-- src/gui/opengl/qtriangulatingstroker_p.h | 4 +- src/gui/painting/qcosmeticstroker.cpp | 2 +- src/gui/painting/qpaintbuffer.cpp | 2 +- src/gui/painting/qpaintengine.cpp | 2 +- src/gui/painting/qpaintengine_raster.cpp | 9 ++-- src/gui/painting/qpaintengineex.cpp | 4 +- src/gui/painting/qpainter.cpp | 51 ++++++---------------- src/gui/painting/qpainter_p.h | 9 ++-- src/gui/painting/qpdf.cpp | 9 ++-- src/gui/painting/qpdf_p.h | 2 +- src/gui/painting/qpen.cpp | 44 ++++++++++++------- src/gui/painting/qpen_p.h | 3 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 10 ++--- src/plugins/platforms/cocoa/qpaintengine_mac.mm | 4 +- src/printsupport/kernel/qpaintengine_alpha.cpp | 8 +++- src/printsupport/kernel/qprintengine_win.cpp | 13 ++++-- src/widgets/graphicsview/qgraphicsitem.cpp | 10 ++--- src/widgets/graphicsview/qgraphicsproxywidget.cpp | 10 ----- src/widgets/graphicsview/qgraphicswidget.cpp | 1 - 21 files changed, 107 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index e0f1fe50a6..8e967207d4 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -1194,7 +1194,7 @@ void QOpenGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) return; QOpenGL2PaintEngineState *s = state(); - if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { + if (qt_pen_is_cosmetic(pen, state()->renderHints) && !qt_scaleForTransform(s->transform(), 0)) { // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. QPaintEngineEx::stroke(path, pen); return; @@ -1229,15 +1229,16 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p : QRectF(0, 0, width, height)); if (penStyle == Qt::SolidLine) { - stroker.process(path, pen, clip); + stroker.process(path, pen, clip, s->renderHints); } else { // Some sort of dash - dasher.process(path, pen, clip); + dasher.process(path, pen, clip, s->renderHints); QVectorPath dashStroke(dasher.points(), dasher.elementCount(), - dasher.elementTypes()); - stroker.process(dashStroke, pen, clip); + dasher.elementTypes(), + s->renderHints); + stroker.process(dashStroke, pen, clip, s->renderHints); } if (!stroker.vertexCount()) @@ -1261,7 +1262,7 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p ? qMax(pen.miterLimit() * width, width) : width; - if (pen.isCosmetic()) + if (qt_pen_is_cosmetic(pen, q->state()->renderHints)) extra = extra * inverseScale; QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); diff --git a/src/gui/opengl/qtriangulatingstroker.cpp b/src/gui/opengl/qtriangulatingstroker.cpp index 0be6e12721..6c8ab7d607 100644 --- a/src/gui/opengl/qtriangulatingstroker.cpp +++ b/src/gui/opengl/qtriangulatingstroker.cpp @@ -81,7 +81,7 @@ static inline void skipDuplicatePoints(const qreal **pts, const qreal *endPts) } } -void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &) +void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &, QPainter::RenderHints hints) { const qreal *pts = path.points(); const QPainterPath::ElementType *types = path.elements(); @@ -95,7 +95,7 @@ void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, co m_width = realWidth / 2; - bool cosmetic = pen.isCosmetic(); + bool cosmetic = qt_pen_is_cosmetic(pen, hints); if (cosmetic) { m_width = m_width * m_inv_scale; } @@ -519,14 +519,14 @@ QDashedStrokeProcessor::QDashedStrokeProcessor() m_dash_stroker.setCubicToHook(qdashprocessor_cubicTo); } -void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip) +void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints) { const qreal *pts = path.points(); const QPainterPath::ElementType *types = path.elements(); int count = path.elementCount(); - bool cosmetic = pen.isCosmetic(); + bool cosmetic = qt_pen_is_cosmetic(pen, hints); m_points.reset(); m_types.reset(); diff --git a/src/gui/opengl/qtriangulatingstroker_p.h b/src/gui/opengl/qtriangulatingstroker_p.h index 295ddbab5a..ba21c0820f 100644 --- a/src/gui/opengl/qtriangulatingstroker_p.h +++ b/src/gui/opengl/qtriangulatingstroker_p.h @@ -55,7 +55,7 @@ class Q_GUI_EXPORT QTriangulatingStroker { public: QTriangulatingStroker() : m_vertices(0) {} - void process(const QVectorPath &path, const QPen &pen, const QRectF &clip); + void process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints); inline int vertexCount() const { return m_vertices.size(); } inline const float *vertices() const { return m_vertices.data(); } @@ -97,7 +97,7 @@ class Q_GUI_EXPORT QDashedStrokeProcessor public: QDashedStrokeProcessor(); - void process(const QVectorPath &path, const QPen &pen, const QRectF &clip); + void process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints); inline void addElement(QPainterPath::ElementType type, qreal x, qreal y) { m_points.add(x); diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp index 2eab7b25c5..7fcab1f087 100644 --- a/src/gui/painting/qcosmeticstroker.cpp +++ b/src/gui/painting/qcosmeticstroker.cpp @@ -275,7 +275,7 @@ void QCosmeticStroker::setup() qreal width = state->lastPen.widthF(); if (width == 0) opacity = 256; - else if (state->lastPen.isCosmetic()) + else if (qt_pen_is_cosmetic(state->lastPen, state->renderHints)) opacity = (int) 256*width; else opacity = (int) 256*width*state->txscale; diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 1e5a00e835..d7b16114b8 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -680,7 +680,7 @@ void QPaintBufferEngine::penChanged() } else { qreal penWidth = (pen.widthF() == 0) ? 1 : pen.widthF(); QPointF transformedWidth(penWidth, penWidth); - if (!pen.isCosmetic()) + if (!qt_pen_is_cosmetic(pen, state()->renderHints)) transformedWidth = painter()->transform().map(transformedWidth); buffer->penWidthAdjustment = transformedWidth.x() / 2.0; } diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp index 09b1f0a8e4..339421f5e2 100644 --- a/src/gui/painting/qpaintengine.cpp +++ b/src/gui/painting/qpaintengine.cpp @@ -445,7 +445,7 @@ void QPaintEngine::drawPoints(const QPointF *points, int pointCount) p->save(); QTransform transform; - if (p->pen().isCosmetic()) { + if (qt_pen_is_cosmetic(p->pen(), p->renderHints())) { transform = p->transform(); p->setTransform(QTransform()); } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index e0eab8dc73..1a63ced897 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -771,7 +771,7 @@ void QRasterPaintEngine::updatePen(const QPen &pen) } else if (pen_style != Qt::NoPen) { if (!d->dashStroker) d->dashStroker.reset(new QDashStroker(&d->basicStroker)); - if (pen.isCosmetic()) { + if (qt_pen_is_cosmetic(pen, s->renderHints)) { d->dashStroker->setClipRect(d->deviceRect); } else { // ### I've seen this inverted devrect multiple places now... @@ -786,10 +786,11 @@ void QRasterPaintEngine::updatePen(const QPen &pen) } ensureRasterState(); // needed because of tx_noshear... + bool cosmetic = qt_pen_is_cosmetic(pen, s->renderHints); s->flags.fast_pen = pen_style > Qt::NoPen && s->penData.blend - && ((pen.isCosmetic() && penWidth <= 1) - || (!pen.isCosmetic() && s->flags.tx_noshear && penWidth * s->txscale <= 1)); + && ((cosmetic && penWidth <= 1) + || (!cosmetic && s->flags.tx_noshear && penWidth * s->txscale <= 1)); s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear; @@ -1610,7 +1611,7 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding); stroker.drawPath(path); } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) { - qreal width = s->lastPen.isCosmetic() + qreal width = qt_pen_is_cosmetic(s->lastPen, s->renderHints) ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen)) : qpen_widthf(s->lastPen) * s->txscale; int dashIndex = 0; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index dd93a58635..113cbd8a8e 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -435,7 +435,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) } if (pen.style() > Qt::SolidLine) { - if (pen.isCosmetic()) { + if (qt_pen_is_cosmetic(pen, state()->renderHints)){ d->activeStroker->setClipRect(d->exDeviceRect); } else { QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect)); @@ -462,7 +462,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) flags |= QVectorPath::CurvedShapeMask; // ### Perspective Xforms are currently not supported... - if (!pen.isCosmetic()) { + if (!qt_pen_is_cosmetic(pen, state()->renderHints)) { // We include cosmetic pens in this case to avoid having to // change the current transform. Normal transformed, // non-cosmetic pens will be transformed as part of fill diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 69267b259b..090faf15aa 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -897,26 +897,8 @@ void QPainterPrivate::updateState(QPainterState *newState) if (!newState) { engine->state = newState; - } else if (newState->state() || engine->state!=newState) { - bool setNonCosmeticPen = (newState->renderHints & QPainter::NonCosmeticDefaultPen) - && newState->pen.widthF() == 0; - if (setNonCosmeticPen) { - // Override the default pen's cosmetic state if the - // NonCosmeticDefaultPen render hint is used. - QPen oldPen = newState->pen; - newState->pen.setWidth(1); - newState->pen.setCosmetic(false); - newState->dirtyFlags |= QPaintEngine::DirtyPen; - - updateStateImpl(newState); - - // Restore the state pen back to its default to preserve visible - // state. - newState->pen = oldPen; - } else { - updateStateImpl(newState); - } + updateStateImpl(newState); } } @@ -1417,14 +1399,13 @@ void QPainterPrivate::updateState(QPainterState *newState) indicating that the engine should use fragment programs and offscreen rendering for antialiasing. - \value NonCosmeticDefaultPen The engine should interpret pens with a width - of 0 (which otherwise enables QPen::isCosmetic()) as being a non-cosmetic - pen with a width of 1. + \value NonCosmeticDefaultPen This value is obsolete, the default for QPen + is now non-cosmetic. \value Qt4CompatiblePainting Compatibility hint telling the engine to use the same X11 based fill rules as in Qt 4, where aliased rendering is offset - by slightly less than half a pixel. Potentially useful when porting a - Qt 4 application to Qt 5. + by slightly less than half a pixel. Also will treat default constructed pens + as cosmetic. Potentially useful when porting a Qt 4 application to Qt 5. \sa renderHints(), setRenderHint(), {QPainter#Rendering Quality}{Rendering Quality}, {Concentric Circles Example} @@ -3849,13 +3830,10 @@ void QPainter::setPen(const QColor &color) return; } - if (d->state->pen.style() == Qt::SolidLine - && d->state->pen.widthF() == 0 - && d->state->pen.isSolid() - && d->state->pen.color() == color) - return; + QPen pen(color.isValid() ? color : QColor(Qt::black)); - QPen pen(color.isValid() ? color : QColor(Qt::black), 0, Qt::SolidLine); + if (d->state->pen == pen) + return; d->state->pen = pen; if (d->extended) @@ -3904,7 +3882,7 @@ void QPainter::setPen(const QPen &pen) /*! \overload - Sets the painter's pen to have the given \a style, width 0 and + Sets the painter's pen to have the given \a style, width 1 and black color. */ @@ -3916,15 +3894,12 @@ void QPainter::setPen(Qt::PenStyle style) return; } - if (d->state->pen.style() == style - && (style == Qt::NoPen || (d->state->pen.widthF() == 0 - && d->state->pen.isSolid() - && d->state->pen.color() == QColor(Qt::black)))) + QPen pen = QPen(style); + + if (d->state->pen == pen) return; - // QPen(Qt::NoPen) is to avoid creating QPenData, including its brush (from the color) - // Note that this works well as long as QPen(Qt::NoPen) returns a black, zero-width pen - d->state->pen = (style == Qt::NoPen) ? QPen(Qt::NoPen) : QPen(Qt::black, 0, style); + d->state->pen = pen; if (d->extended) d->extended->penChanged(); diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 6ad1cb07cc..0e46cee4b5 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -241,10 +241,6 @@ public: void updateMatrix(); void updateInvMatrix(); - int rectSubtraction() const { - return state->pen.style() != Qt::NoPen && state->pen.width() == 0 ? 1 : 0; - } - void checkEmulation(); static QPainterPrivate *get(QPainter *painter) @@ -269,6 +265,11 @@ Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, Q QString qt_generate_brush_key(const QBrush &brush); +inline bool qt_pen_is_cosmetic(const QPen &pen, QPainter::RenderHints hints) +{ + return pen.isCosmetic() || (const_cast(pen).data_ptr()->defaultWidth && (hints & QPainter::Qt4CompatiblePainting)); +} + QT_END_NAMESPACE #endif // QPAINTER_P_H diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index d2aa938aed..1d07d44dd8 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include "private/qfont_p.h" #include @@ -784,7 +785,7 @@ QPdf::Stroker::Stroker() basicStroker.setStrokeWidth(.1); } -void QPdf::Stroker::setPen(const QPen &pen) +void QPdf::Stroker::setPen(const QPen &pen, QPainter::RenderHints hints) { if (pen.style() == Qt::NoPen) { stroker = 0; @@ -792,7 +793,7 @@ void QPdf::Stroker::setPen(const QPen &pen) } qreal w = pen.widthF(); bool zeroWidth = w < 0.0001; - cosmeticPen = pen.isCosmetic(); + cosmeticPen = qt_pen_is_cosmetic(pen, hints); if (zeroWidth) w = .1; @@ -1198,12 +1199,14 @@ void QPdfEngine::updateState(const QPaintEngineState &state) if (flags & DirtyPen) { d->pen = state.pen(); d->hasPen = d->pen.style() != Qt::NoPen; - d->stroker.setPen(d->pen); + d->stroker.setPen(d->pen, state.renderHints()); QBrush penBrush = d->pen.brush(); bool oldSimple = d->simplePen; d->simplePen = (d->hasPen && (penBrush.style() == Qt::SolidPattern) && penBrush.isOpaque()); if (oldSimple != d->simplePen) flags |= DirtyTransform; + } else if (flags & DirtyHints) { + d->stroker.setPen(d->pen, state.renderHints()); } if (flags & DirtyBrush) { d->brush = state.brush(); diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h index ba86803288..735c5d13e0 100644 --- a/src/gui/painting/qpdf_p.h +++ b/src/gui/painting/qpdf_p.h @@ -124,7 +124,7 @@ namespace QPdf { struct Stroker { Stroker(); - void setPen(const QPen &pen); + void setPen(const QPen &pen, QPainter::RenderHints hints); void strokePath(const QPainterPath &path); ByteStream *stream; bool first; diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index d86a5f0392..6b71c3818f 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -86,7 +86,7 @@ typedef QPenPrivate QPenData; \snippet code/src_gui_painting_qpen.cpp 1 - The default pen is a solid black brush with 0 width, square + The default pen is a solid black brush with 1 width, square cap style (Qt::SquareCap), and bevel join style (Qt::BevelJoin). In addition QPen provides the color() and setColor() @@ -230,9 +230,9 @@ typedef QPenPrivate QPenData; \internal */ inline QPenPrivate::QPenPrivate(const QBrush &_brush, qreal _width, Qt::PenStyle penStyle, - Qt::PenCapStyle _capStyle, Qt::PenJoinStyle _joinStyle) + Qt::PenCapStyle _capStyle, Qt::PenJoinStyle _joinStyle, bool _defaultWidth) : ref(1), dashOffset(0), miterLimit(2), - cosmetic(false) + cosmetic(false), defaultWidth(_defaultWidth) { width = _width; brush = _brush; @@ -261,12 +261,12 @@ public: }; Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, defaultPenInstance, - (Qt::black, 0, Qt::SolidLine, qpen_default_cap, qpen_default_join)) + (Qt::black, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join)) Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, nullPenInstance, - (Qt::black, 0, Qt::NoPen, qpen_default_cap, qpen_default_join)) + (Qt::black, 1, Qt::NoPen, qpen_default_cap, qpen_default_join)) /*! - Constructs a default black solid line pen with 0 width. + Constructs a default black solid line pen with 1 width. */ QPen::QPen() @@ -276,7 +276,7 @@ QPen::QPen() } /*! - Constructs a black pen with 0 width and the given \a style. + Constructs a black pen with 1 width and the given \a style. \sa setStyle() */ @@ -287,20 +287,20 @@ QPen::QPen(Qt::PenStyle style) d = nullPenInstance()->pen; d->ref.ref(); } else { - d = new QPenData(Qt::black, 0, style, qpen_default_cap, qpen_default_join); + d = new QPenData(Qt::black, 1, style, qpen_default_cap, qpen_default_join); } } /*! - Constructs a solid line pen with 0 width and the given \a color. + Constructs a solid line pen with 1 width and the given \a color. \sa setBrush(), setColor() */ QPen::QPen(const QColor &color) { - d = new QPenData(color, 0, Qt::SolidLine, qpen_default_cap, qpen_default_join); + d = new QPenData(color, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join); } @@ -315,7 +315,7 @@ QPen::QPen(const QColor &color) QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle s, Qt::PenCapStyle c, Qt::PenJoinStyle j) { - d = new QPenData(brush, width, s, c, j); + d = new QPenData(brush, width, s, c, j, false); } /*! @@ -655,12 +655,15 @@ void QPen::setWidth(int width) void QPen::setWidthF(qreal width) { - if (width < 0.f) + if (width < 0.f) { qWarning("QPen::setWidthF: Setting a pen width with a negative value is not defined"); + return; + } if (qAbs(d->width - width) < 0.00000001f) return; detach(); d->width = width; + d->defaultWidth = false; } @@ -785,8 +788,7 @@ bool QPen::isSolid() const used with. Drawing a shape with a cosmetic pen ensures that its outline will have the same thickness at different scale factors. - A zero width pen is cosmetic by default; pens with a non-zero width - are non-cosmetic. + A zero width pen is cosmetic by default. \sa setCosmetic(), widthF() */ @@ -848,7 +850,8 @@ bool QPen::operator==(const QPen &p) const || (qFuzzyCompare(pdd->dashOffset, dd->dashOffset) && pdd->dashPattern == dd->dashPattern)) && p.d->brush == d->brush - && pdd->cosmetic == dd->cosmetic); + && pdd->cosmetic == dd->cosmetic + && pdd->defaultWidth == dd->defaultWidth); } @@ -910,6 +913,8 @@ QDataStream &operator<<(QDataStream &s, const QPen &p) } if (s.version() >= 9) s << double(p.dashOffset()); + if (s.version() >= QDataStream::Qt_5_0) + s << bool(dd->defaultWidth); } return s; } @@ -935,6 +940,7 @@ QDataStream &operator>>(QDataStream &s, QPen &p) QVector dashPattern; double dashOffset = 0; bool cosmetic = false; + bool defaultWidth = false; if (s.version() < QDataStream::Qt_4_3) { quint8 style8; s >> style8; @@ -967,6 +973,13 @@ QDataStream &operator>>(QDataStream &s, QPen &p) s >> dashOffset; } + if (s.version() >= QDataStream::Qt_5_0) { + s >> defaultWidth; + } else { + // best we can do for legacy pens + defaultWidth = qFuzzyIsNull(width); + } + p.detach(); QPenData *dd = static_cast(p.d); dd->width = width; @@ -978,6 +991,7 @@ QDataStream &operator>>(QDataStream &s, QPen &p) dd->miterLimit = miterLimit; dd->dashOffset = dashOffset; dd->cosmetic = cosmetic; + dd->defaultWidth = defaultWidth; return s; } diff --git a/src/gui/painting/qpen_p.h b/src/gui/painting/qpen_p.h index 93f2532e63..4b2fcaa71d 100644 --- a/src/gui/painting/qpen_p.h +++ b/src/gui/painting/qpen_p.h @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE class QPenPrivate { public: QPenPrivate(const QBrush &brush, qreal width, Qt::PenStyle, Qt::PenCapStyle, - Qt::PenJoinStyle _joinStyle); + Qt::PenJoinStyle _joinStyle, bool defaultWidth = true); QAtomicInt ref; qreal width; QBrush brush; @@ -71,6 +71,7 @@ public: qreal dashOffset; qreal miterLimit; uint cosmetic : 1; + uint defaultWidth : 1; // default-constructed width? used for cosmetic pen compatibility }; QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 7c47f3b3eb..e542397663 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1201,7 +1201,7 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) return; QOpenGL2PaintEngineState *s = state(); - if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { + if (qt_pen_is_cosmetic(pen, s->renderHints) && !qt_scaleForTransform(s->transform(), 0)) { // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. QPaintEngineEx::stroke(path, pen); return; @@ -1236,15 +1236,15 @@ void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) : QRectF(0, 0, width, height)); if (penStyle == Qt::SolidLine) { - stroker.process(path, pen, clip); + stroker.process(path, pen, clip, s->renderHints); } else { // Some sort of dash - dasher.process(path, pen, clip); + dasher.process(path, pen, clip, s->renderHints); QVectorPath dashStroke(dasher.points(), dasher.elementCount(), dasher.elementTypes()); - stroker.process(dashStroke, pen, clip); + stroker.process(dashStroke, pen, clip, s->renderHints); } if (!stroker.vertexCount()) @@ -1268,7 +1268,7 @@ void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) ? qMax(pen.miterLimit() * width, width) : width; - if (pen.isCosmetic()) + if (qt_pen_is_cosmetic(pen, s->renderHints)) extra = extra * inverseScale; QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 8c47527648..404c03dd30 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -717,8 +717,8 @@ QCoreGraphicsPaintEngine::updateState(const QPaintEngineState &state) if (flags & DirtyCompositionMode) updateCompositionMode(state.compositionMode()); - if (flags & (DirtyPen | DirtyTransform)) { - if (!d->current.pen.isCosmetic()) { + if (flags & (DirtyPen | DirtyTransform | DirtyHints)) { + if (!qt_pen_is_cosmetic(d->current.pen, state.renderHints())) { d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticNone; } else if (d->current.transform.m11() < d->current.transform.m22()-1.0 || d->current.transform.m11() > d->current.transform.m22()+1.0) { diff --git a/src/printsupport/kernel/qpaintengine_alpha.cpp b/src/printsupport/kernel/qpaintengine_alpha.cpp index e3312f2db7..387e87766b 100644 --- a/src/printsupport/kernel/qpaintengine_alpha.cpp +++ b/src/printsupport/kernel/qpaintengine_alpha.cpp @@ -45,6 +45,7 @@ #include #include "private/qpaintengine_alpha_p.h" +#include "private/qpainter_p.h" #include "private/qpicture_p.h" #include "private/qfont_p.h" #include "QtGui/qpicture.h" @@ -384,11 +385,14 @@ QAlphaPaintEnginePrivate::~QAlphaPaintEnginePrivate() QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path) { + Q_Q(QAlphaPaintEngine); + QPainterPath tmp = path; if (m_pen.style() == Qt::NoPen) return (path.controlPointRect() * m_transform).boundingRect(); - if (m_pen.isCosmetic()) + bool cosmetic = qt_pen_is_cosmetic(m_pen, q->state->renderHints()); + if (cosmetic) tmp = path * m_transform; QPainterPathStroker stroker; @@ -399,7 +403,7 @@ QRectF QAlphaPaintEnginePrivate::addPenWidth(const QPainterPath &path) stroker.setJoinStyle(m_pen.joinStyle()); stroker.setCapStyle(m_pen.capStyle()); tmp = stroker.createStroke(tmp); - if (m_pen.isCosmetic()) + if (cosmetic) return tmp.controlPointRect(); return (tmp.controlPointRect() * m_transform).boundingRect(); diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index 27351dee48..28e0363d6e 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -852,6 +852,8 @@ void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QCol void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth) { + Q_Q(QWin32PrintEngine); + composeGdiPath(path); LOGBRUSH brush; brush.lbStyle = BS_SOLID; @@ -868,7 +870,9 @@ void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QC else if (pen.joinStyle() == Qt::RoundJoin) joinStyle = PS_JOIN_ROUND; - HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC) + bool cosmetic = qt_pen_is_cosmetic(pen, q->state->renderHints()); + + HPEN pen = ExtCreatePen((cosmetic ? PS_COSMETIC : PS_GEOMETRIC) | PS_SOLID | capStyle | joinStyle, (penWidth == 0) ? 1 : penWidth, &brush, 0, 0); @@ -885,6 +889,8 @@ void QWin32PrintEnginePrivate::fillPath(const QPainterPath &path, const QColor & void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor &color) { + Q_Q(QWin32PrintEngine); + QPainterPathStroker stroker; if (pen.style() == Qt::CustomDashLine) { stroker.setDashPattern(pen.dashPattern()); @@ -898,11 +904,12 @@ void QWin32PrintEnginePrivate::strokePath(const QPainterPath &path, const QColor QPainterPath stroke; qreal width = pen.widthF(); - if (pen.style() == Qt::SolidLine && (pen.isCosmetic() || matrix.type() < QTransform::TxScale)) { + bool cosmetic = qt_pen_is_cosmetic(pen, q->state->renderHints()); + if (pen.style() == Qt::SolidLine && (cosmetic || matrix.type() < QTransform::TxScale)) { strokePath_dev(path * matrix, color, width); } else { stroker.setWidth(width); - if (pen.isCosmetic()) { + if (cosmetic) { stroke = stroker.createStroke(path * matrix); } else { stroke = stroker.createStroke(path) * painterMatrix; diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 375aa9b6ca..c432902fc2 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -8030,7 +8030,7 @@ QAbstractGraphicsShapeItem::~QAbstractGraphicsShapeItem() /*! Returns the item's pen. If no pen has been set, this function returns - QPen(), a default black solid line pen with 0 width. + QPen(), a default black solid line pen with 1 width. */ QPen QAbstractGraphicsShapeItem::pen() const { @@ -8204,7 +8204,7 @@ QRectF QGraphicsPathItem::boundingRect() const { Q_D(const QGraphicsPathItem); if (d->boundingRect.isNull()) { - qreal pw = pen().widthF(); + qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF(); if (pw == 0.0) d->boundingRect = d->path.controlPointRect(); else { @@ -8434,7 +8434,7 @@ QRectF QGraphicsRectItem::boundingRect() const { Q_D(const QGraphicsRectItem); if (d->boundingRect.isNull()) { - qreal halfpw = pen().widthF() / 2; + qreal halfpw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF() / 2; d->boundingRect = d->rect; if (halfpw > 0.0) d->boundingRect.adjust(-halfpw, -halfpw, halfpw, halfpw); @@ -8723,7 +8723,7 @@ QRectF QGraphicsEllipseItem::boundingRect() const { Q_D(const QGraphicsEllipseItem); if (d->boundingRect.isNull()) { - qreal pw = pen().widthF(); + qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF(); if (pw == 0.0 && d->spanAngle == 360 * 16) d->boundingRect = d->rect; else @@ -8959,7 +8959,7 @@ QRectF QGraphicsPolygonItem::boundingRect() const { Q_D(const QGraphicsPolygonItem); if (d->boundingRect.isNull()) { - qreal pw = pen().widthF(); + qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF(); if (pw == 0.0) d->boundingRect = d->polygon.boundingRect(); else diff --git a/src/widgets/graphicsview/qgraphicsproxywidget.cpp b/src/widgets/graphicsview/qgraphicsproxywidget.cpp index 6dd03e76b0..762f93f55b 100644 --- a/src/widgets/graphicsview/qgraphicsproxywidget.cpp +++ b/src/widgets/graphicsview/qgraphicsproxywidget.cpp @@ -1485,17 +1485,7 @@ void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsIt if (exposedWidgetRect.isEmpty()) return; - // Disable QPainter's default pen being cosmetic. This allows widgets and - // styles to follow Qt's existing defaults without getting ugly cosmetic - // lines when scaled. - bool restore = !(painter->renderHints() & QPainter::NonCosmeticDefaultPen); - painter->setRenderHints(QPainter::NonCosmeticDefaultPen, true); - d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect); - - // Restore the render hints if necessary. - if (restore) - painter->setRenderHints(QPainter::NonCosmeticDefaultPen, false); } /*! diff --git a/src/widgets/graphicsview/qgraphicswidget.cpp b/src/widgets/graphicsview/qgraphicswidget.cpp index 05ae51c630..859f07a36b 100644 --- a/src/widgets/graphicsview/qgraphicswidget.cpp +++ b/src/widgets/graphicsview/qgraphicswidget.cpp @@ -2299,7 +2299,6 @@ void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGrap painter->fillRect(windowFrameRect, palette().window()); } } - painter->setRenderHint(QPainter::NonCosmeticDefaultPen); // Draw title int height = (int)d->titleBarHeight(bar); -- cgit v1.2.3 From a0e5d6c1c05f1d9f811eaf2760193618ae8a83ca Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Sun, 21 Oct 2012 12:07:13 +0200 Subject: Fix clipping and font problems with groupbox in Fusion style The groupbox did not take custom fonts into account when calculating the height of its titlebar. This resulted in clipping issues on Windows. Task-number: QTBUG-27655 Change-Id: I7252bc94d2bbb0731b9dbc1caa6cdd2074fdd7ab Reviewed-by: Jens Bache-Wiig --- src/widgets/styles/qfusionstyle.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 603369d117..3fc4cd0f1f 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -87,8 +87,7 @@ static const int windowsItemVMargin = 8; // menu item ver text margin static const int windowsRightBorder = 15; // right border on windows static const int groupBoxBottomMargin = 0; // space below the groupbox -static const int groupBoxTitleMargin = 2; // space between contents and title -static const int groupBoxTopMargin = 18; +static const int groupBoxTopMargin = 3; /* XPM */ @@ -439,7 +438,8 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, case PE_FrameGroupBox: { QPixmap pixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_groupbox.png")); - QRect frame = option->rect.adjusted(0, groupBoxTopMargin, 0, 0); + int topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), option->fontMetrics.height()) + groupBoxTopMargin; + QRect frame = option->rect.adjusted(0, topMargin, 0, 0); qDrawBorderPixmap(painter, frame, QMargins(6, 6, 6, 6), pixmap); break; } @@ -1084,7 +1084,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio // Draws the light line above and the dark line below menu bars and // tool bars. QLinearGradient gradient(option->rect.topLeft(), option->rect.bottomLeft()); - if (!option->state & State_Horizontal) + if (!(option->state & State_Horizontal)) gradient = QLinearGradient(rect.left(), rect.center().y(), rect.right(), rect.center().y()); gradient.setColorAt(0, option->palette.window().color().lighter(104)); @@ -1990,7 +1990,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption if (groupBox->state & State_HasFocus) { QStyleOptionFocusRect fropt; fropt.QStyleOption::operator=(*groupBox); - fropt.rect = textRect.translated(0, -2); + fropt.rect = textRect.adjusted(-2, -1, 2, 1); proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); } } @@ -3011,7 +3011,10 @@ QSize QFusionStyle::sizeFromContents(ContentsType type, const QStyleOption *opti } break; case CT_GroupBox: - newSize += QSize(10, 10); // Add some space below the groupbox + if (option) { + int topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), option->fontMetrics.height()) + groupBoxTopMargin; + newSize += QSize(10, topMargin); // Add some space below the groupbox + } break; case CT_RadioButton: case CT_CheckBox: @@ -3260,21 +3263,22 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom QRect frameRect = option->rect.adjusted(0, 0, 0, -groupBoxBottomMargin); int margin = 3; int leftMarginExtension = 0; - return frameRect.adjusted(leftMarginExtension + margin, margin + groupBoxTopMargin + groupBoxTitleMargin, -margin, -margin - groupBoxBottomMargin); + int topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), option->fontMetrics.height()) + groupBoxTopMargin; + return frameRect.adjusted(leftMarginExtension + margin, margin + topMargin, -margin, -margin - groupBoxBottomMargin); } - QSize textSize = option->fontMetrics.boundingRect(groupBox->text).size() + QSize(4, 4); + QSize textSize = option->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); rect = QRect(); if (subControl == SC_GroupBoxCheckBox) { rect.setWidth(indicatorWidth); rect.setHeight(indicatorHeight); - rect.moveTop((textSize.height() - indicatorHeight - 5) / 2); + rect.moveTop(textSize.height() > indicatorHeight ? (textSize.height() - indicatorHeight) / 2 : 0); rect.moveLeft(1); } else if (subControl == SC_GroupBoxLabel) { rect.setSize(textSize); - rect.moveTop(0); + rect.moveTop(1); if (option->subControls & QStyle::SC_GroupBoxCheckBox) rect.translate(indicatorWidth + 5, 0); } -- cgit v1.2.3 From 087e4bc5171f0ced1f34663e59217d678cd350ba Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Thu, 18 Oct 2012 15:22:15 +0200 Subject: Remove Cleanlooks and Plastique We have a new style Fusion that will replace these styles. They will be moved to a separate module rather than included in platforms that do not need them. Change-Id: I51ebbcad5406e99130e5b12e62ba624d1489088c Reviewed-by: Gabriel de Dietrich --- src/corelib/global/qconfig-minimal.h | 13 +- src/corelib/global/qconfig-small.h | 17 +- src/corelib/global/qfeatures.h | 10 - src/corelib/global/qfeatures.txt | 13 +- .../themes/genericunix/qgenericunixthemes.cpp | 4 +- src/tools/uic/qclass_lib_map.h | 2 - src/widgets/kernel/qapplication.cpp | 2 +- src/widgets/styles/qcleanlooksstyle.cpp | 4419 --------------- src/widgets/styles/qcleanlooksstyle.h | 111 - src/widgets/styles/qcleanlooksstyle_p.h | 79 - src/widgets/styles/qfusionstyle.cpp | 6 +- src/widgets/styles/qgtkstyle.cpp | 3 +- src/widgets/styles/qmacstyle.qdoc | 2 +- src/widgets/styles/qplastiquestyle.cpp | 5843 -------------------- src/widgets/styles/qplastiquestyle.h | 116 - src/widgets/styles/qstylefactory.cpp | 30 +- src/widgets/styles/qstylesheetstyle.cpp | 2 +- src/widgets/styles/qstylesheetstyle_default.cpp | 3 +- src/widgets/styles/qwindowsstyle.cpp | 2 +- src/widgets/styles/qwindowsvistastyle.cpp | 2 +- src/widgets/styles/qwindowsxpstyle.cpp | 2 +- src/widgets/styles/styles.pri | 56 +- src/widgets/widgets/qmenubar.cpp | 11 - 23 files changed, 38 insertions(+), 10710 deletions(-) delete mode 100644 src/widgets/styles/qcleanlooksstyle.cpp delete mode 100644 src/widgets/styles/qcleanlooksstyle.h delete mode 100644 src/widgets/styles/qcleanlooksstyle_p.h delete mode 100644 src/widgets/styles/qplastiquestyle.cpp delete mode 100644 src/widgets/styles/qplastiquestyle.h (limited to 'src') diff --git a/src/corelib/global/qconfig-minimal.h b/src/corelib/global/qconfig-minimal.h index 9c95d124ab..28cb8fbede 100644 --- a/src/corelib/global/qconfig-minimal.h +++ b/src/corelib/global/qconfig-minimal.h @@ -376,17 +376,8 @@ #endif /* Styles */ -#ifndef QT_NO_STYLE_MOTIF -# define QT_NO_STYLE_MOTIF -#endif -#ifndef QT_NO_STYLE_CDE -# define QT_NO_STYLE_CDE -#endif -#ifndef QT_NO_STYLE_CLEANLOOKS -# define QT_NO_STYLE_CLEANLOOKS -#endif -#ifndef QT_NO_STYLE_PLASTIQUE -# define QT_NO_STYLE_PLASTIQUE +#ifndef QT_NO_STYLE_FUSION +# define QT_NO_STYLE_FUSION #endif #ifndef QT_NO_STYLE_STYLESHEET # define QT_NO_STYLE_STYLESHEET diff --git a/src/corelib/global/qconfig-small.h b/src/corelib/global/qconfig-small.h index b3a056b815..9d72cd5d4c 100644 --- a/src/corelib/global/qconfig-small.h +++ b/src/corelib/global/qconfig-small.h @@ -209,23 +209,14 @@ #endif /* Styles */ -#ifndef QT_NO_STYLE_MOTIF -# define QT_NO_STYLE_MOTIF -#endif -#ifndef QT_NO_STYLE_CDE -# define QT_NO_STYLE_CDE -#endif -#ifndef QT_NO_STYLE_CLEANLOOKS -# define QT_NO_STYLE_CLEANLOOKS -#endif -#ifndef QT_NO_STYLE_PLASTIQUE -# define QT_NO_STYLE_PLASTIQUE +#ifndef QT_NO_STYLE_FUSION +# define QT_NO_STYLE_FUSION #endif #ifndef QT_NO_STYLE_STYLESHEET # define QT_NO_STYLE_STYLESHEET #endif -#ifndef QT_NO_STYLE_WINDOWSXP -# define QT_NO_STYLE_WINDOWSXP +#ifndef QT_NO_STYLE_WINDOWSVISTA +# define QT_NO_STYLE_WINDOWSVISTA #endif /* Utilities */ diff --git a/src/corelib/global/qfeatures.h b/src/corelib/global/qfeatures.h index 90ef47cf5b..b4b73a9aaa 100644 --- a/src/corelib/global/qfeatures.h +++ b/src/corelib/global/qfeatures.h @@ -396,16 +396,6 @@ #define QT_NO_SCROLLAREA #endif -// QCleanLooksStyle -#if !defined(QT_NO_STYLE_CLEANLOOKS) && (defined(QT_NO_STYLE_WINDOWS) || defined(QT_NO_IMAGEFORMAT_XPM)) -#define QT_NO_STYLE_CLEANLOOKS -#endif - -// QPlastiqueStyle -#if !defined(QT_NO_STYLE_PLASTIQUE) && (defined(QT_NO_STYLE_WINDOWS) || defined(QT_NO_IMAGEFORMAT_XPM)) -#define QT_NO_STYLE_PLASTIQUE -#endif - // QWindowsCEStyle #if !defined(QT_NO_STYLE_WINDOWSCE) && (defined(QT_NO_STYLE_WINDOWS) || defined(QT_NO_IMAGEFORMAT_XPM)) #define QT_NO_STYLE_WINDOWSCE diff --git a/src/corelib/global/qfeatures.txt b/src/corelib/global/qfeatures.txt index 3b3af8a3fc..7f31259c16 100644 --- a/src/corelib/global/qfeatures.txt +++ b/src/corelib/global/qfeatures.txt @@ -727,11 +727,11 @@ Requires: Name: QWindowsStyle SeeAlso: ??? -Feature: STYLE_PLASTIQUE -Description: Supports a widget style similar to the Plastik style available in KDE. +Feature: STYLE_FUSION +Description: Supports a modern platform independent widget style. Section: Styles Requires: STYLE_WINDOWS IMAGEFORMAT_XPM -Name: QPlastiqueStyle +Name: QFusionStyle SeeAlso: ??? Feature: STYLE_WINDOWSXP @@ -748,13 +748,6 @@ Requires: STYLE_WINDOWSXP Name: QWindowsVistaStyle SeeAlso: ??? -Feature: STYLE_CLEANLOOKS -Description: Supports a Gnome CleanLooks-like look and feel. -Section: Styles -Requires: STYLE_WINDOWS IMAGEFORMAT_XPM -Name: QCleanLooksStyle -SeeAlso: ??? - Feature: STYLE_WINDOWSCE Description: WindowsCE look and feel Section: Styles diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index 2d0139f0e5..d219fbef4e 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -130,7 +130,7 @@ QVariant QGenericUnixTheme::themeHint(ThemeHint hint) const return QVariant(true); case QPlatformTheme::StyleNames: { QStringList styleNames; - styleNames << QStringLiteral("Plastique") << QStringLiteral("Windows"); + styleNames << QStringLiteral("Fusion") << QStringLiteral("Windows"); return QVariant(styleNames); } case QPlatformTheme::KeyboardScheme: @@ -225,7 +225,7 @@ void QKdeTheme::refresh() m_toolButtonStyle = Qt::ToolButtonTextBesideIcon; m_toolBarIconSize = 0; m_styleNames.clear(); - m_styleNames << QStringLiteral("Oxygen") << QStringLiteral("plastique") << QStringLiteral("windows"); + m_styleNames << QStringLiteral("Oxygen") << QStringLiteral("fusion") << QStringLiteral("windows"); m_iconFallbackThemeName = m_iconThemeName = QStringLiteral("oxygen"); // Read settings file. diff --git a/src/tools/uic/qclass_lib_map.h b/src/tools/uic/qclass_lib_map.h index e35697399d..703871c3fb 100644 --- a/src/tools/uic/qclass_lib_map.h +++ b/src/tools/uic/qclass_lib_map.h @@ -834,11 +834,9 @@ QT_CLASS_LIB(QTransform, QtGui, qtransform.h) QT_CLASS_LIB(QWMatrix, QtGui, qwmatrix.h) QT_CLASS_LIB(QKeyEventTransition, QtWidgets, qkeyeventtransition.h) QT_CLASS_LIB(QMouseEventTransition, QtWidgets, qmouseeventtransition.h) -QT_CLASS_LIB(QCleanlooksStyle, QtWidgets, qcleanlooksstyle.h) QT_CLASS_LIB(QCommonStyle, QtWidgets, qcommonstyle.h) QT_CLASS_LIB(QGtkStyle, QtWidgets, qgtkstyle.h) QT_CLASS_LIB(QMacStyle, QtWidgets, qmacstyle_mac.h) -QT_CLASS_LIB(QPlastiqueStyle, QtWidgets, qplastiquestyle.h) QT_CLASS_LIB(QProxyStyle, QtWidgets, qproxystyle.h) QT_CLASS_LIB(QStyle, QtWidgets, qstyle.h) QT_CLASS_LIB(QStyleFactory, QtWidgets, qstylefactory.h) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 86a27b2574..3e0f803f5d 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1212,7 +1212,7 @@ void QApplication::setStyle(QStyle *style) Requests a QStyle object for \a style from the QStyleFactory. The string must be one of the QStyleFactory::keys(), typically one of - "windows", "cleanlooks", "plastique", "windowsxp", or "macintosh". Style + "windows", "fusion", "windowsxp", or "macintosh". Style names are case insensitive. Returns 0 if an unknown \a style is passed, otherwise the QStyle object diff --git a/src/widgets/styles/qcleanlooksstyle.cpp b/src/widgets/styles/qcleanlooksstyle.cpp deleted file mode 100644 index 5b8b5e0b9f..0000000000 --- a/src/widgets/styles/qcleanlooksstyle.cpp +++ /dev/null @@ -1,4419 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qcleanlooksstyle.h" -#include "qcleanlooksstyle_p.h" - -#if !defined(QT_NO_STYLE_CLEANLOOKS) || defined(QT_PLUGIN) - -#include "qwindowsstyle_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -using namespace QStyleHelper; - -enum Direction { - TopDown, - FromLeft, - BottomUp, - FromRight -}; - -// from windows style -static const int windowsItemFrame = 2; // menu item frame width -static const int windowsItemHMargin = 3; // menu item hor text margin -static const int windowsItemVMargin = 8; // menu item ver text margin -static const int windowsRightBorder = 15; // right border on windows - -/* XPM */ -static const char * const dock_widget_close_xpm[] = { - "11 13 7 1", - " c None", - ". c #D5CFCB", - "+ c #8F8B88", - "@ c #6C6A67", - "# c #ABA6A3", - "$ c #B5B0AC", - "% c #A4A09D", - " ", - " +@@@@@@@+ ", - "+# #+", - "@ $@ @$ @", - "@ @@@ @@@ @", - "@ @@@@@ @", - "@ @@@ @", - "@ @@@@@ @", - "@ @@@ @@@ @", - "@ $@ @$ @", - "+% #+", - " +@@@@@@@+ ", - " "}; - -static const char * const qt_cleanlooks_arrow_down_xpm[] = { - "11 7 2 1", - " c None", - "x c #000000", - " ", - " x x ", - " xxx xxx ", - " xxxxxxx ", - " xxxxx ", - " xxx ", - " x "}; - -static const char * const qt_cleanlooks_arrow_up_xpm[] = { - "11 7 2 1", - " c None", - "x c #000000", - " x ", - " xxx ", - " xxxxx ", - " xxxxxxx ", - " xxx xxx ", - " x x ", - " "}; - -static const char * const dock_widget_restore_xpm[] = { - "11 13 7 1", - " c None", - ". c #D5CFCB", - "+ c #8F8B88", - "@ c #6C6A67", - "# c #ABA6A3", - "$ c #B5B0AC", - "% c #A4A09D", - " ", - " +@@@@@@@+ ", - "+# #+", - "@ #@@@# @", - "@ @ @ @", - "@ #@@@# @ @", - "@ @ @ @ @", - "@ @ @@@ @", - "@ @ @ @", - "@ #@@@# @", - "+% #+", - " +@@@@@@@+ ", - " "}; - -static const char * const workspace_minimize[] = { - "11 13 7 1", - " c None", - ". c #D5CFCB", - "+ c #8F8B88", - "@ c #6C6A67", - "# c #ABA6A3", - "$ c #B5B0AC", - "% c #A4A09D", - " ", - " +@@@@@@@+ ", - "+# #+", - "@ @", - "@ @", - "@ @", - "@ @@@@@@@ @", - "@ @@@@@@@ @", - "@ @", - "@ @", - "+% #+", - " +@@@@@@@+ ", - " "}; - - -static const char * const qt_titlebar_context_help[] = { - "10 10 3 1", - " c None", - "# c #000000", - "+ c #444444", - " +####+ ", - " ### ### ", - " ## ## ", - " +##+ ", - " +## ", - " ## ", - " ## ", - " ", - " ## ", - " ## "}; - -static const char * const qt_cleanlooks_radiobutton[] = { - "13 13 9 1", - " c None", - ". c #ABA094", - "+ c #B7ADA0", - "@ c #C4BBB2", - "# c #DDD4CD", - "$ c #E7E1E0", - "% c #F4EFED", - "& c #FFFAF9", - "* c #FCFEFB", - " #@...@# ", - " @+@#$$#+@ ", - " @+$%%***&@@ ", - "#+$%**&&**&+#", - "@@$&&******#@", - ".#**********.", - ".$&******&*&.", - ".$*&******&*.", - "+#********&#@", - "#+*********+#", - " @@*******@@ ", - " @+#%*%#+@ ", - " #@...+# "}; - -static const char * const qt_cleanlooks_radiobutton_checked[] = { - "13 13 20 1", - " c None", - ". c #A8ABAE", - "+ c #596066", - "@ c #283138", - "# c #A9ACAF", - "$ c #A6A9AB", - "% c #6B7378", - "& c #8C9296", - "* c #A2A6AA", - "= c #61696F", - "- c #596065", - "; c #93989C", - "> c #777E83", - ", c #60686E", - "' c #252D33", - ") c #535B62", - "! c #21292E", - "~ c #242B31", - "{ c #1F262B", - "] c #41484E", - " ", - " ", - " ", - " .+@+# ", - " $%&*&=# ", - " -&;>,'+ ", - " @*>,)!@ ", - " +&,)~{+ ", - " #='!{]# ", - " #+@+# ", - " ", - " ", - " "}; - - -static const char * const qt_scrollbar_button_arrow_left[] = { - "4 7 2 1", - " c None", - "* c #BFBFBF", - " *", - " **", - " ***", - "****", - " ***", - " **", - " *"}; - -static const char * const qt_scrollbar_button_arrow_right[] = { - "4 7 2 1", - " c None", - "* c #BFBFBF", - "* ", - "** ", - "*** ", - "****", - "*** ", - "** ", - "* "}; - -static const char * const qt_scrollbar_button_arrow_up[] = { - "7 4 2 1", - " c None", - "* c #BFBFBF", - " * ", - " *** ", - " ***** ", - "*******"}; - -static const char * const qt_scrollbar_button_arrow_down[] = { - "7 4 2 1", - " c None", - "* c #BFBFBF", - "*******", - " ***** ", - " *** ", - " * "}; - -static const char * const qt_spinbox_button_arrow_down[] = { - "7 4 2 1", - " c None", - "* c #BFBFBF", - "*******", - " ***** ", - " *** ", - " * "}; - -static const char * const qt_spinbox_button_arrow_up[] = { - "7 4 2 1", - " c None", - "* c #BFBFBF", - " * ", - " *** ", - " ***** ", - "*******"}; - -static const char * const qt_scrollbar_button_left[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - " .++++++++++++++", - ".+#############+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - ".+<<<<<<<<<<<<<+", - " .++++++++++++++"}; - -static const char * const qt_scrollbar_button_right[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - "++++++++++++++. ", - "+#############+.", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+<<<<<<<<<<<<<+.", - "++++++++++++++. "}; - -static const char * const qt_scrollbar_button_up[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - " .++++++++++++. ", - ".+############+.", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+<<<<<<<<<<<<<<+", - "++++++++++++++++"}; - -static const char * const qt_scrollbar_button_down[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - "++++++++++++++++", - "+##############+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - ".+<<<<<<<<<<<<+.", - " .++++++++++++. "}; - -static const char * const qt_cleanlooks_menuitem_checkbox_checked[] = { - "8 7 6 1", - " g None", - ". g #959595", - "+ g #676767", - "@ g #454545", - "# g #1D1D1D", - "0 g #101010", - " ..", - " .+ ", - " .+ ", - "0 .@ ", - "@#++. ", - " @# ", - " . "}; - -static const char * const qt_cleanlooks_checkbox_checked[] = { - "13 13 3 1", - " c None", - ". c #272D33", - "% c #666666", - - " ", - " % ", - " %. ", - " %.% ", - " %.. ", - " %.% %.. ", - " %..%..% ", - " %...% ", - " %..% ", - " %.% ", - " % ", - " ", - " "}; - -static void qt_cleanlooks_draw_gradient(QPainter *painter, const QRect &rect, const QColor &gradientStart, - const QColor &gradientStop, Direction direction = TopDown, QBrush bgBrush = QBrush()) -{ - int x = rect.center().x(); - int y = rect.center().y(); - QLinearGradient *gradient; - switch(direction) { - case FromLeft: - gradient = new QLinearGradient(rect.left(), y, rect.right(), y); - break; - case FromRight: - gradient = new QLinearGradient(rect.right(), y, rect.left(), y); - break; - case BottomUp: - gradient = new QLinearGradient(x, rect.bottom(), x, rect.top()); - break; - case TopDown: - default: - gradient = new QLinearGradient(x, rect.top(), x, rect.bottom()); - break; - } - if (bgBrush.gradient()) - gradient->setStops(bgBrush.gradient()->stops()); - else { - gradient->setColorAt(0, gradientStart); - gradient->setColorAt(1, gradientStop); - } - painter->fillRect(rect, *gradient); - delete gradient; -} - -static void qt_cleanlooks_draw_buttongradient(QPainter *painter, const QRect &rect, const QColor &gradientStart, - const QColor &gradientMid, const QColor &gradientStop, Direction direction = TopDown, - QBrush bgBrush = QBrush()) -{ - int x = rect.center().x(); - int y = rect.center().y(); - QLinearGradient *gradient; - bool horizontal = false; - switch(direction) { - case FromLeft: - horizontal = true; - gradient = new QLinearGradient(rect.left(), y, rect.right(), y); - break; - case FromRight: - horizontal = true; - gradient = new QLinearGradient(rect.right(), y, rect.left(), y); - break; - case BottomUp: - gradient = new QLinearGradient(x, rect.bottom(), x, rect.top()); - break; - case TopDown: - default: - gradient = new QLinearGradient(x, rect.top(), x, rect.bottom()); - break; - } - if (bgBrush.gradient()) - gradient->setStops(bgBrush.gradient()->stops()); - else { - int size = horizontal ? rect.width() : rect.height() ; - if (size > 4) { - float edge = 4.0/(float)size; - gradient->setColorAt(0, gradientStart); - gradient->setColorAt(edge, gradientMid.lighter(104)); - gradient->setColorAt(1.0 - edge, gradientMid.darker(100)); - gradient->setColorAt(1.0, gradientStop); - } - } - painter->fillRect(rect, *gradient); - delete gradient; -} - -static void qt_cleanlooks_draw_mdibutton(QPainter *painter, const QStyleOptionTitleBar *option, const QRect &tmp, bool hover, bool sunken) -{ - QColor dark; - dark.setHsv(option->palette.button().color().hue(), - qMin(255, (int)(option->palette.button().color().saturation()*1.9)), - qMin(255, (int)(option->palette.button().color().value()*0.7))); - - QColor highlight = option->palette.highlight().color(); - - bool active = (option->titleBarState & QStyle::State_Active); - QColor titleBarHighlight(255, 255, 255, 60); - - if (sunken) - painter->fillRect(tmp.adjusted(1, 1, -1, -1), option->palette.highlight().color().darker(120)); - else if (hover) - painter->fillRect(tmp.adjusted(1, 1, -1, -1), QColor(255, 255, 255, 20)); - - QColor mdiButtonGradientStartColor; - QColor mdiButtonGradientStopColor; - - mdiButtonGradientStartColor = QColor(0, 0, 0, 40); - mdiButtonGradientStopColor = QColor(255, 255, 255, 60); - - if (sunken) - titleBarHighlight = highlight.darker(130); - - QLinearGradient gradient(tmp.center().x(), tmp.top(), tmp.center().x(), tmp.bottom()); - gradient.setColorAt(0, mdiButtonGradientStartColor); - gradient.setColorAt(1, mdiButtonGradientStopColor); - QColor mdiButtonBorderColor(active ? option->palette.highlight().color().darker(180): dark.darker(110)); - - painter->setPen(QPen(mdiButtonBorderColor, 1)); - const QLine lines[4] = { - QLine(tmp.left() + 2, tmp.top(), tmp.right() - 2, tmp.top()), - QLine(tmp.left() + 2, tmp.bottom(), tmp.right() - 2, tmp.bottom()), - QLine(tmp.left(), tmp.top() + 2, tmp.left(), tmp.bottom() - 2), - QLine(tmp.right(), tmp.top() + 2, tmp.right(), tmp.bottom() - 2) - }; - painter->drawLines(lines, 4); - const QPoint points[4] = { - QPoint(tmp.left() + 1, tmp.top() + 1), - QPoint(tmp.right() - 1, tmp.top() + 1), - QPoint(tmp.left() + 1, tmp.bottom() - 1), - QPoint(tmp.right() - 1, tmp.bottom() - 1) - }; - painter->drawPoints(points, 4); - - painter->setPen(titleBarHighlight); - painter->drawLine(tmp.left() + 2, tmp.top() + 1, tmp.right() - 2, tmp.top() + 1); - painter->drawLine(tmp.left() + 1, tmp.top() + 2, tmp.left() + 1, tmp.bottom() - 2); - - painter->setPen(QPen(gradient, 1)); - painter->drawLine(tmp.right() + 1, tmp.top() + 2, tmp.right() + 1, tmp.bottom() - 2); - painter->drawPoint(tmp.right() , tmp.top() + 1); - - painter->drawLine(tmp.left() + 2, tmp.bottom() + 1, tmp.right() - 2, tmp.bottom() + 1); - painter->drawPoint(tmp.left() + 1, tmp.bottom()); - painter->drawPoint(tmp.right() - 1, tmp.bottom()); - painter->drawPoint(tmp.right() , tmp.bottom() - 1); -} - -/*! - \class QCleanlooksStyle - \brief The QCleanlooksStyle class provides a widget style similar to the - Clearlooks style available in GNOME. - \since 4.2 - - \inmodule QtWidgets - - The Cleanlooks style provides a look and feel for widgets - that closely resembles the Clearlooks style, introduced by Richard - Stellingwerff and Daniel Borgmann. - - \sa {Cleanlooks Style Widget Gallery}, QWindowsXPStyle, QMacStyle, QWindowsStyle, - QPlastiqueStyle -*/ - -/*! - Constructs a QCleanlooksStyle object. -*/ -QCleanlooksStyle::QCleanlooksStyle() : QWindowsStyle(*new QCleanlooksStylePrivate) -{ - setObjectName(QLatin1String("CleanLooks")); -} - -/*! - \internal - - Constructs a QCleanlooksStyle object. -*/ -QCleanlooksStyle::QCleanlooksStyle(QCleanlooksStylePrivate &dd) : QWindowsStyle(dd) -{ -} - -/*! - Destroys the QCleanlooksStyle object. -*/ -QCleanlooksStyle::~QCleanlooksStyle() -{ -} - -/*! - \fn void QCleanlooksStyle::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, - bool enabled, const QString& text, QPalette::ColorRole textRole) const - - Draws the given \a text in the specified \a rectangle using the - provided \a painter and \a palette. - - Text is drawn using the painter's pen. If an explicit \a textRole - is specified, then the text is drawn using the \a palette's color - for the specified role. The \a enabled value indicates whether or - not the item is enabled; when reimplementing, this value should - influence how the item is drawn. - - The text is aligned and wrapped according to the specified \a - alignment. - - \sa Qt::Alignment -*/ -void QCleanlooksStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal, - bool enabled, const QString& text, QPalette::ColorRole textRole) const -{ - if (text.isEmpty()) - return; - - QPen savedPen = painter->pen(); - if (textRole != QPalette::NoRole) { - painter->setPen(QPen(pal.brush(textRole), savedPen.widthF())); - } - if (!enabled) { - QPen pen = painter->pen(); - painter->setPen(pen); - } - painter->drawText(rect, alignment, text); - painter->setPen(savedPen); -} - -static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50) -{ - const int maxFactor = 100; - QColor tmp = colorA; - tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor); - tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor); - tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor); - return tmp; -} - -/*! - \reimp -*/ -void QCleanlooksStyle::drawPrimitive(PrimitiveElement elem, - const QStyleOption *option, - QPainter *painter, const QWidget *widget) const -{ - Q_ASSERT(option); - QRect rect = option->rect; - int state = option->state; - QColor button = option->palette.button().color(); - QColor buttonShadow = option->palette.button().color().darker(110); - QColor buttonShadowAlpha = buttonShadow; - buttonShadowAlpha.setAlpha(128); - QColor darkOutline; - QColor dark; - darkOutline.setHsv(button.hue(), - qMin(255, (int)(button.saturation()*3.0)), - qMin(255, (int)(button.value()*0.6))); - dark.setHsv(button.hue(), - qMin(255, (int)(button.saturation()*1.9)), - qMin(255, (int)(button.value()*0.7))); - QColor tabFrameColor = mergedColors(option->palette.background().color(), - dark.lighter(135), 60); - - switch(elem) { -#ifndef QT_NO_TABBAR - case PE_FrameTabBarBase: - if (const QStyleOptionTabBarBase *tbb - = qstyleoption_cast(option)) { - painter->save(); - painter->setPen(QPen(darkOutline.lighter(110), 0)); - switch (tbb->shape) { - case QTabBar::RoundedNorth: { - QRegion region(tbb->rect); - region -= tbb->selectedTabRect; - painter->drawLine(tbb->rect.topLeft(), tbb->rect.topRight()); - painter->setClipRegion(region); - painter->setPen(option->palette.light().color()); - painter->drawLine(tbb->rect.topLeft() + QPoint(0, 1), - tbb->rect.topRight() + QPoint(0, 1)); - } - break; - case QTabBar::RoundedWest: - painter->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom()); - break; - case QTabBar::RoundedSouth: - painter->drawLine(tbb->rect.left(), tbb->rect.bottom(), - tbb->rect.right(), tbb->rect.bottom()); - break; - case QTabBar::RoundedEast: - painter->drawLine(tbb->rect.topRight(), tbb->rect.bottomRight()); - break; - case QTabBar::TriangularNorth: - case QTabBar::TriangularEast: - case QTabBar::TriangularWest: - case QTabBar::TriangularSouth: - painter->restore(); - QWindowsStyle::drawPrimitive(elem, option, painter, widget); - return; - } - painter->restore(); - } - return; -#endif // QT_NO_TABBAR - case PE_IndicatorViewItemCheck: - { - QStyleOptionButton button; - button.QStyleOption::operator=(*option); - button.state &= ~State_MouseOver; - proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget); - } - return; - case PE_IndicatorHeaderArrow: - if (const QStyleOptionHeader *header = qstyleoption_cast(option)) { - QRect r = header->rect; - QImage arrow; - if (header->sortIndicator & QStyleOptionHeader::SortUp) - arrow = QImage(qt_cleanlooks_arrow_up_xpm); - else if (header->sortIndicator & QStyleOptionHeader::SortDown) - arrow = QImage(qt_cleanlooks_arrow_down_xpm); - if (!arrow.isNull()) { - r.setSize(arrow.size()); - r.moveCenter(header->rect.center()); - arrow.setColor(1, header->palette.foreground().color().rgba()); - painter->drawImage(r, arrow); - } - } - break; - case PE_IndicatorButtonDropDown: - proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget); - break; - case PE_IndicatorToolBarSeparator: - { - QRect rect = option->rect; - const int margin = 6; - if (option->state & State_Horizontal) { - const int offset = rect.width()/2; - painter->setPen(QPen(option->palette.background().color().darker(110))); - painter->drawLine(rect.bottomLeft().x() + offset, - rect.bottomLeft().y() - margin, - rect.topLeft().x() + offset, - rect.topLeft().y() + margin); - painter->setPen(QPen(option->palette.background().color().lighter(110))); - painter->drawLine(rect.bottomLeft().x() + offset + 1, - rect.bottomLeft().y() - margin, - rect.topLeft().x() + offset + 1, - rect.topLeft().y() + margin); - } else { //Draw vertical separator - const int offset = rect.height()/2; - painter->setPen(QPen(option->palette.background().color().darker(110))); - painter->drawLine(rect.topLeft().x() + margin , - rect.topLeft().y() + offset, - rect.topRight().x() - margin, - rect.topRight().y() + offset); - painter->setPen(QPen(option->palette.background().color().lighter(110))); - painter->drawLine(rect.topLeft().x() + margin , - rect.topLeft().y() + offset + 1, - rect.topRight().x() - margin, - rect.topRight().y() + offset + 1); - } - } - break; - case PE_Frame: - painter->save(); - painter->setPen(dark.lighter(108)); - painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); - painter->restore(); - break; - case PE_FrameMenu: - painter->save(); - { - painter->setPen(QPen(darkOutline, 1)); - painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); - QColor frameLight = option->palette.background().color().lighter(160); - QColor frameShadow = option->palette.background().color().darker(110); - - //paint beveleffect - QRect frame = option->rect.adjusted(1, 1, -1, -1); - painter->setPen(frameLight); - painter->drawLine(frame.topLeft(), frame.bottomLeft()); - painter->drawLine(frame.topLeft(), frame.topRight()); - - painter->setPen(frameShadow); - painter->drawLine(frame.topRight(), frame.bottomRight()); - painter->drawLine(frame.bottomLeft(), frame.bottomRight()); - } - painter->restore(); - break; - case PE_FrameDockWidget: - - painter->save(); - { - QColor softshadow = option->palette.background().color().darker(120); - - QRect rect= option->rect; - painter->setPen(softshadow); - painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); - painter->setPen(QPen(option->palette.light(), 0)); - painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), QPoint(rect.left() + 1, rect.bottom() - 1)); - painter->setPen(QPen(option->palette.background().color().darker(120), 0)); - painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1), QPoint(rect.right() - 2, rect.bottom() - 1)); - painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1), QPoint(rect.right() - 1, rect.bottom() - 1)); - - } - painter->restore(); - break; - case PE_PanelButtonTool: - painter->save(); - if ((option->state & State_Enabled || option->state & State_On) || !(option->state & State_AutoRaise)) { - QPen oldPen = painter->pen(); - - if (widget && widget->inherits("QDockWidgetTitleButton")) { - if (option->state & State_MouseOver) - proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget); - } else { - proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget); - } - } - painter->restore(); - break; - case PE_IndicatorDockWidgetResizeHandle: - { - QStyleOption dockWidgetHandle = *option; - bool horizontal = option->state & State_Horizontal; - if (horizontal) - dockWidgetHandle.state &= ~State_Horizontal; - else - dockWidgetHandle.state |= State_Horizontal; - proxy()->drawControl(CE_Splitter, &dockWidgetHandle, painter, widget); - } - break; - case PE_FrameWindow: - painter->save(); - { - QRect rect= option->rect; - painter->setPen(QPen(dark.darker(150), 0)); - painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); - painter->setPen(QPen(option->palette.light(), 0)); - painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), - QPoint(rect.left() + 1, rect.bottom() - 1)); - painter->setPen(QPen(option->palette.background().color().darker(120), 0)); - painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1), - QPoint(rect.right() - 2, rect.bottom() - 1)); - painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1), - QPoint(rect.right() - 1, rect.bottom() - 1)); - } - painter->restore(); - break; -#ifndef QT_NO_LINEEDIT - case PE_FrameLineEdit: - // fall through -#endif // QT_NO_LINEEDIT - { - QPen oldPen = painter->pen(); - if (option->state & State_Enabled) { - painter->setPen(QPen(option->palette.background(), 0)); - painter->drawRect(rect.adjusted(0, 0, 0, 0)); - painter->drawRect(rect.adjusted(1, 1, -1, -1)); - } else { - painter->fillRect(rect, option->palette.background()); - } - QRect r = rect.adjusted(0, 1, 0, -1); - painter->setPen(buttonShadowAlpha); - painter->drawLine(QPoint(r.left() + 2, r.top() - 1), QPoint(r.right() - 2, r.top() - 1)); - const QPoint points[8] = { - QPoint(r.right() - 1, r.top()), - QPoint(r.right(), r.top() + 1), - QPoint(r.right() - 1, r.bottom()), - QPoint(r.right(), r.bottom() - 1), - QPoint(r.left() + 1, r.top() ), - QPoint(r.left(), r.top() + 1), - QPoint(r.left() + 1, r.bottom() ), - QPoint(r.left(), r.bottom() - 1) - }; - painter->drawPoints(points, 8); - painter->setPen(QPen(option->palette.background().color(), 1)); - painter->drawLine(QPoint(r.left() + 2, r.top() + 1), QPoint(r.right() - 2, r.top() + 1)); - - if (option->state & State_HasFocus) { - QColor darkoutline = option->palette.highlight().color().darker(150); - QColor innerline = mergedColors(option->palette.highlight().color(), Qt::white); - painter->setPen(QPen(innerline, 0)); - painter->drawRect(rect.adjusted(1, 2, -2, -3)); - painter->setPen(QPen(darkoutline, 0)); - } - else { - QColor highlight = Qt::white; - highlight.setAlpha(130); - painter->setPen(option->palette.base().color().darker(120)); - painter->drawLine(QPoint(r.left() + 1, r.top() + 1), - QPoint(r.right() - 1, r.top() + 1)); - painter->drawLine(QPoint(r.left() + 1, r.top() + 1), - QPoint(r.left() + 1, r.bottom() - 1)); - painter->setPen(option->palette.base().color()); - painter->drawLine(QPoint(r.right() - 1, r.top() + 1), - QPoint(r.right() - 1, r.bottom() - 1)); - painter->setPen(highlight); - painter->drawLine(QPoint(r.left() + 1, r.bottom() + 1), - QPoint(r.right() - 1, r.bottom() + 1)); - painter->drawPoint(QPoint(r.left(), r.bottom())); - painter->drawPoint(QPoint(r.right(), r.bottom() )); - painter->setPen(QPen(darkOutline.lighter(115), 1)); - } - painter->drawLine(QPoint(r.left(), r.top() + 2), QPoint(r.left(), r.bottom() - 2)); - painter->drawLine(QPoint(r.right(), r.top() + 2), QPoint(r.right(), r.bottom() - 2)); - painter->drawLine(QPoint(r.left() + 2, r.bottom()), QPoint(r.right() - 2, r.bottom())); - const QPoint points2[4] = { - QPoint(r.right() - 1, r.bottom() - 1), - QPoint(r.right() - 1, r.top() + 1), - QPoint(r.left() + 1, r.bottom() - 1), - QPoint(r.left() + 1, r.top() + 1) - }; - painter->drawPoints(points2, 4); - painter->drawLine(QPoint(r.left() + 2, r.top()), QPoint(r.right() - 2, r.top())); - painter->setPen(oldPen); - } - break; - case PE_IndicatorCheckBox: - painter->save(); - if (const QStyleOptionButton *checkbox = qstyleoption_cast(option)) { - QRect checkRect; - checkRect.setX(rect.left() ); - checkRect.setY(rect.top() ); - checkRect.setWidth(rect.width() - 1); - checkRect.setHeight(rect.height() - 1); - if (state & State_Sunken) - painter->setBrush(dark.lighter(130)); - else - painter->setBrush(option->palette.base()); - painter->setPen(QPen(dark.lighter(110), 0)); - painter->drawRect(checkRect); - if (checkbox->state & (State_On | State_Sunken | State_NoChange)) { - QImage image(qt_cleanlooks_checkbox_checked); - QColor fillColor = option->palette.text().color(); - image.setColor(1, fillColor.rgba()); - fillColor.setAlpha(100); - image.setColor(2, fillColor.rgba()); - painter->drawImage(rect, image); - if (checkbox->state & State_NoChange) { - QColor bgc = option->palette.background().color(); - bgc.setAlpha(127); - painter->fillRect(checkRect.adjusted(1, 1, -1, -1), bgc); - } - } - } - painter->restore(); - break; - case PE_IndicatorRadioButton: - painter->save(); - { - painter->setRenderHint(QPainter::SmoothPixmapTransform); - QRect checkRect = rect.adjusted(0, 0, 0, 0); - if (state & (State_On )) { - painter->drawImage(rect, QImage(qt_cleanlooks_radiobutton)); - painter->drawImage(checkRect, QImage(qt_cleanlooks_radiobutton_checked)); - } - else if (state & State_Sunken) { - painter->drawImage(rect, QImage(qt_cleanlooks_radiobutton)); - QColor bgc = buttonShadow; - painter->setRenderHint(QPainter::Antialiasing); - painter->setBrush(bgc); - painter->setPen(Qt::NoPen); - painter->drawEllipse(rect.adjusted(1, 1, -1, -1)); } - else { - painter->drawImage(rect, QImage(qt_cleanlooks_radiobutton)); - } - } - painter->restore(); - break; - case PE_IndicatorToolBarHandle: - painter->save(); - if (option->state & State_Horizontal) { - for (int i = rect.height()/5; i <= 4*(rect.height()/5) ; ++i) { - int y = rect.topLeft().y() + i + 1; - int x1 = rect.topLeft().x() + 3; - int x2 = rect.topRight().x() - 2; - - if (i % 2 == 0) - painter->setPen(QPen(option->palette.light(), 0)); - else - painter->setPen(QPen(dark.lighter(110), 0)); - painter->drawLine(x1, y, x2, y); - } - } - else { //vertical toolbar - for (int i = rect.width()/5; i <= 4*(rect.width()/5) ; ++i) { - int x = rect.topLeft().x() + i + 1; - int y1 = rect.topLeft().y() + 3; - int y2 = rect.topLeft().y() + 5; - - if (i % 2 == 0) - painter->setPen(QPen(option->palette.light(), 0)); - else - painter->setPen(QPen(dark.lighter(110), 0)); - painter->drawLine(x, y1, x, y2); - } - } - painter->restore(); - break; - case PE_FrameDefaultButton: - case PE_FrameFocusRect: - if (const QStyleOptionFocusRect *focusFrame = qstyleoption_cast(option)) { - if (!(focusFrame->state & State_KeyboardFocusChange)) - return; - QRect rect = focusFrame->rect; - painter->save(); - painter->setBackgroundMode(Qt::TransparentMode); - painter->setBrush(QBrush(dark.darker(120), Qt::Dense4Pattern)); - painter->setBrushOrigin(rect.topLeft()); - painter->setPen(Qt::NoPen); - const QRect rects[4] = { - QRect(rect.left(), rect.top(), rect.width(), 1), // Top - QRect(rect.left(), rect.bottom(), rect.width(), 1), // Bottom - QRect(rect.left(), rect.top(), 1, rect.height()), // Left - QRect(rect.right(), rect.top(), 1, rect.height()) // Right - }; - painter->drawRects(rects, 4); - painter->restore(); - } - break; - case PE_PanelButtonCommand: - { - bool isDefault = false; - bool isFlat = false; - bool isDown = (option->state & State_Sunken) || (option->state & State_On); - QPen oldPen = painter->pen(); - QBrush oldBrush = painter->brush(); - QRect r; - - if (const QStyleOptionButton *button = qstyleoption_cast(option)) { - isDefault = (button->features & QStyleOptionButton::DefaultButton) && (button->state & State_Enabled); - isFlat = (button->features & QStyleOptionButton::Flat); - } - - if (isFlat && !isDown) { - if (isDefault) { - r = option->rect.adjusted(0, 1, 0, -1); - painter->setPen(QPen(Qt::black, 0)); - const QLine lines[4] = { - QLine(QPoint(r.left() + 2, r.top()), - QPoint(r.right() - 2, r.top())), - QLine(QPoint(r.left(), r.top() + 2), - QPoint(r.left(), r.bottom() - 2)), - QLine(QPoint(r.right(), r.top() + 2), - QPoint(r.right(), r.bottom() - 2)), - QLine(QPoint(r.left() + 2, r.bottom()), - QPoint(r.right() - 2, r.bottom())) - }; - painter->drawLines(lines, 4); - const QPoint points[4] = { - QPoint(r.right() - 1, r.bottom() - 1), - QPoint(r.right() - 1, r.top() + 1), - QPoint(r.left() + 1, r.bottom() - 1), - QPoint(r.left() + 1, r.top() + 1) - }; - painter->drawPoints(points, 4); - painter->setPen(oldPen); - } - return; - } - - BEGIN_STYLE_PIXMAPCACHE(QString::fromLatin1("pushbutton-%1").arg(isDefault)) - r = rect.adjusted(0, 1, 0, -1); - - bool isEnabled = (option->state & State_Enabled); - - QColor highlightedGradientStartColor = option->palette.button().color().lighter(107); - QColor highlightedGradientMidColor = option->palette.button().color().lighter(105); - QColor highlightedGradientStopColor = buttonShadow.lighter(107); - QColor gradientStartColor = option->palette.button().color().lighter(108); - - QColor buttonColor = option->palette.button().color(); - QColor gradientMidColor = option->palette.button().color(); - QColor gradientStopColor; - gradientStopColor.setHsv(buttonColor.hue(), - qMin(255, (int)(buttonColor.saturation()*1.9)), - qMin(255, (int)(buttonColor.value()*0.96))); - - QRect gradRect = rect.adjusted(1, 2, -1, -2); - // gradient fill - QRect innerBorder = r.adjusted(1, 1, -1, 0); - - if (isDown) { - QBrush fillColor = gradientStopColor.darker(110); - if (option->palette.button().gradient()) - fillColor = option->palette.button(); - p->fillRect(gradRect, fillColor); - p->setPen(gradientStopColor.darker(125)); - p->drawLine(innerBorder.topLeft(), innerBorder.topRight()); - p->drawLine(innerBorder.topLeft(), innerBorder.bottomLeft()); - } else { - if (isEnabled && option->state & State_MouseOver ) { - qt_cleanlooks_draw_buttongradient(p, gradRect, - highlightedGradientStartColor, - highlightedGradientMidColor, - highlightedGradientStopColor, TopDown, option->palette.button()); - } else { - qt_cleanlooks_draw_buttongradient(p, gradRect, - gradientStartColor, - gradientMidColor, - gradientStopColor, TopDown, option->palette.button()); - } - } - - bool hasFocus = option->state & State_HasFocus; - - if (!isEnabled) - p->setPen(QPen(dark.lighter(115))); - else if (isDefault) - p->setPen(QPen(Qt::black, 1)); - else - p->setPen(QPen(darkOutline, 1)); - - p->drawLine(QPoint(r.left(), r.top() + 2), - QPoint(r.left(), r.bottom() - 2)); - p->drawLine(QPoint(r.right(), r.top() + 2), - QPoint(r.right(), r.bottom() - 2)); - p->drawLine(QPoint(r.left() + 2, r.bottom()), - QPoint(r.right() - 2, r.bottom())); - const QPoint points[4] = { - QPoint(r.right() - 1, r.bottom() - 1), - QPoint(r.right() - 1, r.top() + 1), - QPoint(r.left() + 1, r.bottom() - 1), - QPoint(r.left() + 1, r.top() + 1) - }; - p->drawPoints(points, 4); - - if (!isDefault && !hasFocus && isEnabled) - p->setPen(QPen(darkOutline.darker(110), 0)); - - p->drawLine(QPoint(r.left() + 2, r.top()), - QPoint(r.right() - 2, r.top())); - - QColor highlight = Qt::white; - highlight.setAlpha(110); - p->setPen(highlight); - p->drawLine(QPoint(r.left() + 1, r.top() + 2), - QPoint(r.left() + 1, r.bottom() - 2)); - p->drawLine(QPoint(r.left() + 3, r.bottom() + 1), - QPoint(r.right() - 3, r.bottom() + 1)); - - QColor topShadow = darkOutline; - topShadow.setAlpha(60); - - p->setPen(topShadow); - const QPoint points2[8] = { - QPoint(r.right(), r.top() + 1), - QPoint(r.right() - 1, r.top() ), - QPoint(r.right(), r.bottom() - 1), - QPoint(r.right() - 1, r.bottom() ), - QPoint(r.left() + 1, r.bottom()), - QPoint(r.left(), r.bottom() - 1), - QPoint(r.left() + 1, r.top()), - QPoint(r.left(), r.top() + 1) - }; - p->drawPoints(points2, 8); - - topShadow.setAlpha(30); - p->setPen(topShadow); - - p->drawLine(QPoint(r.right() - 1, r.top() + 2), - QPoint(r.right() - 1, r.bottom() - 2)); - p->drawLine(QPoint(r.left() + 2, r.top() - 1), - QPoint(r.right() - 2, r.top() - 1)); - - if (isDefault) { - r.adjust(-1, -1, 1, 1); - p->setPen(buttonShadowAlpha.darker(120)); - const QLine lines[4] = { - QLine(r.topLeft() + QPoint(3, 0), r.topRight() - QPoint(3, 0)), - QLine(r.bottomLeft() + QPoint(3, 0), r.bottomRight() - QPoint(3, 0)), - QLine(r.topLeft() + QPoint(0, 3), r.bottomLeft() - QPoint(0, 3)), - QLine(r.topRight() + QPoint(0, 3), r.bottomRight() - QPoint(0, 3)) - }; - p->drawLines(lines, 4); - const QPoint points3[8] = { - r.topRight() + QPoint(-2, 1), - r.topRight() + QPoint(-1, 2), - r.bottomRight() + QPoint(-1, -2), - r.bottomRight() + QPoint(-2, -1), - r.topLeft() + QPoint(1, 2), - r.topLeft() + QPoint(2, 1), - r.bottomLeft() + QPoint(1, -2), - r.bottomLeft() + QPoint(2, -1) - }; - p->drawPoints(points3, 8); - } - painter->setPen(oldPen); - painter->setBrush(oldBrush); - END_STYLE_PIXMAPCACHE - } - break; -#ifndef QT_NO_TABBAR - case PE_FrameTabWidget: - painter->save(); - { - painter->fillRect(option->rect, tabFrameColor); - } -#ifndef QT_NO_TABWIDGET - if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast(option)) { - QColor borderColor = darkOutline.lighter(110); - QColor alphaCornerColor = mergedColors(borderColor, option->palette.background().color()); - - int borderThickness = proxy()->pixelMetric(PM_TabBarBaseOverlap, twf, widget); - bool reverse = (twf->direction == Qt::RightToLeft); - QRect tabBarRect; - - switch (twf->shape) { - case QTabBar::RoundedNorth: - if (reverse) { - tabBarRect = QRect(twf->rect.right() - twf->leftCornerWidgetSize.width() - - twf->tabBarSize.width() + 1, - twf->rect.top(), - twf->tabBarSize.width(), borderThickness); - } else { - tabBarRect = QRect(twf->rect.left() + twf->leftCornerWidgetSize.width(), - twf->rect.top(), - twf->tabBarSize.width(), borderThickness); - } - break ; - case QTabBar::RoundedWest: - tabBarRect = QRect(twf->rect.left(), - twf->rect.top() + twf->leftCornerWidgetSize.height(), - borderThickness, - twf->tabBarSize.height()); - tabBarRect = tabBarRect; //adjust - break ; - case QTabBar::RoundedEast: - tabBarRect = QRect(twf->rect.right() - borderThickness + 1, - twf->rect.top() + twf->leftCornerWidgetSize.height(), - 0, - twf->tabBarSize.height()); - break ; - case QTabBar::RoundedSouth: - if (reverse) { - tabBarRect = QRect(twf->rect.right() - twf->leftCornerWidgetSize.width() - twf->tabBarSize.width() + 1, - twf->rect.bottom() + 1, - twf->tabBarSize.width(), - borderThickness); - } else { - tabBarRect = QRect(twf->rect.left() + twf->leftCornerWidgetSize.width(), - twf->rect.bottom() + 1, - twf->tabBarSize.width(), - borderThickness); - } - break; - default: - break; - } - - QRegion region(twf->rect); - region -= tabBarRect; - painter->setClipRegion(region); - - // Outer border - QLine leftLine = QLine(twf->rect.topLeft() + QPoint(0, 2), twf->rect.bottomLeft() - QPoint(0, 2)); - QLine rightLine = QLine(twf->rect.topRight(), twf->rect.bottomRight() - QPoint(0, 2)); - QLine bottomLine = QLine(twf->rect.bottomLeft() + QPoint(2, 0), twf->rect.bottomRight() - QPoint(2, 0)); - QLine topLine = QLine(twf->rect.topLeft(), twf->rect.topRight()); - - painter->setPen(borderColor); - painter->drawLine(topLine); - - // Inner border - QLine innerLeftLine = QLine(leftLine.p1() + QPoint(1, 0), leftLine.p2() + QPoint(1, 0)); - QLine innerRightLine = QLine(rightLine.p1() - QPoint(1, -1), rightLine.p2() - QPoint(1, 0)); - QLine innerBottomLine = QLine(bottomLine.p1() - QPoint(0, 1), bottomLine.p2() - QPoint(0, 1)); - QLine innerTopLine = QLine(topLine.p1() + QPoint(0, 1), topLine.p2() + QPoint(-1, 1)); - - // Rounded Corner - QPoint leftBottomOuterCorner = QPoint(innerLeftLine.p2() + QPoint(0, 1)); - QPoint leftBottomInnerCorner1 = QPoint(leftLine.p2() + QPoint(0, 1)); - QPoint leftBottomInnerCorner2 = QPoint(bottomLine.p1() - QPoint(1, 0)); - QPoint rightBottomOuterCorner = QPoint(innerRightLine.p2() + QPoint(0, 1)); - QPoint rightBottomInnerCorner1 = QPoint(rightLine.p2() + QPoint(0, 1)); - QPoint rightBottomInnerCorner2 = QPoint(bottomLine.p2() + QPoint(1, 0)); - QPoint leftTopOuterCorner = QPoint(innerLeftLine.p1() - QPoint(0, 1)); - QPoint leftTopInnerCorner1 = QPoint(leftLine.p1() - QPoint(0, 1)); - QPoint leftTopInnerCorner2 = QPoint(topLine.p1() - QPoint(1, 0)); - - painter->setPen(borderColor); - painter->drawLine(leftLine); - painter->drawLine(rightLine); - painter->drawLine(bottomLine); - painter->drawPoint(leftBottomOuterCorner); - painter->drawPoint(rightBottomOuterCorner); - painter->drawPoint(leftTopOuterCorner); - - painter->setPen(option->palette.light().color()); - painter->drawLine(innerLeftLine); - painter->drawLine(innerTopLine); - - painter->setPen(buttonShadowAlpha); - painter->drawLine(innerRightLine); - painter->drawLine(innerBottomLine); - - painter->setPen(alphaCornerColor); - const QPoint points[6] = { - leftBottomInnerCorner1, - leftBottomInnerCorner2, - rightBottomInnerCorner1, - rightBottomInnerCorner2, - leftTopInnerCorner1, - leftTopInnerCorner2 - }; - painter->drawPoints(points, 6); - } -#endif // QT_NO_TABWIDGET - painter->restore(); - break ; - - case PE_FrameStatusBarItem: - break; - case PE_IndicatorTabClose: - { - Q_D(const QCleanlooksStyle); - if (d->tabBarcloseButtonIcon.isNull()) - d->tabBarcloseButtonIcon = standardIcon(SP_DialogCloseButton, option, widget); - if ((option->state & State_Enabled) && (option->state & State_MouseOver)) - proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget); - QPixmap pixmap = d->tabBarcloseButtonIcon.pixmap(QSize(16, 16), QIcon::Normal, QIcon::On); - proxy()->drawItemPixmap(painter, option->rect, Qt::AlignCenter, pixmap); - } - break; - -#endif // QT_NO_TABBAR - default: - QWindowsStyle::drawPrimitive(elem, option, painter, widget); - break; - } -} - -/*! - \reimp -*/ -void QCleanlooksStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, - const QWidget *widget) const -{ - QColor button = option->palette.button().color(); - QColor dark; - dark.setHsv(button.hue(), - qMin(255, (int)(button.saturation()*1.9)), - qMin(255, (int)(button.value()*0.7))); - QColor darkOutline; - darkOutline.setHsv(button.hue(), - qMin(255, (int)(button.saturation()*2.0)), - qMin(255, (int)(button.value()*0.6))); - QRect rect = option->rect; - QColor shadow = mergedColors(option->palette.background().color().darker(120), - dark.lighter(130), 60); - QColor tabFrameColor = mergedColors(option->palette.background().color(), - dark.lighter(135), 60); - - QColor highlight = option->palette.highlight().color(); - - switch(element) { - case CE_RadioButton: //fall through - case CE_CheckBox: - if (const QStyleOptionButton *btn = qstyleoption_cast(option)) { - bool hover = (btn->state & State_MouseOver && btn->state & State_Enabled); - if (hover) - painter->fillRect(rect, btn->palette.background().color().lighter(104)); - QStyleOptionButton copy = *btn; - copy.rect.adjust(2, 0, -2, 0); - QWindowsStyle::drawControl(element, ©, painter, widget); - } - break; - case CE_Splitter: - painter->save(); - { - // hover appearance - QBrush fillColor = option->palette.background().color(); - if (option->state & State_MouseOver && option->state & State_Enabled) - fillColor = fillColor.color().lighter(106); - - painter->fillRect(option->rect, fillColor); - - QColor grooveColor = mergedColors(dark.lighter(110), option->palette.button().color(),40); - QColor gripShadow = grooveColor.darker(110); - QPalette palette = option->palette; - bool vertical = !(option->state & State_Horizontal); - QRect scrollBarSlider = option->rect; - int gripMargin = 4; - //draw grips - if (vertical) { - for( int i = -20; i< 20 ; i += 2) { - painter->setPen(QPen(gripShadow, 1)); - painter->drawLine( - QPoint(scrollBarSlider.center().x() + i , - scrollBarSlider.top() + gripMargin), - QPoint(scrollBarSlider.center().x() + i, - scrollBarSlider.bottom() - gripMargin)); - painter->setPen(QPen(palette.light(), 1)); - painter->drawLine( - QPoint(scrollBarSlider.center().x() + i + 1, - scrollBarSlider.top() + gripMargin ), - QPoint(scrollBarSlider.center().x() + i + 1, - scrollBarSlider.bottom() - gripMargin)); - } - } else { - for (int i = -20; i < 20 ; i += 2) { - painter->setPen(QPen(gripShadow, 1)); - painter->drawLine( - QPoint(scrollBarSlider.left() + gripMargin , - scrollBarSlider.center().y()+ i), - QPoint(scrollBarSlider.right() - gripMargin, - scrollBarSlider.center().y()+ i)); - painter->setPen(QPen(palette.light(), 1)); - painter->drawLine( - QPoint(scrollBarSlider.left() + gripMargin, - scrollBarSlider.center().y() + 1 + i), - QPoint(scrollBarSlider.right() - gripMargin, - scrollBarSlider.center().y() + 1 + i)); - - } - } - } - painter->restore(); - break; -#ifndef QT_NO_SIZEGRIP - case CE_SizeGrip: - painter->save(); - { - int x, y, w, h; - option->rect.getRect(&x, &y, &w, &h); - int sw = qMin(h, w); - if (h > w) - painter->translate(0, h - w); - else - painter->translate(w - h, 0); - - int sx = x; - int sy = y; - int s = 4; - if (option->direction == Qt::RightToLeft) { - sx = x + sw; - for (int i = 0; i < 4; ++i) { - painter->setPen(QPen(option->palette.light().color(), 1)); - painter->drawLine(x, sy - 1 , sx + 1, sw); - painter->setPen(QPen(dark.lighter(120), 1)); - painter->drawLine(x, sy, sx, sw); - sx -= s; - sy += s; - } - } else { - for (int i = 0; i < 4; ++i) { - painter->setPen(QPen(option->palette.light().color(), 1)); - painter->drawLine(sx - 1, sw, sw, sy - 1); - painter->setPen(QPen(dark.lighter(120), 1)); - painter->drawLine(sx, sw, sw, sy); - sx += s; - sy += s; - } - } - } - painter->restore(); - break; -#endif // QT_NO_SIZEGRIP -#ifndef QT_NO_TOOLBAR - case CE_ToolBar: - // Reserve the beveled appearance only for mainwindow toolbars - if (!(widget && qobject_cast (widget->parentWidget()))) - break; - - painter->save(); - if (const QStyleOptionToolBar *toolbar = qstyleoption_cast(option)) { - QRect rect = option->rect; - - bool paintLeftBorder = true; - bool paintRightBorder = true; - bool paintBottomBorder = true; - - switch (toolbar->toolBarArea) { - case Qt::BottomToolBarArea: - switch(toolbar->positionOfLine) { - case QStyleOptionToolBar::Beginning: - case QStyleOptionToolBar::OnlyOne: - paintBottomBorder = false; - default: - break; - } - case Qt::TopToolBarArea: - switch (toolbar->positionWithinLine) { - case QStyleOptionToolBar::Beginning: - paintLeftBorder = false; - break; - case QStyleOptionToolBar::End: - paintRightBorder = false; - break; - case QStyleOptionToolBar::OnlyOne: - paintRightBorder = false; - paintLeftBorder = false; - default: - break; - } - if (toolbar->direction == Qt::RightToLeft) { //reverse layout changes the order of Beginning/end - bool tmp = paintLeftBorder; - paintRightBorder=paintLeftBorder; - paintLeftBorder=tmp; - } - break; - case Qt::RightToolBarArea: - switch (toolbar->positionOfLine) { - case QStyleOptionToolBar::Beginning: - case QStyleOptionToolBar::OnlyOne: - paintRightBorder = false; - break; - default: - break; - } - break; - case Qt::LeftToolBarArea: - switch (toolbar->positionOfLine) { - case QStyleOptionToolBar::Beginning: - case QStyleOptionToolBar::OnlyOne: - paintLeftBorder = false; - break; - default: - break; - } - break; - default: - break; - } - - QColor light = option->palette.background().color().lighter(110); - - //draw top border - painter->setPen(QPen(light)); - painter->drawLine(rect.topLeft().x(), - rect.topLeft().y(), - rect.topRight().x(), - rect.topRight().y()); - - if (paintLeftBorder) { - painter->setPen(QPen(light)); - painter->drawLine(rect.topLeft().x(), - rect.topLeft().y(), - rect.bottomLeft().x(), - rect.bottomLeft().y()); - } - - if (paintRightBorder) { - painter->setPen(QPen(shadow)); - painter->drawLine(rect.topRight().x(), - rect.topRight().y(), - rect.bottomRight().x(), - rect.bottomRight().y()); - } - - if (paintBottomBorder) { - painter->setPen(QPen(shadow)); - painter->drawLine(rect.bottomLeft().x(), - rect.bottomLeft().y(), - rect.bottomRight().x(), - rect.bottomRight().y()); - } - } - painter->restore(); - break; -#endif // QT_NO_TOOLBAR -#ifndef QT_NO_DOCKWIDGET - case CE_DockWidgetTitle: - painter->save(); - if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast(option)) { - const QStyleOptionDockWidgetV2 *v2 - = qstyleoption_cast(dwOpt); - bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar; - - QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, option, widget); - if (verticalTitleBar) { - QRect rect = dwOpt->rect; - QRect r = rect; - QSize s = r.size(); - s.transpose(); - r.setSize(s); - titleRect = QRect(r.left() + rect.bottom() - - titleRect.bottom(), - r.top() + titleRect.left() - rect.left(), - titleRect.height(), titleRect.width()); - } - - if (!dwOpt->title.isEmpty()) { - QString titleText - = painter->fontMetrics().elidedText(dwOpt->title, - Qt::ElideRight, titleRect.width()); - proxy()->drawItemText(painter, - titleRect, - Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, dwOpt->palette, - dwOpt->state & State_Enabled, titleText, - QPalette::WindowText); - } - } - painter->restore(); - break; -#endif // QT_NO_DOCKWIDGET - case CE_HeaderSection: - painter->save(); - // Draws the header in tables. - if (const QStyleOptionHeader *header = qstyleoption_cast(option)) { - QPixmap cache; - QString pixmapName = QStyleHelper::uniqueName(QLatin1String("headersection"), option, option->rect.size()); - pixmapName += QString::number(- int(header->position)); - pixmapName += QString::number(- int(header->orientation)); - QRect r = option->rect; - QColor gradientStopColor; - QColor gradientStartColor = option->palette.button().color(); - gradientStopColor.setHsv(gradientStartColor.hue(), - qMin(255, (int)(gradientStartColor.saturation()*2)), - qMin(255, (int)(gradientStartColor.value()*0.96))); - QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); - if (option->palette.background().gradient()) { - gradient.setStops(option->palette.background().gradient()->stops()); - } else { - gradient.setColorAt(0, gradientStartColor); - gradient.setColorAt(0.8, gradientStartColor); - gradient.setColorAt(1, gradientStopColor); - } - painter->fillRect(r, gradient); - - if (!QPixmapCache::find(pixmapName, cache)) { - cache = QPixmap(r.size()); - cache.fill(Qt::transparent); - QRect pixmapRect(0, 0, r.width(), r.height()); - QPainter cachePainter(&cache); - if (header->orientation == Qt::Vertical) { - cachePainter.setPen(QPen(dark)); - cachePainter.drawLine(pixmapRect.topRight(), pixmapRect.bottomRight()); - if (header->position != QStyleOptionHeader::End) { - cachePainter.setPen(QPen(shadow)); - cachePainter.drawLine(pixmapRect.bottomLeft() + QPoint(3, -1), pixmapRect.bottomRight() + QPoint(-3, -1)); cachePainter.setPen(QPen(option->palette.light().color())); - cachePainter.drawLine(pixmapRect.bottomLeft() + QPoint(3, 0), pixmapRect.bottomRight() + QPoint(-3, 0)); } - } else { - cachePainter.setPen(QPen(dark)); - cachePainter.drawLine(pixmapRect.bottomLeft(), pixmapRect.bottomRight()); - cachePainter.setPen(QPen(shadow)); - cachePainter.drawLine(pixmapRect.topRight() + QPoint(-1, 3), pixmapRect.bottomRight() + QPoint(-1, -3)); cachePainter.setPen(QPen(option->palette.light().color())); - cachePainter.drawLine(pixmapRect.topRight() + QPoint(0, 3), pixmapRect.bottomRight() + QPoint(0, -3)); } - cachePainter.end(); - QPixmapCache::insert(pixmapName, cache); - } - painter->drawPixmap(r.topLeft(), cache); - } - painter->restore(); - break; - case CE_ProgressBarGroove: - painter->save(); - { - painter->fillRect(rect, option->palette.base()); - QColor borderColor = dark.lighter(110); - painter->setPen(QPen(borderColor, 0)); - const QLine lines[4] = { - QLine(QPoint(rect.left() + 1, rect.top()), QPoint(rect.right() - 1, rect.top())), - QLine(QPoint(rect.left() + 1, rect.bottom()), QPoint(rect.right() - 1, rect.bottom())), - QLine(QPoint(rect.left(), rect.top() + 1), QPoint(rect.left(), rect.bottom() - 1)), - QLine(QPoint(rect.right(), rect.top() + 1), QPoint(rect.right(), rect.bottom() - 1)) - }; - painter->drawLines(lines, 4); - QColor alphaCorner = mergedColors(borderColor, option->palette.background().color()); - QColor innerShadow = mergedColors(borderColor, option->palette.base().color()); - - //corner smoothing - painter->setPen(alphaCorner); - const QPoint points[4] = { - rect.topRight(), - rect.topLeft(), - rect.bottomRight(), - rect.bottomLeft() - }; - painter->drawPoints(points, 4); - - //inner shadow - painter->setPen(innerShadow); - painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), - QPoint(rect.right() - 1, rect.top() + 1)); - painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), - QPoint(rect.left() + 1, rect.bottom() + 1)); - - } - painter->restore(); - break; - case CE_ProgressBarContents: - painter->save(); - if (const QStyleOptionProgressBar *bar = qstyleoption_cast(option)) { - QRect rect = bar->rect; - bool vertical = false; - bool inverted = false; - bool indeterminate = (bar->minimum == 0 && bar->maximum == 0); - - // Get extra style options if version 2 - if (const QStyleOptionProgressBarV2 *bar2 = qstyleoption_cast(option)) { - vertical = (bar2->orientation == Qt::Vertical); - inverted = bar2->invertedAppearance; - } - - // If the orientation is vertical, we use a transform to rotate - // the progress bar 90 degrees clockwise. This way we can use the - // same rendering code for both orientations. - if (vertical) { - rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height - QTransform m = QTransform::fromTranslate(rect.height()-1, -1.0); - m.rotate(90.0); - painter->setTransform(m, true); - } - - int maxWidth = rect.width() - 4; - int minWidth = 4; - qreal progress = qMax(bar->progress, bar->minimum); // workaround for bug in QProgressBar - int progressBarWidth = (progress - bar->minimum) * qreal(maxWidth) / qMax(qreal(1.0), qreal(bar->maximum) - bar->minimum); - int width = indeterminate ? maxWidth : qMax(minWidth, progressBarWidth); - - bool reverse = (!vertical && (bar->direction == Qt::RightToLeft)) || vertical; - if (inverted) - reverse = !reverse; - - QRect progressBar; - Q_D(const QCleanlooksStyle); - if (!indeterminate) { - if (!reverse) { - progressBar.setRect(rect.left() + 1, rect.top() + 1, width + 1, rect.height() - 3); - } else { - progressBar.setRect(rect.right() - 1 - width, rect.top() + 1, width + 1, rect.height() - 3); - } - d->stopAnimation(option->styleObject); - } else { - int slideWidth = ((rect.width() - 4) * 2) / 3; - int step = 0; - if (QProgressStyleAnimation *animation = qobject_cast(d->animation(option->styleObject))) - step = animation->progressStep(slideWidth); - else - d->startAnimation(new QProgressStyleAnimation(d->animationFps, option->styleObject)); - progressBar.setRect(rect.left() + 1 + step, rect.top() + 1, - slideWidth / 2, rect.height() - 3); - } - QColor highlight = option->palette.color(QPalette::Normal, QPalette::Highlight); - painter->setPen(QPen(highlight.darker(140), 0)); - - QColor highlightedGradientStartColor = highlight.lighter(100); - QColor highlightedGradientStopColor = highlight.lighter(130); - - QLinearGradient gradient(rect.topLeft(), QPoint(rect.bottomLeft().x(), - rect.bottomLeft().y()*2)); - - gradient.setColorAt(0, highlightedGradientStartColor); - gradient.setColorAt(1, highlightedGradientStopColor); - - painter->setBrush(gradient); - painter->drawRect(progressBar); - - painter->setPen(QPen(highlight.lighter(120), 0)); - painter->drawLine(QPoint(progressBar.left() + 1, progressBar.top() + 1), - QPoint(progressBar.right(), progressBar.top() + 1)); - painter->drawLine(QPoint(progressBar.left() + 1, progressBar.top() + 1), - QPoint(progressBar.left() + 1, progressBar.bottom() - 1)); - - painter->setPen(QPen(highlightedGradientStartColor, 7.0));//QPen(option->palette.highlight(), 3)); - - painter->save(); - painter->setClipRect(progressBar.adjusted(2, 2, -1, -1)); - for (int x = progressBar.left() - 32; x < rect.right() ; x+=18) { - painter->drawLine(x, progressBar.bottom() + 1, x + 23, progressBar.top() - 2); - } - painter->restore(); - - } - painter->restore(); - break; - case CE_MenuBarItem: - painter->save(); - if (const QStyleOptionMenuItem *mbi = qstyleoption_cast(option)) - { - QStyleOptionMenuItem item = *mbi; - item.rect = mbi->rect.adjusted(0, 3, 0, -1); - QColor highlightOutline = highlight.darker(125); - QLinearGradient gradient(rect.topLeft(), QPoint(rect.bottomLeft().x(), rect.bottomLeft().y()*2)); - - if (option->palette.button().gradient()) { - gradient.setStops(option->palette.button().gradient()->stops()); - } else { - gradient.setColorAt(0, option->palette.button().color()); - gradient.setColorAt(1, option->palette.button().color().darker(110)); - } - painter->fillRect(rect, gradient); - - QCommonStyle::drawControl(element, &item, painter, widget); - - bool act = mbi->state & State_Selected && mbi->state & State_Sunken; - bool dis = !(mbi->state & State_Enabled); - - QRect r = option->rect; - if (act) { - qt_cleanlooks_draw_gradient(painter, r.adjusted(1, 1, -1, -1), - highlight, - highlightOutline, TopDown, - option->palette.highlight()); - - painter->setPen(QPen(highlightOutline, 0)); - const QLine lines[4] = { - QLine(QPoint(r.left(), r.top() + 1), QPoint(r.left(), r.bottom())), - QLine(QPoint(r.right(), r.top() + 1), QPoint(r.right(), r.bottom())), - QLine(QPoint(r.left() + 1, r.bottom()), QPoint(r.right() - 1, r.bottom())), - QLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top())) - }; - painter->drawLines(lines, 4); - - //draw text - QPalette::ColorRole textRole = dis ? QPalette::Text : QPalette::HighlightedText; - uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; - if (!styleHint(SH_UnderlineShortcut, mbi, widget)) - alignment |= Qt::TextHideMnemonic; - proxy()->drawItemText(painter, item.rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole); - } - - } - painter->restore(); - break; - case CE_MenuItem: - painter->save(); - // Draws one item in a popup menu. - if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(option)) { - QColor highlightOutline = highlight.darker(125); - QColor menuBackground = option->palette.background().color().lighter(104); - QColor borderColor = option->palette.background().color().darker(160); - QColor alphaCornerColor; - - if (widget) { - // ### backgroundrole/foregroundrole should be part of the style option - alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), borderColor); - } else { - alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); - } - if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { - painter->fillRect(menuItem->rect, menuBackground); - int w = 0; - if (!menuItem->text.isEmpty()) { - painter->setFont(menuItem->font); - proxy()->drawItemText(painter, menuItem->rect.adjusted(5, 0, -5, 0), Qt::AlignLeft | Qt::AlignVCenter, - menuItem->palette, menuItem->state & State_Enabled, menuItem->text, - QPalette::Text); - w = menuItem->fontMetrics.width(menuItem->text) + 5; - } - painter->setPen(shadow.lighter(106)); - bool reverse = menuItem->direction == Qt::RightToLeft; - painter->drawLine(menuItem->rect.left() + 5 + (reverse ? 0 : w), menuItem->rect.center().y(), - menuItem->rect.right() - 5 - (reverse ? w : 0), menuItem->rect.center().y()); - painter->restore(); - break; - } - bool selected = menuItem->state & State_Selected && menuItem->state & State_Enabled; - if (selected) { - QRect r = option->rect.adjusted(1, 0, -2, -1); - qt_cleanlooks_draw_gradient(painter, r, highlight, - highlightOutline, TopDown, - highlight); - r = r.adjusted(-1, 0, 1, 0); - painter->setPen(QPen(highlightOutline, 0)); - const QLine lines[4] = { - QLine(QPoint(r.left(), r.top() + 1), QPoint(r.left(), r.bottom() - 1)), - QLine(QPoint(r.right(), r.top() + 1), QPoint(r.right(), r.bottom() - 1)), - QLine(QPoint(r.left() + 1, r.bottom()), QPoint(r.right() - 1, r.bottom())), - QLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top())) - }; - painter->drawLines(lines, 4); - } else { - painter->fillRect(option->rect, menuBackground); - } - - bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable; - bool checked = menuItem->checked; - bool sunken = menuItem->state & State_Sunken; - bool enabled = menuItem->state & State_Enabled; - - bool ignoreCheckMark = false; - int checkcol = qMax(menuItem->maxIconWidth, 20); - -#ifndef QT_NO_COMBOBOX - if (qobject_cast(widget)) - ignoreCheckMark = true; //ignore the checkmarks provided by the QComboMenuDelegate -#endif - - if (!ignoreCheckMark) { - // Check - QRect checkRect(option->rect.left() + 7, option->rect.center().y() - 6, 13, 13); - checkRect = visualRect(menuItem->direction, menuItem->rect, checkRect); - if (checkable) { - if (menuItem->checkType & QStyleOptionMenuItem::Exclusive) { - // Radio button - if (checked || sunken) { - painter->setRenderHint(QPainter::Antialiasing); - painter->setPen(Qt::NoPen); - - QPalette::ColorRole textRole = !enabled ? QPalette::Text: - selected ? QPalette::HighlightedText : QPalette::ButtonText; - painter->setBrush(option->palette.brush( option->palette.currentColorGroup(), textRole)); - painter->drawEllipse(checkRect.adjusted(4, 4, -4, -4)); - } - } else { - // Check box - if (menuItem->icon.isNull()) { - if (checked || sunken) { - QImage image(qt_cleanlooks_menuitem_checkbox_checked); - if (enabled && (menuItem->state & State_Selected)) { - image.setColor(1, 0x55ffffff); - image.setColor(2, 0xAAffffff); - image.setColor(3, 0xBBffffff); - image.setColor(4, 0xFFffffff); - image.setColor(5, 0x33ffffff); - } else { - image.setColor(1, 0x55000000); - image.setColor(2, 0xAA000000); - image.setColor(3, 0xBB000000); - image.setColor(4, 0xFF000000); - image.setColor(5, 0x33000000); - } - painter->drawImage(QPoint(checkRect.center().x() - image.width() / 2, - checkRect.center().y() - image.height() / 2), image); - } - } - } - } - } else { //ignore checkmark - if (menuItem->icon.isNull()) - checkcol = 0; - else - checkcol = menuItem->maxIconWidth; - } - - // Text and icon, ripped from windows style - bool dis = !(menuItem->state & State_Enabled); - bool act = menuItem->state & State_Selected; - const QStyleOption *opt = option; - const QStyleOptionMenuItem *menuitem = menuItem; - - QPainter *p = painter; - QRect vCheckRect = visualRect(opt->direction, menuitem->rect, - QRect(menuitem->rect.x(), menuitem->rect.y(), - checkcol, menuitem->rect.height())); - if (!menuItem->icon.isNull()) { - QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; - if (act && !dis) - mode = QIcon::Active; - QPixmap pixmap; - - int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize, option, widget); - QSize iconSize(smallIconSize, smallIconSize); -#ifndef QT_NO_COMBOBOX - if (const QComboBox *combo = qobject_cast(widget)) - iconSize = combo->iconSize(); -#endif // QT_NO_COMBOBOX - if (checked) - pixmap = menuItem->icon.pixmap(iconSize, mode, QIcon::On); - else - pixmap = menuItem->icon.pixmap(iconSize, mode); - - int pixw = pixmap.width(); - int pixh = pixmap.height(); - - QRect pmr(0, 0, pixw, pixh); - pmr.moveCenter(vCheckRect.center()); - painter->setPen(menuItem->palette.text().color()); - if (checkable && checked) { - QStyleOption opt = *option; - if (act) { - QColor activeColor = mergedColors(option->palette.background().color(), - option->palette.highlight().color()); - opt.palette.setBrush(QPalette::Button, activeColor); - } - opt.state |= State_Sunken; - opt.rect = vCheckRect; - proxy()->drawPrimitive(PE_PanelButtonCommand, &opt, painter, widget); - } - painter->drawPixmap(pmr.topLeft(), pixmap); - } - if (selected) { - painter->setPen(menuItem->palette.highlightedText().color()); - } else { - painter->setPen(menuItem->palette.text().color()); - } - int x, y, w, h; - menuitem->rect.getRect(&x, &y, &w, &h); - int tab = menuitem->tabWidth; - QColor discol; - if (dis) { - discol = menuitem->palette.text().color(); - p->setPen(discol); - } - int xm = windowsItemFrame + checkcol + windowsItemHMargin; - int xpos = menuitem->rect.x() + xm; - - QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin); - QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect); - QString s = menuitem->text; - if (!s.isEmpty()) { // draw text - p->save(); - int t = s.indexOf(QLatin1Char('\t')); - int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; - if (!styleHint(SH_UnderlineShortcut, menuitem, widget)) - text_flags |= Qt::TextHideMnemonic; - text_flags |= Qt::AlignLeft; - if (t >= 0) { - QRect vShortcutRect = visualRect(opt->direction, menuitem->rect, - QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom()))); - if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) { - p->setPen(menuitem->palette.light().color()); - p->drawText(vShortcutRect.adjusted(1, 1, 1, 1), text_flags, s.mid(t + 1)); - p->setPen(discol); - } - p->drawText(vShortcutRect, text_flags, s.mid(t + 1)); - s = s.left(t); - } - QFont font = menuitem->font; - // font may not have any "hard" flags set. We override - // the point size so that when it is resolved against the device, this font will win. - // This is mainly to handle cases where someone sets the font on the window - // and then the combo inherits it and passes it onward. At that point the resolve mask - // is very, very weak. This makes it stonger. - font.setPointSizeF(QFontInfo(menuItem->font).pointSizeF()); - - if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem) - font.setBold(true); - - p->setFont(font); - if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) { - p->setPen(menuitem->palette.light().color()); - p->drawText(vTextRect.adjusted(1, 1, 1, 1), text_flags, s.left(t)); - p->setPen(discol); - } - p->drawText(vTextRect, text_flags, s.left(t)); - p->restore(); - } - - // Arrow - if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow - int dim = (menuItem->rect.height() - 4) / 2; - PrimitiveElement arrow; - arrow = QApplication::isRightToLeft() ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight; - int xpos = menuItem->rect.left() + menuItem->rect.width() - 3 - dim; - QRect vSubMenuRect = visualRect(option->direction, menuItem->rect, - QRect(xpos, menuItem->rect.top() + menuItem->rect.height() / 2 - dim / 2, dim, dim)); - QStyleOptionMenuItem newMI = *menuItem; - newMI.rect = vSubMenuRect; - newMI.state = !enabled ? State_None : State_Enabled; - if (selected) - newMI.palette.setColor(QPalette::ButtonText, - newMI.palette.highlightedText().color()); - proxy()->drawPrimitive(arrow, &newMI, painter, widget); - } - } - painter->restore(); - break; - case CE_MenuHMargin: - case CE_MenuVMargin: - break; - case CE_MenuEmptyArea: - break; - case CE_PushButtonLabel: - if (const QStyleOptionButton *button = qstyleoption_cast(option)) { - QRect ir = button->rect; - uint tf = Qt::AlignVCenter; - if (styleHint(SH_UnderlineShortcut, button, widget)) - tf |= Qt::TextShowMnemonic; - else - tf |= Qt::TextHideMnemonic; - - if (!button->icon.isNull()) { - //Center both icon and text - QPoint point; - - QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal - : QIcon::Disabled; - if (mode == QIcon::Normal && button->state & State_HasFocus) - mode = QIcon::Active; - QIcon::State state = QIcon::Off; - if (button->state & State_On) - state = QIcon::On; - - QPixmap pixmap = button->icon.pixmap(button->iconSize, mode, state); - int w = pixmap.width(); - int h = pixmap.height(); - - if (!button->text.isEmpty()) - w += button->fontMetrics.boundingRect(option->rect, tf, button->text).width() + 2; - - point = QPoint(ir.x() + ir.width() / 2 - w / 2, - ir.y() + ir.height() / 2 - h / 2); - - if (button->direction == Qt::RightToLeft) - point.rx() += pixmap.width(); - - painter->drawPixmap(visualPos(button->direction, button->rect, point), pixmap); - - if (button->direction == Qt::RightToLeft) - ir.translate(-point.x() - 2, 0); - else - ir.translate(point.x() + pixmap.width(), 0); - - // left-align text if there is - if (!button->text.isEmpty()) - tf |= Qt::AlignLeft; - - } else { - tf |= Qt::AlignHCenter; - } - - if (button->features & QStyleOptionButton::HasMenu) - ir = ir.adjusted(0, 0, -proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget), 0); - proxy()->drawItemText(painter, ir, tf, button->palette, (button->state & State_Enabled), - button->text, QPalette::ButtonText); - } - break; - case CE_MenuBarEmptyArea: - painter->save(); - { - QColor shadow = mergedColors(option->palette.background().color().darker(120), - dark.lighter(140), 60); - - QLinearGradient gradient(rect.topLeft(), QPoint(rect.bottomLeft().x(), rect.bottomLeft().y()*2)); - gradient.setColorAt(0, option->palette.button().color()); - gradient.setColorAt(1, option->palette.button().color().darker(110)); - painter->fillRect(rect, gradient); - -#ifndef QT_NO_MAINWINDOW - if (widget && qobject_cast(widget->parentWidget())) { - QPen oldPen = painter->pen(); - painter->setPen(QPen(shadow)); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - } -#endif // QT_NO_MAINWINDOW - } - painter->restore(); - break; -#ifndef QT_NO_TABBAR - case CE_TabBarTabShape: - painter->save(); - if (const QStyleOptionTab *tab = qstyleoption_cast(option)) { - - bool rtlHorTabs = (tab->direction == Qt::RightToLeft - && (tab->shape == QTabBar::RoundedNorth - || tab->shape == QTabBar::RoundedSouth)); - bool selected = tab->state & State_Selected; - bool lastTab = ((!rtlHorTabs && tab->position == QStyleOptionTab::End) - || (rtlHorTabs - && tab->position == QStyleOptionTab::Beginning)); - bool onlyTab = tab->position == QStyleOptionTab::OnlyOneTab; - bool leftCornerWidget = (tab->cornerWidgets & QStyleOptionTab::LeftCornerWidget); - - bool atBeginning = ((tab->position == (tab->direction == Qt::LeftToRight ? - QStyleOptionTab::Beginning : QStyleOptionTab::End)) || onlyTab); - - bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab; - bool previousSelected = - ((!rtlHorTabs - && tab->selectedPosition == QStyleOptionTab::PreviousIsSelected) - || (rtlHorTabs - && tab->selectedPosition == QStyleOptionTab::NextIsSelected)); - bool nextSelected = - ((!rtlHorTabs - && tab->selectedPosition == QStyleOptionTab::NextIsSelected) - || (rtlHorTabs - && tab->selectedPosition - == QStyleOptionTab::PreviousIsSelected)); - int tabBarAlignment = proxy()->styleHint(SH_TabBar_Alignment, tab, widget); - bool leftAligned = (!rtlHorTabs && tabBarAlignment == Qt::AlignLeft) - || (rtlHorTabs - && tabBarAlignment == Qt::AlignRight); - - bool rightAligned = (!rtlHorTabs && tabBarAlignment == Qt::AlignRight) - || (rtlHorTabs - && tabBarAlignment == Qt::AlignLeft); - - QColor light = tab->palette.light().color(); - - QColor background = tab->palette.background().color(); - int borderThinkness = proxy()->pixelMetric(PM_TabBarBaseOverlap, tab, widget); - if (selected) - borderThinkness /= 2; - QRect r2(option->rect); - int x1 = r2.left(); - int x2 = r2.right(); - int y1 = r2.top(); - int y2 = r2.bottom(); - - QTransform rotMatrix; - bool flip = false; - painter->setPen(shadow); - QColor activeHighlight = option->palette.color(QPalette::Normal, QPalette::Highlight); - switch (tab->shape) { - case QTabBar::RoundedNorth: - break; - case QTabBar::RoundedSouth: - rotMatrix.rotate(180); - rotMatrix.translate(0, -rect.height() + 1); - rotMatrix.scale(-1, 1); - painter->setTransform(rotMatrix, true); - break; - case QTabBar::RoundedWest: - rotMatrix.rotate(180 + 90); - rotMatrix.scale(-1, 1); - flip = true; - painter->setTransform(rotMatrix, true); - break; - case QTabBar::RoundedEast: - rotMatrix.rotate(90); - rotMatrix.translate(0, - rect.width() + 1); - flip = true; - painter->setTransform(rotMatrix, true); - break; - default: - painter->restore(); - QWindowsStyle::drawControl(element, tab, painter, widget); - return; - } - - if (flip) { - QRect tmp = rect; - rect = QRect(tmp.y(), tmp.x(), tmp.height(), tmp.width()); - int temp = x1; - x1 = y1; - y1 = temp; - temp = x2; - x2 = y2; - y2 = temp; - } - - QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); - if (option->palette.button().gradient()) { - if (selected) - gradient.setStops(option->palette.background().gradient()->stops()); - else - gradient.setStops(option->palette.background().gradient()->stops()); - } - else if (selected) { - gradient.setColorAt(0, option->palette.background().color().lighter(104)); - gradient.setColorAt(1, tabFrameColor); - painter->fillRect(rect.adjusted(0, 2, 0, -1), gradient); - } else { - y1 += 2; - gradient.setColorAt(0, option->palette.background().color()); - gradient.setColorAt(1, dark.lighter(120)); - painter->fillRect(rect.adjusted(0, 2, 0, -2), gradient); - } - - // Delete border - if (selected) { - painter->setPen(QPen(activeHighlight, 0)); - painter->drawLine(x1 + 1, y1 + 1, x2 - 1, y1 + 1); - painter->drawLine(x1 , y1 + 2, x2 , y1 + 2); - } else { - painter->setPen(dark); - painter->drawLine(x1, y2 - 1, x2 + 2, y2 - 1 ); - if (tab->shape == QTabBar::RoundedNorth || tab->shape == QTabBar::RoundedWest) { - painter->setPen(light); - painter->drawLine(x1, y2 , x2, y2 ); - } - } - // Left - if (atBeginning || selected ) { - painter->setPen(light); - painter->drawLine(x1 + 1, y1 + 2 + 1, x1 + 1, y2 - ((onlyOne || atBeginning) && selected && leftAligned ? 0 : borderThinkness) - (atBeginning && leftCornerWidget ? 1 : 0)); - painter->drawPoint(x1 + 1, y1 + 1); - painter->setPen(dark); - painter->drawLine(x1, y1 + 2, x1, y2 - ((onlyOne || atBeginning) && leftAligned ? 0 : borderThinkness) - (atBeginning && leftCornerWidget ? 1 : 0)); - } - // Top - { - int beg = x1 + (previousSelected ? 0 : 2); - int end = x2 - (nextSelected ? 0 : 2); - painter->setPen(light); - - if (!selected)painter->drawLine(beg - 2, y1 + 1, end, y1 + 1); - - if (selected) - painter->setPen(QPen(activeHighlight.darker(150), 0)); - else - painter->setPen(darkOutline); - painter->drawLine(beg, y1 , end, y1); - - if (atBeginning|| selected) { - painter->drawPoint(beg - 1, y1 + 1); - } else if (!atBeginning) { - painter->drawPoint(beg - 1, y1); - painter->drawPoint(beg - 2, y1); - if (!lastTab) { - painter->setPen(dark.lighter(130)); - painter->drawPoint(end + 1, y1); - painter->drawPoint(end + 2 , y1); - painter->drawPoint(end + 2, y1 + 1); - } - } - } - // Right - if (lastTab || selected || onlyOne || !nextSelected) { - painter->setPen(darkOutline); - painter->drawLine(x2, y1 + 2, x2, y2 - ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness)); - if (selected) - painter->setPen(QPen(activeHighlight.darker(150), 0)); - else - painter->setPen(darkOutline); - painter->drawPoint(x2 - 1, y1 + 1); - - if (selected) { - painter->setPen(background.darker(110)); - painter->drawLine(x2 - 1, y1 + 3, x2 - 1, y2 - ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness)); - } - } - } - painter->restore(); - break; - -#endif // QT_NO_TABBAR - default: - QWindowsStyle::drawControl(element,option,painter,widget); - break; - } -} - -/*! - \reimp -*/ -QPalette QCleanlooksStyle::standardPalette () const -{ - QPalette palette = QWindowsStyle::standardPalette(); - palette.setBrush(QPalette::Active, QPalette::Highlight, QColor(98, 140, 178)); - palette.setBrush(QPalette::Inactive, QPalette::Highlight, QColor(145, 141, 126)); - palette.setBrush(QPalette::Disabled, QPalette::Highlight, QColor(145, 141, 126)); - - QColor backGround(239, 235, 231); - - QColor light = backGround.lighter(150); - QColor base = Qt::white; - QColor dark = QColor(170, 156, 143).darker(110); - dark = backGround.darker(150); - QColor darkDisabled = QColor(209, 200, 191).darker(110); - - //### Find the correct disabled text color - palette.setBrush(QPalette::Disabled, QPalette::Text, QColor(190, 190, 190)); - - palette.setBrush(QPalette::Window, backGround); - palette.setBrush(QPalette::Mid, backGround.darker(130)); - palette.setBrush(QPalette::Light, light); - - palette.setBrush(QPalette::Active, QPalette::Base, base); - palette.setBrush(QPalette::Inactive, QPalette::Base, base); - palette.setBrush(QPalette::Disabled, QPalette::Base, backGround); - - palette.setBrush(QPalette::Midlight, palette.mid().color().lighter(110)); - - palette.setBrush(QPalette::All, QPalette::Dark, dark); - palette.setBrush(QPalette::Disabled, QPalette::Dark, darkDisabled); - - QColor button = backGround; - - palette.setBrush(QPalette::Button, button); - - QColor shadow = dark.darker(135); - palette.setBrush(QPalette::Shadow, shadow); - palette.setBrush(QPalette::Disabled, QPalette::Shadow, shadow.lighter(150)); - palette.setBrush(QPalette::HighlightedText, QColor(QRgb(0xffffffff))); - return palette; -} - -/*! - \reimp -*/ -void QCleanlooksStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, - QPainter *painter, const QWidget *widget) const -{ - QColor button = option->palette.button().color(); - QColor dark; - QColor grooveColor; - QColor darkOutline; - dark.setHsv(button.hue(), - qMin(255, (int)(button.saturation()*1.9)), - qMin(255, (int)(button.value()*0.7))); - grooveColor.setHsv(button.hue(), - qMin(255, (int)(button.saturation()*2.6)), - qMin(255, (int)(button.value()*0.9))); - darkOutline.setHsv(button.hue(), - qMin(255, (int)(button.saturation()*3.0)), - qMin(255, (int)(button.value()*0.6))); - - QColor alphaCornerColor; - if (widget) { - // ### backgroundrole/foregroundrole should be part of the style option - alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), darkOutline); - } else { - alphaCornerColor = mergedColors(option->palette.background().color(), darkOutline); - } - QColor gripShadow = grooveColor.darker(110); - QColor buttonShadow = option->palette.button().color().darker(110); - - QColor gradientStartColor = option->palette.button().color().lighter(108); - QColor gradientStopColor = mergedColors(option->palette.button().color().darker(108), dark.lighter(150), 70); - - QPalette palette = option->palette; - - switch (control) { -#ifndef QT_NO_SPINBOX - case CC_SpinBox: - if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast(option)) { - QPixmap cache; - QString pixmapName = QStyleHelper::uniqueName(QLatin1String("spinbox"), spinBox, spinBox->rect.size()); - if (!QPixmapCache::find(pixmapName, cache)) { - cache = QPixmap(spinBox->rect.size()); - cache.fill(Qt::transparent); - QRect pixmapRect(0, 0, spinBox->rect.width(), spinBox->rect.height()); - QPainter cachePainter(&cache); - - bool isEnabled = (spinBox->state & State_Enabled); - //bool focus = isEnabled && (spinBox->state & State_HasFocus); - bool hover = isEnabled && (spinBox->state & State_MouseOver); - bool sunken = (spinBox->state & State_Sunken); - bool upIsActive = (spinBox->activeSubControls == SC_SpinBoxUp); - bool downIsActive = (spinBox->activeSubControls == SC_SpinBoxDown); - - QRect rect = pixmapRect; - QStyleOptionSpinBox spinBoxCopy = *spinBox; - spinBoxCopy.rect = pixmapRect; - QRect upRect = proxy()->subControlRect(CC_SpinBox, &spinBoxCopy, SC_SpinBoxUp, widget); - QRect downRect = proxy()->subControlRect(CC_SpinBox, &spinBoxCopy, SC_SpinBoxDown, widget); - - int fw = spinBoxCopy.frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, &spinBoxCopy, widget) : 0; - cachePainter.fillRect(rect.adjusted(1, qMax(fw - 1, 0), -1, -fw), - option->palette.base()); - - QRect r = rect.adjusted(0, 1, 0, -1); - if (spinBox->frame) { - - QColor topShadow = darkOutline; - topShadow.setAlpha(60); - cachePainter.setPen(topShadow); - - // antialias corners - const QPoint points[8] = { - QPoint(r.right(), r.top() + 1), - QPoint(r.right() - 1, r.top() ), - QPoint(r.right(), r.bottom() - 1), - QPoint(r.right() - 1, r.bottom() ), - QPoint(r.left() + 1, r.bottom()), - QPoint(r.left(), r.bottom() - 1), - QPoint(r.left() + 1, r.top()), - QPoint(r.left(), r.top() + 1) - }; - cachePainter.drawPoints(points, 8); - - // draw frame - topShadow.setAlpha(30); - cachePainter.setPen(topShadow); - cachePainter.drawLine(QPoint(r.left() + 2, r.top() - 1), QPoint(r.right() - 2, r.top() - 1)); - - cachePainter.setPen(QPen(option->palette.background().color(), 1)); - cachePainter.drawLine(QPoint(r.left() + 2, r.top() + 1), QPoint(r.right() - 2, r.top() + 1)); - QColor highlight = Qt::white; - highlight.setAlpha(130); - cachePainter.setPen(option->palette.base().color().darker(120)); - cachePainter.drawLine(QPoint(r.left() + 1, r.top() + 1), - QPoint(r.right() - 1, r.top() + 1)); - cachePainter.drawLine(QPoint(r.left() + 1, r.top() + 1), - QPoint(r.left() + 1, r.bottom() - 1)); - cachePainter.setPen(option->palette.base().color()); - cachePainter.drawLine(QPoint(r.right() - 1, r.top() + 1), - QPoint(r.right() - 1, r.bottom() - 1)); - cachePainter.drawLine(QPoint(r.left() + 1, r.bottom() - 1), - QPoint(r.right() - 1, r.bottom() - 1)); - cachePainter.setPen(highlight); - cachePainter.drawLine(QPoint(r.left() + 3, r.bottom() + 1), - QPoint(r.right() - 3, r.bottom() + 1)); - - cachePainter.setPen(QPen(darkOutline, 1)); - - // top and bottom lines - const QLine lines[4] = { - QLine(QPoint(r.left() + 2, r.bottom()), QPoint(r.right()- 2, r.bottom())), - QLine(QPoint(r.left() + 2, r.top()), QPoint(r.right() - 2, r.top())), - QLine(QPoint(r.right(), r.top() + 2), QPoint(r.right(), r.bottom() - 2)), - QLine(QPoint(r.left(), r.top() + 2), QPoint(r.left(), r.bottom() - 2)) - }; - cachePainter.drawLines(lines, 4); - } - - // gradients - qt_cleanlooks_draw_gradient(&cachePainter, upRect, - gradientStartColor.darker(106), - gradientStopColor, TopDown, option->palette.button()); - qt_cleanlooks_draw_gradient(&cachePainter, downRect.adjusted(0, 0, 0, 1), - gradientStartColor.darker(106), - gradientStopColor, TopDown, option->palette.button()); - if (isEnabled) { - if(upIsActive) { - if (sunken) { - cachePainter.fillRect(upRect.adjusted(1, 0, 0, 0), gradientStopColor.darker(110)); - } else if (hover) { - qt_cleanlooks_draw_gradient(&cachePainter, upRect.adjusted(1, 0, 0, 0), - gradientStartColor.lighter(110), - gradientStopColor.lighter(110), TopDown, option->palette.button()); - } - } - if(downIsActive) { - if (sunken) { - cachePainter.fillRect(downRect.adjusted(1, 0, 0, 1), gradientStopColor.darker(110)); - - } else if (hover) { - qt_cleanlooks_draw_gradient(&cachePainter, downRect.adjusted(1, 0, 0, 1), - gradientStartColor.lighter(110), - gradientStopColor.lighter(110), TopDown, option->palette.button()); - } - } - } - - if (spinBox->frame) { - // rounded corners - const QPoint points[4] = { - QPoint(r.left() + 1, r.bottom() - 1), - QPoint(r.left() + 1, r.top() + 1), - QPoint(r.right() - 1, r.bottom() - 1), - QPoint(r.right() - 1, r.top() + 1) - }; - cachePainter.drawPoints(points, 4); - - if (option->state & State_HasFocus) { - QColor darkoutline = option->palette.highlight().color().darker(150); - QColor innerline = mergedColors(option->palette.highlight().color(), Qt::white); - cachePainter.setPen(QPen(innerline, 0)); - if (spinBox->direction == Qt::LeftToRight) { - cachePainter.drawRect(rect.adjusted(1, 2, -3 -downRect.width(), -3)); - cachePainter.setPen(QPen(darkoutline, 0)); - const QLine lines[4] = { - QLine(QPoint(r.left() + 2, r.bottom()), QPoint(r.right()- downRect.width() - 1, r.bottom())), - QLine(QPoint(r.left() + 2, r.top()), QPoint(r.right() - downRect.width() - 1, r.top())), - QLine(QPoint(r.right() - downRect.width() - 1, r.top() + 1), QPoint(r.right()- downRect.width() - 1, r.bottom() - 1)), - QLine(QPoint(r.left(), r.top() + 2), QPoint(r.left(), r.bottom() - 2)) - }; - cachePainter.drawLines(lines, 4); - cachePainter.drawPoint(QPoint(r.left() + 1, r.bottom() - 1)); - cachePainter.drawPoint(QPoint(r.left() + 1, r.top() + 1)); - cachePainter.drawLine(QPoint(r.left(), r.top() + 2), QPoint(r.left(), r.bottom() - 2)); - } else { - cachePainter.drawRect(rect.adjusted(downRect.width() + 2, 2, -2, -3)); - cachePainter.setPen(QPen(darkoutline, 0)); - cachePainter.drawLine(QPoint(r.left() + downRect.width(), r.bottom()), QPoint(r.right()- 2 - 1, r.bottom())); - cachePainter.drawLine(QPoint(r.left() + downRect.width(), r.top()), QPoint(r.right() - 2 - 1, r.top())); - - cachePainter.drawLine(QPoint(r.right(), r.top() + 2), QPoint(r.right(), r.bottom() - 2)); - cachePainter.drawPoint(QPoint(r.right() - 1, r.bottom() - 1)); - cachePainter.drawPoint(QPoint(r.right() - 1, r.top() + 1)); - cachePainter.drawLine(QPoint(r.left() + downRect.width() + 1, r.top()), - QPoint(r.left() + downRect.width() + 1, r.bottom())); - } - } - } - - // outline the up/down buttons - cachePainter.setPen(darkOutline); - QColor light = option->palette.light().color().lighter(); - - if (spinBox->direction == Qt::RightToLeft) { - cachePainter.drawLine(upRect.right(), upRect.top() - 1, upRect.right(), downRect.bottom() + 1); - cachePainter.setPen(light); - cachePainter.drawLine(upRect.right() - 1, upRect.top() + 3, upRect.right() - 1, downRect.bottom() ); - } else { - cachePainter.drawLine(upRect.left(), upRect.top() - 1, upRect.left(), downRect.bottom() + 1); - cachePainter.setPen(light); - cachePainter.drawLine(upRect.left() + 1, upRect.top() , upRect.left() + 1, downRect.bottom() ); - } - if (upIsActive && sunken) { - cachePainter.setPen(gradientStopColor.darker(130)); - cachePainter.drawLine(upRect.left() + 1, upRect.top(), upRect.left() + 1, upRect.bottom()); - cachePainter.drawLine(upRect.left(), upRect.top() - 1, upRect.right(), upRect.top() - 1); - } else { - cachePainter.setPen(light); - cachePainter.drawLine(upRect.topLeft() + QPoint(1, -1), upRect.topRight() + QPoint(-1, -1)); - cachePainter.setPen(darkOutline); - cachePainter.drawLine(upRect.bottomLeft(), upRect.bottomRight()); - } - if (downIsActive && sunken) { - cachePainter.setPen(gradientStopColor.darker(130)); - cachePainter.drawLine(downRect.left() + 1, downRect.top(), downRect.left() + 1, downRect.bottom() + 1); - cachePainter.drawLine(downRect.left(), downRect.top(), downRect.right(), downRect.top()); - cachePainter.setPen(gradientStopColor.darker(110)); - cachePainter.drawLine(downRect.left(), downRect.bottom() + 1, downRect.right(), downRect.bottom() + 1); - } else { - cachePainter.setPen(light); - cachePainter.drawLine(downRect.topLeft() + QPoint(2,0), downRect.topRight()); - } - - if (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) { - int centerX = upRect.center().x(); - int centerY = upRect.center().y(); - cachePainter.setPen(spinBox->palette.foreground().color()); - - // plus/minus - if (spinBox->activeSubControls == SC_SpinBoxUp && sunken) { - cachePainter.drawLine(1 + centerX - 2, 1 + centerY, 1 + centerX + 2, 1 + centerY); - cachePainter.drawLine(1 + centerX, 1 + centerY - 2, 1 + centerX, 1 + centerY + 2); - } else { - cachePainter.drawLine(centerX - 2, centerY, centerX + 2, centerY); - cachePainter.drawLine(centerX, centerY - 2, centerX, centerY + 2); - } - - centerX = downRect.center().x(); - centerY = downRect.center().y(); - if (spinBox->activeSubControls == SC_SpinBoxDown && sunken) { - cachePainter.drawLine(1 + centerX - 2, 1 + centerY, 1 + centerX + 2, 1 + centerY); - } else { - cachePainter.drawLine(centerX - 2, centerY, centerX + 2, centerY); - } - } else if (spinBox->buttonSymbols == QAbstractSpinBox::UpDownArrows){ - // arrows - QImage upArrow(qt_spinbox_button_arrow_up); - upArrow.setColor(1, spinBox->palette.foreground().color().rgba()); - - cachePainter.drawImage(upRect.center().x() - upArrow.width() / 2, - upRect.center().y() - upArrow.height() / 2, - upArrow); - - QImage downArrow(qt_spinbox_button_arrow_down); - downArrow.setColor(1, spinBox->palette.foreground().color().rgba()); - - cachePainter.drawImage(downRect.center().x() - downArrow.width() / 2, - downRect.center().y() - downArrow.height() / 2 + 1, - downArrow); - } - - QColor disabledColor = option->palette.background().color(); - disabledColor.setAlpha(150); - if (!(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled)) - cachePainter.fillRect(upRect.adjusted(1, 0, 0, 0), disabledColor); - if (!(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled)) { - cachePainter.fillRect(downRect.adjusted(1, 0, 0, 0), disabledColor); - } - cachePainter.end(); - QPixmapCache::insert(pixmapName, cache); - } - painter->drawPixmap(spinBox->rect.topLeft(), cache); - } - break; -#endif // QT_NO_SPINBOX - case CC_TitleBar: - painter->save(); - if (const QStyleOptionTitleBar *titleBar = qstyleoption_cast(option)) { - const int buttonMargin = 5; - bool active = (titleBar->titleBarState & State_Active); - QRect fullRect = titleBar->rect; - QPalette palette = option->palette; - QColor highlight = option->palette.highlight().color(); - - QColor titleBarFrameBorder(active ? highlight.darker(180): dark.darker(110)); - QColor titleBarHighlight(active ? highlight.lighter(120): palette.background().color().lighter(120)); - QColor textColor(active ? 0xffffff : 0xff000000); - QColor textAlphaColor(active ? 0xffffff : 0xff000000 ); - - { - // Fill title bar gradient - QColor titlebarColor = QColor(active ? highlight: palette.background().color()); - QLinearGradient gradient(option->rect.center().x(), option->rect.top(), - option->rect.center().x(), option->rect.bottom()); - - gradient.setColorAt(0, titlebarColor.lighter(114)); - gradient.setColorAt(0.5, titlebarColor.lighter(102)); - gradient.setColorAt(0.51, titlebarColor.darker(104)); - gradient.setColorAt(1, titlebarColor); - painter->fillRect(option->rect.adjusted(1, 1, -1, 0), gradient); - - // Frame and rounded corners - painter->setPen(titleBarFrameBorder); - - // top outline - painter->drawLine(fullRect.left() + 5, fullRect.top(), fullRect.right() - 5, fullRect.top()); - painter->drawLine(fullRect.left(), fullRect.top() + 4, fullRect.left(), fullRect.bottom()); - const QPoint points[5] = { - QPoint(fullRect.left() + 4, fullRect.top() + 1), - QPoint(fullRect.left() + 3, fullRect.top() + 1), - QPoint(fullRect.left() + 2, fullRect.top() + 2), - QPoint(fullRect.left() + 1, fullRect.top() + 3), - QPoint(fullRect.left() + 1, fullRect.top() + 4) - }; - painter->drawPoints(points, 5); - - painter->drawLine(fullRect.right(), fullRect.top() + 4, fullRect.right(), fullRect.bottom()); - const QPoint points2[5] = { - QPoint(fullRect.right() - 3, fullRect.top() + 1), - QPoint(fullRect.right() - 4, fullRect.top() + 1), - QPoint(fullRect.right() - 2, fullRect.top() + 2), - QPoint(fullRect.right() - 1, fullRect.top() + 3), - QPoint(fullRect.right() - 1, fullRect.top() + 4) - }; - painter->drawPoints(points2, 5); - - // draw bottomline - painter->drawLine(fullRect.right(), fullRect.bottom(), fullRect.left(), fullRect.bottom()); - - // top highlight - painter->setPen(titleBarHighlight); - painter->drawLine(fullRect.left() + 6, fullRect.top() + 1, fullRect.right() - 6, fullRect.top() + 1); - } - // draw title - QRect textRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarLabel, widget); - QFont font = painter->font(); - font.setBold(true); - painter->setFont(font); - painter->setPen(active? (titleBar->palette.text().color().lighter(120)) : - titleBar->palette.text().color() ); - // Note workspace also does elliding but it does not use the correct font - QString title = QFontMetrics(font).elidedText(titleBar->text, Qt::ElideRight, textRect.width() - 14); - painter->drawText(textRect.adjusted(1, 1, 1, 1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter)); - painter->setPen(Qt::white); - if (active) - painter->drawText(textRect, title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter)); - // min button - if ((titleBar->subControls & SC_TitleBarMinButton) && (titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) && - !(titleBar->titleBarState& Qt::WindowMinimized)) { - QRect minButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMinButton, widget); - if (minButtonRect.isValid()) { - bool hover = (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_Sunken); - qt_cleanlooks_draw_mdibutton(painter, titleBar, minButtonRect, hover, sunken); - QRect minButtonIconRect = minButtonRect.adjusted(buttonMargin ,buttonMargin , -buttonMargin, -buttonMargin); - painter->setPen(textColor); - painter->drawLine(minButtonIconRect.center().x() - 2, minButtonIconRect.center().y() + 3, - minButtonIconRect.center().x() + 3, minButtonIconRect.center().y() + 3); - painter->drawLine(minButtonIconRect.center().x() - 2, minButtonIconRect.center().y() + 4, - minButtonIconRect.center().x() + 3, minButtonIconRect.center().y() + 4); - painter->setPen(textAlphaColor); - painter->drawLine(minButtonIconRect.center().x() - 3, minButtonIconRect.center().y() + 3, - minButtonIconRect.center().x() - 3, minButtonIconRect.center().y() + 4); - painter->drawLine(minButtonIconRect.center().x() + 4, minButtonIconRect.center().y() + 3, - minButtonIconRect.center().x() + 4, minButtonIconRect.center().y() + 4); - } - } - // max button - if ((titleBar->subControls & SC_TitleBarMaxButton) && (titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) && - !(titleBar->titleBarState & Qt::WindowMaximized)) { - QRect maxButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMaxButton, widget); - if (maxButtonRect.isValid()) { - bool hover = (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_Sunken); - qt_cleanlooks_draw_mdibutton(painter, titleBar, maxButtonRect, hover, sunken); - - QRect maxButtonIconRect = maxButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin); - - painter->setPen(textColor); - painter->drawRect(maxButtonIconRect.adjusted(0, 0, -1, -1)); - painter->drawLine(maxButtonIconRect.left() + 1, maxButtonIconRect.top() + 1, - maxButtonIconRect.right() - 1, maxButtonIconRect.top() + 1); - painter->setPen(textAlphaColor); - const QPoint points[4] = { - maxButtonIconRect.topLeft(), - maxButtonIconRect.topRight(), - maxButtonIconRect.bottomLeft(), - maxButtonIconRect.bottomRight() - }; - painter->drawPoints(points, 4); - } - } - - // close button - if ((titleBar->subControls & SC_TitleBarCloseButton) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) { - QRect closeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarCloseButton, widget); - if (closeButtonRect.isValid()) { - bool hover = (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_Sunken); - qt_cleanlooks_draw_mdibutton(painter, titleBar, closeButtonRect, hover, sunken); - QRect closeIconRect = closeButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin); - painter->setPen(textAlphaColor); - const QLine lines[4] = { - QLine(closeIconRect.left() + 1, closeIconRect.top(), - closeIconRect.right(), closeIconRect.bottom() - 1), - QLine(closeIconRect.left(), closeIconRect.top() + 1, - closeIconRect.right() - 1, closeIconRect.bottom()), - QLine(closeIconRect.right() - 1, closeIconRect.top(), - closeIconRect.left(), closeIconRect.bottom() - 1), - QLine(closeIconRect.right(), closeIconRect.top() + 1, - closeIconRect.left() + 1, closeIconRect.bottom()) - }; - painter->drawLines(lines, 4); - const QPoint points[4] = { - closeIconRect.topLeft(), - closeIconRect.topRight(), - closeIconRect.bottomLeft(), - closeIconRect.bottomRight() - }; - painter->drawPoints(points, 4); - - painter->setPen(textColor); - painter->drawLine(closeIconRect.left() + 1, closeIconRect.top() + 1, - closeIconRect.right() - 1, closeIconRect.bottom() - 1); - painter->drawLine(closeIconRect.left() + 1, closeIconRect.bottom() - 1, - closeIconRect.right() - 1, closeIconRect.top() + 1); - } - } - - // normalize button - if ((titleBar->subControls & SC_TitleBarNormalButton) && - (((titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) && - (titleBar->titleBarState & Qt::WindowMinimized)) || - ((titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) && - (titleBar->titleBarState & Qt::WindowMaximized)))) { - QRect normalButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarNormalButton, widget); - if (normalButtonRect.isValid()) { - - bool hover = (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_Sunken); - QRect normalButtonIconRect = normalButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin); - qt_cleanlooks_draw_mdibutton(painter, titleBar, normalButtonRect, hover, sunken); - - QRect frontWindowRect = normalButtonIconRect.adjusted(0, 3, -3, 0); - painter->setPen(textColor); - painter->drawRect(frontWindowRect.adjusted(0, 0, -1, -1)); - painter->drawLine(frontWindowRect.left() + 1, frontWindowRect.top() + 1, - frontWindowRect.right() - 1, frontWindowRect.top() + 1); - painter->setPen(textAlphaColor); - const QPoint points[4] = { - frontWindowRect.topLeft(), - frontWindowRect.topRight(), - frontWindowRect.bottomLeft(), - frontWindowRect.bottomRight() - }; - painter->drawPoints(points, 4); - - QRect backWindowRect = normalButtonIconRect.adjusted(3, 0, 0, -3); - QRegion clipRegion = backWindowRect; - clipRegion -= frontWindowRect; - painter->save(); - painter->setClipRegion(clipRegion); - painter->setPen(textColor); - painter->drawRect(backWindowRect.adjusted(0, 0, -1, -1)); - painter->drawLine(backWindowRect.left() + 1, backWindowRect.top() + 1, - backWindowRect.right() - 1, backWindowRect.top() + 1); - painter->setPen(textAlphaColor); - const QPoint points2[4] = { - backWindowRect.topLeft(), - backWindowRect.topRight(), - backWindowRect.bottomLeft(), - backWindowRect.bottomRight() - }; - painter->drawPoints(points2, 4); - painter->restore(); - } - } - - // context help button - if (titleBar->subControls & SC_TitleBarContextHelpButton - && (titleBar->titleBarFlags & Qt::WindowContextHelpButtonHint)) { - QRect contextHelpButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarContextHelpButton, widget); - if (contextHelpButtonRect.isValid()) { - bool hover = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_Sunken); - qt_cleanlooks_draw_mdibutton(painter, titleBar, contextHelpButtonRect, hover, sunken); - - QColor blend; - QImage image(qt_titlebar_context_help); - QColor alpha = textColor; - alpha.setAlpha(128); - image.setColor(1, textColor.rgba()); - image.setColor(2, alpha.rgba()); - painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->drawImage(contextHelpButtonRect.adjusted(4, 4, -4, -4), image); - } - } - - // shade button - if (titleBar->subControls & SC_TitleBarShadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) { - QRect shadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarShadeButton, widget); - if (shadeButtonRect.isValid()) { - bool hover = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_Sunken); - qt_cleanlooks_draw_mdibutton(painter, titleBar, shadeButtonRect, hover, sunken); - QImage image(qt_scrollbar_button_arrow_up); - image.setColor(1, textColor.rgba()); - painter->drawImage(shadeButtonRect.adjusted(5, 7, -5, -7), image); - } - } - - // unshade button - if (titleBar->subControls & SC_TitleBarUnshadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) { - QRect unshadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarUnshadeButton, widget); - if (unshadeButtonRect.isValid()) { - bool hover = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_Sunken); - qt_cleanlooks_draw_mdibutton(painter, titleBar, unshadeButtonRect, hover, sunken); - QImage image(qt_scrollbar_button_arrow_down); - image.setColor(1, textColor.rgba()); - painter->drawImage(unshadeButtonRect.adjusted(5, 7, -5, -7), image); - } - } - - if ((titleBar->subControls & SC_TitleBarSysMenu) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) { - QRect iconRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarSysMenu, widget); - if (iconRect.isValid()) { - if (!titleBar->icon.isNull()) { - titleBar->icon.paint(painter, iconRect); - } else { - QStyleOption tool(0); - tool.palette = titleBar->palette; - QPixmap pm = standardIcon(SP_TitleBarMenuButton, &tool, widget).pixmap(16, 16); - tool.rect = iconRect; - painter->save(); - proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm); - painter->restore(); - } - } - } - } - painter->restore(); - break; -#ifndef QT_NO_SCROLLBAR - case CC_ScrollBar: - painter->save(); - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - bool isEnabled = scrollBar->state & State_Enabled; - bool reverse = scrollBar->direction == Qt::RightToLeft; - bool horizontal = scrollBar->orientation == Qt::Horizontal; - bool sunken = scrollBar->state & State_Sunken; - - painter->fillRect(option->rect, option->palette.background()); - - QRect scrollBarSubLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSubLine, widget); - QRect scrollBarAddLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarAddLine, widget); - QRect scrollBarSlider = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSlider, widget); - QRect grooveRect = proxy()->subControlRect(control, scrollBar, SC_ScrollBarGroove, widget); - - // paint groove - if (scrollBar->subControls & SC_ScrollBarGroove) { - painter->setBrush(grooveColor); - painter->setPen(Qt::NoPen); - if (horizontal) { - painter->drawRect(grooveRect); - painter->setPen(darkOutline); - painter->drawLine(grooveRect.topLeft(), grooveRect.topRight()); - painter->drawLine(grooveRect.bottomLeft(), grooveRect.bottomRight()); - } else { - painter->drawRect(grooveRect); - painter->setPen(darkOutline); - painter->drawLine(grooveRect.topLeft(), grooveRect.bottomLeft()); - painter->drawLine(grooveRect.topRight(), grooveRect.bottomRight()); - } - } - //paint slider - if (scrollBar->subControls & SC_ScrollBarSlider) { - QRect pixmapRect = scrollBarSlider; - if (horizontal) - pixmapRect.adjust(-1, 0, 0, -1); - else - pixmapRect.adjust(0, -1, -1, 0); - - if (isEnabled) { - QLinearGradient gradient(pixmapRect.center().x(), pixmapRect.top(), - pixmapRect.center().x(), pixmapRect.bottom()); - if (!horizontal) - gradient = QLinearGradient(pixmapRect.left(), pixmapRect.center().y(), - pixmapRect.right(), pixmapRect.center().y()); - - if (option->palette.button().gradient()) { - gradient.setStops(option->palette.button().gradient()->stops()); - } else { - if (sunken || (option->state & State_MouseOver && - (scrollBar->activeSubControls & SC_ScrollBarSlider))) { - gradient.setColorAt(0, gradientStartColor.lighter(110)); - gradient.setColorAt(1, gradientStopColor.lighter(110)); - } else { - gradient.setColorAt(0, gradientStartColor); - gradient.setColorAt(1, gradientStopColor); - } - } - painter->setPen(QPen(darkOutline, 0)); - painter->setBrush(gradient); - painter->drawRect(pixmapRect); - - - //calculate offsets used by highlight and shadow - int yoffset, xoffset; - if (option->state & State_Horizontal) { - xoffset = 0; - yoffset = 1; - } else { - xoffset = 1; - yoffset = 0; - } - //draw slider highlights - painter->setPen(QPen(gradientStopColor, 0)); - painter->drawLine(scrollBarSlider.left() + xoffset, - scrollBarSlider.bottom() - yoffset, - scrollBarSlider.right() - xoffset, - scrollBarSlider.bottom() - yoffset); - painter->drawLine(scrollBarSlider.right() - xoffset, - scrollBarSlider.top() + yoffset, - scrollBarSlider.right() - xoffset, - scrollBarSlider.bottom() - yoffset); - - //draw slider shadow - painter->setPen(QPen(gradientStartColor, 0)); - painter->drawLine(scrollBarSlider.left() + xoffset, - scrollBarSlider.top() + yoffset, - scrollBarSlider.right() - xoffset, - scrollBarSlider.top() + yoffset); - painter->drawLine(scrollBarSlider.left() + xoffset, - scrollBarSlider.top() + yoffset, - scrollBarSlider.left() + xoffset, - scrollBarSlider.bottom() - yoffset); - } else { - QLinearGradient gradient(pixmapRect.center().x(), pixmapRect.top(), - pixmapRect.center().x(), pixmapRect.bottom()); - if (!horizontal) { - gradient = QLinearGradient(pixmapRect.left(), pixmapRect.center().y(), - pixmapRect.right(), pixmapRect.center().y()); - } - if (sunken) { - gradient.setColorAt(0, gradientStartColor.lighter(110)); - gradient.setColorAt(1, gradientStopColor.lighter(110)); - } else { - gradient.setColorAt(0, gradientStartColor); - gradient.setColorAt(1, gradientStopColor); - } - painter->setPen(darkOutline); - painter->setBrush(gradient); - painter->drawRect(pixmapRect); - } - int gripMargin = 4; - //draw grips - if (horizontal) { - for (int i = -3; i< 6 ; i += 3) { - painter->setPen(QPen(gripShadow, 1)); - painter->drawLine( - QPoint(scrollBarSlider.center().x() + i , - scrollBarSlider.top() + gripMargin), - QPoint(scrollBarSlider.center().x() + i, - scrollBarSlider.bottom() - gripMargin)); - painter->setPen(QPen(palette.light(), 1)); - painter->drawLine( - QPoint(scrollBarSlider.center().x() + i + 1, - scrollBarSlider.top() + gripMargin ), - QPoint(scrollBarSlider.center().x() + i + 1, - scrollBarSlider.bottom() - gripMargin)); - } - } else { - for (int i = -3; i < 6 ; i += 3) { - painter->setPen(QPen(gripShadow, 1)); - painter->drawLine( - QPoint(scrollBarSlider.left() + gripMargin , - scrollBarSlider.center().y()+ i), - QPoint(scrollBarSlider.right() - gripMargin, - scrollBarSlider.center().y()+ i)); - painter->setPen(QPen(palette.light(), 1)); - painter->drawLine( - QPoint(scrollBarSlider.left() + gripMargin, - scrollBarSlider.center().y() + 1 + i), - QPoint(scrollBarSlider.right() - gripMargin, - scrollBarSlider.center().y() + 1 + i)); - } - } - } - - // The SubLine (up/left) buttons - if (scrollBar->subControls & SC_ScrollBarSubLine) { - //int scrollBarExtent = proxy()->pixelMetric(PM_ScrollBarExtent, option, widget); - QRect pixmapRect = scrollBarSubLine; - if (isEnabled ) { - QRect fillRect = pixmapRect.adjusted(1, 1, -1, -1); - // Gradients - if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken) { - qt_cleanlooks_draw_gradient(painter, - QRect(fillRect), - gradientStopColor.darker(120), - gradientStopColor.darker(120), - horizontal ? TopDown : FromLeft, option->palette.button()); - } else { - qt_cleanlooks_draw_gradient(painter, - QRect(fillRect), - gradientStartColor.lighter(105), - gradientStopColor, - horizontal ? TopDown : FromLeft, option->palette.button()); - } - } - // Details - QImage subButton; - if (horizontal) { - subButton = QImage(reverse ? qt_scrollbar_button_right : qt_scrollbar_button_left); - } else { - subButton = QImage(qt_scrollbar_button_up); - } - subButton.setColor(1, alphaCornerColor.rgba()); - subButton.setColor(2, darkOutline.rgba()); - if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken) { - subButton.setColor(3, gradientStopColor.darker(140).rgba()); - subButton.setColor(4, gradientStopColor.darker(120).rgba()); - } else { - subButton.setColor(3, gradientStartColor.lighter(105).rgba()); - subButton.setColor(4, gradientStopColor.rgba()); - } - subButton.setColor(5, scrollBar->palette.text().color().rgba()); - painter->drawImage(pixmapRect, subButton); - - // Arrows - PrimitiveElement arrow; - if (option->state & State_Horizontal) - arrow = option->direction == Qt::LeftToRight ? PE_IndicatorArrowLeft: PE_IndicatorArrowRight; - else - arrow = PE_IndicatorArrowUp; - QStyleOption arrowOpt = *option; - arrowOpt.rect = scrollBarSubLine.adjusted(3, 3, -2, -2); - proxy()->drawPrimitive(arrow, &arrowOpt, painter, widget); - - - // The AddLine (down/right) button - if (scrollBar->subControls & SC_ScrollBarAddLine) { - QString addLinePixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_addline"), option, QSize(16, 16)); - QRect pixmapRect = scrollBarAddLine; - if (isEnabled) { - QRect fillRect = pixmapRect.adjusted(1, 1, -1, -1); - // Gradients - if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken) { - qt_cleanlooks_draw_gradient(painter, - fillRect, - gradientStopColor.darker(120), - gradientStopColor.darker(120), - horizontal ? TopDown: FromLeft, option->palette.button()); - } else { - qt_cleanlooks_draw_gradient(painter, - fillRect, - gradientStartColor.lighter(105), - gradientStopColor, - horizontal ? TopDown : FromLeft, option->palette.button()); - } - } - // Details - QImage addButton; - if (horizontal) { - addButton = QImage(reverse ? qt_scrollbar_button_left : qt_scrollbar_button_right); - } else { - addButton = QImage(qt_scrollbar_button_down); - } - addButton.setColor(1, alphaCornerColor.rgba()); - addButton.setColor(2, darkOutline.rgba()); - if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken) { - addButton.setColor(3, gradientStopColor.darker(140).rgba()); - addButton.setColor(4, gradientStopColor.darker(120).rgba()); - } else { - addButton.setColor(3, gradientStartColor.lighter(105).rgba()); - addButton.setColor(4, gradientStopColor.rgba()); - } - addButton.setColor(5, scrollBar->palette.text().color().rgba()); - painter->drawImage(pixmapRect, addButton); - - PrimitiveElement arrow; - if (option->state & State_Horizontal) - arrow = option->direction == Qt::LeftToRight ? PE_IndicatorArrowRight : PE_IndicatorArrowLeft; - else - arrow = PE_IndicatorArrowDown; - - QStyleOption arrowOpt = *option; - arrowOpt.rect = scrollBarAddLine.adjusted(3, 3, -2, -2); - proxy()->drawPrimitive(arrow, &arrowOpt, painter, widget); - } - } - } - painter->restore(); - break;; -#endif // QT_NO_SCROLLBAR -#ifndef QT_NO_COMBOBOX - case CC_ComboBox: - painter->save(); - if (const QStyleOptionComboBox *comboBox = qstyleoption_cast(option)) { - bool sunken = comboBox->state & State_On; // play dead, if combobox has no items - bool isEnabled = (comboBox->state & State_Enabled); - bool focus = isEnabled && (comboBox->state & State_HasFocus); - QPixmap cache; - QString pixmapName = QStyleHelper::uniqueName(QLatin1String("combobox"), option, comboBox->rect.size()); - if (sunken) - pixmapName += QLatin1String("-sunken"); - if (comboBox->editable) - pixmapName += QLatin1String("-editable"); - if (isEnabled) - pixmapName += QLatin1String("-enabled"); - - if (!QPixmapCache::find(pixmapName, cache)) { - cache = QPixmap(comboBox->rect.size()); - cache.fill(Qt::transparent); - QPainter cachePainter(&cache); - QRect pixmapRect(0, 0, comboBox->rect.width(), comboBox->rect.height()); - QStyleOptionComboBox comboBoxCopy = *comboBox; - comboBoxCopy.rect = pixmapRect; - - QRect rect = pixmapRect; - QRect downArrowRect = proxy()->subControlRect(CC_ComboBox, &comboBoxCopy, - SC_ComboBoxArrow, widget); - QRect editRect = proxy()->subControlRect(CC_ComboBox, &comboBoxCopy, - SC_ComboBoxEditField, widget); - // Draw a push button - if (comboBox->editable) { - QStyleOptionFrame buttonOption; - buttonOption.QStyleOption::operator=(*comboBox); - buttonOption.rect = rect; - buttonOption.state = comboBox->state & (State_Enabled | State_MouseOver); - - if (sunken) { - buttonOption.state |= State_Sunken; - buttonOption.state &= ~State_MouseOver; - } - - proxy()->drawPrimitive(PE_PanelButtonCommand, &buttonOption, &cachePainter, widget); - - //remove shadow from left side of edit field when pressed: - if (comboBox->direction != Qt::RightToLeft) - cachePainter.fillRect(editRect.left() - 1, editRect.top() + 1, editRect.left(), - editRect.bottom() - 3, option->palette.base()); - - cachePainter.setPen(dark.lighter(110)); - if (!sunken) { - int borderSize = 2; - if (comboBox->direction == Qt::RightToLeft) { - cachePainter.drawLine(QPoint(downArrowRect.right() - 1, downArrowRect.top() + borderSize ), - QPoint(downArrowRect.right() - 1, downArrowRect.bottom() - borderSize)); - cachePainter.setPen(option->palette.light().color()); - cachePainter.drawLine(QPoint(downArrowRect.right(), downArrowRect.top() + borderSize), - QPoint(downArrowRect.right(), downArrowRect.bottom() - borderSize)); - } else { - cachePainter.drawLine(QPoint(downArrowRect.left() , downArrowRect.top() + borderSize), - QPoint(downArrowRect.left() , downArrowRect.bottom() - borderSize)); - cachePainter.setPen(option->palette.light().color()); - cachePainter.drawLine(QPoint(downArrowRect.left() + 1, downArrowRect.top() + borderSize), - QPoint(downArrowRect.left() + 1, downArrowRect.bottom() - borderSize)); - } - } else { - if (comboBox->direction == Qt::RightToLeft) { - cachePainter.drawLine(QPoint(downArrowRect.right(), downArrowRect.top() + 2), - QPoint(downArrowRect.right(), downArrowRect.bottom() - 2)); - - } else { - cachePainter.drawLine(QPoint(downArrowRect.left(), downArrowRect.top() + 2), - QPoint(downArrowRect.left(), downArrowRect.bottom() - 2)); - } - } - } else { - QStyleOptionButton buttonOption; - buttonOption.QStyleOption::operator=(*comboBox); - buttonOption.rect = rect; - buttonOption.state = comboBox->state & (State_Enabled | State_MouseOver); - if (sunken) { - buttonOption.state |= State_Sunken; - buttonOption.state &= ~State_MouseOver; - } - proxy()->drawPrimitive(PE_PanelButtonCommand, &buttonOption, &cachePainter, widget); - - cachePainter.setPen(buttonShadow.darker(102)); - int borderSize = 4; - - if (!sunken) { - if (comboBox->direction == Qt::RightToLeft) { - cachePainter.drawLine(QPoint(downArrowRect.right() + 1, downArrowRect.top() + borderSize), - QPoint(downArrowRect.right() + 1, downArrowRect.bottom() - borderSize)); - cachePainter.setPen(option->palette.light().color()); - cachePainter.drawLine(QPoint(downArrowRect.right(), downArrowRect.top() + borderSize), - QPoint(downArrowRect.right(), downArrowRect.bottom() - borderSize)); - } else { - cachePainter.drawLine(QPoint(downArrowRect.left() - 1, downArrowRect.top() + borderSize), - QPoint(downArrowRect.left() - 1, downArrowRect.bottom() - borderSize)); - cachePainter.setPen(option->palette.light().color()); - cachePainter.drawLine(QPoint(downArrowRect.left() , downArrowRect.top() + borderSize), - QPoint(downArrowRect.left() , downArrowRect.bottom() - borderSize)); - } - } else { - cachePainter.setPen(dark.lighter(110)); - if (comboBox->direction == Qt::RightToLeft) { - cachePainter.drawLine(QPoint(downArrowRect.right() + 1, downArrowRect.top() + borderSize), - QPoint(downArrowRect.right() + 1, downArrowRect.bottom() - borderSize)); - - } else { - cachePainter.drawLine(QPoint(downArrowRect.left() - 1, downArrowRect.top() + borderSize), - QPoint(downArrowRect.left() - 1, downArrowRect.bottom() - borderSize)); - } - } - } - - - if (comboBox->subControls & SC_ComboBoxArrow) { - if (comboBox->editable) { - // Draw the down arrow - QImage downArrow(qt_cleanlooks_arrow_down_xpm); - downArrow.setColor(1, comboBox->palette.foreground().color().rgba()); - cachePainter.drawImage(downArrowRect.center().x() - downArrow.width() / 2, - downArrowRect.center().y() - downArrow.height() / 2 + 1, downArrow); - } else { - // Draw the up/down arrow - QImage upArrow(qt_scrollbar_button_arrow_up); - upArrow.setColor(1, comboBox->palette.foreground().color().rgba()); - QImage downArrow(qt_scrollbar_button_arrow_down); - downArrow.setColor(1, comboBox->palette.foreground().color().rgba()); - cachePainter.drawImage(downArrowRect.center().x() - downArrow.width() / 2, - downArrowRect.center().y() - upArrow.height() - 1 , upArrow); - cachePainter.drawImage(downArrowRect.center().x() - downArrow.width() / 2, - downArrowRect.center().y() + 2, downArrow); - } - } - // Draw the focus rect - if (focus && !comboBox->editable - && ((option->state & State_KeyboardFocusChange) || styleHint(SH_UnderlineShortcut, option, widget))) { - QStyleOptionFocusRect focus; - focus.rect = proxy()->subControlRect(CC_ComboBox, &comboBoxCopy, SC_ComboBoxEditField, widget) - .adjusted(0, 2, option->direction == Qt::RightToLeft ? 1 : -1, -2); - proxy()->drawPrimitive(PE_FrameFocusRect, &focus, &cachePainter, widget); - } - cachePainter.end(); - QPixmapCache::insert(pixmapName, cache); - } - painter->drawPixmap(comboBox->rect.topLeft(), cache); - } - painter->restore(); - break; -#endif // QT_NO_COMBOBOX -#ifndef QT_NO_GROUPBOX - case CC_GroupBox: - painter->save(); - if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(option)) { - QRect textRect = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxLabel, widget); - QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxCheckBox, widget); - bool flat = groupBox->features & QStyleOptionFrameV2::Flat; - - if(!flat) { - if (groupBox->subControls & QStyle::SC_GroupBoxFrame) { - QStyleOptionFrameV2 frame; - frame.QStyleOption::operator=(*groupBox); - frame.features = groupBox->features; - frame.lineWidth = groupBox->lineWidth; - frame.midLineWidth = groupBox->midLineWidth; - frame.rect = proxy()->subControlRect(CC_GroupBox, option, SC_GroupBoxFrame, widget); - - painter->save(); - QRegion region(groupBox->rect); - bool ltr = groupBox->direction == Qt::LeftToRight; - region -= checkBoxRect.united(textRect).adjusted(ltr ? -4 : 0, 0, ltr ? 0 : 4, 0); - if (!groupBox->text.isEmpty() || groupBox->subControls & SC_GroupBoxCheckBox) - painter->setClipRegion(region); - frame.palette.setBrush(QPalette::Dark, option->palette.mid().color().lighter(110)); - proxy()->drawPrimitive(PE_FrameGroupBox, &frame, painter); - painter->restore(); - } - } - // Draw title - if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) { - if (!groupBox->text.isEmpty()) { - QColor textColor = groupBox->textColor; - if (textColor.isValid()) - painter->setPen(textColor); - int alignment = int(groupBox->textAlignment); - if (!styleHint(QStyle::SH_UnderlineShortcut, option, widget)) - alignment |= Qt::TextHideMnemonic; - if (flat) { - QFont font = painter->font(); - font.setBold(true); - painter->setFont(font); - if (groupBox->subControls & SC_GroupBoxCheckBox) { - textRect.adjust(checkBoxRect.right() + 4, 0, checkBoxRect.right() + 4, 0); - } - } - painter->drawText(textRect, Qt::TextShowMnemonic | Qt::AlignLeft| alignment, groupBox->text); - } - } - if (groupBox->subControls & SC_GroupBoxCheckBox) { - QStyleOptionButton box; - box.QStyleOption::operator=(*groupBox); - box.rect = checkBoxRect; - proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget); - } - } - painter->restore(); - break; -#endif // QT_NO_GROUPBOX -#ifndef QT_NO_SLIDER - case CC_Slider: - if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { - QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget); - QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); - - bool horizontal = slider->orientation == Qt::Horizontal; - bool ticksAbove = slider->tickPosition & QSlider::TicksAbove; - bool ticksBelow = slider->tickPosition & QSlider::TicksBelow; - QColor activeHighlight = option->palette.color(QPalette::Normal, QPalette::Highlight); - QPixmap cache; - - QBrush oldBrush = painter->brush(); - QPen oldPen = painter->pen(); - - QColor shadowAlpha(Qt::black); - shadowAlpha.setAlpha(10); - QColor highlightAlpha(Qt::white); - highlightAlpha.setAlpha(80); - - if ((option->subControls & SC_SliderGroove) && groove.isValid()) { - QString groovePixmapName = QStyleHelper::uniqueName(QLatin1String("slider_groove"), option, groove.size()); - QRect pixmapRect(0, 0, groove.width(), groove.height()); - - // draw background groove - if (!QPixmapCache::find(groovePixmapName, cache)) { - cache = QPixmap(pixmapRect.size()); - cache.fill(Qt::transparent); - QPainter groovePainter(&cache); - - groovePainter.setPen(shadowAlpha); - groovePainter.drawLine(1, 0, groove.width(), 0); - groovePainter.drawLine(0, 0, 0, groove.height() - 1); - - groovePainter.setPen(highlightAlpha); - groovePainter.drawLine(1, groove.height() - 1, groove.width() - 1, groove.height() - 1); - groovePainter.drawLine(groove.width() - 1, 1, groove.width() - 1, groove.height() - 1); - QLinearGradient gradient; - if (horizontal) { - gradient.setStart(pixmapRect.center().x(), pixmapRect.top()); - gradient.setFinalStop(pixmapRect.center().x(), pixmapRect.bottom()); - } - else { - gradient.setStart(pixmapRect.left(), pixmapRect.center().y()); - gradient.setFinalStop(pixmapRect.right(), pixmapRect.center().y()); - } - groovePainter.setPen(QPen(darkOutline.darker(110), 0)); - gradient.setColorAt(0, grooveColor.darker(110));//dark.lighter(120)); - gradient.setColorAt(1, grooveColor.lighter(110));//palette.button().color().darker(115)); - groovePainter.setBrush(gradient); - groovePainter.drawRect(pixmapRect.adjusted(1, 1, -2, -2)); - groovePainter.end(); - QPixmapCache::insert(groovePixmapName, cache); - } - painter->drawPixmap(groove.topLeft(), cache); - - // draw blue groove highlight - QRect clipRect; - groovePixmapName += QLatin1String("_blue"); - if (!QPixmapCache::find(groovePixmapName, cache)) { - cache = QPixmap(pixmapRect.size()); - cache.fill(Qt::transparent); - QPainter groovePainter(&cache); - QLinearGradient gradient; - if (horizontal) { - gradient.setStart(pixmapRect.center().x(), pixmapRect.top()); - gradient.setFinalStop(pixmapRect.center().x(), pixmapRect.bottom()); - } - else { - gradient.setStart(pixmapRect.left(), pixmapRect.center().y()); - gradient.setFinalStop(pixmapRect.right(), pixmapRect.center().y()); - } - groovePainter.setPen(QPen(activeHighlight.darker(150), 0)); - gradient.setColorAt(0, activeHighlight.darker(120)); - gradient.setColorAt(1, activeHighlight.lighter(160)); - groovePainter.setBrush(gradient); - groovePainter.drawRect(pixmapRect.adjusted(1, 1, -2, -2)); - groovePainter.end(); - QPixmapCache::insert(groovePixmapName, cache); - } - if (horizontal) { - if (slider->upsideDown) - clipRect = QRect(handle.right(), groove.top(), groove.right() - handle.right(), groove.height()); - else - clipRect = QRect(groove.left(), groove.top(), handle.left(), groove.height()); - } else { - if (slider->upsideDown) - clipRect = QRect(groove.left(), handle.bottom(), groove.width(), groove.height() - handle.bottom()); - else - clipRect = QRect(groove.left(), groove.top(), groove.width(), handle.top() - groove.top()); - } - painter->save(); - painter->setClipRect(clipRect.adjusted(0, 0, 1, 1)); - painter->drawPixmap(groove.topLeft(), cache); - painter->restore(); - } - - // draw handle - if ((option->subControls & SC_SliderHandle) ) { - QString handlePixmapName = QStyleHelper::uniqueName(QLatin1String("slider_handle"), option, handle.size()); - if (!QPixmapCache::find(handlePixmapName, cache)) { - cache = QPixmap(handle.size()); - cache.fill(Qt::transparent); - QRect pixmapRect(0, 0, handle.width(), handle.height()); - QPainter handlePainter(&cache); - - QColor gradientStartColor = mergedColors(option->palette.button().color().lighter(155), - dark.lighter(155), 50); - QColor gradientStopColor = gradientStartColor.darker(108); - QRect gradRect = pixmapRect.adjusted(2, 2, -2, -2); - - QColor gradientBgStartColor = gradientStartColor; - QColor gradientBgStopColor = gradientStopColor; - - QColor outline = option->state & State_Enabled ? dark : dark.lighter(130); - if (option->state & State_Enabled && option->activeSubControls & SC_SliderHandle) { - gradientBgStartColor = option->palette.highlight().color().lighter(180); - gradientBgStopColor = option->palette.highlight().color().lighter(110); - outline = option->palette.highlight().color().darker(130); - } - - // gradient fill - QRect r = pixmapRect.adjusted(1, 1, -1, -1); - - qt_cleanlooks_draw_gradient(&handlePainter, gradRect, - gradientBgStartColor, - gradientBgStopColor, - horizontal ? TopDown : FromLeft, option->palette.button()); - - handlePainter.setPen(QPen(outline.darker(110), 1)); - handlePainter.drawLine(QPoint(r.left(), r.top() + 3), QPoint(r.left(), r.bottom() - 3)); - handlePainter.drawLine(QPoint(r.right(), r.top() + 3), QPoint(r.right(), r.bottom() - 3)); - handlePainter.drawLine(QPoint(r.left() + 3, r.bottom()), QPoint(r.right() - 3, r.bottom())); - - handlePainter.save(); - handlePainter.setRenderHint(QPainter::Antialiasing); - handlePainter.translate(0.5, 0.5); - const QLine lines[4] = { - QLine(QPoint(r.left(), r.bottom() - 2), QPoint(r.left() + 2, r.bottom())), - QLine(QPoint(r.left(), r.top() + 2), QPoint(r.left() + 2, r.top())), - QLine(QPoint(r.right(), r.bottom() - 2), QPoint(r.right() - 2, r.bottom())), - QLine(QPoint(r.right(), r.top() + 2), QPoint(r.right() - 2, r.top())) - }; - handlePainter.drawLines(lines, 4); - handlePainter.restore();; - handlePainter.setPen(QPen(outline.darker(130), 1)); - handlePainter.drawLine(QPoint(r.left() + 3, r.top()), QPoint(r.right() - 3, r.top())); - QColor cornerAlpha = outline.darker(120); - cornerAlpha.setAlpha(80); - - handlePainter.setPen(cornerAlpha); - if (horizontal) { - handlePainter.drawLine(QPoint(r.left() + 6, r.top()), QPoint(r.left() + 6, r.bottom())); - handlePainter.drawLine(QPoint(r.right() - 6, r.top()), QPoint(r.right() - 6, r.bottom())); - } else { - handlePainter.drawLine(QPoint(r.left(), r.top() + 6), QPoint(r.right(), r.top() + 6)); - handlePainter.drawLine(QPoint(r.left(), r.bottom() - 6), QPoint(r.right(), r.bottom() - 6)); - } - - //handle shadow - handlePainter.setPen(shadowAlpha); - handlePainter.drawLine(QPoint(r.left() + 2, r.bottom() + 1), QPoint(r.right() - 2, r.bottom() + 1)); - handlePainter.drawLine(QPoint(r.right() + 1, r.bottom() - 3), QPoint(r.right() + 1, r.top() + 4)); - handlePainter.drawLine(QPoint(r.right() - 1, r.bottom()), QPoint(r.right() + 1, r.bottom() - 2)); - - qt_cleanlooks_draw_gradient(&handlePainter, horizontal ? - gradRect.adjusted(6, 0, -6, 0) : gradRect.adjusted(0, 6, 0, -6), - gradientStartColor, - gradientStopColor.darker(106), - horizontal ? TopDown : FromLeft, - option->palette.button()); - - //draw grips - for (int i = -3; i< 6 ; i += 3) { - for (int j = -3; j< 6 ; j += 3) { - handlePainter.fillRect(r.center().x() + i, r.center().y() + j, 2, 2, highlightAlpha); - handlePainter.setPen(gripShadow); - handlePainter.drawPoint(r.center().x() + i, r.center().y() + j ); - } - } - handlePainter.end(); - QPixmapCache::insert(handlePixmapName, cache); - } - - painter->drawPixmap(handle.topLeft(), cache); - - if (slider->state & State_HasFocus) { - QStyleOptionFocusRect fropt; - fropt.QStyleOption::operator=(*slider); - fropt.rect = slider->rect; - proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); - } - } - if (option->subControls & SC_SliderTickmarks) { - painter->setPen(darkOutline); - int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); - int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget); - int interval = slider->tickInterval; - if (interval <= 0) { - interval = slider->singleStep; - if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval, - available) - - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, - 0, available) < 3) - interval = slider->pageStep; - } - if (interval <= 0) - interval = 1; - - int v = slider->minimum; - int len = proxy()->pixelMetric(PM_SliderLength, slider, widget); - while (v <= slider->maximum + 1) { - if (v == slider->maximum + 1 && interval == 1) - break; - const int v_ = qMin(v, slider->maximum); - int pos = sliderPositionFromValue(slider->minimum, slider->maximum, - v_, (horizontal - ? slider->rect.width() - : slider->rect.height()) - len, - slider->upsideDown) + len / 2; - int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0); - - if (horizontal) { - if (ticksAbove) { - painter->drawLine(pos, slider->rect.top() + extra, - pos, slider->rect.top() + tickSize); - } - if (ticksBelow) { - painter->drawLine(pos, slider->rect.bottom() - extra, - pos, slider->rect.bottom() - tickSize); - } - } else { - if (ticksAbove) { - painter->drawLine(slider->rect.left() + extra, pos, - slider->rect.left() + tickSize, pos); - } - if (ticksBelow) { - painter->drawLine(slider->rect.right() - extra, pos, - slider->rect.right() - tickSize, pos); - } - } - // in the case where maximum is max int - int nextInterval = v + interval; - if (nextInterval < v) - break; - v = nextInterval; - } - } - painter->setBrush(oldBrush); - painter->setPen(oldPen); - } - break; -#endif // QT_NO_SLIDER -#ifndef QT_NO_DIAL - case CC_Dial: - if (const QStyleOptionSlider *dial = qstyleoption_cast(option)) - QStyleHelper::drawDial(dial, painter); - break; -#endif // QT_NO_DIAL - default: - QWindowsStyle::drawComplexControl(control, option, painter, widget); - break; - } -} - -/*! - \reimp -*/ -int QCleanlooksStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const -{ - int ret = -1; - switch (metric) { - case PM_ToolTipLabelFrameWidth: - ret = 2; - break; - case PM_ButtonDefaultIndicator: - ret = 0; - break; - case PM_ButtonShiftHorizontal: - case PM_ButtonShiftVertical: - ret = 0; - break; - case PM_MessageBoxIconSize: - ret = 48; - break; - case PM_ListViewIconSize: - ret = 24; - break; - case PM_DialogButtonsSeparator: - case PM_SplitterWidth: - ret = 6; - break; - case PM_ScrollBarSliderMin: - ret = 26; - break; - case PM_MenuPanelWidth: //menu framewidth - ret = 2; - break; - case PM_TitleBarHeight: - ret = 24; - break; - case PM_ScrollBarExtent: - ret = 15; - break; - case PM_SliderThickness: - ret = 15; - break; - case PM_SliderLength: - ret = 27; - break; - case PM_DockWidgetTitleMargin: - ret = 1; - break; - case PM_MenuBarVMargin: - ret = 1; - break; - case PM_DefaultFrameWidth: - ret = 2; - break; - case PM_SpinBoxFrameWidth: - ret = 3; - break; - case PM_MenuBarItemSpacing: - ret = 6; - break; - case PM_MenuBarHMargin: - ret = 0; - break; - case PM_ToolBarHandleExtent: - ret = 9; - break; - case PM_ToolBarItemSpacing: - ret = 2; - break; - case PM_ToolBarFrameWidth: - ret = 0; - break; - case PM_ToolBarItemMargin: - ret = 1; - break; - case PM_SmallIconSize: - ret = 16; - break; - case PM_ButtonIconSize: - ret = 24; - break; - case PM_MenuVMargin: - case PM_MenuHMargin: - ret = 0; - break; - case PM_DockWidgetTitleBarButtonMargin: - ret = 4; - break; - case PM_MaximumDragDistance: - return -1; - case PM_TabCloseIndicatorWidth: - case PM_TabCloseIndicatorHeight: - return 20; - default: - break; - } - - return ret != -1 ? ret : QWindowsStyle::pixelMetric(metric, option, widget); -} - -/*! - \reimp -*/ -QSize QCleanlooksStyle::sizeFromContents(ContentsType type, const QStyleOption *option, - const QSize &size, const QWidget *widget) const -{ - QSize newSize = QWindowsStyle::sizeFromContents(type, option, size, widget); - switch (type) { - case CT_PushButton: - if (const QStyleOptionButton *btn = qstyleoption_cast(option)) { - if (!btn->text.isEmpty() && newSize.width() < 80) - newSize.setWidth(80); - if (!btn->icon.isNull() && btn->iconSize.height() > 16) - newSize -= QSize(0, 2); - newSize += QSize(0, 1); - } - break; -#ifndef QT_NO_GROUPBOX - case CT_GroupBox: - // Since we use a bold font we have to recalculate base width - if (const QGroupBox *gb = qobject_cast(widget)) { - QFont font = gb->font(); - font.setBold(true); - QFontMetrics metrics(font); - int baseWidth = metrics.width(gb->title()) + metrics.width(QLatin1Char(' ')); - if (gb->isCheckable()) { - baseWidth += proxy()->pixelMetric(QStyle::PM_IndicatorWidth, option, widget); - baseWidth += proxy()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, option, widget); - } - newSize.setWidth(qMax(baseWidth, newSize.width())); - } - newSize += QSize(0, 1); - break; -#endif //QT_NO_GROUPBOX - case CT_RadioButton: - case CT_CheckBox: - newSize += QSize(0, 1); - break; - case CT_ToolButton: -#ifndef QT_NO_TOOLBAR - if (widget && qobject_cast(widget->parentWidget())) - newSize += QSize(4, 6); -#endif // QT_NO_TOOLBAR - break; - case CT_SpinBox: - newSize += QSize(0, -2); - break; - case CT_ComboBox: - newSize += QSize(2, 4); - break; - case CT_LineEdit: - newSize += QSize(0, 4); - break; - case CT_MenuBarItem: - newSize += QSize(0, 2); - break; - case CT_MenuItem: - if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(option)) { - if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { - if (!menuItem->text.isEmpty()) { - newSize.setHeight(menuItem->fontMetrics.height()); - } - } -#ifndef QT_NO_COMBOBOX - else if (!menuItem->icon.isNull()) { - if (const QComboBox *combo = qobject_cast(widget)) { - newSize.setHeight(qMax(combo->iconSize().height() + 2, newSize.height())); - } - } -#endif // QT_NO_COMBOBOX - } - break; - case CT_SizeGrip: - newSize += QSize(4, 4); - break; - case CT_MdiControls: - if (const QStyleOptionComplex *styleOpt = qstyleoption_cast(option)) { - int width = 0; - if (styleOpt->subControls & SC_MdiMinButton) - width += 19 + 1; - if (styleOpt->subControls & SC_MdiNormalButton) - width += 19 + 1; - if (styleOpt->subControls & SC_MdiCloseButton) - width += 19 + 1; - newSize = QSize(width, 19); - } else { - newSize = QSize(60, 19); - } - break; - default: - break; - } - return newSize; -} - -/*! - \reimp -*/ -void QCleanlooksStyle::polish(QApplication *app) -{ - QWindowsStyle::polish(app); -} - -/*! - \reimp -*/ -void QCleanlooksStyle::polish(QWidget *widget) -{ - QWindowsStyle::polish(widget); - if (qobject_cast(widget) -#ifndef QT_NO_COMBOBOX - || qobject_cast(widget) -#endif -#ifndef QT_NO_PROGRESSBAR - || qobject_cast(widget) -#endif -#ifndef QT_NO_SCROLLBAR - || qobject_cast(widget) -#endif -#ifndef QT_NO_SPLITTER - || qobject_cast(widget) -#endif - || qobject_cast(widget) -#ifndef QT_NO_SPINBOX - || qobject_cast(widget) -#endif - || (widget->inherits("QDockSeparator")) - || (widget->inherits("QDockWidgetSeparator")) - ) { - widget->setAttribute(Qt::WA_Hover, true); - } -} - -/*! - \reimp -*/ -void QCleanlooksStyle::polish(QPalette &pal) -{ - QWindowsStyle::polish(pal); - //this is a workaround for some themes such as Human, where the contrast - //between text and background is too low. - QColor highlight = pal.highlight().color(); - QColor highlightText = pal.highlightedText().color(); - if (qAbs(qGray(highlight.rgb()) - qGray(highlightText.rgb())) < 150) { - if (qGray(highlightText.rgb()) < 128) - pal.setBrush(QPalette::Highlight, highlight.lighter(145)); - } -} - -/*! - \reimp -*/ -void QCleanlooksStyle::unpolish(QWidget *widget) -{ - QWindowsStyle::unpolish(widget); - if (qobject_cast(widget) -#ifndef QT_NO_COMBOBOX - || qobject_cast(widget) -#endif -#ifndef QT_NO_PROGRESSBAR - || qobject_cast(widget) -#endif -#ifndef QT_NO_SCROLLBAR - || qobject_cast(widget) -#endif -#ifndef QT_NO_SPLITTER - || qobject_cast(widget) -#endif - || qobject_cast(widget) -#ifndef QT_NO_SPINBOX - || qobject_cast(widget) -#endif - || (widget->inherits("QDockSeparator")) - || (widget->inherits("QDockWidgetSeparator")) - ) { - widget->setAttribute(Qt::WA_Hover, false); - } -} - -/*! - \reimp -*/ -void QCleanlooksStyle::unpolish(QApplication *app) -{ - QWindowsStyle::unpolish(app); -} - -/*! - \reimp -*/ -QRect QCleanlooksStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, - SubControl subControl, const QWidget *widget) const -{ - QRect rect = QWindowsStyle::subControlRect(control, option, subControl, widget); - - switch (control) { -#ifndef QT_NO_SLIDER - case CC_Slider: - if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { - int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); - switch (subControl) { - case SC_SliderHandle: { - if (slider->orientation == Qt::Horizontal) { - rect.setHeight(proxy()->pixelMetric(PM_SliderThickness)); - rect.setWidth(proxy()->pixelMetric(PM_SliderLength)); - int centerY = slider->rect.center().y() - rect.height() / 2; - if (slider->tickPosition & QSlider::TicksAbove) - centerY += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - centerY -= tickSize; - rect.moveTop(centerY); - } else { - rect.setWidth(proxy()->pixelMetric(PM_SliderThickness)); - rect.setHeight(proxy()->pixelMetric(PM_SliderLength)); - int centerX = slider->rect.center().x() - rect.width() / 2; - if (slider->tickPosition & QSlider::TicksAbove) - centerX += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - centerX -= tickSize; - rect.moveLeft(centerX); - } - } - break; - case SC_SliderGroove: { - QPoint grooveCenter = slider->rect.center(); - if (slider->orientation == Qt::Horizontal) { - rect.setHeight(7); - if (slider->tickPosition & QSlider::TicksAbove) - grooveCenter.ry() += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - grooveCenter.ry() -= tickSize; - } else { - rect.setWidth(7); - if (slider->tickPosition & QSlider::TicksAbove) - grooveCenter.rx() += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - grooveCenter.rx() -= tickSize; - } - rect.moveCenter(grooveCenter); - break; - } - default: - break; - } - } - break; -#endif // QT_NO_SLIDER - case CC_ScrollBar: - break; -#ifndef QT_NO_SPINBOX - case CC_SpinBox: - if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast(option)) { - QSize bs; - int center = spinbox->rect.height() / 2; - int fw = spinbox->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0; - int y = fw; - bs.setHeight(qMax(8, spinbox->rect.height()/2 - y)); - bs.setWidth(15); - int x, lx, rx; - x = spinbox->rect.width() - y - bs.width() + 2; - lx = fw; - rx = x - fw; - switch (subControl) { - case SC_SpinBoxUp: - if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) - return QRect(); - rect = QRect(x, fw, bs.width(), center - fw); - break; - case SC_SpinBoxDown: - if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) - return QRect(); - - rect = QRect(x, center, bs.width(), spinbox->rect.bottom() - center - fw + 1); - break; - case SC_SpinBoxEditField: - if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) { - rect = QRect(lx, fw, spinbox->rect.width() - 2*fw, spinbox->rect.height() - 2*fw); - } else { - rect = QRect(lx, fw, rx - qMax(fw - 1, 0), spinbox->rect.height() - 2*fw); - } - break; - case SC_SpinBoxFrame: - rect = spinbox->rect; - default: - break; - } - rect = visualRect(spinbox->direction, spinbox->rect, rect); - } - break; -#endif // Qt_NO_SPINBOX -#ifndef QT_NO_GROUPBOX - case CC_GroupBox: - if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(option)) { - int topMargin = 0; - int topHeight = 0; - int verticalAlignment = proxy()->styleHint(SH_GroupBox_TextLabelVerticalAlignment, groupBox, widget); - bool flat = groupBox->features & QStyleOptionFrameV2::Flat; - if (!groupBox->text.isEmpty()) { - topHeight = groupBox->fontMetrics.height(); - if (verticalAlignment & Qt::AlignVCenter) - topMargin = topHeight / 2; - else if (verticalAlignment & Qt::AlignTop) - topMargin = topHeight; - } - QRect frameRect = groupBox->rect; - frameRect.setTop(topMargin); - if (subControl == SC_GroupBoxFrame) { - return rect; - } - else if (subControl == SC_GroupBoxContents) { - if( flat ) { - int margin = 0; - int leftMarginExtension = 16; - rect = frameRect.adjusted(leftMarginExtension + margin, margin + topHeight, -margin, -margin); - } - break; - } - if(flat) { - if (const QGroupBox *groupBoxWidget = qobject_cast(widget)) { - //Prepare metrics for a bold font - QFont font = widget->font(); - font.setBold(true); - QFontMetrics fontMetrics(font); - - QSize textRect = fontMetrics.boundingRect(groupBoxWidget->title()).size() + QSize(2, 2); - if (subControl == SC_GroupBoxCheckBox) { - int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); - int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); - rect.setWidth(indicatorWidth); - rect.setHeight(indicatorHeight); - rect.moveTop((fontMetrics.height() - indicatorHeight) / 2 + 2); - } else if (subControl == SC_GroupBoxLabel) { - rect.setSize(textRect); - } - } - } - } - return rect; -#ifndef QT_NO_COMBOBOX - case CC_ComboBox: - switch (subControl) { - case SC_ComboBoxArrow: - rect = visualRect(option->direction, option->rect, rect); - rect.setRect(rect.right() - 18, rect.top() - 2, - 19, rect.height() + 4); - rect = visualRect(option->direction, option->rect, rect); - break; - case SC_ComboBoxEditField: { - int frameWidth = proxy()->pixelMetric(PM_DefaultFrameWidth); - rect = visualRect(option->direction, option->rect, rect); - rect.setRect(option->rect.left() + frameWidth, option->rect.top() + frameWidth, - option->rect.width() - 19 - 2 * frameWidth, - option->rect.height() - 2 * frameWidth); - if (const QStyleOptionComboBox *box = qstyleoption_cast(option)) { - if (!box->editable) { - rect.adjust(2, 0, 0, 0); - if (box->state & (State_Sunken | State_On)) - rect.translate(1, 1); - } - } - rect = visualRect(option->direction, option->rect, rect); - break; - } - default: - break; - } - break; -#endif // QT_NO_COMBOBOX -#endif //QT_NO_GROUPBOX - case CC_TitleBar: - if (const QStyleOptionTitleBar *tb = qstyleoption_cast(option)) { - SubControl sc = subControl; - QRect &ret = rect; - const int indent = 3; - const int controlTopMargin = 3; - const int controlBottomMargin = 3; - const int controlWidthMargin = 2; - const int controlHeight = tb->rect.height() - controlTopMargin - controlBottomMargin ; - const int delta = controlHeight + controlWidthMargin; - int offset = 0; - - bool isMinimized = tb->titleBarState & Qt::WindowMinimized; - bool isMaximized = tb->titleBarState & Qt::WindowMaximized; - - switch (sc) { - case SC_TitleBarLabel: - if (tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) { - ret = tb->rect; - if (tb->titleBarFlags & Qt::WindowSystemMenuHint) - ret.adjust(delta, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) - ret.adjust(0, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) - ret.adjust(0, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowShadeButtonHint) - ret.adjust(0, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) - ret.adjust(0, 0, -delta, 0); - } - break; - case SC_TitleBarContextHelpButton: - if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) - offset += delta; - case SC_TitleBarMinButton: - if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarMinButton) - break; - case SC_TitleBarNormalButton: - if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)) - offset += delta; - else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarNormalButton) - break; - case SC_TitleBarMaxButton: - if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarMaxButton) - break; - case SC_TitleBarShadeButton: - if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarShadeButton) - break; - case SC_TitleBarUnshadeButton: - if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarUnshadeButton) - break; - case SC_TitleBarCloseButton: - if (tb->titleBarFlags & Qt::WindowSystemMenuHint) - offset += delta; - else if (sc == SC_TitleBarCloseButton) - break; - ret.setRect(tb->rect.right() - indent - offset, tb->rect.top() + controlTopMargin, - controlHeight, controlHeight); - break; - case SC_TitleBarSysMenu: - if (tb->titleBarFlags & Qt::WindowSystemMenuHint) { - ret.setRect(tb->rect.left() + controlWidthMargin + indent, tb->rect.top() + controlTopMargin, - controlHeight, controlHeight); - } - break; - default: - break; - } - ret = visualRect(tb->direction, tb->rect, ret); - } - break; - default: - break; - } - - return rect; -} - - -/*! - \reimp -*/ -QRect QCleanlooksStyle::itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const -{ - return QWindowsStyle::itemPixmapRect(r, flags, pixmap); -} - -/*! - \reimp -*/ -void QCleanlooksStyle::drawItemPixmap(QPainter *painter, const QRect &rect, - int alignment, const QPixmap &pixmap) const -{ - QWindowsStyle::drawItemPixmap(painter, rect, alignment, pixmap); -} - -/*! - \reimp -*/ -QStyle::SubControl QCleanlooksStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, - const QPoint &pt, const QWidget *w) const -{ - return QWindowsStyle::hitTestComplexControl(cc, opt, pt, w); -} - -/*! - \reimp -*/ -QPixmap QCleanlooksStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, - const QStyleOption *opt) const -{ - return QWindowsStyle::generatedIconPixmap(iconMode, pixmap, opt); -} - -/*! - \reimp -*/ -int QCleanlooksStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, - QStyleHintReturn *returnData) const -{ - int ret = 0; - switch (hint) { - case SH_ScrollBar_MiddleClickAbsolutePosition: - ret = true; - break; - case SH_EtchDisabledText: - ret = 1; - break; - case SH_Menu_AllowActiveAndDisabled: - ret = false; - break; - case SH_MainWindow_SpaceBelowMenuBar: - ret = 0; - break; - case SH_MenuBar_MouseTracking: - ret = 1; - break; - case SH_TitleBar_AutoRaise: - ret = 1; - break; - case SH_TitleBar_NoBorder: - ret = 1; - break; - case SH_ItemView_ShowDecorationSelected: - ret = true; - break; - case SH_Table_GridLineColor: - if (option) { - ret = option->palette.background().color().darker(120).rgb(); - break; - } - case SH_ComboBox_Popup: - if (const QStyleOptionComboBox *cmb = qstyleoption_cast(option)) - ret = !cmb->editable; - else - ret = 0; - break; - case SH_WindowFrame_Mask: - ret = 1; - if (QStyleHintReturnMask *mask = qstyleoption_cast(returnData)) { - //left rounded corner - mask->region = option->rect; - mask->region -= QRect(option->rect.left(), option->rect.top(), 5, 1); - mask->region -= QRect(option->rect.left(), option->rect.top() + 1, 3, 1); - mask->region -= QRect(option->rect.left(), option->rect.top() + 2, 2, 1); - mask->region -= QRect(option->rect.left(), option->rect.top() + 3, 1, 2); - - //right rounded corner - mask->region -= QRect(option->rect.right() - 4, option->rect.top(), 5, 1); - mask->region -= QRect(option->rect.right() - 2, option->rect.top() + 1, 3, 1); - mask->region -= QRect(option->rect.right() - 1, option->rect.top() + 2, 2, 1); - mask->region -= QRect(option->rect.right() , option->rect.top() + 3, 1, 2); - } - break; - case SH_MessageBox_TextInteractionFlags: - ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; - break; - case SH_DialogButtonBox_ButtonsHaveIcons: - ret = false; - break; - case SH_MessageBox_CenterButtons: - ret = false; - break; -#ifndef QT_NO_WIZARD - case SH_WizardStyle: - ret = QWizard::ClassicStyle; - break; -#endif - case SH_ItemView_ArrowKeysNavigateIntoChildren: - ret = false; - break; - case SH_Menu_SubMenuPopupDelay: - ret = 225; // default from GtkMenu - break; - default: - ret = QWindowsStyle::styleHint(hint, option, widget, returnData); - break; - } - return ret; -} - -/*! \reimp */ -QRect QCleanlooksStyle::subElementRect(SubElement sr, const QStyleOption *opt, const QWidget *w) const -{ - QRect r = QWindowsStyle::subElementRect(sr, opt, w); - switch (sr) { - case SE_PushButtonFocusRect: - r.adjust(0, 1, 0, -1); - break; - case SE_DockWidgetTitleBarText: { - const QStyleOptionDockWidgetV2 *v2 - = qstyleoption_cast(opt); - bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar; - if (verticalTitleBar) { - r.adjust(0, 0, 0, -4); - } else { - if (opt->direction == Qt::LeftToRight) - r.adjust(4, 0, 0, 0); - else - r.adjust(0, 0, -4, 0); - } - - break; - } - case SE_ProgressBarContents: - r = subElementRect(SE_ProgressBarGroove, opt, w); - break; - default: - break; - } - return r; -} - -/*! - \reimp -*/ -QIcon QCleanlooksStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, - const QWidget *widget) const -{ - return QWindowsStyle::standardIcon(standardIcon, option, widget); -} - -/*! - \reimp - */ -QPixmap QCleanlooksStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, - const QWidget *widget) const -{ - QPixmap pixmap; - -#ifndef QT_NO_IMAGEFORMAT_XPM - switch (standardPixmap) { - case SP_TitleBarNormalButton: - return QPixmap((const char **)dock_widget_restore_xpm); - case SP_TitleBarMinButton: - return QPixmap((const char **)workspace_minimize); - case SP_TitleBarCloseButton: - case SP_DockWidgetCloseButton: - return QPixmap((const char **)dock_widget_close_xpm); - - default: - break; - } -#endif //QT_NO_IMAGEFORMAT_XPM - - return QWindowsStyle::standardPixmap(standardPixmap, opt, widget); -} - -QT_END_NAMESPACE - -#endif // QT_NO_STYLE_CLEANLOOKS || QT_PLUGIN diff --git a/src/widgets/styles/qcleanlooksstyle.h b/src/widgets/styles/qcleanlooksstyle.h deleted file mode 100644 index 7e19032d22..0000000000 --- a/src/widgets/styles/qcleanlooksstyle.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QCLEANLOOKSSTYLE_H -#define QCLEANLOOKSSTYLE_H - -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - - -#if !defined(QT_NO_STYLE_CLEANLOOKS) - -class QCleanlooksStylePrivate; -class Q_WIDGETS_EXPORT QCleanlooksStyle : public QWindowsStyle -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QCleanlooksStyle) - -public: - QCleanlooksStyle(); - ~QCleanlooksStyle(); - - QPalette standardPalette () const; - void drawPrimitive(PrimitiveElement elem, - const QStyleOption *option, - QPainter *painter, const QWidget *widget = 0) const; - void drawControl(ControlElement ce, const QStyleOption *option, QPainter *painter, - const QWidget *widget) const; - int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const; - void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, - QPainter *painter, const QWidget *widget) const; - QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget = 0) const; - QSize sizeFromContents(ContentsType type, const QStyleOption *option, - const QSize &size, const QWidget *widget) const; - SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, - const QPoint &pt, const QWidget *w = 0) const; - QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, - SubControl sc, const QWidget *widget) const; - QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, - const QStyleOption *opt) const; - int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, - QStyleHintReturn *returnData = 0) const; - QRect itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const; - QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = 0, - const QWidget *widget = 0) const; - QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, - const QWidget *widget = 0) const; - void drawItemPixmap(QPainter *painter, const QRect &rect, - int alignment, const QPixmap &pixmap) const; - void drawItemText(QPainter *painter, const QRect &rect, - int flags, const QPalette &pal, bool enabled, - const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; - void polish(QWidget *widget); - void polish(QApplication *app); - void polish(QPalette &pal); - void unpolish(QWidget *widget); - void unpolish(QApplication *app); - -protected: - QCleanlooksStyle(QCleanlooksStylePrivate &dd); - -}; - -#endif // QT_NO_STYLE_CLEANLOOKS - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QCLEANLOOKSSTYLE_H diff --git a/src/widgets/styles/qcleanlooksstyle_p.h b/src/widgets/styles/qcleanlooksstyle_p.h deleted file mode 100644 index 5a6bef5fe7..0000000000 --- a/src/widgets/styles/qcleanlooksstyle_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QCLEANLOOKSSTYLE_P_H -#define QCLEANLOOKSSTYLE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header -// file may change from version to version without notice, or even be removed. -// -// We mean it. -// - -#include "qwindowsstyle.h" -#include "qwindowsstyle_p.h" - -#ifndef QT_NO_STYLE_CLEANLOOKS - -QT_BEGIN_NAMESPACE - -class QCleanlooksStylePrivate : public QWindowsStylePrivate -{ - Q_DECLARE_PUBLIC(QCleanlooksStyle) -public: - QCleanlooksStylePrivate() - : QWindowsStylePrivate() { - } - - ~QCleanlooksStylePrivate() { - } -}; - -QT_END_NAMESPACE - -#endif // QT_NO_STYLE_CLEANLOOKS - -#endif //QCLEANLOOKSSTYLE_P_H diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 3fc4cd0f1f..8e52a4b425 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -350,7 +350,7 @@ QFusionStylePrivate::QFusionStylePrivate() The Fusion style provides a custom look and feel that is not tied to a particular platform. //{Fusion Style Widget Gallery} - \sa QWindowsXPStyle, QMacStyle, QCommonStyle, QPlastiqueStyle + \sa QWindowsStyle, QWindowsVistaStyle, QMacStyle, QCommonStyle */ /*! @@ -3024,7 +3024,7 @@ QSize QFusionStyle::sizeFromContents(ContentsType type, const QStyleOption *opti newSize += QSize(2, 2); break; case CT_SpinBox: - newSize += QSize(0, -2); + newSize += QSize(0, -3); break; case CT_ComboBox: newSize += QSize(2, 4); @@ -3478,7 +3478,7 @@ int QFusionStyle::styleHint(StyleHint hint, const QStyleOption *option, const QW return 0; case SH_Table_GridLineColor: - return option->palette.background().color().darker(120).rgb(); + return option ? option->palette.background().color().darker(120).rgb() : 0; case SH_MessageBox_TextInteractionFlags: return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; diff --git a/src/widgets/styles/qgtkstyle.cpp b/src/widgets/styles/qgtkstyle.cpp index e9701f9d6f..4a7f972436 100644 --- a/src/widgets/styles/qgtkstyle.cpp +++ b/src/widgets/styles/qgtkstyle.cpp @@ -277,8 +277,7 @@ static GdkColor fromQColor(const QColor &color) Note: The style requires GTK+ version 2.10 or later. The Qt3-based "Qt" GTK+ theme engine will not work with QGtkStyle. - \sa {Cleanlooks Style Widget Gallery}, QWindowsXPStyle, QMacStyle, QWindowsStyle, - QPlastiqueStyle, QCleanlooksStyle + \sa QWindowsXPStyle, QMacStyle, QWindowsStyle, QFusionStyle */ /*! diff --git a/src/widgets/styles/qmacstyle.qdoc b/src/widgets/styles/qmacstyle.qdoc index e419f7360a..001f45b919 100644 --- a/src/widgets/styles/qmacstyle.qdoc +++ b/src/widgets/styles/qmacstyle.qdoc @@ -81,7 +81,7 @@ documentation. \image qmacstyle.png - \sa QWindowsXPStyle, QWindowsStyle, QPlastiqueStyle + \sa QWindowsXPStyle, QWindowsStyle, QFusionStyle */ diff --git a/src/widgets/styles/qplastiquestyle.cpp b/src/widgets/styles/qplastiquestyle.cpp deleted file mode 100644 index 449783fb90..0000000000 --- a/src/widgets/styles/qplastiquestyle.cpp +++ /dev/null @@ -1,5843 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qplastiquestyle.h" - -#if !defined(QT_NO_STYLE_PLASTIQUE) || defined(QT_PLUGIN) - -static const bool AnimateBusyProgressBar = true; -static const bool AnimateProgressBar = false; -// #define QPlastique_MaskButtons -static const int ProgressBarFps = 25; -static const int blueFrameWidth = 2; // with of line edit focus frame - -#include "qwindowsstyle_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -// from windows style -static const int windowsItemFrame = 2; // menu item frame width -static const int windowsSepHeight = 2; // separator item height -static const int windowsItemHMargin = 3; // menu item hor text margin -static const int windowsItemVMargin = 2; // menu item ver text margin -static const int windowsArrowHMargin = 6; // arrow horizontal margin -static const int windowsTabSpacing = 12; // space between text and tab -static const int windowsRightBorder = 15; // right border on windows -static const int windowsCheckMarkWidth = 12; // checkmarks width on windows - -static const char * const qt_plastique_slider_verticalhandle[] = { - "15 11 6 1", - " c None", - "+ c #979797", - "@ c #C9C9C9", - "$ c #C1C1C1", - "b c None", - "d c None", - " $++++++++$ ", - "$+bbbbbbbb+$ ", - "+b $$ +$ ", - "+b $@ +$ ", - "+b +$", - "+b d+", - "+b d+$", - "+b $$ d+$ ", - "+b $@ d+$ ", - "$+dddddddd+$ ", - " $++++++++$ "}; - -static const char * const qt_plastique_slider_verticalhandle_left[] = { - "15 11 6 1", - " c None", - "+ c #979797", - "@ c #C9C9C9", - "$ c #C1C1C1", - "b c None", - "d c None", - " $++++++++$ ", - " $+bbbbbbbb+$", - " $+b $$ d+", - " $+b $@ d+", - "$+b d+", - "+b d+", - "$+ d+", - " $+ $$ d+", - " $+ $@ d+", - " $+dddddddd+$", - " $++++++++$ "}; - -static const char * const qt_plastique_slider_horizontalhandle[] = { - "11 15 6 1", - " c None", - "+ c #979797", - "@ c #C9C9C9", - "$ c #C1C1C1", - "b c None", - "d c None", - " $+++++++$ ", - "$+bbbbbbb+$", - "+b d+", - "+b$$ $$d+", - "+b$@ $@d+", - "+b d+", - "+b d+", - "+b d+", - "+b d+", - "+b d+", - "$+ d+$", - " $+ d+$ ", - " $+ d+$ ", - " $+d+$ ", - " $+$ "}; - -static const char * const qt_plastique_slider_horizontalhandle_up[] = { - "11 15 6 1", - " c None", - "+ c #979797", - "@ c #C9C9C9", - "$ c #C1C1C1", - "b c None", - "d c None", - " $+$ ", - " $+b+$ ", - " $+b +$ ", - " $+b +$ ", - "$+b +$", - "+b d+", - "+b d+", - "+b d+", - "+b d+", - "+b d+", - "+b$$ $$d+", - "+b$@ $@d+", - "+b d+", - "$+ddddddd+$", - " $+++++++$ "}; - -static const char * const qt_scrollbar_button_arrow_left[] = { - "4 7 2 1", - " c None", - "* c #BFBFBF", - " *", - " **", - " ***", - "****", - " ***", - " **", - " *"}; - -static const char * const qt_scrollbar_button_arrow_right[] = { - "4 7 2 1", - " c None", - "* c #BFBFBF", - "* ", - "** ", - "*** ", - "****", - "*** ", - "** ", - "* "}; - -static const char * const qt_scrollbar_button_arrow_up[] = { - "7 4 2 1", - " c None", - "* c #BFBFBF", - " * ", - " *** ", - " ***** ", - "*******"}; - -static const char * const qt_scrollbar_button_arrow_down[] = { - "7 4 2 1", - " c None", - "* c #BFBFBF", - "*******", - " ***** ", - " *** ", - " * "}; - -static const char * const qt_scrollbar_button_left[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - " .+++++++++++++.", - ".+#############+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - ".+<<<<<<<<<<<<<+", - " .+++++++++++++."}; - -static const char * const qt_scrollbar_button_right[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - ".+++++++++++++. ", - "+#############+.", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+<<<<<<<<<<<<<+.", - ".+++++++++++++. "}; - -static const char * const qt_scrollbar_button_up[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - " .++++++++++++. ", - ".+############+.", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+<<<<<<<<<<<<<<+", - ".++++++++++++++."}; - -static const char * const qt_scrollbar_button_down[] = { - "16 16 6 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - "# c #FAFAFA", - "< c #FAFAFA", - "* c #FAFAFA", - "++++++++++++++++", - "+##############+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - "+# <+", - ".+<<<<<<<<<<<<+.", - " .++++++++++++. "}; - -static const char * const qt_scrollbar_slider_pattern_vertical[] = { - "10 18 3 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - ".. .. ..", - ".+ .+ .+", - " ", - " ", - ".. .. ..", - ".+ .+ .+", - " ", - " ", - ".. .. ..", - ".+ .+ .+", - " ", - " ", - ".. .. ..", - ".+ .+ .+", - " ", - " ", - ".. .. ..", - ".+ .+ .+"}; - -static const char * const qt_scrollbar_slider_pattern_horizontal[] = { - "18 10 3 1", - " c None", - ". c #BFBFBF", - "+ c #979797", - ".. .. .. .. ..", - ".+ .+ .+ .+ .+", - " ", - " ", - ".. .. .. .. ..", - ".+ .+ .+ .+ .+", - " ", - " ", - ".. .. .. .. ..", - ".+ .+ .+ .+ .+"}; - -static const char * const qt_toolbarhandle[] = { - "6 6 4 1", - " c None", - ". c #C5C5C5", - "+ c #EEEEEE", - "@ c #FAFAFA", - ".. ", - ".+@ ", - " @@ ", - " .. ", - " .+@", - " @@"}; - -static const char * const qt_simple_toolbarhandle[] = { - "3 3 4 1", - " c None", - ". c #C5C5C5", - "+ c #EEEEEE", - "@ c #FAFAFA", - ".. ", - ".+@", - " @@"}; - -static const char * const qt_titlebar_context_help[] = { -"27 27 5 1", -" c None", -". c #0A0C12", -"+ c #1B202D", -"@ c #293144", -"# c #3C435D", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" +@##@+ ", -" .@@@.+@@.. ", -" .##+ +@@+. ", -" .##@ @#@+. ", -" .... +@+.. ", -" .@+@@.. ", -" +#@@+ ", -" .##. ", -" .++. ", -" .++. ", -" +##+ ", -" .@@. ", -" ", -" ", -" ", -" ", -" ", -" ", -" "}; - -static QLinearGradient qMapGradientToRect(const QLinearGradient &gradient, const QRectF &rect) -{ - QLinearGradient tmpGrad(rect.center().x(), rect.top(), - rect.center().x(), rect.bottom()); - tmpGrad.setStops(gradient.stops()); - return tmpGrad; -} - -static QBrush qMapBrushToRect(const QBrush &brush, const QRectF &rect) -{ - if (!brush.gradient()) - return brush; - - // ### Ugly assumption that it's a linear gradient - QBrush tmp(qMapGradientToRect(*static_cast(brush.gradient()), rect)); - return tmp; -} - -static void qBrushSetAlphaF(QBrush *brush, qreal alpha) -{ - if (const QGradient *gradient = brush->gradient()) { - // Use the gradient. Call QColor::setAlphaF() on all color stops. - QGradientStops stops = gradient->stops(); - QMutableVectorIterator it(stops); - QColor tmpColor; - while (it.hasNext()) { - it.next(); - tmpColor = it.value().second; - tmpColor.setAlphaF(alpha * tmpColor.alphaF()); - it.setValue(QPair(it.value().first, tmpColor)); - } - - switch (gradient->type()) { - case QGradient::RadialGradient: { - QRadialGradient grad = *static_cast(gradient); - grad.setStops(stops); - *brush = QBrush(grad); - break; - } - case QGradient::ConicalGradient: { - QConicalGradient grad = *static_cast(gradient); - grad.setStops(stops); - *brush = QBrush(grad); - break; - } - default: - qWarning("QPlastiqueStyle::qBrushLight() - unknown gradient type" - " - falling back to QLinearGradient"); - case QGradient::LinearGradient: { - QLinearGradient grad = *static_cast(gradient); - grad.setStops(stops); - *brush = QBrush(grad); - break; - } - } - } else if (!brush->texture().isNull()) { - // Modify the texture - ridiculously expensive. - QPixmap texture = brush->texture(); - QPixmap pixmap; - QString name = QLatin1String("qbrushtexture-alpha") - % HexString(alpha) - % HexString(texture.cacheKey()); - if (!QPixmapCache::find(name, pixmap)) { - QImage image = texture.toImage(); - QRgb *rgb = reinterpret_cast(image.bits()); - int pixels = image.width() * image.height(); - QColor tmpColor; - while (pixels--) { - tmpColor.setRgb(*rgb); - tmpColor.setAlphaF(alpha * tmpColor.alphaF()); - *rgb++ = tmpColor.rgba(); - } - pixmap = QPixmap::fromImage(image); - QPixmapCache::insert(name, pixmap); - } - brush->setTexture(pixmap); - } else { - // Use the color - QColor tmpColor = brush->color(); - tmpColor.setAlphaF(alpha * tmpColor.alphaF()); - brush->setColor(tmpColor); - } -} - -static QBrush qBrushLight(QBrush brush, int light) -{ - if (const QGradient *gradient = brush.gradient()) { - // Use the gradient. Call QColor::lighter() on all color stops. - QGradientStops stops = gradient->stops(); - QMutableVectorIterator it(stops); - while (it.hasNext()) { - it.next(); - it.setValue(QPair(it.value().first, it.value().second.lighter(light))); - } - - switch (gradient->type()) { - case QGradient::RadialGradient: { - QRadialGradient grad = *static_cast(gradient); - grad.setStops(stops); - brush = QBrush(grad); - break; - } - case QGradient::ConicalGradient: { - QConicalGradient grad = *static_cast(gradient); - grad.setStops(stops); - brush = QBrush(grad); - break; - } - default: - qWarning("QPlastiqueStyle::qBrushLight() - unknown gradient type" - " - falling back to QLinearGradient"); - case QGradient::LinearGradient: { - QLinearGradient grad = *static_cast(gradient); - grad.setStops(stops); - brush = QBrush(grad); - break; - } - } - } else if (!brush.texture().isNull()) { - // Modify the texture - ridiculously expensive. - QPixmap texture = brush.texture(); - QPixmap pixmap; - QString name = QLatin1String("qbrushtexture-light") - % HexString(light) - % HexString(texture.cacheKey()); - - if (!QPixmapCache::find(name, pixmap)) { - QImage image = texture.toImage(); - QRgb *rgb = reinterpret_cast(image.bits()); - int pixels = image.width() * image.height(); - QColor tmpColor; - while (pixels--) { - tmpColor.setRgb(*rgb); - *rgb++ = tmpColor.lighter(light).rgba(); - } - pixmap = QPixmap::fromImage(image); - QPixmapCache::insert(name, pixmap); - } - brush.setTexture(pixmap); - } else { - // Use the color - brush.setColor(brush.color().lighter(light)); - } - return brush; -} - -static QBrush qBrushDark(QBrush brush, int dark) -{ - if (const QGradient *gradient = brush.gradient()) { - // Use the gradient. Call QColor::darker() on all color stops. - QGradientStops stops = gradient->stops(); - QMutableVectorIterator it(stops); - while (it.hasNext()) { - it.next(); - it.setValue(QPair(it.value().first, it.value().second.darker(dark))); - } - - switch (gradient->type()) { - case QGradient::RadialGradient: { - QRadialGradient grad = *static_cast(gradient); - grad.setStops(stops); - brush = QBrush(grad); - break; - } - case QGradient::ConicalGradient: { - QConicalGradient grad = *static_cast(gradient); - grad.setStops(stops); - brush = QBrush(grad); - break; - } - default: - qWarning("QPlastiqueStyle::qBrushDark() - unknown gradient type" - " - falling back to QLinearGradient"); - case QGradient::LinearGradient: { - QLinearGradient grad = *static_cast(gradient); - grad.setStops(stops); - brush = QBrush(grad); - break; - } - } - } else if (!brush.texture().isNull()) { - // Modify the texture - ridiculously expensive. - QPixmap texture = brush.texture(); - QPixmap pixmap; - QString name = QLatin1String("qbrushtexture-dark") - % HexString(dark) - % HexString(texture.cacheKey()); - - if (!QPixmapCache::find(name, pixmap)) { - QImage image = texture.toImage(); - QRgb *rgb = reinterpret_cast(image.bits()); - int pixels = image.width() * image.height(); - QColor tmpColor; - while (pixels--) { - tmpColor.setRgb(*rgb); - *rgb++ = tmpColor.darker(dark).rgba(); - } - pixmap = QPixmap::fromImage(image); - QPixmapCache::insert(name, pixmap); - } - brush.setTexture(pixmap); - } else { - // Use the color - brush.setColor(brush.color().darker(dark)); - } - return brush; -} - -/* - Draws a rounded frame using the provided brush for 1, and adds 0.5 alpha - for 0. - - 0111111110 - 01 10 - 1 1 - 1 1 - 1 1 - 01 10 - 0111111110 -*/ -static void qt_plastique_draw_frame(QPainter *painter, const QRect &rect, const QStyleOption *option, - QFrame::Shadow shadow = QFrame::Plain) -{ - QPen oldPen = painter->pen(); - QBrush border; - QBrush corner; - QBrush innerTopLeft; - QBrush innerBottomRight; - - if (shadow != QFrame::Plain && (option->state & QStyle::State_HasFocus)) { - border = option->palette.highlight(); - qBrushSetAlphaF(&border, qreal(0.8)); - corner = option->palette.highlight(); - qBrushSetAlphaF(&corner, 0.5); - innerTopLeft = qBrushDark(option->palette.highlight(), 125); - innerBottomRight = option->palette.highlight(); - qBrushSetAlphaF(&innerBottomRight, qreal(0.65)); - } else { - border = option->palette.shadow(); - qBrushSetAlphaF(&border, qreal(0.4)); - corner = option->palette.shadow(); - qBrushSetAlphaF(&corner, 0.25); - innerTopLeft = option->palette.shadow(); - innerBottomRight = option->palette.shadow(); - if (shadow == QFrame::Sunken) { - qBrushSetAlphaF(&innerTopLeft, qreal(0.23)); - qBrushSetAlphaF(&innerBottomRight, qreal(0.075)); - } else { - qBrushSetAlphaF(&innerTopLeft, qreal(0.075)); - qBrushSetAlphaF(&innerBottomRight, qreal(0.23)); - } - } - - QLine lines[4]; - QPoint points[8]; - - // Opaque corner lines - painter->setPen(QPen(border, 0)); - lines[0] = QLine(rect.left() + 2, rect.top(), rect.right() - 2, rect.top()); - lines[1] = QLine(rect.left() + 2, rect.bottom(), rect.right() - 2, rect.bottom()); - lines[2] = QLine(rect.left(), rect.top() + 2, rect.left(), rect.bottom() - 2); - lines[3] = QLine(rect.right(), rect.top() + 2, rect.right(), rect.bottom() - 2); - painter->drawLines(lines, 4); - - // Opaque corner dots - points[0] = QPoint(rect.left() + 1, rect.top() + 1); - points[1] = QPoint(rect.left() + 1, rect.bottom() - 1); - points[2] = QPoint(rect.right() - 1, rect.top() + 1); - points[3] = QPoint(rect.right() - 1, rect.bottom() - 1); - painter->drawPoints(points, 4); - - // Shaded corner dots - painter->setPen(QPen(corner, 0)); - points[0] = QPoint(rect.left(), rect.top() + 1); - points[1] = QPoint(rect.left(), rect.bottom() - 1); - points[2] = QPoint(rect.left() + 1, rect.top()); - points[3] = QPoint(rect.left() + 1, rect.bottom()); - points[4] = QPoint(rect.right(), rect.top() + 1); - points[5] = QPoint(rect.right(), rect.bottom() - 1); - points[6] = QPoint(rect.right() - 1, rect.top()); - points[7] = QPoint(rect.right() - 1, rect.bottom()); - painter->drawPoints(points, 8); - - // Shadows - if (shadow != QFrame::Plain) { - painter->setPen(QPen(innerTopLeft, 0)); - lines[0] = QLine(rect.left() + 2, rect.top() + 1, rect.right() - 2, rect.top() + 1); - lines[1] = QLine(rect.left() + 1, rect.top() + 2, rect.left() + 1, rect.bottom() - 2); - painter->drawLines(lines, 2); - painter->setPen(QPen(innerBottomRight, 0)); - lines[0] = QLine(rect.left() + 2, rect.bottom() - 1, rect.right() - 2, rect.bottom() - 1); - lines[1] = QLine(rect.right() - 1, rect.top() + 2, rect.right() - 1, rect.bottom() - 2); - painter->drawLines(lines, 2); - } - - painter->setPen(oldPen); -} - -static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50) -{ - const int maxFactor = 100; - QColor tmp = colorA; - tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor); - tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor); - tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor); - return tmp; -} - -static void qt_plastique_draw_gradient(QPainter *painter, const QRect &rect, const QColor &gradientStart, - const QColor &gradientStop) -{ - QString gradientName = QLatin1String("qplastique-g") - % HexString(rect.width()) - % HexString(rect.height()) - % HexString(gradientStart.rgba()) - % HexString(gradientStop.rgba()); - - QPixmap cache; - QPainter *p = painter; - QRect r = rect; - - bool doPixmapCache = painter->deviceTransform().isIdentity() - && painter->worldMatrix().isIdentity(); - if (doPixmapCache && QPixmapCache::find(gradientName, cache)) { - painter->drawPixmap(rect, cache); - } else { - if (doPixmapCache) { - cache = QPixmap(rect.size()); - cache.fill(Qt::transparent); - p = new QPainter(&cache); - r = QRect(0, 0, rect.width(), rect.height()); - } - - int x = r.center().x(); - QLinearGradient gradient(x, r.top(), x, r.bottom()); - gradient.setColorAt(0, gradientStart); - gradient.setColorAt(1, gradientStop); - p->fillRect(r, gradient); - - if (doPixmapCache) { - p->end(); - delete p; - painter->drawPixmap(rect, cache); - QPixmapCache::insert(gradientName, cache); - } - } -} - -static void qt_plastique_drawFrame(QPainter *painter, const QStyleOption *option, const QWidget *widget) -{ - QRect rect = option->rect; - QPen oldPen = painter->pen(); - - QColor borderColor = option->palette.background().color().darker(178); - QColor gradientStartColor = option->palette.button().color().lighter(104); - QColor gradientStopColor = option->palette.button().color().darker(105); - QColor alphaCornerColor; - if (widget) { - // ### backgroundrole/foregroundrole should be part of the style option - alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), borderColor); - } else { - alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); - } - - QLine lines[4]; - QPoint points[8]; - - // outline / border - painter->setPen(borderColor); - lines[0] = QLine(rect.left() + 2, rect.top(), rect.right() - 2, rect.top()); - lines[1] = QLine(rect.left() + 2, rect.bottom(), rect.right() - 2, rect.bottom()); - lines[2] = QLine(rect.left(), rect.top() + 2, rect.left(), rect.bottom() - 2); - lines[3] = QLine(rect.right(), rect.top() + 2, rect.right(), rect.bottom() - 2); - painter->drawLines(lines, 4); - - points[0] = QPoint(rect.left() + 1, rect.top() + 1); - points[1] = QPoint(rect.right() - 1, rect.top() + 1); - points[2] = QPoint(rect.left() + 1, rect.bottom() - 1); - points[3] = QPoint(rect.right() - 1, rect.bottom() - 1); - painter->drawPoints(points, 4); - - painter->setPen(alphaCornerColor); - - points[0] = QPoint(rect.left() + 1, rect.top()); - points[1] = QPoint(rect.right() - 1, rect.top()); - points[2] = QPoint(rect.left() + 1, rect.bottom()); - points[3] = QPoint(rect.right() - 1, rect.bottom()); - points[4] = QPoint(rect.left(), rect.top() + 1); - points[5] = QPoint(rect.right(), rect.top() + 1); - points[6] = QPoint(rect.left(), rect.bottom() - 1); - points[7] = QPoint(rect.right(), rect.bottom() - 1); - painter->drawPoints(points, 8); - - // inner border - if ((option->state & QStyle::State_Sunken) || (option->state & QStyle::State_On)) - painter->setPen(option->palette.button().color().darker(118)); - else - painter->setPen(gradientStartColor); - - lines[0] = QLine(rect.left() + 2, rect.top() + 1, rect.right() - 2, option->rect.top() + 1); - lines[1] = QLine(rect.left() + 1, rect.top() + 2, rect.left() + 1, option->rect.bottom() - 2); - painter->drawLines(lines, 2); - - if ((option->state & QStyle::State_Sunken) || (option->state & QStyle::State_On)) - painter->setPen(option->palette.button().color().darker(110)); - else - painter->setPen(gradientStopColor.darker(102)); - - lines[0] = QLine(rect.left() + 2, rect.bottom() - 1, rect.right() - 2, rect.bottom() - 1); - lines[1] = QLine(rect.right() - 1, rect.top() + 2, rect.right() - 1, rect.bottom() - 2); - painter->drawLines(lines, 2); - - painter->setPen(oldPen); -} - -static void qt_plastique_drawShadedPanel(QPainter *painter, const QStyleOption *option, bool base, - const QWidget *widget) -{ - QRect rect = option->rect; - QPen oldPen = painter->pen(); - - QColor gradientStartColor = option->palette.button().color().lighter(104); - QColor gradientStopColor = option->palette.button().color().darker(105); - - // gradient fill - if ((option->state & QStyle::State_Enabled) || !(option->state & QStyle::State_AutoRaise)) { - if ((option->state & QStyle::State_Sunken) || (option->state & QStyle::State_On)) { - qt_plastique_draw_gradient(painter, rect.adjusted(1, 1, -1, -1), - option->palette.button().color().darker(114), - option->palette.button().color().darker(106)); - } else { - qt_plastique_draw_gradient(painter, rect.adjusted(1, 1, -1, -1), - base ? option->palette.background().color().lighter(105) : gradientStartColor, - base ? option->palette.background().color().darker(102) : gradientStopColor); - } - } - - qt_plastique_drawFrame(painter, option, widget); - - painter->setPen(oldPen); -} - -static void qt_plastique_draw_mdibutton(QPainter *painter, const QStyleOptionTitleBar *option, const QRect &tmp, bool hover, bool sunken) -{ - if (tmp.isNull()) - return; - bool active = (option->titleBarState & QStyle::State_Active); - - // ### use palette colors instead - QColor mdiButtonGradientStartColor; - QColor mdiButtonGradientStopColor; - if (active) { - mdiButtonGradientStartColor = QColor((hover || sunken) ? 0x7d8bb1 : 0x55689a); - mdiButtonGradientStopColor = QColor((hover || sunken) ? 0x939ebe : 0x7381ab); - } else { - mdiButtonGradientStartColor = QColor((hover || sunken) ? 0x9e9e9e : 0x818181); - mdiButtonGradientStopColor = QColor((hover || sunken) ? 0xababab : 0x929292); - } - - qt_plastique_draw_gradient(painter, tmp.adjusted(1, 1, -1, -1), - mdiButtonGradientStartColor, mdiButtonGradientStopColor); - - QColor mdiButtonBorderColor; - if (active) { - mdiButtonBorderColor = (hover || sunken) ? QColor(0x627097) : QColor(0x324577); - } else { - mdiButtonBorderColor = (hover || sunken) ? QColor(0x838383) : QColor(0x5e5e5e); - } - painter->setPen(QPen(mdiButtonBorderColor, 1)); - - const QLine lines[4] = { - QLine(tmp.left() + 2, tmp.top(), tmp.right() - 2, tmp.top()), - QLine(tmp.left() + 2, tmp.bottom(), tmp.right() - 2, tmp.bottom()), - QLine(tmp.left(), tmp.top() + 2, tmp.left(), tmp.bottom() - 2), - QLine(tmp.right(), tmp.top() + 2, tmp.right(), tmp.bottom() - 2) }; - painter->drawLines(lines, 4); - - const QPoint points[4] = { - QPoint(tmp.left() + 1, tmp.top() + 1), - QPoint(tmp.right() - 1, tmp.top() + 1), - QPoint(tmp.left() + 1, tmp.bottom() - 1), - QPoint(tmp.right() - 1, tmp.bottom() - 1) }; - painter->drawPoints(points, 4); -} - -#ifndef QT_NO_DOCKWIDGET -static QString elliditide(const QString &text, const QFontMetrics &fontMetrics, const QRect &rect, int *textWidth = 0) -{ - // Chop and insert ellide into title if text is too wide - QString title = text; - int width = textWidth ? *textWidth : fontMetrics.width(text); - QString ellipsis = QLatin1String("..."); - if (width > rect.width()) { - QString leftHalf = title.left(title.size() / 2); - QString rightHalf = title.mid(leftHalf.size() + 1); - while (!leftHalf.isEmpty() && !rightHalf.isEmpty()) { - leftHalf.chop(1); - int width = fontMetrics.width(leftHalf + ellipsis + rightHalf); - if (width < rect.width()) { - title = leftHalf + ellipsis + rightHalf; - break; - } - rightHalf.remove(0, 1); - width = fontMetrics.width(leftHalf + ellipsis + rightHalf); - if (width < rect.width()) { - title = leftHalf + ellipsis + rightHalf; - break; - } - } - } - if (textWidth) - *textWidth = width; - return title; -} -#endif - -#if !defined(QT_NO_DOCKWIDGET) || !defined(QT_NO_SPLITTER) -static void qt_plastique_draw_handle(QPainter *painter, const QStyleOption *option, - const QRect &rect, Qt::Orientation orientation, - const QWidget *widget) -{ - QColor borderColor = option->palette.background().color().darker(178); - QColor alphaCornerColor; - if (widget) { - // ### backgroundrole/foregroundrole should be part of the style option - alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), borderColor); - } else { - alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); - } - QImage handle(qt_simple_toolbarhandle); - alphaCornerColor.setAlpha(170); - handle.setColor(1, alphaCornerColor.rgba()); - handle.setColor(2, mergedColors(alphaCornerColor, option->palette.light().color()).rgba()); - handle.setColor(3, option->palette.light().color().rgba()); - - const int spacing = 2; - - if (orientation == Qt::Vertical) { - int nchunks = rect.width() / (handle.width() + spacing); - for (int i = 0; i < nchunks; ++i) - painter->drawImage(QPoint(rect.left() + i * (handle.width() + spacing), rect.top()), handle); - } else { - int nchunks = rect.height() / (handle.height() + spacing); - for (int i = 0; i < nchunks; ++i) - painter->drawImage(QPoint(rect.left(), rect.top() + i * (handle.height() + spacing)), handle); - } -} -#endif - -class QPlastiqueStylePrivate : public QWindowsStylePrivate -{ - Q_DECLARE_PUBLIC(QPlastiqueStyle) -public: - QPlastiqueStylePrivate(); - virtual ~QPlastiqueStylePrivate(); - void drawPartialFrame(QPainter *painter, const QStyleOptionComplex *option, - const QRect &rect, const QWidget *widget) const; -}; - -/*! - \internal - */ -QPlastiqueStylePrivate::QPlastiqueStylePrivate() : - QWindowsStylePrivate() -{ -} - -/*! - \internal - */ -QPlastiqueStylePrivate::~QPlastiqueStylePrivate() -{ -} - -/*! - \class QPlastiqueStyle - \brief The QPlastiqueStyle class provides a widget style similar to the - Plastik style available in KDE. - - \inmodule QtWidgets - - The Plastique style provides a default look and feel for widgets on X11 - that closely resembles the Plastik style, introduced by Sandro Giessl in - KDE 3.2. - - \image qplastiquestyle.png - \sa QWindowsXPStyle, QMacStyle, QWindowsStyle -*/ - -/*! - Constructs a QPlastiqueStyle object. -*/ -QPlastiqueStyle::QPlastiqueStyle() - : QWindowsStyle(*new QPlastiqueStylePrivate) -{ - setObjectName(QLatin1String("Plastique")); -} - -/*! - Destructs the QPlastiqueStyle object. -*/ -QPlastiqueStyle::~QPlastiqueStyle() -{ -} - -/* - Used by spin- and combo box. - Draws a rounded frame around rect but omits the right hand edge -*/ -void QPlastiqueStylePrivate::drawPartialFrame(QPainter *painter, const QStyleOptionComplex *option, - const QRect &rect, const QWidget *widget) const -{ - Q_Q(const QPlastiqueStyle); - bool reverse = option->direction == Qt::RightToLeft; - QStyleOptionFrame frameOpt; -#ifndef QT_NO_LINEEDIT - if (QLineEdit *lineedit = widget->findChild()) - frameOpt.initFrom(lineedit); -#else - Q_UNUSED(widget) -#endif // QT_NO_LINEEDIT - - frameOpt.rect = rect; - painter->save(); - frameOpt.rect.adjust(-blueFrameWidth + (reverse ? 1 : 0), -blueFrameWidth, - blueFrameWidth + (reverse ? 0 : -1), blueFrameWidth); - painter->setClipRect(frameOpt.rect); - frameOpt.rect.adjust(reverse ? -2 : 0, 0, reverse ? 0 : 2, 0); - frameOpt.lineWidth = q->pixelMetric(QStyle::PM_DefaultFrameWidth); - frameOpt.midLineWidth = 0; - frameOpt.state = option->state | QStyle::State_Sunken; - frameOpt.palette = option->palette; - q->drawPrimitive(QStyle::PE_PanelLineEdit, &frameOpt, painter, widget); - painter->restore(); - - // Draw a two pixel highlight on the flat edge - if (option->state & QStyle::State_HasFocus) { - painter->setPen(QPen(option->palette.highlight(), 0)); - QBrush focusBorder = option->palette.highlight(); - qBrushSetAlphaF(&focusBorder, qreal(0.65)); - if (!reverse) { - painter->drawLine(rect.topRight() + QPoint(1, -1), - rect.bottomRight() + QPoint(1, 1)); - painter->setPen(QPen(focusBorder, 0)); - painter->drawLine(rect.topRight(), - rect.bottomRight()); - } - else { - painter->drawLine(rect.topLeft() + QPoint(-1, -1), - rect.bottomLeft() + QPoint(-1, 1)); - painter->setPen(QPen(focusBorder, 0)); - painter->drawLine(rect.topLeft(), - rect.bottomLeft()); - } - } -} - -/*! - \reimp -*/ -void QPlastiqueStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget) const -{ - Q_ASSERT(option); - - QColor borderColor = option->palette.background().color().darker(178); - QColor alphaCornerColor; - if (widget) { - // ### backgroundrole/foregroundrole should be part of the style option - alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), borderColor); - } else { - alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); - } - QColor alphaTextColor = mergedColors(option->palette.background().color(), option->palette.text().color()); - - switch (element) { - case PE_IndicatorButtonDropDown: - proxy()->drawPrimitive(PE_PanelButtonTool, option, painter, widget); - break; - case PE_FrameDefaultButton: { - if (!(option->state & QStyle::State_Enabled)) - break; - painter->setPen(QPen(QColor(0, 0, 0, 127), 0)); - const QLine lines[4] = { - QLine(option->rect.left() + 2, option->rect.top(), - option->rect.right() - 2, option->rect.top()), - QLine(option->rect.left() + 2, option->rect.bottom(), - option->rect.right() - 2, option->rect.bottom()), - QLine(option->rect.left(), option->rect.top() + 2, - option->rect.left(), option->rect.bottom() - 2), - QLine(option->rect.right(), option->rect.top() + 2, - option->rect.right(), option->rect.bottom() - 2) }; - painter->drawLines(lines, 4); - - QPoint points[8]; - points[0] = QPoint(option->rect.left() + 1, option->rect.top() + 1); - points[1] = QPoint(option->rect.right() - 1, option->rect.top() + 1); - points[2] = QPoint(option->rect.left() + 1, option->rect.bottom() - 1); - points[3] = QPoint(option->rect.right() - 1, option->rect.bottom() - 1); - painter->drawPoints(points, 4); - - painter->setPen(QPen(QColor(0, 0, 0, 63), 0)); - points[0] = QPoint(option->rect.left() + 1, option->rect.top()); - points[1] = QPoint(option->rect.right() - 1, option->rect.top()); - points[2] = QPoint(option->rect.left(), option->rect.top() + 1); - points[3] = QPoint(option->rect.right(), option->rect.top() + 1); - points[4] = QPoint(option->rect.left() + 1, option->rect.bottom()); - points[5] = QPoint(option->rect.right() - 1, option->rect.bottom()); - points[6] = QPoint(option->rect.left(), option->rect.bottom() - 1); - points[7] = QPoint(option->rect.right(), option->rect.bottom() - 1); - painter->drawPoints(points, 8); - - break; - } -#ifndef QT_NO_TABWIDGET - case PE_FrameTabWidget: - if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast(option)) { - if (twf->shape != QTabBar::RoundedNorth && twf->shape != QTabBar::RoundedWest && - twf->shape != QTabBar::RoundedSouth && twf->shape != QTabBar::RoundedEast) { - QWindowsStyle::drawPrimitive(element, option, painter, widget); - break; - } - - int borderThickness = proxy()->pixelMetric(PM_TabBarBaseOverlap, twf, widget); - bool reverse = (twf->direction == Qt::RightToLeft); - - painter->save(); - - // Start by filling the contents of the tab widget frame (which is - // actually a panel). - painter->fillRect(option->rect.adjusted(1, 1, -1, -1), option->palette.window()); - - QRect tabBarRect; - switch (twf->shape) { - case QTabBar::RoundedNorth: - if (reverse) - tabBarRect = QRect(twf->rect.right() - twf->leftCornerWidgetSize.width() - twf->tabBarSize.width() + 1, twf->rect.top(), twf->tabBarSize.width(), borderThickness); - else - tabBarRect = QRect(twf->rect.left() + twf->leftCornerWidgetSize.width(), twf->rect.top(), twf->tabBarSize.width(), borderThickness); - break ; - case QTabBar::RoundedWest: - tabBarRect = QRect(twf->rect.left(), twf->rect.top() + twf->leftCornerWidgetSize.height(), borderThickness, twf->tabBarSize.height()); - break ; - case QTabBar::RoundedEast: - tabBarRect = QRect(twf->rect.right() - borderThickness + 1, twf->rect.top() + twf->leftCornerWidgetSize.height(), - borderThickness, twf->tabBarSize.height()); - break ; - case QTabBar::RoundedSouth: - if (reverse) - tabBarRect = QRect(twf->rect.right() - twf->leftCornerWidgetSize.width() - twf->tabBarSize.width() + 1, - twf->rect.bottom() - borderThickness + 1, twf->tabBarSize.width(), borderThickness); - else - tabBarRect = QRect(twf->rect.left() + twf->leftCornerWidgetSize.width(), - twf->rect.bottom() - borderThickness + 1, twf->tabBarSize.width(), borderThickness); - break ; - default: - break; - } - - QRegion region(twf->rect); - region -= tabBarRect; - painter->setClipRegion(region); - - // Outer border - QLine leftLine = QLine(twf->rect.topLeft() + QPoint(0, 2), twf->rect.bottomLeft() - QPoint(0, 2)); - QLine rightLine = QLine(twf->rect.topRight() + QPoint(0, 2), twf->rect.bottomRight() - QPoint(0, 2)); - QLine bottomLine = QLine(twf->rect.bottomLeft() + QPoint(2, 0), twf->rect.bottomRight() - QPoint(2, 0)); - QLine topLine = QLine(twf->rect.topLeft() + QPoint(2, 0), twf->rect.topRight() - QPoint(2, 0)); - - QBrush border = option->palette.shadow(); - qBrushSetAlphaF(&border, qreal(0.4)); - painter->setPen(QPen(border, 0)); - - QVarLengthArray lines; - QVarLengthArray points; - - lines.append(topLine); - - // Inner border - QLine innerLeftLine = QLine(leftLine.p1() + QPoint(1, 0), leftLine.p2() + QPoint(1, 0)); - QLine innerRightLine = QLine(rightLine.p1() - QPoint(1, 0), rightLine.p2() - QPoint(1, 0)); - QLine innerBottomLine = QLine(bottomLine.p1() - QPoint(0, 1), bottomLine.p2() - QPoint(0, 1)); - QLine innerTopLine = QLine(topLine.p1() + QPoint(0, 1), topLine.p2() + QPoint(0, 1)); - - // Rounded Corner - QPoint leftBottomOuterCorner = QPoint(innerLeftLine.p2() + QPoint(0, 1)); - QPoint leftBottomInnerCorner1 = QPoint(leftLine.p2() + QPoint(0, 1)); - QPoint leftBottomInnerCorner2 = QPoint(bottomLine.p1() - QPoint(1, 0)); - QPoint rightBottomOuterCorner = QPoint(innerRightLine.p2() + QPoint(0, 1)); - QPoint rightBottomInnerCorner1 = QPoint(rightLine.p2() + QPoint(0, 1)); - QPoint rightBottomInnerCorner2 = QPoint(bottomLine.p2() + QPoint(1, 0)); - QPoint rightTopOuterCorner = QPoint(innerRightLine.p1() - QPoint(0, 1)); - QPoint rightTopInnerCorner1 = QPoint(rightLine.p1() - QPoint(0, 1)); - QPoint rightTopInnerCorner2 = QPoint(topLine.p2() + QPoint(1, 0)); - QPoint leftTopOuterCorner = QPoint(innerLeftLine.p1() - QPoint(0, 1)); - QPoint leftTopInnerCorner1 = QPoint(leftLine.p1() - QPoint(0, 1)); - QPoint leftTopInnerCorner2 = QPoint(topLine.p1() - QPoint(1, 0)); - - lines.append(leftLine); - lines.append(rightLine); - lines.append(bottomLine); - - painter->drawLines(lines.constData(), lines.size()); - lines.clear(); - - points.append(leftBottomOuterCorner); - points.append(rightBottomOuterCorner); - points.append(rightTopOuterCorner); - points.append(leftTopOuterCorner); - - painter->drawPoints(points.constData(), points.size()); - points.clear(); - - QBrush innerTopLeft = option->palette.shadow(); - qBrushSetAlphaF(&innerTopLeft, qreal(0.075)); - painter->setPen(QPen(innerTopLeft, 0)); - - lines.append(innerLeftLine); - lines.append(innerTopLine); - painter->drawLines(lines.constData(), lines.size()); - lines.clear(); - - QBrush innerBottomRight = option->palette.shadow(); - qBrushSetAlphaF(&innerBottomRight, qreal(0.23)); - painter->setPen(QPen(innerBottomRight, 0)); - lines.append(innerRightLine); - lines.append(innerBottomLine); - painter->drawLines(lines.constData(), lines.size()); - lines.clear(); - - QBrush corner = option->palette.shadow(); - qBrushSetAlphaF(&corner, 0.25); - painter->setPen(QPen(corner, 0)); - points.append(leftBottomInnerCorner1); - points.append(leftBottomInnerCorner2); - points.append(rightBottomInnerCorner1); - points.append(rightBottomInnerCorner2); - points.append(rightTopInnerCorner1); - points.append(rightTopInnerCorner2); - points.append(leftTopInnerCorner1); - points.append(leftTopInnerCorner2); - painter->drawPoints(points.constData(), points.size()); - points.clear(); - - painter->restore(); - } - break ; -#endif // QT_NO_TABWIDGET -#ifndef QT_NO_TABBAR - case PE_FrameTabBarBase: - if (const QStyleOptionTabBarBase *tbb = qstyleoption_cast(option)) { - if (tbb->shape != QTabBar::RoundedNorth && tbb->shape != QTabBar::RoundedWest && - tbb->shape != QTabBar::RoundedSouth && tbb->shape != QTabBar::RoundedEast) { - QWindowsStyle::drawPrimitive(element, option, painter, widget); - break; - } - - painter->save(); - - QRegion region(tbb->rect); - region -= tbb->tabBarRect; - painter->setClipRegion(region); - - QLine topLine = QLine(tbb->rect.bottomLeft() - QPoint(0, 1), tbb->rect.bottomRight() - QPoint(0, 1)); - QLine bottomLine = QLine(tbb->rect.bottomLeft(), tbb->rect.bottomRight()); - - QBrush border = option->palette.shadow(); - qBrushSetAlphaF(&border, qreal(0.4)); - QBrush innerTopLeft = option->palette.shadow(); - qBrushSetAlphaF(&innerTopLeft, qreal(0.075)); - QBrush innerBottomRight = option->palette.shadow(); - qBrushSetAlphaF(&innerBottomRight, qreal(0.23)); - QBrush corner = option->palette.shadow(); - qBrushSetAlphaF(&corner, 0.25); - - if (tbb->shape == QTabBar::RoundedSouth) - painter->setPen(QPen(corner, 0)); - else - painter->setPen(QPen(border, 0)); - painter->drawLine(topLine); - - if (tbb->shape != QTabBar::RoundedSouth) - painter->setPen(QPen(innerTopLeft, 0)); - else - painter->setPen(QPen(border, 0)); - painter->drawLine(bottomLine); - - painter->restore(); - } - break ; -#endif // QT_NO_TABBAR -#ifndef QT_NO_GROUPBOX - case PE_FrameGroupBox: - if (const QStyleOptionFrame *frame = qstyleoption_cast(option)) { - QStyleOptionFrameV2 frameV2(*frame); - if (frameV2.features & QStyleOptionFrameV2::Flat) { - QPen oldPen = painter->pen(); - painter->setPen(borderColor); - painter->drawLine(frameV2.rect.topLeft(), frameV2.rect.topRight()); - painter->setPen(oldPen); - } else { - frameV2.state &= ~(State_Sunken | State_HasFocus); - proxy()->drawPrimitive(PE_Frame, &frameV2, painter, widget); - } - } - break; -#endif // QT_NO_GROUPBOX - case PE_Frame: { - QFrame::Shadow shadow = QFrame::Plain; - if (option->state & State_Sunken) - shadow = QFrame::Sunken; - else if (option->state & State_Raised) - shadow = QFrame::Raised; - qt_plastique_draw_frame(painter, option->rect, option, shadow); - break; - } -#ifndef QT_NO_LINEEDIT - case PE_FrameLineEdit: - qt_plastique_draw_frame(painter, option->rect, option, QFrame::Sunken); - break; - case PE_PanelLineEdit: - if (const QStyleOptionFrame *lineEdit = qstyleoption_cast(option)) { - // Panel of a line edit inside combo box or spin box is drawn in CC_ComboBox and CC_SpinBox - if (widget) { -#ifndef QT_NO_SPINBOX - // Spinbox doesn't need a separate palette for the lineedit - if (qobject_cast(widget->parentWidget())) - break; -#endif - } - - painter->save(); - - // Fill the line edit insides - QRect filledRect = lineEdit->rect.adjusted(1, 1, -1, -1); - QBrush baseBrush = qMapBrushToRect(lineEdit->palette.base(), filledRect); - painter->setBrushOrigin(filledRect.topLeft()); - painter->fillRect(filledRect.adjusted(1, 1, -1, -1), baseBrush); - - painter->setPen(QPen(baseBrush, 0)); - const QLine lines[4] = { - QLine(filledRect.left(), filledRect.top() + 1, - filledRect.left(), filledRect.bottom() - 1), - QLine(filledRect.right(), filledRect.top() + 1, - filledRect.right(), filledRect.bottom() - 1), - QLine(filledRect.left() + 1, filledRect.top(), - filledRect.right() - 1, filledRect.top()), - QLine(filledRect.left() + 1, filledRect.bottom(), - filledRect.right() - 1, filledRect.bottom()) }; - painter->drawLines(lines, 4); - - if (lineEdit->lineWidth != 0) - qt_plastique_draw_frame(painter, option->rect, option, QFrame::Sunken); - - painter->restore(); - break; - } -#endif // QT_NO_LINEEDIT - case PE_FrameDockWidget: - case PE_FrameMenu: - case PE_FrameStatusBarItem: { - // Draws the frame around a popup menu. - QPen oldPen = painter->pen(); - painter->setPen(borderColor); - painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); - painter->setPen(alphaCornerColor); - const QPoint points[4] = { - QPoint(option->rect.topLeft()), - QPoint(option->rect.topRight()), - QPoint(option->rect.bottomLeft()), - QPoint(option->rect.bottomRight()) }; - painter->drawPoints(points, 4); - painter->setPen(oldPen); - break; - } -#ifndef QT_NO_MAINWINDOW - case PE_PanelMenuBar: - if ((widget && qobject_cast(widget->parentWidget())) - ) { - // Draws the light line above and the dark line below menu bars and - // tool bars. - QPen oldPen = painter->pen(); - if (element == PE_PanelMenuBar || (option->state & State_Horizontal)) { - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.left(), option->rect.bottom(), - option->rect.right(), option->rect.bottom()); - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.left(), option->rect.top(), - option->rect.right(), option->rect.top()); - } else { - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.left(), option->rect.top(), - option->rect.left(), option->rect.bottom()); - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.right(), option->rect.top(), - option->rect.right(), option->rect.bottom()); - } - painter->setPen(oldPen); - } - break; -#endif // QT_NO_MAINWINDOW - case PE_IndicatorHeaderArrow: { - bool usedAntialiasing = painter->renderHints() & QPainter::Antialiasing; - if (!usedAntialiasing) - painter->setRenderHint(QPainter::Antialiasing); - QWindowsStyle::drawPrimitive(element, option, painter, widget); - if (!usedAntialiasing) - painter->setRenderHint(QPainter::Antialiasing, false); - break; - } - case PE_PanelButtonTool: - // Draws a tool button (f.ex., in QToolBar and QTabBar) - if ((option->state & State_Enabled || option->state & State_On) || !(option->state & State_AutoRaise)) - qt_plastique_drawShadedPanel(painter, option, true, widget); - break; -#ifndef QT_NO_TOOLBAR - case PE_IndicatorToolBarHandle: { - QPixmap cache; - QRect rect = option->rect; - QString pixmapName = QStyleHelper::uniqueName(QLatin1String("toolbarhandle"), option, rect.size()); - if (!QPixmapCache::find(pixmapName, cache)) { - cache = QPixmap(rect.size()); - cache.fill(Qt::transparent); - QPainter cachePainter(&cache); - QRect cacheRect(QPoint(0, 0), rect.size()); - if (widget) - cachePainter.fillRect(cacheRect, option->palette.brush(widget->backgroundRole())); - else - cachePainter.fillRect(cacheRect, option->palette.background()); - - QImage handle(qt_toolbarhandle); - alphaCornerColor.setAlpha(170); - handle.setColor(1, alphaCornerColor.rgba()); - handle.setColor(2, mergedColors(alphaCornerColor, option->palette.light().color()).rgba()); - handle.setColor(3, option->palette.light().color().rgba()); - - if (option->state & State_Horizontal) { - int nchunks = cacheRect.height() / handle.height(); - int indent = (cacheRect.height() - (nchunks * handle.height())) / 2; - for (int i = 0; i < nchunks; ++i) - cachePainter.drawImage(QPoint(cacheRect.left() + 3, cacheRect.top() + indent + i * handle.height()), - handle); - } else { - int nchunks = cacheRect.width() / handle.width(); - int indent = (cacheRect.width() - (nchunks * handle.width())) / 2; - for (int i = 0; i < nchunks; ++i) - cachePainter.drawImage(QPoint(cacheRect.left() + indent + i * handle.width(), cacheRect.top() + 3), - handle); - } - cachePainter.end(); - QPixmapCache::insert(pixmapName, cache); - } - painter->drawPixmap(rect.topLeft(), cache); - break; - } - case PE_IndicatorToolBarSeparator: { - QPen oldPen = painter->pen(); - painter->setPen(alphaCornerColor); - if (option->state & State_Horizontal) { - painter->drawLine(option->rect.left(), option->rect.top() + 1, option->rect.left(), option->rect.bottom() - 2); - painter->setPen(option->palette.base().color()); - painter->drawLine(option->rect.right(), option->rect.top() + 1, option->rect.right(), option->rect.bottom() - 2); - } else { - painter->drawLine(option->rect.left() + 1, option->rect.top(), option->rect.right() - 2, option->rect.top()); - painter->setPen(option->palette.base().color()); - painter->drawLine(option->rect.left() + 1, option->rect.bottom(), option->rect.right() - 2, option->rect.bottom()); - } - painter->setPen(oldPen); - break; - } -#endif // QT_NO_TOOLBAR - case PE_PanelButtonCommand: - if (const QStyleOptionButton *button = qstyleoption_cast(option)) { - bool sunken = (button->state & State_Sunken) || (button->state & State_On); - if ((button->features & QStyleOptionButton::Flat) && !sunken) - break; - - bool defaultButton = (button->features & (QStyleOptionButton::DefaultButton - | QStyleOptionButton::AutoDefaultButton)); - - BEGIN_STYLE_PIXMAPCACHE(QString::fromLatin1("pushbutton-%1").arg(defaultButton)) - - QPen oldPen = p->pen(); - bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver); - - // Give the painter a different brush origin for sunken buttons - if (sunken) { - // ### No such function - // p->setPenOrigin(rect.left() + 1, rect.top() + 1); - p->setBrushOrigin(rect.left() + 1, rect.top() + 1); - } - - // Draw border - qt_plastique_draw_frame(p, rect, option); - - // Fill the panel - QRectF fillRect = rect.adjusted(2, 2, -2, -2); - - // Button colors - QBrush alphaCornerBrush = qMapBrushToRect(qBrushDark(option->palette.button(), 165), rect); - qBrushSetAlphaF(&alphaCornerBrush, 0.5); - QBrush buttonGradientBrush; - QBrush leftLineGradientBrush; - QBrush rightLineGradientBrush; - QBrush sunkenButtonGradientBrush; - QBrush sunkenLeftLineGradientBrush; - QBrush sunkenRightLineGradientBrush; - QBrush buttonBrush = qMapBrushToRect(option->palette.button(), rect); - if (buttonBrush.gradient() || !buttonBrush.texture().isNull()) { - buttonGradientBrush = buttonBrush; - sunkenButtonGradientBrush = qBrushDark(buttonBrush, 108); - leftLineGradientBrush = qBrushLight(buttonBrush, 105); - rightLineGradientBrush = qBrushDark(buttonBrush, 105); - sunkenLeftLineGradientBrush = qBrushDark(buttonBrush, 110); - sunkenRightLineGradientBrush = qBrushDark(buttonBrush, 106); - } else { - // Generate gradients - QLinearGradient buttonGradient(rect.topLeft(), rect.bottomLeft()); - if (hover) { - buttonGradient.setColorAt(0.0, mergedColors(option->palette.highlight().color(), - buttonBrush.color().lighter(104), 6)); - buttonGradient.setColorAt(1.0, mergedColors(option->palette.highlight().color(), - buttonBrush.color().darker(110), 6)); - } else { - buttonGradient.setColorAt(0.0, buttonBrush.color().lighter(104)); - buttonGradient.setColorAt(1.0, buttonBrush.color().darker(110)); - } - buttonGradientBrush = QBrush(buttonGradient); - - QLinearGradient buttonGradient2(rect.topLeft(), rect.bottomLeft()); - buttonGradient2.setColorAt(0.0, buttonBrush.color().darker(113)); - buttonGradient2.setColorAt(1.0, buttonBrush.color().darker(103)); - sunkenButtonGradientBrush = QBrush(buttonGradient2); - - QLinearGradient buttonGradient3(rect.topLeft(), rect.bottomLeft()); - buttonGradient3.setColorAt(0.0, buttonBrush.color().lighter(105)); - buttonGradient3.setColorAt(1.0, buttonBrush.color()); - leftLineGradientBrush = QBrush(buttonGradient3); - - QLinearGradient buttonGradient4(rect.topLeft(), rect.bottomLeft()); - buttonGradient4.setColorAt(0.0, buttonBrush.color()); - buttonGradient4.setColorAt(1.0, buttonBrush.color().darker(110)); - rightLineGradientBrush = QBrush(buttonGradient4); - - QLinearGradient buttonGradient5(rect.topLeft(), rect.bottomLeft()); - buttonGradient5.setColorAt(0.0, buttonBrush.color().darker(113)); - buttonGradient5.setColorAt(1.0, buttonBrush.color().darker(107)); - sunkenLeftLineGradientBrush = QBrush(buttonGradient5); - - QLinearGradient buttonGradient6(rect.topLeft(), rect.bottomLeft()); - buttonGradient6.setColorAt(0.0, buttonBrush.color().darker(108)); - buttonGradient6.setColorAt(1.0, buttonBrush.color().darker(103)); - sunkenRightLineGradientBrush = QBrush(buttonGradient6); - } - - // Main fill - p->fillRect(fillRect, - qMapBrushToRect(sunken ? sunkenButtonGradientBrush - : buttonGradientBrush, rect)); - - // Top line - p->setPen(QPen(qBrushLight(qMapBrushToRect(sunken ? sunkenButtonGradientBrush - : buttonGradientBrush, rect), 105), 0)); - p->drawLine(QPointF(rect.left() + 2, rect.top() + 1), - QPointF(rect.right() - 2, rect.top() + 1)); - - // Bottom line - p->setPen(QPen(qBrushDark(qMapBrushToRect(sunken ? sunkenButtonGradientBrush - : buttonGradientBrush, rect), 105), 0)); - p->drawLine(QPointF(rect.left() + 2, rect.bottom() - 1), - QPointF(rect.right() - 2, rect.bottom() - 1)); - - // Left line - p->setPen(QPen(qMapBrushToRect(sunken ? sunkenLeftLineGradientBrush - : leftLineGradientBrush, rect), 1)); - p->drawLine(QPointF(rect.left() + 1, rect.top() + 2), - QPointF(rect.left() + 1, rect.bottom() - 2)); - - // Right line - p->setPen(QPen(qMapBrushToRect(sunken ? sunkenRightLineGradientBrush - : rightLineGradientBrush, rect), 1)); - p->drawLine(QPointF(rect.right() - 1, rect.top() + 2), - QPointF(rect.right() - 1, rect.bottom() - 2)); - - // Hovering - if (hover && !sunken) { - QBrush hover = qMapBrushToRect(option->palette.highlight(), rect); - QBrush hoverOuter = hover; - qBrushSetAlphaF(&hoverOuter, qreal(0.7)); - - QLine lines[2]; - - p->setPen(QPen(hoverOuter, 0)); - lines[0] = QLine(rect.left() + 1, rect.top() + 1, rect.right() - 1, rect.top() + 1); - lines[1] = QLine(rect.left() + 1, rect.bottom() - 1, rect.right() - 1, rect.bottom() - 1); - p->drawLines(lines, 2); - - QBrush hoverInner = hover; - qBrushSetAlphaF(&hoverInner, qreal(0.45)); - p->setPen(QPen(hoverInner, 0)); - lines[0] = QLine(rect.left() + 1, rect.top() + 2, rect.right() - 1, rect.top() + 2); - lines[1] = QLine(rect.left() + 1, rect.bottom() - 2, rect.right() - 1, rect.bottom() - 2); - p->drawLines(lines, 2); - - QBrush hoverSide = hover; - qBrushSetAlphaF(&hoverSide, qreal(0.075)); - p->setPen(QPen(hoverSide, 0)); - lines[0] = QLine(rect.left() + 1, rect.top() + 2, rect.left() + 1, rect.bottom() - 2); - lines[1] = QLine(rect.right() - 1, rect.top() + 2, rect.right() - 1, rect.bottom() - 2); - p->drawLines(lines, 2); - } - - p->setPen(oldPen); - - END_STYLE_PIXMAPCACHE - } - break; - case PE_IndicatorCheckBox: - if (const QStyleOptionButton *button = qstyleoption_cast(option)) { - BEGIN_STYLE_PIXMAPCACHE(QLatin1String("checkbox")) - - p->save(); - - // Outline - QBrush border = option->palette.shadow(); - qBrushSetAlphaF(&border, qreal(0.4)); - p->setPen(QPen(border, 0)); - const QLine lines[4] = { - QLine(rect.left() + 1, rect.top(), rect.right() - 1, rect.top()), - QLine(rect.left() + 1, rect.bottom(), rect.right() - 1, rect.bottom()), - QLine(rect.left(), rect.top() + 1, rect.left(), rect.bottom() - 1), - QLine(rect.right(), rect.top() + 1, rect.right(), rect.bottom() - 1) }; - p->drawLines(lines, 4); - - QBrush corner = option->palette.shadow(); - qBrushSetAlphaF(&corner, qreal(0.2)); - p->setPen(QPen(corner, 0)); - const QPoint points[4] = { - rect.topLeft(), rect.topRight(), - rect.bottomLeft(), rect.bottomRight() }; - p->drawPoints(points, 4); - - // Fill - QBrush baseBrush = qMapBrushToRect(button->palette.base(), rect); - if (!baseBrush.gradient() && baseBrush.texture().isNull()) { - QLinearGradient gradient(rect.center().x(), rect.top(), rect.center().x(), rect.bottom()); - gradient.setColorAt(0, baseBrush.color()); - gradient.setColorAt(1, baseBrush.color().darker(105)); - baseBrush = gradient; - } - p->fillRect(rect.adjusted(1, 1, -1, -1), baseBrush); - - // Hover - if ((button->state & State_Enabled) && (button->state & State_MouseOver)) { - QBrush pen = qMapBrushToRect(button->palette.highlight(), rect); - qBrushSetAlphaF(&pen, qreal(0.8)); - p->setPen(QPen(pen, 0)); - p->drawRect(rect.adjusted(1, 1, -2, -2)); - qBrushSetAlphaF(&pen, 0.5); - p->setPen(QPen(pen, 0)); - p->drawRect(rect.adjusted(2, 2, -3, -3)); - - qBrushSetAlphaF(&pen, qreal(0.2)); - p->setBrush(pen); - p->drawRect(rect.adjusted(2, 2, -3, -3)); - } - - // Indicator - bool on = button->state & State_On; - bool sunken = button->state & State_Sunken; - bool unchanged = button->state & State_NoChange; - bool enabled = button->state & State_Enabled; - if (on || (enabled && sunken) || unchanged) { - p->setRenderHint(QPainter::Antialiasing); - QBrush pointBrush = qMapBrushToRect(button->palette.text(), rect); - if (sunken) - qBrushSetAlphaF(&pointBrush, qreal(0.5)); - else if (unchanged) - qBrushSetAlphaF(&pointBrush, qreal(0.3)); - p->setPen(QPen(pointBrush, 3)); - const QLine lines[2] = { - QLine(rect.left() + 4, rect.top() + 4, rect.right() - 3, rect.bottom() - 3), - QLine(rect.right() - 3, rect.top() + 4, rect.left() + 4, rect.bottom() - 3) }; - p->drawLines(lines, 2); - } - - p->restore(); - END_STYLE_PIXMAPCACHE - } - break; - case PE_IndicatorRadioButton: - if (const QStyleOptionButton *button = qstyleoption_cast(option)) { - BEGIN_STYLE_PIXMAPCACHE(QLatin1String("radiobutton")) - - p->save(); - p->setRenderHint(QPainter::Antialiasing); - - // The the filled ellipse - QBrush border = qMapBrushToRect(option->palette.shadow(), rect); - qBrushSetAlphaF(&border, qreal(0.51)); - p->setPen(QPen(border, 0)); - - QBrush baseBrush = qMapBrushToRect(button->palette.base(), rect); - if (!baseBrush.gradient() && baseBrush.texture().isNull()) { - QLinearGradient gradient(rect.center().x(), rect.top(), rect.center().x(), rect.bottom()); - gradient.setColorAt(0, baseBrush.color()); - gradient.setColorAt(1, baseBrush.color().darker(105)); - baseBrush = gradient; - } - p->setBrush(baseBrush); - p->drawEllipse(QRectF(rect).adjusted(1, 1, -1, -1)); - - // Hover - if ((button->state & State_Enabled) && (button->state & State_MouseOver)) { - QBrush pen = qMapBrushToRect(button->palette.highlight(), rect); - qBrushSetAlphaF(&pen, qreal(0.8)); - p->setPen(QPen(pen, 0)); - qBrushSetAlphaF(&pen, qreal(0.2)); - p->setBrush(pen); - p->drawEllipse(QRectF(rect).adjusted(2, 2, -2, -2)); - } - - // Indicator - bool on = button->state & State_On; - bool sunken = button->state & State_Sunken; - bool enabled = button->state & State_Enabled; - if (on || (enabled && sunken)) { - p->setPen(Qt::NoPen); - QBrush pointBrush = qMapBrushToRect(button->palette.text(), rect); - if (sunken) - qBrushSetAlphaF(&pointBrush, 0.5); - p->setBrush(pointBrush); - p->drawEllipse(QRectF(rect).adjusted(3, 3, -3, -3)); - } - - p->restore(); - END_STYLE_PIXMAPCACHE - } - break; -#ifndef QT_NO_DOCKWIDGET - case PE_IndicatorDockWidgetResizeHandle: - if ((option->state & State_Enabled) && (option->state & State_MouseOver)) - painter->fillRect(option->rect, QColor(255, 255, 255, 128)); - if (option->state & State_Horizontal) { - int width = option->rect.width() / 3; - QRect rect(option->rect.center().x() - width / 2, - option->rect.top() + (option->rect.height() / 2) - 1, width, 3); - qt_plastique_draw_handle(painter, option, rect, Qt::Vertical, widget); - } else { - int height = option->rect.height() / 3; - QRect rect(option->rect.left() + (option->rect.width() / 2 - 1), - option->rect.center().y() - height / 2, 3, height); - qt_plastique_draw_handle(painter, option, rect, Qt::Horizontal, widget); - } - break; -#endif // QT_NO_DOCKWIDGET - case PE_IndicatorViewItemCheck: { - QStyleOptionButton button; - button.QStyleOption::operator=(*option); - button.state &= ~State_MouseOver; - proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget); - break; - } - case PE_FrameWindow: { - painter->save(); - bool active = (option->state & State_Active); - int titleBarStop = option->rect.top() + proxy()->pixelMetric(PM_TitleBarHeight, option, widget); - - QPalette palette = option->palette; - if (!active) - palette.setCurrentColorGroup(QPalette::Disabled); - - // Frame and rounded corners - painter->setPen(mergedColors(palette.highlight().color(), Qt::black, 50)); - - QLine lines[3]; - QPoint points[4]; - - // bottom border line - lines[0] = QLine(option->rect.left() + 1, option->rect.bottom(), option->rect.right() - 1, option->rect.bottom()); - - // bottom left and right side border lines - lines[1] = QLine(option->rect.left(), titleBarStop, option->rect.left(), option->rect.bottom() - 1); - lines[2] = QLine(option->rect.right(), titleBarStop, option->rect.right(), option->rect.bottom() - 1); - painter->drawLines(lines, 3); - points[0] = QPoint(option->rect.left() + 1, option->rect.bottom() - 1); - points[1] = QPoint(option->rect.right() - 1, option->rect.bottom() - 1); - painter->drawPoints(points, 2); - - - // alpha corners - painter->setPen(mergedColors(palette.highlight().color(), palette.background().color(), 55)); - points[0] = QPoint(option->rect.left() + 2, option->rect.bottom() - 1); - points[1] = QPoint(option->rect.left() + 1, option->rect.bottom() - 2); - points[2] = QPoint(option->rect.right() - 2, option->rect.bottom() - 1); - points[3] = QPoint(option->rect.right() - 1, option->rect.bottom() - 2); - painter->drawPoints(points, 4); - - - // upper and lower left inner - painter->setPen(active ? mergedColors(palette.highlight().color(), palette.background().color()) : palette.background().color().darker(120)); - painter->drawLine(option->rect.left() + 1, titleBarStop, option->rect.left() + 1, option->rect.bottom() - 2); - - - painter->setPen(active ? mergedColors(palette.highlight().color(), palette.background().color(), 57) : palette.background().color().darker(130)); - lines[0] = QLine(option->rect.right() - 1, titleBarStop, option->rect.right() - 1, option->rect.bottom() - 2); - lines[1] = QLine(option->rect.left() + 1, option->rect.bottom() - 1, option->rect.right() - 1, option->rect.bottom() - 1); - painter->drawLines(lines, 2); - - painter->restore(); - } - break; - case PE_IndicatorBranch: { - int mid_h = option->rect.x() + option->rect.width() / 2; - int mid_v = option->rect.y() + option->rect.height() / 2; - int bef_h = mid_h; - int bef_v = mid_v; - int aft_h = mid_h; - int aft_v = mid_v; - QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern); - if (option->state & State_Item) { - if (option->direction == Qt::RightToLeft) - painter->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush); - else - painter->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush); - } - if (option->state & State_Sibling) - painter->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush); - if (option->state & (State_Open | State_Children | State_Item | State_Sibling)) - painter->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush); - - if (option->state & State_Children) { - painter->save(); - QPoint center = option->rect.center(); - // border - QRect fullRect(center.x() - 4, center.y() - 4, 9, 9); - painter->setPen(borderColor); - - const QLine lines[4] = { - QLine(fullRect.left() + 1, fullRect.top(), - fullRect.right() - 1, fullRect.top()), - QLine(fullRect.left() + 1, fullRect.bottom(), - fullRect.right() - 1, fullRect.bottom()), - QLine(fullRect.left(), fullRect.top() + 1, - fullRect.left(), fullRect.bottom() - 1), - QLine(fullRect.right(), fullRect.top() + 1, - fullRect.right(), fullRect.bottom() - 1) }; - painter->drawLines(lines, 4); - - // "antialiased" corners - painter->setPen(alphaCornerColor); - const QPoint points[4] = { - fullRect.topLeft(), - fullRect.topRight(), - fullRect.bottomLeft(), - fullRect.bottomRight() }; - painter->drawPoints(points, 4); - - // fill - QRect adjustedRect = fullRect; - QRect gradientRect(adjustedRect.left() + 1, adjustedRect.top() + 1, - adjustedRect.right() - adjustedRect.left() - 1, - adjustedRect.bottom() - adjustedRect.top() - 1); - if (option->palette.base().style() == Qt::SolidPattern) { - QColor baseGradientStartColor = option->palette.base().color().darker(101); - QColor baseGradientStopColor = option->palette.base().color().darker(106); - qt_plastique_draw_gradient(painter, gradientRect, baseGradientStartColor, baseGradientStopColor); - } else { - painter->fillRect(gradientRect, option->palette.base()); - } - // draw "+" or "-" - painter->setPen(alphaTextColor); - painter->drawLine(center.x() - 2, center.y(), center.x() + 2, center.y()); - if (!(option->state & State_Open)) - painter->drawLine(center.x(), center.y() - 2, center.x(), center.y() + 2); - painter->restore(); - } - } - break; - default: - QWindowsStyle::drawPrimitive(element, option, painter, widget); - break; - } -} - -/*! - \reimp -*/ -void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget) const -{ - QColor borderColor = option->palette.background().color().darker(178); - QColor alphaCornerColor; - if (widget) { - // ### backgroundrole/foregroundrole should be part of the style option - alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), borderColor); - } else { - alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); - } - - QColor gradientStartColor = option->palette.button().color().lighter(104); - QColor gradientStopColor = option->palette.button().color().darker(105); - - QColor highlightedGradientStartColor = option->palette.button().color().lighter(101); - QColor highlightedGradientStopColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 85); - - QColor lightShadowGradientStartColor = highlightedGradientStartColor.lighter(105); - QColor lightShadowGradientStopColor = highlightedGradientStopColor.lighter(105); - - QColor highlightedDarkInnerBorderColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 35); - QColor highlightedLightInnerBorderColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 58); - - QColor alphaInnerColor = mergedColors(highlightedDarkInnerBorderColor, option->palette.base().color()); - - switch (element) { -#ifndef QT_NO_TABBAR - case CE_TabBarTabShape: - if (const QStyleOptionTab *tab = qstyleoption_cast(option)) { - - if (tab->shape != QTabBar::RoundedNorth && tab->shape != QTabBar::RoundedWest && - tab->shape != QTabBar::RoundedSouth && tab->shape != QTabBar::RoundedEast) { - QWindowsStyle::drawControl(element, option, painter, widget); - break; - } - - painter->save(); - - // Set up some convenience variables - bool disabled = !(tab->state & State_Enabled); - bool onlyTab = tab->position == QStyleOptionTab::OnlyOneTab; - bool selected = tab->state & State_Selected; - bool mouseOver = (tab->state & State_MouseOver) && !selected && !disabled; - bool previousSelected = tab->selectedPosition == QStyleOptionTab::PreviousIsSelected; - bool nextSelected = tab->selectedPosition == QStyleOptionTab::NextIsSelected; - bool leftCornerWidget = (tab->cornerWidgets & QStyleOptionTab::LeftCornerWidget); - bool reverse = (tab->direction == Qt::RightToLeft); - - int lowerTop = selected ? 0 : 3; // to make the selected tab bigger than the rest - bool atEnd = (tab->position == QStyleOptionTab::End) || onlyTab; - bool atBeginning = ((tab->position == QStyleOptionTab::Beginning) || onlyTab) - && !leftCornerWidget; - bool reverseShadow = false; - - int borderThickness = proxy()->pixelMetric(PM_TabBarBaseOverlap, tab, widget); - int marginLeft = 0; - if ((atBeginning && !selected) || (selected && leftCornerWidget && ((tab->position == QStyleOptionTab::Beginning) || onlyTab))) { - marginLeft = 1; - } - - // I've set the names based on the natural coordinate system. Vectors are used to rotate everything - // if the orientation of the tab bare is different than north. - { - // Coordinates of corners of rectangle for transformation - QPoint topLeft; - QPoint topRight; - QPoint bottomLeft; - QPoint bottomRight; - - // Fill with normalized vectors in the direction of the coordinate system - // (down and right should be complement of up and left, or it will look odd) - QPoint vectorUp; - QPoint vectorDown; - QPoint vectorLeft; - QPoint vectorRight; - - QBrush border = option->palette.shadow(); - qBrushSetAlphaF(&border, qreal(0.4)); - QBrush innerTopLeft = option->palette.shadow(); - qBrushSetAlphaF(&innerTopLeft, qreal(0.075)); - QBrush innerBottomRight = option->palette.shadow(); - qBrushSetAlphaF(&innerBottomRight, qreal(0.23)); - QBrush corner = option->palette.shadow(); - qBrushSetAlphaF(&corner, qreal(0.25)); - - QBrush baseColor1; - QBrush baseColor2; - - switch (tab->shape) { - case QTabBar::RoundedNorth: - vectorUp = QPoint(0, -1); - vectorDown = QPoint(0, 1); - - if (reverse) { - vectorLeft = QPoint(1, 0); - vectorRight = QPoint(-1, 0); - reverseShadow = true; - } else { - vectorLeft = QPoint(-1, 0); - vectorRight = QPoint(1, 0); - } - - if (reverse) { - topLeft = tab->rect.topRight(); - topRight = tab->rect.topLeft(); - bottomLeft = tab->rect.bottomRight(); - bottomRight = tab->rect.bottomLeft(); - } else { - topLeft = tab->rect.topLeft(); - topRight = tab->rect.topRight(); - bottomLeft = tab->rect.bottomLeft(); - bottomRight = tab->rect.bottomRight(); - } - - - baseColor1 = border; - baseColor2 = innerTopLeft; - break ; - case QTabBar::RoundedWest: - vectorUp = QPoint(-1, 0); - vectorDown = QPoint(1, 0); - vectorLeft = QPoint(0, -1); - vectorRight = QPoint(0, 1); - - topLeft = tab->rect.topLeft(); - topRight = tab->rect.bottomLeft(); - bottomLeft = tab->rect.topRight(); - bottomRight = tab->rect.bottomRight(); - - baseColor1 = border; - baseColor2 = innerTopLeft; - break ; - case QTabBar::RoundedEast: - vectorUp = QPoint(1, 0); - vectorDown = QPoint(-1, 0); - vectorLeft = QPoint(0, -1); - vectorRight = QPoint(0, 1); - - topLeft = tab->rect.topRight(); - topRight = tab->rect.bottomRight(); - bottomLeft = tab->rect.topLeft(); - bottomRight = tab->rect.bottomLeft(); - - baseColor1 = border; - baseColor2 = innerBottomRight; - break ; - case QTabBar::RoundedSouth: - vectorUp = QPoint(0, 1); - vectorDown = QPoint(0, -1); - - if (reverse) { - vectorLeft = QPoint(1, 0); - vectorRight = QPoint(-1, 0); - reverseShadow = true; - - topLeft = tab->rect.bottomRight(); - topRight = tab->rect.bottomLeft(); - bottomLeft = tab->rect.topRight(); - bottomRight = tab->rect.topLeft(); - } else { - vectorLeft = QPoint(-1, 0); - vectorRight = QPoint(1, 0); - - topLeft = tab->rect.bottomLeft(); - topRight = tab->rect.bottomRight(); - bottomLeft = tab->rect.topLeft(); - bottomRight = tab->rect.topRight(); - } - - baseColor1 = border; - baseColor2 = innerBottomRight; - break ; - default: - break; - } - - // Make the tab smaller when it's at the end, so that we are able to draw the corner - if (atEnd) { - topRight += vectorLeft; - bottomRight += vectorLeft; - } - - { - // Outer border - QLine topLine; - { - QPoint adjustTopLineLeft = (vectorRight * (marginLeft + (previousSelected ? 0 : 1))) + - (vectorDown * lowerTop); - QPoint adjustTopLineRight = (vectorDown * lowerTop); - if (atBeginning || selected) - adjustTopLineLeft += vectorRight; - if (atEnd || selected) - adjustTopLineRight += 2 * vectorLeft; - - topLine = QLine(topLeft + adjustTopLineLeft, topRight + adjustTopLineRight); - } - - QLine leftLine; - { - QPoint adjustLeftLineTop = (vectorRight * marginLeft) + (vectorDown * (lowerTop + 1)); - QPoint adjustLeftLineBottom = (vectorRight * marginLeft) + (vectorUp * borderThickness); - if (atBeginning || selected) - adjustLeftLineTop += vectorDown; // Make place for rounded corner - if (atBeginning && selected) - adjustLeftLineBottom += borderThickness * vectorDown; - else if (selected) - adjustLeftLineBottom += vectorUp; - - leftLine = QLine(topLeft + adjustLeftLineTop, bottomLeft + adjustLeftLineBottom); - } - - QLine rightLine; - { - QPoint adjustRightLineTop = vectorDown * (2 + lowerTop); - QPoint adjustRightLineBottom = vectorUp * borderThickness; - if (selected) - adjustRightLineBottom += vectorUp; - - rightLine = QLine(topRight + adjustRightLineTop, bottomRight + adjustRightLineBottom); - } - - // Background - QPoint startPoint = topLine.p1() + vectorDown + vectorLeft; - if (mouseOver) - startPoint += vectorDown; - QPoint endPoint = rightLine.p2(); - - if (tab->state & State_Enabled) { - QRect fillRect = QRect(startPoint, endPoint).normalized(); - if (fillRect.isValid()) { - if (selected) { - fillRect = QRect(startPoint, endPoint + vectorLeft + vectorDown * 3).normalized(); - painter->fillRect(fillRect, option->palette.window()); - - // Connect to the base - painter->setPen(QPen(option->palette.window(), 0)); - QVarLengthArray points; - points.append(rightLine.p2() + vectorDown); - points.append(rightLine.p2() + vectorDown + vectorDown); - points.append(rightLine.p2() + vectorDown + vectorDown + vectorRight); - if (tab->position != QStyleOptionTab::Beginning) { - points.append(leftLine.p2() + vectorDown); - points.append(leftLine.p2() + vectorDown + vectorDown); - points.append(leftLine.p2() + vectorDown + vectorDown + vectorLeft); - } - painter->drawPoints(points.constData(), points.size()); - } else { - QBrush buttonGradientBrush; - QBrush buttonBrush = qMapBrushToRect(option->palette.button(), fillRect); - if (buttonBrush.gradient() || !buttonBrush.texture().isNull()) { - buttonGradientBrush = buttonBrush; - } else { - // Generate gradients - QLinearGradient buttonGradient(fillRect.topLeft(), fillRect.bottomLeft()); - buttonGradient.setColorAt(0.0, buttonBrush.color().lighter(104)); - buttonGradient.setColorAt(1.0, buttonBrush.color().darker(110)); - buttonGradientBrush = QBrush(buttonGradient); - } - - painter->fillRect(fillRect, buttonGradientBrush); - } - } - } - - QPoint rightCornerDot = topRight + vectorLeft + (lowerTop + 1)*vectorDown; - QPoint leftCornerDot = topLeft + (marginLeft + 1)*vectorRight + (lowerTop + 1)*vectorDown; - QPoint bottomRightConnectToBase = rightLine.p2() + vectorRight + vectorDown; - QPoint bottomLeftConnectToBase = leftLine.p2() + vectorLeft + vectorDown; - - painter->setPen(QPen(border, 0)); - - QVarLengthArray lines; - QVarLengthArray points; - - lines.append(topLine); - - if (mouseOver) { - painter->drawLines(lines.constData(), lines.count()); - lines.clear(); - - QLine secondHoverLine = QLine(topLine.p1() + vectorDown * 2 + vectorLeft, topLine.p2() + vectorDown * 2 + vectorRight); - painter->setPen(highlightedLightInnerBorderColor); - painter->drawLine(secondHoverLine); - } - - if (mouseOver) - painter->setPen(QPen(border, 0)); - - if (!previousSelected) - lines.append(leftLine); - if (atEnd || selected) { - lines.append(rightLine); - points.append(rightCornerDot); - } - if (atBeginning || selected) - points.append(leftCornerDot); - if (selected) { - points.append(bottomRightConnectToBase); - points.append(bottomLeftConnectToBase); - } - if (lines.size() > 0) { - painter->drawLines(lines.constData(), lines.size()); - lines.clear(); - } - if (points.size() > 0) { - painter->drawPoints(points.constData(), points.size()); - points.clear(); - } - - // Antialiasing - painter->setPen(QPen(corner, 0)); - if (atBeginning || selected) - points.append(topLine.p1() + vectorLeft); - if (!previousSelected) - points.append(leftLine.p1() + vectorUp); - if (atEnd || selected) { - points.append(topLine.p2() + vectorRight); - points.append(rightLine.p1() + vectorUp); - } - - if (selected) { - points.append(bottomRightConnectToBase + vectorLeft); - if (!atBeginning) { - points.append(bottomLeftConnectToBase + vectorRight); - - if (((tab->position == QStyleOptionTab::Beginning) || onlyTab) && leftCornerWidget) { - // A special case: When the first tab is selected and - // has a left corner widget, it needs to do more work - // to connect to the base - QPoint p1 = bottomLeftConnectToBase + vectorDown; - - points.append(p1); - } - } - } - if (points.size() > 0) { - painter->drawPoints(points.constData(), points.size()); - points.clear(); - } - - // Inner border - QLine innerTopLine = QLine(topLine.p1() + vectorDown, topLine.p2() + vectorDown); - if (!selected) { - QLinearGradient topLineGradient(innerTopLine.p1(),innerTopLine.p2()); - topLineGradient.setColorAt(0, lightShadowGradientStartColor); - topLineGradient.setColorAt(1, lightShadowGradientStopColor); - painter->setPen(QPen(mouseOver ? QBrush(highlightedDarkInnerBorderColor) : QBrush(topLineGradient), 1)); - } else { - painter->setPen(QPen(innerTopLeft, 0)); - } - painter->drawLine(innerTopLine); - - QLine innerLeftLine = QLine(leftLine.p1() + vectorRight + vectorDown, leftLine.p2() + vectorRight); - QLine innerRightLine = QLine(rightLine.p1() + vectorLeft + vectorDown, rightLine.p2() + vectorLeft); - - if (selected) { - innerRightLine = QLine(innerRightLine.p1() + vectorUp, innerRightLine.p2()); - innerLeftLine = QLine(innerLeftLine.p1() + vectorUp, innerLeftLine.p2()); - } - - if (selected || atBeginning) { - QBrush leftLineGradientBrush; - QRect rect = QRect(innerLeftLine.p1(), innerLeftLine.p2()).normalized(); - QBrush buttonBrush = qMapBrushToRect(option->palette.button(), rect); - if (buttonBrush.gradient() || !buttonBrush.texture().isNull()) { - leftLineGradientBrush = qBrushLight(buttonBrush, 105); - } else { - QLinearGradient buttonGradient3(rect.topLeft(), rect.bottomLeft()); - buttonGradient3.setColorAt(0.0, buttonBrush.color().lighter(105)); - buttonGradient3.setColorAt(1.0, buttonBrush.color()); - leftLineGradientBrush = QBrush(buttonGradient3); - } - - if (!selected) - painter->setPen(QPen(leftLineGradientBrush, 0)); - - // Assume the sun is on the same side in Right-To-Left layouts and draw the - // light shadow on the left side always (the right line is on the left side in - // reverse layouts for north and south) - if (reverseShadow) - painter->drawLine(innerRightLine); - else - painter->drawLine(innerLeftLine); - } - - if (atEnd || selected) { - if (!selected) { - QBrush rightLineGradientBrush; - QRect rect = QRect(innerRightLine.p1(), innerRightLine.p2()).normalized(); - QBrush buttonBrush = qMapBrushToRect(option->palette.button(), rect); - if (buttonBrush.gradient() || !buttonBrush.texture().isNull()) { - rightLineGradientBrush = qBrushDark(buttonBrush, 105); - } else { - QLinearGradient buttonGradient4(rect.topLeft(), rect.bottomLeft()); - buttonGradient4.setColorAt(0.0, buttonBrush.color()); - buttonGradient4.setColorAt(1.0, buttonBrush.color().darker(110)); - rightLineGradientBrush = QBrush(buttonGradient4); - } - - painter->setPen(QPen(rightLineGradientBrush, 0)); - } else { - painter->setPen(QPen(innerBottomRight, 0)); - } - - if (reverseShadow) - painter->drawLine(innerLeftLine); - else - painter->drawLine(innerRightLine); - } - - - // Base - QLine baseLine = QLine(bottomLeft + marginLeft * 2 * vectorRight, bottomRight); - { - - QPoint adjustedLeft; - QPoint adjustedRight; - - if (atEnd && !selected) { - baseLine = QLine(baseLine.p1(), baseLine.p2() + vectorRight); - } - - if (nextSelected) { - adjustedRight += vectorLeft; - baseLine = QLine(baseLine.p1(), baseLine.p2() + vectorLeft); - } - if (previousSelected) { - adjustedLeft += vectorRight; - baseLine = QLine(baseLine.p1() + vectorRight, baseLine.p2()); - } - if (atBeginning) - adjustedLeft += vectorRight; - - painter->setPen(QPen(baseColor2, 0)); - if (!selected) - painter->drawLine(baseLine); - - if (atEnd && !selected) - painter->drawPoint(baseLine.p2() + vectorRight); - - if (atBeginning && !selected) - adjustedLeft = vectorRight; - else - adjustedLeft = QPoint(0, 0); - painter->setPen(QPen(baseColor1, 0)); - if (!selected) - painter->drawLine(bottomLeft + vectorUp + adjustedLeft, baseLine.p2() + vectorUp); - - QPoint endPoint = bottomRight + vectorUp; - if (atEnd && !selected) - painter->drawPoint(endPoint); - - // For drawing a lower left "fake" corner on the base when the first tab is unselected - if (atBeginning && !selected) { - painter->drawPoint(baseLine.p1() + vectorLeft); - } - - painter->setPen(QPen(corner, 0)); - if (nextSelected) - painter->drawPoint(endPoint); - else if (selected) - painter->drawPoint(endPoint + vectorRight); - - // For drawing a lower left "fake" corner on the base when the first tab is unselected - if (atBeginning && !selected) { - painter->drawPoint(baseLine.p1() + 2 * vectorLeft); - } - } - } - } - - // Yay we're done - - painter->restore(); - } - break; -#endif // QT_NO_TABBAR - - case CE_ProgressBarGroove: - if (const QStyleOptionProgressBar *bar = qstyleoption_cast(option)) { - QRect rect = bar->rect; - QPen oldPen = painter->pen(); - - QLine lines[4]; - - // outline - painter->setPen(borderColor); - lines[0] = QLine(rect.left() + 2, rect.top(), rect.right() - 2, rect.top()); - lines[1] = QLine(rect.left() + 2, rect.bottom(), rect.right() - 2, rect.bottom()); - lines[2] = QLine(rect.left(), rect.top() + 2, rect.left(), rect.bottom() - 2); - lines[3] = QLine(rect.right(), rect.top() + 2, rect.right(), rect.bottom() - 2); - painter->drawLines(lines, 4); - - QPoint points[8]; - points[0] = QPoint(rect.left() + 1, rect.top() + 1); - points[1] = QPoint(rect.right() - 1, rect.top() + 1); - points[2] = QPoint(rect.left() + 1, rect.bottom() - 1); - points[3] = QPoint(rect.right() - 1, rect.bottom() - 1); - painter->drawPoints(points, 4); - - // alpha corners - painter->setPen(alphaCornerColor); - points[0] = QPoint(rect.left(), rect.top() + 1); - points[1] = QPoint(rect.left() + 1, rect.top()); - points[2] = QPoint(rect.right(), rect.top() + 1); - points[3] = QPoint(rect.right() - 1, rect.top()); - points[4] = QPoint(rect.left(), rect.bottom() - 1); - points[5] = QPoint(rect.left() + 1, rect.bottom()); - points[6] = QPoint(rect.right(), rect.bottom() - 1); - points[7] = QPoint(rect.right() - 1, rect.bottom()); - painter->drawPoints(points, 8); - - // inner outline, north-west - painter->setPen(gradientStartColor.darker(105)); - lines[0] = QLine(rect.left() + 2, rect.top() + 1, rect.right() - 2, rect.top() + 1); - lines[1] = QLine(rect.left() + 1, rect.top() + 2, rect.left() + 1, rect.bottom() - 2); - painter->drawLines(lines, 2); - - // base of the groove - painter->setPen(QPen()); - painter->fillRect(rect.adjusted(2, 2, -2, -1), QBrush(bar->palette.base().color())); - painter->setPen(bar->palette.base().color()); - painter->drawLine(rect.right() - 1, rect.top() + 2, rect.right() - 1, rect.bottom() - 2); - - painter->setPen(oldPen); - } - break; - case CE_ProgressBarLabel: - if (const QStyleOptionProgressBar *bar = qstyleoption_cast(option)) { - // The busy indicator doesn't draw a label - if (bar->minimum == 0 && bar->maximum == 0) - return; - - painter->save(); - - QRect rect = bar->rect; - QRect leftRect; - - QFont font; - font.setBold(true); - painter->setFont(font); - painter->setPen(bar->palette.text().color()); - - bool vertical = false; - bool inverted = false; - bool bottomToTop = false; - // Get extra style options if version 2 - if (const QStyleOptionProgressBarV2 *bar2 = qstyleoption_cast(option)) { - vertical = (bar2->orientation == Qt::Vertical); - inverted = bar2->invertedAppearance; - bottomToTop = bar2->bottomToTop; - } - - if (vertical) { - rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height - QTransform m; - if (bottomToTop) { - m.translate(0.0, rect.width()); - m.rotate(-90); - } else { - m.translate(rect.height(), 0.0); - m.rotate(90); - } - painter->setTransform(m, true); - } - - int progressIndicatorPos = (bar->progress - qreal(bar->minimum)) / qMax(qreal(1.0), qreal(bar->maximum) - bar->minimum) * rect.width(); - - bool flip = (!vertical && (((bar->direction == Qt::RightToLeft) && !inverted) - || ((bar->direction == Qt::LeftToRight) && inverted))) || (vertical && ((!inverted && !bottomToTop) || (inverted && bottomToTop))); - if (flip) { - int indicatorPos = rect.width() - progressIndicatorPos; - if (indicatorPos >= 0 && indicatorPos <= rect.width()) { - painter->setPen(bar->palette.base().color()); - leftRect = QRect(rect.left(), rect.top(), indicatorPos, rect.height()); - } else if (indicatorPos > rect.width()) { - painter->setPen(bar->palette.text().color()); - } else { - painter->setPen(bar->palette.base().color()); - } - } else { - if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.width()) { - leftRect = QRect(rect.left(), rect.top(), progressIndicatorPos, rect.height()); - } else if (progressIndicatorPos > rect.width()) { - painter->setPen(bar->palette.base().color()); - } else { - painter->setPen(bar->palette.text().color()); - } - } - - QRegion rightRect = rect; - rightRect = rightRect.subtracted(leftRect); - painter->setClipRegion(rightRect); - painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter)); - if (!leftRect.isNull()) { - painter->setPen(flip ? bar->palette.text().color() : bar->palette.base().color()); - painter->setClipRect(leftRect); - painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter)); - } - - painter->restore(); - } - break; - case CE_ProgressBarContents: - if (const QStyleOptionProgressBar *bar = qstyleoption_cast(option)) { - Q_D(const QPlastiqueStyle); - QRect rect = bar->rect; - bool vertical = false; - bool inverted = false; - bool indeterminate = (bar->minimum == 0 && bar->maximum == 0); - if (!indeterminate && bar->progress == -1) - break; - - painter->save(); - - // Get extra style options if version 2 - if (const QStyleOptionProgressBarV2 *bar2 = qstyleoption_cast(option)) { - vertical = (bar2->orientation == Qt::Vertical); - inverted = bar2->invertedAppearance; - } - - // If the orientation is vertical, we use a transform to rotate - // the progress bar 90 degrees clockwise. This way we can use the - // same rendering code for both orientations. - if (vertical) { - rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height - QTransform m = QTransform::fromTranslate(rect.height()-1, 0); - m.rotate(90.0); - painter->setTransform(m, true); - } - - int maxWidth = rect.width() - 4; - int minWidth = 4; - qint64 progress = qMax(bar->progress, bar->minimum); // workaround for bug in QProgressBar - double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth); - int width = indeterminate ? maxWidth : qMax(int(vc6_workaround), minWidth); - bool reverse = (!vertical && (bar->direction == Qt::RightToLeft)) || vertical; - if (inverted) - reverse = !reverse; - - QRect progressBar; - if (!indeterminate) { - if (!reverse) { - progressBar.setRect(rect.left() + 2, rect.top() + 2, width, rect.height() - 4); - } else { - progressBar.setRect(rect.right() - 1 - width, rect.top() + 2, width, rect.height() - 4); - } - d->stopAnimation(option->styleObject); - } else { - int slideWidth = ((rect.width() - 4) * 2) / 3; - int step = 0; - if (QProgressStyleAnimation *animation = qobject_cast(d->animation(option->styleObject))) - step = animation->progressStep(slideWidth); - else - d->startAnimation(new QProgressStyleAnimation(d->animationFps, option->styleObject)); - progressBar.setRect(rect.left() + 2 + step, rect.top() + 2, - slideWidth / 2, rect.height() - 4); - } - - // outline - painter->setPen(highlightedDarkInnerBorderColor); - - QVarLengthArray lines; - QVarLengthArray points; - if (!reverse) { - if (width == minWidth) { - points.append(QPoint(progressBar.left() + 1, progressBar.top())); - points.append(QPoint(progressBar.left() + 1, progressBar.bottom())); - } else { - if (indeterminate) { - lines.append(QLine(progressBar.left() + 2, progressBar.top(), - progressBar.right() - 2, progressBar.top())); - lines.append(QLine(progressBar.left() + 2, progressBar.bottom(), - progressBar.right() - 2, progressBar.bottom())); - } else { - lines.append(QLine(progressBar.left() + 1, progressBar.top(), - progressBar.right() - 2, progressBar.top())); - lines.append(QLine(progressBar.left() + 1, progressBar.bottom(), - progressBar.right() - 2, progressBar.bottom())); - } - } - - if (indeterminate) { - lines.append(QLine(progressBar.left(), progressBar.top() + 2, - progressBar.left(), progressBar.bottom() - 2)); - } else { - lines.append(QLine(progressBar.left(), progressBar.top() + 1, - progressBar.left(), progressBar.bottom() - 1)); - } - lines.append(QLine(progressBar.right(), progressBar.top() + 2, - progressBar.right(), progressBar.bottom() - 2)); - } else { - if (width == minWidth) { - points.append(QPoint(progressBar.right() - 1, progressBar.top())); - points.append(QPoint(progressBar.right() - 1, progressBar.bottom())); - } else { - if (indeterminate) { - lines.append(QLine(progressBar.right() - 2, progressBar.top(), - progressBar.left() + 2, progressBar.top())); - lines.append(QLine(progressBar.right() - 2, progressBar.bottom(), - progressBar.left() + 2, progressBar.bottom())); - } else { - lines.append(QLine(progressBar.right() - 1, progressBar.top(), - progressBar.left() + 2, progressBar.top())); - lines.append(QLine(progressBar.right() - 1, progressBar.bottom(), - progressBar.left() + 2, progressBar.bottom())); - } - } - if (indeterminate) { - lines.append(QLine(progressBar.right(), progressBar.top() + 2, - progressBar.right(), progressBar.bottom() - 2)); - } else { - lines.append(QLine(progressBar.right(), progressBar.top() + 1, - progressBar.right(), progressBar.bottom() - 1)); - } - lines.append(QLine(progressBar.left(), progressBar.top() + 2, - progressBar.left(), progressBar.bottom() - 2)); - } - - if (points.size() > 0) { - painter->drawPoints(points.constData(), points.size()); - points.clear(); - } - painter->drawLines(lines.constData(), lines.size()); - lines.clear(); - - // alpha corners - painter->setPen(alphaInnerColor); - if (!reverse) { - if (indeterminate) { - points.append(QPoint(progressBar.left() + 1, progressBar.top())); - points.append(QPoint(progressBar.left(), progressBar.top() + 1)); - points.append(QPoint(progressBar.left() + 1, progressBar.bottom())); - points.append(QPoint(progressBar.left(), progressBar.bottom() - 1)); - } else { - points.append(QPoint(progressBar.left(), progressBar.top())); - points.append(QPoint(progressBar.left(), progressBar.bottom())); - } - points.append(QPoint(progressBar.right() - 1, progressBar.top())); - points.append(QPoint(progressBar.right(), progressBar.top() + 1)); - points.append(QPoint(progressBar.right() - 1, progressBar.bottom())); - points.append(QPoint(progressBar.right(), progressBar.bottom() - 1)); - } else { - if (indeterminate) { - points.append(QPoint(progressBar.right() - 1, progressBar.top())); - points.append(QPoint(progressBar.right(), progressBar.top() + 1)); - points.append(QPoint(progressBar.right() - 1, progressBar.bottom())); - points.append(QPoint(progressBar.right(), progressBar.bottom() - 1)); - } else { - points.append(QPoint(progressBar.right(), progressBar.top())); - points.append(QPoint(progressBar.right(), progressBar.bottom())); - } - points.append(QPoint(progressBar.left() + 1, progressBar.top())); - points.append(QPoint(progressBar.left(), progressBar.top() + 1)); - points.append(QPoint(progressBar.left() + 1, progressBar.bottom())); - points.append(QPoint(progressBar.left(), progressBar.bottom() - 1)); - } - - painter->drawPoints(points.constData(), points.size()); - points.clear(); - - // contents - painter->setPen(QPen()); - - QString progressBarName = QStyleHelper::uniqueName(QLatin1String("progressBarContents"), - option, rect.size()); - QPixmap cache; - if (!QPixmapCache::find(progressBarName, cache) && rect.height() > 7) { - QSize size = rect.size(); - cache = QPixmap(QSize(size.width() - 6 + 30, size.height() - 6)); - cache.fill(Qt::white); - QPainter cachePainter(&cache); - QRect pixmapRect(0, 0, cache.width(), cache.height()); - - int leftEdge = 0; - bool flip = false; - while (leftEdge < cache.width() + 1) { - QColor rectColor = option->palette.highlight().color(); - QColor lineColor = option->palette.highlight().color(); - if (flip) { - flip = false; - rectColor = rectColor.lighter(105); - lineColor = lineColor.lighter(105); - } else { - flip = true; - } - - cachePainter.setPen(lineColor); - const QLine cacheLines[2] = { - QLine(pixmapRect.left() + leftEdge - 1, pixmapRect.top(), - pixmapRect.left() + leftEdge + 9, pixmapRect.top()), - QLine(pixmapRect.left() + leftEdge - 1, pixmapRect.bottom(), - pixmapRect.left() + leftEdge + 9, pixmapRect.bottom()) }; - cachePainter.drawLines(cacheLines, 2); - cachePainter.fillRect(QRect(pixmapRect.left() + leftEdge, pixmapRect.top(), - 10, pixmapRect.height()), rectColor); - - leftEdge += 10; - } - - QPixmapCache::insert(progressBarName, cache); - } - painter->setClipRect(progressBar.adjusted(1, 0, -1, -1)); - - if (!vertical) - progressBar.adjust(0, 1, 0, 1); - if (!indeterminate) { - int step = 0; - if (AnimateProgressBar || (indeterminate && AnimateBusyProgressBar)) { - if (QProgressStyleAnimation *animation = qobject_cast(d->animation(widget))) - step = animation->animationStep() % 20; - } - if (reverse) - painter->drawPixmap(progressBar.left() - 25 + step, progressBar.top(), cache); - else - painter->drawPixmap(progressBar.left() - 25 - step + width % 20, progressBar.top(), cache); - } else { - painter->drawPixmap(progressBar.left(), progressBar.top(), cache); - } - - painter->restore(); - } - break; - - case CE_HeaderSection: - // Draws the header in tables. - if (const QStyleOptionHeader *header = qstyleoption_cast(option)) { - QPixmap cache; - QString pixmapName = QStyleHelper::uniqueName(QLatin1String("headersection"), option, option->rect.size()); - pixmapName += QString::number(- int(header->position)); - pixmapName += QString::number(- int(header->orientation)); - - if (!QPixmapCache::find(pixmapName, cache)) { - cache = QPixmap(option->rect.size()); - cache.fill(Qt::white); - QRect pixmapRect(0, 0, option->rect.width(), option->rect.height()); - QPainter cachePainter(&cache); - - bool sunken = (header->state & State_Enabled) && (header->state & State_Sunken); - - QColor headerGradientStart = sunken ? option->palette.background().color().darker(114) : gradientStartColor; - QColor headerGradientStop = sunken ? option->palette.background().color().darker(106) : gradientStopColor; - - QColor lightLine = sunken ? option->palette.background().color().darker(118) : gradientStartColor; - QColor darkLine = sunken ? option->palette.background().color().darker(110) : gradientStopColor.darker(105); - - qt_plastique_draw_gradient(&cachePainter, pixmapRect, - headerGradientStart, headerGradientStop); - - cachePainter.setPen(borderColor); - cachePainter.drawRect(pixmapRect.adjusted(0, 0, -1, -1)); - cachePainter.setPen(alphaCornerColor); - - const QPoint points[4] = { - pixmapRect.topLeft(), pixmapRect.topRight(), - pixmapRect.bottomLeft(), pixmapRect.bottomRight() }; - cachePainter.drawPoints(points, 4); - - QLine lines[2]; - - // inner lines - cachePainter.setPen(lightLine); - lines[0] = QLine(pixmapRect.left() + 2, pixmapRect.top() + 1, - pixmapRect.right() - 2, pixmapRect.top() + 1); - lines[1] = QLine(pixmapRect.left() + 1, pixmapRect.top() + 2, - pixmapRect.left() + 1, pixmapRect.bottom() - 2); - cachePainter.drawLines(lines, 2); - - cachePainter.setPen(darkLine); - lines[0] = QLine(pixmapRect.left() + 2, pixmapRect.bottom() - 1, - pixmapRect.right() - 2, pixmapRect.bottom() - 1); - lines[1] = QLine(pixmapRect.right() - 1, pixmapRect.bottom() - 2, - pixmapRect.right() - 1, pixmapRect.top() + 2); - cachePainter.drawLines(lines, 2); - - cachePainter.end(); - QPixmapCache::insert(pixmapName, cache); - } - painter->drawPixmap(option->rect.topLeft(), cache); - - } - break; -#ifndef QT_NO_MENU - case CE_MenuItem: - // Draws one item in a popup menu. - if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(option)) { - painter->save(); - QBrush textBrush; - if (option->palette.resolve() & (1 << QPalette::ButtonText)) - textBrush = option->palette.buttonText(); - else - textBrush = option->palette.windowText(); // KDE uses windowText rather than buttonText for menus - - if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { - painter->fillRect(menuItem->rect, option->palette.background().color().lighter(103)); - - int w = 0; - if (!menuItem->text.isEmpty()) { - painter->setFont(menuItem->font); - proxy()->drawItemText(painter, menuItem->rect.adjusted(5, 0, -5, 0), Qt::AlignLeft | Qt::AlignVCenter, - menuItem->palette, menuItem->state & State_Enabled, menuItem->text, - QPalette::Text); - w = menuItem->fontMetrics.width(menuItem->text) + 5; - } - - painter->setPen(alphaCornerColor); - bool reverse = menuItem->direction == Qt::RightToLeft; - painter->drawLine(menuItem->rect.left() + 5 + (reverse ? 0 : w), menuItem->rect.center().y(), - menuItem->rect.right() - 5 - (reverse ? w : 0), menuItem->rect.center().y()); - - painter->restore(); - break; - } - - bool selected = menuItem->state & State_Selected; - bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable; - bool checked = menuItem->checked; - - if (selected) { - qt_plastique_draw_gradient(painter, menuItem->rect, - option->palette.highlight().color().lighter(105), - option->palette.highlight().color().darker(110)); - - painter->setPen(option->palette.highlight().color().lighter(110)); - painter->drawLine(option->rect.topLeft(), option->rect.topRight()); - painter->setPen(option->palette.highlight().color().darker(115)); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - } else { - painter->fillRect(option->rect, option->palette.background().color().lighter(103)); - } - - // Check - QRect checkRect(option->rect.left() + 7, option->rect.center().y() - 6, 13, 13); - checkRect = visualRect(menuItem->direction, menuItem->rect, checkRect); - if (checkable) { - if ((menuItem->checkType & QStyleOptionMenuItem::Exclusive) && menuItem->icon.isNull()) { - QStyleOptionButton button; - button.rect = checkRect; - button.state = menuItem->state; - if (checked) - button.state |= State_On; - button.palette = menuItem->palette; - proxy()->drawPrimitive(PE_IndicatorRadioButton, &button, painter, widget); - } else { - if (menuItem->icon.isNull()) { - QStyleOptionButton button; - button.rect = checkRect; - button.state = menuItem->state; - if (checked) - button.state |= State_On; - button.palette = menuItem->palette; - proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget); - } else if (checked) { - int iconSize = qMax(menuItem->maxIconWidth, 20); - QRect sunkenRect(option->rect.left() + 1, - option->rect.top() + (option->rect.height() - iconSize) / 2 + 1, - iconSize, iconSize); - sunkenRect = visualRect(menuItem->direction, menuItem->rect, sunkenRect); - - QStyleOption opt = *option; - opt.state |= State_Sunken; - opt.rect = sunkenRect; - qt_plastique_drawShadedPanel(painter, &opt, false, widget); - } - } - } - - // Text and icon, ripped from windows style - bool dis = !(menuItem->state & State_Enabled); - bool act = menuItem->state & State_Selected; - const QStyleOption *opt = option; - const QStyleOptionMenuItem *menuitem = menuItem; - int checkcol = qMax(menuitem->maxIconWidth, 20); - QPainter *p = painter; - QRect vCheckRect = visualRect(opt->direction, menuitem->rect, - QRect(menuitem->rect.x(), menuitem->rect.y(), - checkcol, menuitem->rect.height())); - if (!menuItem->icon.isNull()) { - QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; - if (act && !dis) - mode = QIcon::Active; - QPixmap pixmap; - if (checked) - pixmap = menuItem->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On); - else - pixmap = menuItem->icon.pixmap(pixelMetric(PM_SmallIconSize, option, widget), mode); - int pixw = pixmap.width(); - int pixh = pixmap.height(); - - QRect pmr(0, 0, pixw, pixh); - pmr.moveCenter(vCheckRect.center()); - painter->setPen(textBrush.color()); - if (checkable && checked) - painter->drawPixmap(QPoint(pmr.left() + 1, pmr.top() + 1), pixmap); - else - painter->drawPixmap(pmr.topLeft(), pixmap); - } - - if (selected) { - painter->setPen(menuItem->palette.highlightedText().color()); - } else { - painter->setPen(textBrush.color()); - } - int x, y, w, h; - menuitem->rect.getRect(&x, &y, &w, &h); - int tab = menuitem->tabWidth; - QColor discol; - if (dis) { - discol = textBrush.color(); - p->setPen(discol); - } - int xm = windowsItemFrame + checkcol + windowsItemHMargin; - int xpos = menuitem->rect.x() + xm; - QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin); - QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect); - QString s = menuitem->text; - if (!s.isEmpty()) { // draw text - p->save(); - int t = s.indexOf(QLatin1Char('\t')); - int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; - if (!styleHint(SH_UnderlineShortcut, menuitem, widget)) - text_flags |= Qt::TextHideMnemonic; - text_flags |= Qt::AlignLeft; - if (t >= 0) { - QRect vShortcutRect = visualRect(opt->direction, menuitem->rect, - QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom()))); - if (dis && !act && styleHint(SH_EtchDisabledText, option, widget)) { - p->setPen(menuitem->palette.light().color()); - p->drawText(vShortcutRect.adjusted(1,1,1,1), text_flags, s.mid(t + 1)); - p->setPen(discol); - } - p->drawText(vShortcutRect, text_flags, s.mid(t + 1)); - s = s.left(t); - } - QFont font = menuitem->font; - if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem) - font.setBold(true); - p->setFont(font); - if (dis && !act && styleHint(SH_EtchDisabledText, option, widget)) { - p->setPen(menuitem->palette.light().color()); - p->drawText(vTextRect.adjusted(1,1,1,1), text_flags, s.left(t)); - p->setPen(discol); - } - p->drawText(vTextRect, text_flags, s.left(t)); - p->restore(); - } - - // Arrow - if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow - int dim = (menuItem->rect.height() - 4) / 2; - PrimitiveElement arrow; - arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight; - int xpos = menuItem->rect.left() + menuItem->rect.width() - 6 - 2 - dim; - QRect vSubMenuRect = visualRect(option->direction, menuItem->rect, - QRect(xpos, menuItem->rect.top() + menuItem->rect.height() / 2 - dim / 2, dim, dim)); - QStyleOptionMenuItem newMI = *menuItem; - newMI.rect = vSubMenuRect; - newMI.state = option->state & State_Enabled; - if (selected) - newMI.palette.setColor(QPalette::ButtonText, - newMI.palette.highlightedText().color()); - else - newMI.palette.setColor(QPalette::ButtonText, textBrush.color()); - proxy()->drawPrimitive(arrow, &newMI, painter, widget); - } - - painter->restore(); - } - break; -#endif // QT_NO_MENU -#ifndef QT_NO_MENUBAR - case CE_MenuBarItem: - // Draws a menu bar item; File, Edit, Help etc.. - if ((option->state & State_Selected)) { - QPixmap cache; - QString pixmapName = QStyleHelper::uniqueName(QLatin1String("menubaritem"), option, option->rect.size()); - if (!QPixmapCache::find(pixmapName, cache)) { - cache = QPixmap(option->rect.size()); - cache.fill(Qt::white); - QRect pixmapRect(0, 0, option->rect.width(), option->rect.height()); - QPainter cachePainter(&cache); - - QRect rect = pixmapRect; - - // gradient fill - if ((option->state & QStyle::State_Sunken) || (option->state & QStyle::State_On)) { - qt_plastique_draw_gradient(&cachePainter, rect.adjusted(1, 1, -1, -1), - option->palette.button().color().darker(114), - option->palette.button().color().darker(106)); - } else { - qt_plastique_draw_gradient(&cachePainter, rect.adjusted(1, 1, -1, -1), - option->palette.background().color().lighter(105), - option->palette.background().color().darker(102)); - } - - // outer border and corners - cachePainter.setPen(borderColor); - cachePainter.drawRect(rect.adjusted(0, 0, -1, -1)); - cachePainter.setPen(alphaCornerColor); - - const QPoint points[4] = { - rect.topLeft(), - rect.topRight(), - rect.bottomLeft(), - rect.bottomRight() }; - cachePainter.drawPoints(points, 4); - - // inner border - if ((option->state & QStyle::State_Sunken) || (option->state & QStyle::State_On)) - cachePainter.setPen(option->palette.button().color().darker(118)); - else - cachePainter.setPen(gradientStartColor); - - QLine lines[2]; - lines[0] = QLine(rect.left() + 1, rect.top() + 1, rect.right() - 1, rect.top() + 1); - lines[1] = QLine(rect.left() + 1, rect.top() + 2, rect.left() + 1, rect.bottom() - 2); - cachePainter.drawLines(lines, 2); - - if ((option->state & QStyle::State_Sunken) || (option->state & QStyle::State_On)) - cachePainter.setPen(option->palette.button().color().darker(114)); - else - cachePainter.setPen(gradientStopColor.darker(102)); - lines[0] = QLine(rect.left() + 1, rect.bottom() - 1, rect.right() - 1, rect.bottom() - 1); - lines[1] = QLine(rect.right() - 1, rect.top() + 1, rect.right() - 1, rect.bottom() - 2); - cachePainter.drawLines(lines, 2); - cachePainter.end(); - QPixmapCache::insert(pixmapName, cache); - } - painter->drawPixmap(option->rect.topLeft(), cache); - } else { - painter->fillRect(option->rect, option->palette.background()); - } - - if (const QStyleOptionMenuItem *mbi = qstyleoption_cast(option)) { - QStyleOptionMenuItem newMI = *mbi; - if (!(option->palette.resolve() & (1 << QPalette::ButtonText))) //KDE uses windowText rather than buttonText for menus - newMI.palette.setColor(QPalette::ButtonText, newMI.palette.windowText().color()); - QCommonStyle::drawControl(element, &newMI, painter, widget); - } - break; - -#ifndef QT_NO_MAINWINDOW - case CE_MenuBarEmptyArea: - if (widget && qobject_cast(widget->parentWidget())) { - painter->fillRect(option->rect, option->palette.window()); - QPen oldPen = painter->pen(); - painter->setPen(QPen(option->palette.dark().color())); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - painter->setPen(oldPen); - } - break; -#endif // QT_NO_MAINWINDOW - -#endif // QT_NO_MENUBAR - -#ifndef QT_NO_TOOLBOX - case CE_ToolBoxTabShape: - if (const QStyleOptionToolBox *toolBox = qstyleoption_cast(option)) { - painter->save(); - - int width = toolBox->rect.width(); - int diag = toolBox->rect.height() - 2; - - // The essential points - QPoint rightMost; - QPoint rightEdge; - QPoint leftEdge; - QPoint leftMost; - QPoint leftOne; - QPoint rightOne; - QPoint upOne(0, -1); - QPoint downOne(0, 1); - - if (toolBox->direction != Qt::RightToLeft) { - rightMost = QPoint(toolBox->rect.right(), toolBox->rect.bottom() - 2); - rightEdge = QPoint(toolBox->rect.right() - width / 10, toolBox->rect.bottom() - 2); - leftEdge = QPoint(toolBox->rect.right() - width / 10 - diag, toolBox->rect.top()); - leftMost = QPoint(toolBox->rect.left(), toolBox->rect.top()); - leftOne = QPoint(-1, 0); - rightOne = QPoint(1, 0); - } else { - rightMost = QPoint(toolBox->rect.left(), toolBox->rect.bottom() - 2); - rightEdge = QPoint(toolBox->rect.left() + width / 10, toolBox->rect.bottom() - 2); - leftEdge = QPoint(toolBox->rect.left() + width / 10 + diag, toolBox->rect.top()); - leftMost = QPoint(toolBox->rect.right(), toolBox->rect.top()); - leftOne = QPoint(1, 0); - rightOne = QPoint(-1, 0); - } - - QLine lines[3]; - - // Draw the outline - painter->setPen(borderColor); - lines[0] = QLine(rightMost, rightEdge); - lines[1] = QLine(rightEdge + leftOne, leftEdge); - lines[2] = QLine(leftEdge + leftOne, leftMost); - painter->drawLines(lines, 3); - painter->setPen(toolBox->palette.base().color()); - lines[0] = QLine(rightMost + downOne, rightEdge + downOne); - lines[1] = QLine(rightEdge + leftOne + downOne, leftEdge + downOne); - lines[2] = QLine(leftEdge + leftOne + downOne, leftMost + downOne); - painter->drawLines(lines, 3); - - painter->restore(); - } - break; -#endif // QT_NO_TOOLBOX -#ifndef QT_NO_SPLITTER - case CE_Splitter: - if ((option->state & State_Enabled) && (option->state & State_MouseOver)) - painter->fillRect(option->rect, QColor(255, 255, 255, 128)); - if (option->state & State_Horizontal) { - int height = option->rect.height() / 3; - QRect rect(option->rect.left() + (option->rect.width() / 2 - 1), - option->rect.center().y() - height / 2, 3, height); - qt_plastique_draw_handle(painter, option, rect, Qt::Horizontal, widget); - } else { - int width = option->rect.width() / 3; - QRect rect(option->rect.center().x() - width / 2, - option->rect.top() + (option->rect.height() / 2) - 1, width, 3); - qt_plastique_draw_handle(painter, option, rect, Qt::Vertical, widget); - } - break; -#endif // QT_NO_SPLITTER -#ifndef QT_NO_DOCKWIDGET - case CE_DockWidgetTitle: - if (const QStyleOptionDockWidget *dockWidget = qstyleoption_cast(option)) { - painter->save(); - - const QStyleOptionDockWidgetV2 *v2 - = qstyleoption_cast(dockWidget); - bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar; - - // Find text width and title rect - int textWidth = option->fontMetrics.width(dockWidget->title); - int margin = 4; - QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, option, widget); - QRect rect = dockWidget->rect; - - if (verticalTitleBar) { - QRect r = rect; - QSize s = r.size(); - s.transpose(); - r.setSize(s); - - titleRect = QRect(r.left() + rect.bottom() - - titleRect.bottom(), - r.top() + titleRect.left() - rect.left(), - titleRect.height(), titleRect.width()); - - painter->translate(r.left(), r.top() + r.width()); - painter->rotate(-90); - painter->translate(-r.left(), -r.top()); - - rect = r; - } - - // Chop and insert ellide into title if text is too wide - QString title = elliditide(dockWidget->title, dockWidget->fontMetrics, titleRect, &textWidth); - - // Draw the toolbar handle pattern to the left and right of the text - QImage handle(qt_toolbarhandle); - alphaCornerColor.setAlpha(170); - handle.setColor(1, alphaCornerColor.rgba()); - handle.setColor(2, mergedColors(alphaCornerColor, option->palette.light().color()).rgba()); - handle.setColor(3, option->palette.light().color().rgba()); - - if (title.isEmpty()) { - // Joint handle if there's no title - QRect r; - r.setRect(titleRect.left(), titleRect.top(), titleRect.width(), titleRect.bottom()); - int nchunks = (r.width() / handle.width()) - 1; - int indent = (r.width() - (nchunks * handle.width())) / 2; - for (int i = 0; i < nchunks; ++i) { - painter->drawImage(QPoint(r.left() + indent + i * handle.width(), - r.center().y() - handle.height() / 2), - handle); - } - } else { - // Handle pattern to the left of the title - QRect leftSide(titleRect.left(), titleRect.top(), - titleRect.width() / 2 - textWidth / 2 - margin, titleRect.bottom()); - int nchunks = leftSide.width() / handle.width(); - int indent = (leftSide.width() - (nchunks * handle.width())) / 2; - for (int i = 0; i < nchunks; ++i) { - painter->drawImage(QPoint(leftSide.left() + indent - + i * handle.width(), - leftSide.center().y() - - handle.height() / 2), - handle); - } - - // Handle pattern to the right of the title - QRect rightSide = titleRect.adjusted(titleRect.width() / 2 + textWidth / 2 + margin, 0, 0, 0); - nchunks = rightSide.width() / handle.width(); - indent = (rightSide.width() - (nchunks * handle.width())) / 2; - for (int j = 0; j < nchunks; ++j) { - painter->drawImage(QPoint(rightSide.left() + indent + j * handle.width(), - rightSide.center().y() - handle.height() / 2), - handle); - } - } - - // Draw the text centered - QFont font = painter->font(); - font.setPointSize(QFontInfo(font).pointSize() - 1); - painter->setFont(font); - painter->setPen(dockWidget->palette.windowText().color()); - painter->drawText(titleRect, - int(Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextShowMnemonic), - title); - - painter->restore(); - } - - break; -#endif // QT_NO_DOCKWIDGET -#ifndef QT_NO_TOOLBAR - case CE_ToolBar: - if (const QStyleOptionToolBar *toolBar = qstyleoption_cast(option)) { - // Draws the light line above and the dark line below menu bars and - // tool bars. - QPen oldPen = painter->pen(); - if (toolBar->toolBarArea == Qt::TopToolBarArea) { - if (toolBar->positionOfLine == QStyleOptionToolBar::End - || toolBar->positionOfLine == QStyleOptionToolBar::OnlyOne) { - // The end and onlyone top toolbar lines draw a double - // line at the bottom to blend with the central - // widget. - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.left(), option->rect.bottom() - 1, - option->rect.right(), option->rect.bottom() - 1); - } else { - // All others draw a single dark line at the bottom. - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - } - // All top toolbar lines draw a light line at the top. - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.topLeft(), option->rect.topRight()); - } else if (toolBar->toolBarArea == Qt::BottomToolBarArea) { - if (toolBar->positionOfLine == QStyleOptionToolBar::End - || toolBar->positionOfLine == QStyleOptionToolBar::Middle) { - // The end and middle bottom tool bar lines draw a dark - // line at the bottom. - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - } - if (toolBar->positionOfLine == QStyleOptionToolBar::Beginning - || toolBar->positionOfLine == QStyleOptionToolBar::OnlyOne) { - // The beginning and only one tool bar lines draw a - // double line at the bottom to blend with the - // status bar. - // ### The styleoption could contain whether the - // main window has a menu bar and a status bar, and - // possibly dock widgets. - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.left(), option->rect.bottom() - 1, - option->rect.right(), option->rect.bottom() - 1); - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - } - if (toolBar->positionOfLine == QStyleOptionToolBar::End) { - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.topLeft(), option->rect.topRight()); - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.left(), option->rect.top() + 1, - option->rect.right(), option->rect.top() + 1); - - } else { - // All other bottom toolbars draw a light line at the top. - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.topLeft(), option->rect.topRight()); - } - } - if (toolBar->toolBarArea == Qt::LeftToolBarArea) { - if (toolBar->positionOfLine == QStyleOptionToolBar::Middle - || toolBar->positionOfLine == QStyleOptionToolBar::End) { - // The middle and left end toolbar lines draw a light - // line to the left. - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.topLeft(), option->rect.bottomLeft()); - } - if (toolBar->positionOfLine == QStyleOptionToolBar::End) { - // All other left toolbar lines draw a dark line to the right - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.right() - 1, option->rect.top(), - option->rect.right() - 1, option->rect.bottom()); - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.topRight(), option->rect.bottomRight()); - } else { - // All other left toolbar lines draw a dark line to the right - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.topRight(), option->rect.bottomRight()); - } - } else if (toolBar->toolBarArea == Qt::RightToolBarArea) { - if (toolBar->positionOfLine == QStyleOptionToolBar::Middle - || toolBar->positionOfLine == QStyleOptionToolBar::End) { - // Right middle and end toolbar lines draw the dark right line - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.topRight(), option->rect.bottomRight()); - } - if (toolBar->positionOfLine == QStyleOptionToolBar::End - || toolBar->positionOfLine == QStyleOptionToolBar::OnlyOne) { - // The right end and single toolbar draws the dark - // line on its left edge - painter->setPen(alphaCornerColor); - painter->drawLine(option->rect.topLeft(), option->rect.bottomLeft()); - // And a light line next to it - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.left() + 1, option->rect.top(), - option->rect.left() + 1, option->rect.bottom()); - } else { - // Other right toolbars draw a light line on its left edge - painter->setPen(option->palette.background().color().lighter(104)); - painter->drawLine(option->rect.topLeft(), option->rect.bottomLeft()); - } - } - painter->setPen(oldPen); - } - break; -#endif // QT_NO_TOOLBAR -#ifndef QT_NO_SCROLLBAR - case CE_ScrollBarAddLine: - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - - bool horizontal = scrollBar->orientation == Qt::Horizontal; - bool reverse = scrollBar->direction == Qt::RightToLeft; - bool sunken = scrollBar->state & State_Sunken; - - QString addLinePixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_addline"), option, option->rect.size()); - QPixmap cache; - if (!QPixmapCache::find(addLinePixmapName, cache)) { - cache = QPixmap(option->rect.size()); - cache.fill(Qt::white); - QRect pixmapRect(0, 0, cache.width(), cache.height()); - QPainter addLinePainter(&cache); - addLinePainter.fillRect(pixmapRect, option->palette.background()); - - if (option->state & State_Enabled) { - // Gradient - QLinearGradient gradient(pixmapRect.center().x(), pixmapRect.top() + 2, - pixmapRect.center().x(), pixmapRect.bottom() - 2); - if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken) { - gradient.setColorAt(0, gradientStopColor); - gradient.setColorAt(1, gradientStopColor); - } else { - gradient.setColorAt(0, gradientStartColor.lighter(105)); - gradient.setColorAt(1, gradientStopColor); - } - addLinePainter.fillRect(pixmapRect.left() + 2, pixmapRect.top() + 2, - pixmapRect.right() - 3, pixmapRect.bottom() - 3, - gradient); - } - - // Details - QImage addButton; - if (horizontal) { - addButton = QImage(reverse ? qt_scrollbar_button_left : qt_scrollbar_button_right); - } else { - addButton = QImage(qt_scrollbar_button_down); - } - addButton.setColor(1, alphaCornerColor.rgba()); - addButton.setColor(2, borderColor.rgba()); - if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken) { - addButton.setColor(3, gradientStopColor.rgba()); - addButton.setColor(4, gradientStopColor.rgba()); - } else { - addButton.setColor(3, gradientStartColor.lighter(105).rgba()); - addButton.setColor(4, gradientStopColor.rgba()); - } - addButton.setColor(5, scrollBar->palette.text().color().rgba()); - addLinePainter.drawImage(pixmapRect, addButton); - - // Arrow - if (horizontal) { - QImage arrow(reverse ? qt_scrollbar_button_arrow_left : qt_scrollbar_button_arrow_right); - arrow.setColor(1, scrollBar->palette.foreground().color().rgba()); - - if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken) - addLinePainter.translate(1, 1); - addLinePainter.drawImage(QPoint(pixmapRect.center().x() - 2, pixmapRect.center().y() - 3), arrow); - } else { - QImage arrow(qt_scrollbar_button_arrow_down); - arrow.setColor(1, scrollBar->palette.foreground().color().rgba()); - - if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken) - addLinePainter.translate(1, 1); - addLinePainter.drawImage(QPoint(pixmapRect.center().x() - 3, pixmapRect.center().y() - 2), arrow); - } - addLinePainter.end(); - QPixmapCache::insert(addLinePixmapName, cache); - } - painter->drawPixmap(option->rect.topLeft(), cache); - } - break; - case CE_ScrollBarSubPage: - case CE_ScrollBarAddPage: - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - bool sunken = scrollBar->state & State_Sunken; - bool horizontal = scrollBar->orientation == Qt::Horizontal; - - QString groovePixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_groove"), option, option->rect.size()); - if (sunken) - groovePixmapName += QLatin1String("-sunken"); - if (element == CE_ScrollBarAddPage) - groovePixmapName += QLatin1String("-addpage"); - - QPixmap cache; - if (!QPixmapCache::find(groovePixmapName, cache)) { - cache = QPixmap(option->rect.size()); - cache.fill(option->palette.background().color()); - QPainter groovePainter(&cache); - QRect pixmapRect = QRect(0, 0, option->rect.width(), option->rect.height()); - QColor color = scrollBar->palette.base().color().darker(sunken ? 125 : 100); - groovePainter.setBrushOrigin((element == CE_ScrollBarAddPage) ? pixmapRect.width() : 0, - (element == CE_ScrollBarAddPage) ? pixmapRect.height() : 0); - groovePainter.fillRect(pixmapRect, QBrush(color, Qt::Dense4Pattern)); - - QColor edgeColor = scrollBar->palette.base().color().darker(125); - if (horizontal) { - groovePainter.setBrushOrigin((element == CE_ScrollBarAddPage) ? pixmapRect.width() : 1, 0); - groovePainter.fillRect(QRect(pixmapRect.topLeft(), QSize(pixmapRect.width(), 1)), - QBrush(edgeColor, Qt::Dense4Pattern)); - groovePainter.fillRect(QRect(pixmapRect.bottomLeft(), QSize(pixmapRect.width(), 1)), - QBrush(edgeColor, Qt::Dense4Pattern)); - } else { - groovePainter.setBrushOrigin(0, (element == CE_ScrollBarAddPage) ? pixmapRect.height() : 1); - groovePainter.fillRect(QRect(pixmapRect.topLeft(), QSize(1, pixmapRect.height())), - QBrush(edgeColor, Qt::Dense4Pattern)); - groovePainter.fillRect(QRect(pixmapRect.topRight(), QSize(1, pixmapRect.height())), - QBrush(edgeColor, Qt::Dense4Pattern)); - } - - groovePainter.end(); - QPixmapCache::insert(groovePixmapName, cache); - } - painter->drawPixmap(option->rect.topLeft(), cache); - } - break; - case CE_ScrollBarSubLine: - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - QRect scrollBarSubLine = scrollBar->rect; - - bool horizontal = scrollBar->orientation == Qt::Horizontal; - bool isEnabled = scrollBar->state & State_Enabled; - bool reverse = scrollBar->direction == Qt::RightToLeft; - bool sunken = scrollBar->state & State_Sunken; - - // The SubLine (up/left) buttons - QRect button1; - QRect button2; - int scrollBarExtent = proxy()->pixelMetric(PM_ScrollBarExtent, option, widget); - if (horizontal) { - button1.setRect(scrollBarSubLine.left(), scrollBarSubLine.top(), scrollBarExtent, scrollBarSubLine.height()); - button2.setRect(scrollBarSubLine.right() - (scrollBarExtent - 1), scrollBarSubLine.top(), scrollBarExtent, scrollBarSubLine.height()); - } else { - button1.setRect(scrollBarSubLine.left(), scrollBarSubLine.top(), scrollBarSubLine.width(), scrollBarExtent); - button2.setRect(scrollBarSubLine.left(), scrollBarSubLine.bottom() - (scrollBarExtent - 1), scrollBarSubLine.width(), scrollBarExtent); - } - - QString subLinePixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_subline"), option, button1.size()); - QPixmap cache; - if (!QPixmapCache::find(subLinePixmapName, cache)) { - cache = QPixmap(button1.size()); - cache.fill(Qt::white); - QRect pixmapRect(0, 0, cache.width(), cache.height()); - QPainter subLinePainter(&cache); - subLinePainter.fillRect(pixmapRect, option->palette.background()); - - if (isEnabled) { - // Gradients - if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken) { - qt_plastique_draw_gradient(&subLinePainter, - QRect(pixmapRect.left() + 2, pixmapRect.top() + 2, - pixmapRect.right() - 3, pixmapRect.bottom() - 3), - gradientStopColor, - gradientStopColor); - } else { - qt_plastique_draw_gradient(&subLinePainter, - QRect(pixmapRect.left() + 2, pixmapRect.top() + 2, - pixmapRect.right() - 3, pixmapRect.bottom() - 3), - gradientStartColor.lighter(105), - gradientStopColor); - } - } - - // Details - QImage subButton; - if (horizontal) { - subButton = QImage(reverse ? qt_scrollbar_button_right : qt_scrollbar_button_left); - } else { - subButton = QImage(qt_scrollbar_button_up); - } - subButton.setColor(1, alphaCornerColor.rgba()); - subButton.setColor(2, borderColor.rgba()); - if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken) { - subButton.setColor(3, gradientStopColor.rgba()); - subButton.setColor(4, gradientStopColor.rgba()); - } else { - subButton.setColor(3, gradientStartColor.lighter(105).rgba()); - subButton.setColor(4, gradientStopColor.rgba()); - } - subButton.setColor(5, scrollBar->palette.text().color().rgba()); - subLinePainter.drawImage(pixmapRect, subButton); - - // Arrows - if (horizontal) { - QImage arrow(reverse ? qt_scrollbar_button_arrow_right : qt_scrollbar_button_arrow_left); - arrow.setColor(1, scrollBar->palette.foreground().color().rgba()); - - if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken) - subLinePainter.translate(1, 1); - subLinePainter.drawImage(QPoint(pixmapRect.center().x() - 2, pixmapRect.center().y() - 3), arrow); - } else { - QImage arrow(qt_scrollbar_button_arrow_up); - arrow.setColor(1, scrollBar->palette.foreground().color().rgba()); - - if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken) - subLinePainter.translate(1, 1); - subLinePainter.drawImage(QPoint(pixmapRect.center().x() - 3, pixmapRect.center().y() - 2), arrow); - } - subLinePainter.end(); - QPixmapCache::insert(subLinePixmapName, cache); - } - painter->drawPixmap(button1.topLeft(), cache); - painter->drawPixmap(button2.topLeft(), cache); - } - break; - case CE_ScrollBarSlider: - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - bool horizontal = scrollBar->orientation == Qt::Horizontal; - bool isEnabled = scrollBar->state & State_Enabled; - - // The slider - if (option->rect.isValid()) { - QString sliderPixmapName = QStyleHelper::uniqueName(QLatin1String("scrollbar_slider"), option, option->rect.size()); - if (horizontal) - sliderPixmapName += QLatin1String("-horizontal"); - - QPixmap cache; - if (!QPixmapCache::find(sliderPixmapName, cache)) { - cache = QPixmap(option->rect.size()); - cache.fill(Qt::white); - QRect pixmapRect(0, 0, cache.width(), cache.height()); - QPainter sliderPainter(&cache); - bool sunken = (scrollBar->state & State_Sunken); - - if (isEnabled) { - QLinearGradient gradient(pixmapRect.left(), pixmapRect.center().y(), - pixmapRect.right(), pixmapRect.center().y()); - if (horizontal) - gradient = QLinearGradient(pixmapRect.center().x(), pixmapRect.top(), - pixmapRect.center().x(), pixmapRect.bottom()); - - if (sunken) { - gradient.setColorAt(0, gradientStartColor.lighter(110)); - gradient.setColorAt(1, gradientStopColor.lighter(105)); - } else { - gradient.setColorAt(0, gradientStartColor.lighter(105)); - gradient.setColorAt(1, gradientStopColor); - } - sliderPainter.fillRect(pixmapRect.adjusted(2, 2, -2, -2), gradient); - } else { - sliderPainter.fillRect(pixmapRect.adjusted(2, 2, -2, -2), option->palette.background()); - } - - sliderPainter.setPen(borderColor); - sliderPainter.drawRect(pixmapRect.adjusted(0, 0, -1, -1)); - sliderPainter.setPen(alphaCornerColor); - QPoint points[4] = { - QPoint(pixmapRect.left(), pixmapRect.top()), - QPoint(pixmapRect.left(), pixmapRect.bottom()), - QPoint(pixmapRect.right(), pixmapRect.top()), - QPoint(pixmapRect.right(), pixmapRect.bottom()) }; - sliderPainter.drawPoints(points, 4); - - QLine lines[2]; - sliderPainter.setPen(sunken ? gradientStartColor.lighter(110) : gradientStartColor.lighter(105)); - lines[0] = QLine(pixmapRect.left() + 1, pixmapRect.top() + 1, - pixmapRect.right() - 1, pixmapRect.top() + 1); - lines[1] = QLine(pixmapRect.left() + 1, pixmapRect.top() + 2, - pixmapRect.left() + 1, pixmapRect.bottom() - 2); - sliderPainter.drawLines(lines, 2); - - sliderPainter.setPen(sunken ? gradientStopColor.lighter(105) : gradientStopColor); - lines[0] = QLine(pixmapRect.left() + 1, pixmapRect.bottom() - 1, - pixmapRect.right() - 1, pixmapRect.bottom() - 1); - lines[1] = QLine(pixmapRect.right() - 1, pixmapRect.top() + 2, - pixmapRect.right() - 1, pixmapRect.bottom() - 1); - sliderPainter.drawLines(lines, 2); - - int sliderMinLength = proxy()->pixelMetric(PM_ScrollBarSliderMin, scrollBar, widget); - if ((horizontal && scrollBar->rect.width() > sliderMinLength) - || (!horizontal && scrollBar->rect.height() > sliderMinLength)) { - QImage pattern(horizontal ? qt_scrollbar_slider_pattern_horizontal - : qt_scrollbar_slider_pattern_vertical); - pattern.setColor(1, alphaCornerColor.rgba()); - pattern.setColor(2, (sunken ? gradientStartColor.lighter(110) : gradientStartColor.lighter(105)).rgba()); - - if (horizontal) { - sliderPainter.drawImage(pixmapRect.center().x() - pattern.width() / 2 + 1, - pixmapRect.center().y() - 4, - pattern); - } else { - sliderPainter.drawImage(pixmapRect.center().x() - 4, - pixmapRect.center().y() - pattern.height() / 2 + 1, - pattern); - } - } - sliderPainter.end(); - // insert the slider into the cache - QPixmapCache::insert(sliderPixmapName, cache); - } - painter->drawPixmap(option->rect.topLeft(), cache); - } - } - break; -#endif -#ifndef QT_NO_COMBOBOX - case CE_ComboBoxLabel: - if (const QStyleOptionComboBox *comboBox = qstyleoption_cast(option)) { - painter->save(); - if (!comboBox->editable) { - // Plastique's non-editable combo box is drawn as a button, so - // we need the label to be drawn using ButtonText where it - // would usually use Text. - painter->setPen(QPen(comboBox->palette.buttonText(), 0)); - QWindowsStyle::drawControl(element, option, painter, widget); - } else if (!comboBox->currentIcon.isNull()) { - { - QRect editRect = proxy()->subControlRect(CC_ComboBox, comboBox, SC_ComboBoxEditField, widget); - if (comboBox->direction == Qt::RightToLeft) - editRect.adjust(0, 2, -2, -2); - else - editRect.adjust(2, 2, 0, -2); - painter->save(); - painter->setClipRect(editRect); - if (!comboBox->currentIcon.isNull()) { - QIcon::Mode mode = comboBox->state & State_Enabled ? QIcon::Normal - : QIcon::Disabled; - QPixmap pixmap = comboBox->currentIcon.pixmap(comboBox->iconSize, mode); - QRect iconRect(editRect); - iconRect.setWidth(comboBox->iconSize.width() + 5); - iconRect = alignedRect(comboBox->direction, - Qt::AlignLeft | Qt::AlignVCenter, - iconRect.size(), editRect); - painter->fillRect(iconRect, option->palette.brush(QPalette::Base)); - proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); - } - painter->restore(); - } - } else { - QWindowsStyle::drawControl(element, option, painter, widget); - } - - painter->restore(); - } - break; -#endif - default: - QWindowsStyle::drawControl(element, option, painter, widget); - break; - } -} - -/*! - \reimp -*/ -void QPlastiqueStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, - QPainter *painter, const QWidget *widget) const -{ - QColor borderColor = option->palette.background().color().darker(178); - QColor alphaCornerColor; - if (widget) { - // ### backgroundrole/foregroundrole should be part of the style option - alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), borderColor); - } else { - alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); - } - QColor gradientStartColor = option->palette.button().color().lighter(104); - QColor gradientStopColor = option->palette.button().color().darker(105); - - switch (control) { -#ifndef QT_NO_SLIDER - case CC_Slider: - if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { - QRect grooveRegion = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget); - QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); - bool horizontal = slider->orientation == Qt::Horizontal; - bool ticksAbove = slider->tickPosition & QSlider::TicksAbove; - bool ticksBelow = slider->tickPosition & QSlider::TicksBelow; - - QRect groove; - //The clickable region is 5 px wider than the visible groove for improved usability - if (grooveRegion.isValid()) - groove = horizontal ? grooveRegion.adjusted(0, 5, 0, -5) : grooveRegion.adjusted(5, 0, -5, 0); - - - QPixmap cache; - - if ((option->subControls & SC_SliderGroove) && groove.isValid()) { - BEGIN_STYLE_PIXMAPCACHE(QString::fromLatin1("slider_groove-%0-%1").arg(ticksAbove).arg(ticksBelow)) - p->fillRect(groove, option->palette.background()); - - rect = groove; - rect.moveTo(groove.left() - option->rect.left(), groove.top() - option->rect.top()); - - // draw groove - if (horizontal) { - p->setPen(borderColor); - const QLine lines[4] = { - QLine(rect.left() + 1, rect.top(), - rect.right() - 1, rect.top()), - QLine(rect.left() + 1, rect.bottom(), - rect.right() - 1, rect.bottom()), - QLine(rect.left(), rect.top() + 1, - rect.left(), rect.bottom() - 1), - QLine(rect.right(), rect.top() + 1, - rect.right(), rect.bottom() - 1) }; - p->drawLines(lines, 4); - - p->setPen(alphaCornerColor); - const QPoint points[4] = { - QPoint(rect.left(), rect.top()), - QPoint(rect.left(), rect.bottom()), - QPoint(rect.right(), rect.top()), - QPoint(rect.right(), rect.bottom()) }; - p->drawPoints(points, 4); - } else { - p->setPen(borderColor); - const QLine lines[4] = { - QLine(rect.left() + 1, rect.top(), - rect.right() - 1, rect.top()), - QLine(rect.left() + 1, rect.bottom(), - rect.right() - 1, rect.bottom()), - QLine(rect.left(), rect.top() + 1, - rect.left(), rect.bottom() - 1), - QLine(rect.right(), rect.top() + 1, - rect.right(), rect.bottom() - 1) }; - p->drawLines(lines, 4); - - p->setPen(alphaCornerColor); - const QPoint points[4] = { - QPoint(rect.left(), rect.top()), - QPoint(rect.right(), rect.top()), - QPoint(rect.left(), rect.bottom()), - QPoint(rect.right(), rect.bottom()) }; - p->drawPoints(points, 4); - } - END_STYLE_PIXMAPCACHE - } - - if ((option->subControls & SC_SliderHandle) && handle.isValid()) { - QString handlePixmapName = QStyleHelper::uniqueName(QLatin1String("slider_handle"), option, handle.size()); - if (ticksAbove && !ticksBelow) - handlePixmapName += QLatin1String("-flipped"); - if ((option->activeSubControls & SC_SliderHandle) && (option->state & State_Sunken)) - handlePixmapName += QLatin1String("-sunken"); - - if (!QPixmapCache::find(handlePixmapName, cache)) { - cache = QPixmap(handle.size()); - cache.fill(Qt::transparent); - QRect pixmapRect(0, 0, handle.width(), handle.height()); - QPainter handlePainter(&cache); - - // draw handle - if (horizontal) { - QPainterPath path; - if (ticksAbove && !ticksBelow) { - path.moveTo(QPoint(pixmapRect.right(), pixmapRect.bottom())); - path.lineTo(QPoint(pixmapRect.right(), pixmapRect.bottom() - 10)); - path.lineTo(QPoint(pixmapRect.right() - 5, pixmapRect.bottom() - 14)); - path.lineTo(QPoint(pixmapRect.left() + 1, pixmapRect.bottom() - 10)); - path.lineTo(QPoint(pixmapRect.left() + 1, pixmapRect.bottom())); - path.lineTo(QPoint(pixmapRect.right(), pixmapRect.bottom())); - } else { - path.moveTo(QPoint(pixmapRect.right(), pixmapRect.top() + 1)); - path.lineTo(QPoint(pixmapRect.right(), pixmapRect.top() + 10)); - path.lineTo(QPoint(pixmapRect.right() - 5, pixmapRect.top() + 14)); - path.lineTo(QPoint(pixmapRect.left() + 1, pixmapRect.top() + 10)); - path.lineTo(QPoint(pixmapRect.left() + 1, pixmapRect.top() + 1)); - path.lineTo(QPoint(pixmapRect.right(), pixmapRect.top() + 1)); - } - if (slider->state & State_Enabled) { - QLinearGradient gradient(pixmapRect.center().x(), pixmapRect.top(), - pixmapRect.center().x(), pixmapRect.bottom()); - if ((option->activeSubControls & SC_SliderHandle) && (option->state & State_Sunken)) { - gradient.setColorAt(0, gradientStartColor.lighter(110)); - gradient.setColorAt(1, gradientStopColor.lighter(110)); - } else { - gradient.setColorAt(0, gradientStartColor); - gradient.setColorAt(1, gradientStopColor); - } - handlePainter.fillPath(path, gradient); - } else { - handlePainter.fillPath(path, slider->palette.background()); - } - } else { - QPainterPath path; - if (ticksAbove && !ticksBelow) { - path.moveTo(QPoint(pixmapRect.right(), pixmapRect.top() + 1)); - path.lineTo(QPoint(pixmapRect.right() - 10, pixmapRect.top() + 1)); - path.lineTo(QPoint(pixmapRect.right() - 14, pixmapRect.top() + 5)); - path.lineTo(QPoint(pixmapRect.right() - 10, pixmapRect.bottom())); - path.lineTo(QPoint(pixmapRect.right(), pixmapRect.bottom())); - path.lineTo(QPoint(pixmapRect.right(), pixmapRect.top() + 1)); - } else { - path.moveTo(QPoint(pixmapRect.left() + 1, pixmapRect.top() + 1)); - path.lineTo(QPoint(pixmapRect.left() + 10, pixmapRect.top() + 1)); - path.lineTo(QPoint(pixmapRect.left() + 14, pixmapRect.top() + 5)); - path.lineTo(QPoint(pixmapRect.left() + 10, pixmapRect.bottom())); - path.lineTo(QPoint(pixmapRect.left() + 1, pixmapRect.bottom())); - path.lineTo(QPoint(pixmapRect.left() + 1, pixmapRect.top() + 1)); - } - if (slider->state & State_Enabled) { - QLinearGradient gradient(pixmapRect.center().x(), pixmapRect.top(), - pixmapRect.center().x(), pixmapRect.bottom()); - gradient.setColorAt(0, gradientStartColor); - gradient.setColorAt(1, gradientStopColor); - handlePainter.fillPath(path, gradient); - } else { - handlePainter.fillPath(path, slider->palette.background()); - } - } - - QImage image; - if (horizontal) { - image = QImage((ticksAbove && !ticksBelow) ? qt_plastique_slider_horizontalhandle_up : qt_plastique_slider_horizontalhandle); - } else { - image = QImage((ticksAbove && !ticksBelow) ? qt_plastique_slider_verticalhandle_left : qt_plastique_slider_verticalhandle); - } - - image.setColor(1, borderColor.rgba()); - image.setColor(2, gradientStartColor.rgba()); - image.setColor(3, alphaCornerColor.rgba()); - if (option->state & State_Enabled) { - image.setColor(4, 0x80ffffff); - image.setColor(5, 0x25000000); - } - handlePainter.drawImage(pixmapRect, image); - handlePainter.end(); - QPixmapCache::insert(handlePixmapName, cache); - } - - painter->drawPixmap(handle.topLeft(), cache); - - if (slider->state & State_HasFocus) { - QStyleOptionFocusRect fropt; - fropt.QStyleOption::operator=(*slider); - fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget); - proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); - } - } - - if (option->subControls & SC_SliderTickmarks) { - QPen oldPen = painter->pen(); - painter->setPen(borderColor); - int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); - int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget); - int interval = slider->tickInterval; - if (interval <= 0) { - interval = slider->singleStep; - if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval, - available) - - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, - 0, available) < 3) - interval = slider->pageStep; - } - if (interval <= 0) - interval = 1; - - int v = slider->minimum; - int len = proxy()->pixelMetric(PM_SliderLength, slider, widget); - QVarLengthArray lines; - while (v <= slider->maximum + 1) { - if (v == slider->maximum + 1 && interval == 1) - break; - const int v_ = qMin(v, slider->maximum); - int pos = sliderPositionFromValue(slider->minimum, slider->maximum, - v_, (horizontal - ? slider->rect.width() - : slider->rect.height()) - len, - slider->upsideDown) + len / 2; - - int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0); - - if (horizontal) { - if (ticksAbove) { - lines.append(QLine(pos, slider->rect.top() + extra, - pos, slider->rect.top() + tickSize)); - } - if (ticksBelow) { - lines.append(QLine(pos, slider->rect.bottom() - extra, - pos, slider->rect.bottom() - tickSize)); - } - } else { - if (ticksAbove) { - lines.append(QLine(slider->rect.left() + extra, pos, - slider->rect.left() + tickSize, pos)); - } - if (ticksBelow) { - lines.append(QLine(slider->rect.right() - extra, pos, - slider->rect.right() - tickSize, pos)); - } - } - - // in the case where maximum is max int - int nextInterval = v + interval; - if (nextInterval < v) - break; - v = nextInterval; - } - painter->drawLines(lines.constData(), lines.size()); - painter->setPen(oldPen); - } - } - break; -#endif // QT_NO_SLIDER -#ifndef QT_NO_SPINBOX - case CC_SpinBox: - if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast(option)) { - painter->save(); - bool upSunken = (spinBox->activeSubControls & SC_SpinBoxUp) && (spinBox->state & (State_Sunken | State_On)); - bool downSunken = (spinBox->activeSubControls & SC_SpinBoxDown) && (spinBox->state & (State_Sunken | State_On)); - bool reverse = (spinBox->direction == Qt::RightToLeft); - - // Rects - QRect upRect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget); - QRect downRect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget); - QRect buttonRect = upRect | downRect; - - // Brushes - QBrush corner = qMapBrushToRect(option->palette.shadow(), buttonRect); - qBrushSetAlphaF(&corner, qreal(0.25)); - QBrush border = qMapBrushToRect(option->palette.shadow(), buttonRect); - qBrushSetAlphaF(&border, qreal(0.4)); - - QVarLengthArray points; - - Q_D(const QPlastiqueStyle); - if (spinBox->buttonSymbols == QAbstractSpinBox::NoButtons) { - QRect filledRect = option->rect.adjusted(1, 1, -1, -1); - QBrush baseBrush = qMapBrushToRect(option->palette.base(), filledRect); - painter->setBrushOrigin(filledRect.topLeft()); - painter->fillRect(filledRect.adjusted(1, 1, -1, -1), baseBrush); - qt_plastique_draw_frame(painter, option->rect, option, QFrame::Sunken); - } else { - d->drawPartialFrame(painter, - option, - proxy()->subControlRect(CC_SpinBox, spinBox, SC_SpinBoxEditField, widget), - widget); - } - // Paint buttons - if (spinBox->buttonSymbols == QAbstractSpinBox::NoButtons) { - painter->restore(); - break; - } - // Button outlines - painter->setPen(QPen(border, 0)); - if (!reverse) - painter->drawLine(buttonRect.topLeft() + QPoint(0, 1), buttonRect.bottomLeft() + QPoint(0, -1)); - else - painter->drawLine(buttonRect.topRight() + QPoint(0, -1), buttonRect.bottomRight() + QPoint(0, 1)); - - if (!reverse) { - const QLine lines[4] = { - QLine(upRect.left(), upRect.top(), upRect.right() - 2, upRect.top()), - QLine(upRect.left() + 1, upRect.bottom(), upRect.right() - 1, upRect.bottom()), - QLine(downRect.left(), downRect.bottom(), downRect.right() - 2, downRect.bottom()), - QLine(buttonRect.right(), buttonRect.top() + 2, buttonRect.right(), buttonRect.bottom() - 2) }; - painter->drawLines(lines, 4); - - points.append(QPoint(upRect.right() - 1, upRect.top() + 1)); - points.append(QPoint(downRect.right() - 1, downRect.bottom() - 1)); - painter->drawPoints(points.constData(), points.size()); - points.clear(); - painter->setPen(QPen(corner, 0)); - points.append(QPoint(upRect.right() - 1, upRect.top())); - points.append(QPoint(upRect.right(), upRect.top() + 1)); - points.append(QPoint(upRect.right(), downRect.bottom() - 1)); - points.append(QPoint(upRect.right() - 1, downRect.bottom())); - } else { - const QLine lines[4] = { - QLine(upRect.right(), upRect.top(), upRect.left() + 2, upRect.top()), - QLine(upRect.right() - 1, upRect.bottom(), upRect.left() + 1, upRect.bottom()), - QLine(downRect.right(), downRect.bottom(), downRect.left() + 2, downRect.bottom()), - QLine(buttonRect.left(), buttonRect.top() + 2, buttonRect.left(), buttonRect.bottom() - 2) }; - painter->drawLines(lines, 4); - - points.append(QPoint(upRect.left() + 1, upRect.top() + 1)); - points.append(QPoint(downRect.left() + 1, downRect.bottom() - 1)); - painter->drawPoints(points.constData(), points.size()); - points.clear(); - painter->setPen(QPen(corner, 0)); - points.append(QPoint(upRect.left() + 1, upRect.top())); - points.append(QPoint(upRect.left(), upRect.top() + 1)); - points.append(QPoint(upRect.left(), downRect.bottom() - 1)); - points.append(QPoint(upRect.left() + 1, downRect.bottom())); - } - painter->drawPoints(points.constData(), points.size()); - points.clear(); - - // Button colors - QBrush buttonGradientBrush; - QBrush leftLineGradientBrush; - QBrush rightLineGradientBrush; - QBrush sunkenButtonGradientBrush; - QBrush sunkenLeftLineGradientBrush; - QBrush sunkenRightLineGradientBrush; - QBrush buttonBrush = qMapBrushToRect(option->palette.button(), buttonRect); - if (buttonBrush.gradient() || !buttonBrush.texture().isNull()) { - buttonGradientBrush = buttonBrush; - sunkenButtonGradientBrush = qBrushDark(buttonBrush, 108); - leftLineGradientBrush = qBrushLight(buttonBrush, 105); - rightLineGradientBrush = qBrushDark(buttonBrush, 105); - sunkenLeftLineGradientBrush = qBrushDark(buttonBrush, 110); - sunkenRightLineGradientBrush = qBrushDark(buttonBrush, 106); - } else { - // Generate gradients - QLinearGradient buttonGradient(buttonRect.topLeft(), buttonRect.bottomLeft()); - buttonGradient.setColorAt(0.0, buttonBrush.color().lighter(104)); - buttonGradient.setColorAt(1.0, buttonBrush.color().darker(110)); - buttonGradientBrush = QBrush(buttonGradient); - - QLinearGradient buttonGradient2(buttonRect.topLeft(), buttonRect.bottomLeft()); - buttonGradient2.setColorAt(0.0, buttonBrush.color().darker(113)); - buttonGradient2.setColorAt(1.0, buttonBrush.color().darker(103)); - sunkenButtonGradientBrush = QBrush(buttonGradient2); - - QLinearGradient buttonGradient3(buttonRect.topLeft(), buttonRect.bottomLeft()); - buttonGradient3.setColorAt(0.0, buttonBrush.color().lighter(105)); - buttonGradient3.setColorAt(1.0, buttonBrush.color()); - leftLineGradientBrush = QBrush(buttonGradient3); - - QLinearGradient buttonGradient4(buttonRect.topLeft(), buttonRect.bottomLeft()); - buttonGradient4.setColorAt(0.0, buttonBrush.color()); - buttonGradient4.setColorAt(1.0, buttonBrush.color().darker(110)); - rightLineGradientBrush = QBrush(buttonGradient4); - - QLinearGradient buttonGradient5(buttonRect.topLeft(), buttonRect.bottomLeft()); - buttonGradient5.setColorAt(0.0, buttonBrush.color().darker(113)); - buttonGradient5.setColorAt(1.0, buttonBrush.color().darker(107)); - sunkenLeftLineGradientBrush = QBrush(buttonGradient5); - - QLinearGradient buttonGradient6(buttonRect.topLeft(), buttonRect.bottomLeft()); - buttonGradient6.setColorAt(0.0, buttonBrush.color().darker(108)); - buttonGradient6.setColorAt(1.0, buttonBrush.color().darker(103)); - sunkenRightLineGradientBrush = QBrush(buttonGradient6); - } - - // Main fill - painter->fillRect(upRect.adjusted(2, 2, -2, -2), - qMapBrushToRect(upSunken ? sunkenButtonGradientBrush - : buttonGradientBrush, upRect)); - painter->fillRect(downRect.adjusted(2, 2, -2, -2), - qMapBrushToRect(downSunken ? sunkenButtonGradientBrush - : buttonGradientBrush, downRect)); - - // Top line - painter->setPen(QPen(qBrushLight(qMapBrushToRect(upSunken ? sunkenButtonGradientBrush - : buttonGradientBrush, upRect), 105), 0)); - if (!reverse) { - painter->drawLine(upRect.left() + 1, upRect.top() + 1, - upRect.right() - 2, upRect.top() + 1); - } else { - painter->drawLine(upRect.right() - 1, upRect.top() + 1, - upRect.left() + 2, upRect.top() + 1); - } - painter->setPen(QPen(qBrushLight(qMapBrushToRect(downSunken ? sunkenButtonGradientBrush - : buttonGradientBrush, downRect), 105), 0)); - if (!reverse) { - painter->drawLine(downRect.left() + 1, downRect.top() + 1, - downRect.right() - 1, downRect.top() + 1); - } else { - painter->drawLine(downRect.right() - 1, downRect.top() + 1, - downRect.left() + 1, downRect.top() + 1); - } - - // Left line - painter->setPen(QPen(qMapBrushToRect(upSunken ? sunkenLeftLineGradientBrush - : leftLineGradientBrush, upRect), 1)); - if (!reverse) { - painter->drawLine(upRect.left() + 1, upRect.top() + 2, - upRect.left() + 1, upRect.bottom() - 1); - } else { - painter->drawLine(upRect.left() + 1, upRect.top() + 2, - upRect.left() + 1, upRect.bottom() - 1); - } - painter->setPen(QPen(qMapBrushToRect(downSunken ? sunkenLeftLineGradientBrush - : leftLineGradientBrush, downRect), 1)); - if (!reverse) { - painter->drawLine(downRect.left() + 1, downRect.top() + 2, - downRect.left() + 1, downRect.bottom() - 1); - } else { - painter->drawLine(downRect.left() + 1, downRect.top() + 1, - downRect.left() + 1, downRect.bottom() - 2); - } - - // Bottom line - painter->setPen(QPen(qBrushDark(qMapBrushToRect(upSunken ? sunkenButtonGradientBrush - : buttonGradientBrush, upRect), 105), 0)); - if (!reverse) { - painter->drawLine(upRect.left() + 2, upRect.bottom() - 1, - upRect.right() - 1, upRect.bottom() - 1); - } else { - painter->drawLine(upRect.right() - 2, upRect.bottom() - 1, - upRect.left() + 1, upRect.bottom() - 1); - } - painter->setPen(QPen(qBrushDark(qMapBrushToRect(downSunken ? sunkenButtonGradientBrush - : buttonGradientBrush, downRect), 105), 0)); - if (!reverse) { - painter->drawLine(downRect.left() + 2, downRect.bottom() - 1, - downRect.right() - 2, downRect.bottom() - 1); - } else { - painter->drawLine(downRect.right() - 2, downRect.bottom() - 1, - downRect.left() + 2, downRect.bottom() - 1); - } - - // Right line - painter->setPen(QPen(qMapBrushToRect(upSunken ? sunkenRightLineGradientBrush - : rightLineGradientBrush, upRect), 1)); - if (!reverse) { - painter->drawLine(upRect.right() - 1, upRect.top() + 2, - upRect.right() - 1, upRect.bottom() - 1); - } else { - painter->drawLine(upRect.right() - 1, upRect.top() + 2, - upRect.right() - 1, upRect.bottom() - 1); - } - painter->setPen(QPen(qMapBrushToRect(downSunken ? sunkenRightLineGradientBrush - : rightLineGradientBrush, downRect), 1)); - if (!reverse) { - painter->drawLine(downRect.right() - 1, downRect.top() + 1, - downRect.right() - 1, downRect.bottom() - 2); - } else { - painter->drawLine(downRect.right() - 1, downRect.top() + 2, - downRect.right() - 1, downRect.bottom() - 1); - } - - QBrush indicatorBrush = qMapBrushToRect(option->palette.buttonText(), buttonRect); - painter->setPen(QPen(indicatorBrush, 0)); - if (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) { - QPoint center; - if (spinBox->subControls & SC_SpinBoxUp) { - // ....... - // ...X... - // ...X... - // .XXXXX. - // ...X... - // ...X... - // ....... - center = upRect.center(); - if (upSunken) { - ++center.rx(); - ++center.ry(); - } - painter->drawLine(center.x(), center.y() - 2, center.x(), center.y() + 2); - painter->drawLine(center.x() - 2, center.y(), center.x() + 2, center.y()); - } - if (spinBox->subControls & SC_SpinBoxDown) { - // ....... - // ....... - // ....... - // .XXXXX. - // ....... - // ....... - // ....... - center = downRect.center(); - if (downSunken) { - ++center.rx(); - ++center.ry(); - } - painter->drawLine(center.x() - 2, center.y(), center.x() + 2, center.y()); - } - } else { - int offset; - int centerX; - if (spinBox->subControls & SC_SpinBoxUp) { - // ........... - // .....X..... - // ....XXX.... - // ...XXXXX... - // ..XXXXXXX.. - // ........... - offset = upSunken ? 1 : 0; - QRect upArrowRect(upRect.center().x() - 3 + offset, upRect.center().y() - 2 + offset, 7, 4); - centerX = upArrowRect.center().x(); - painter->drawPoint(centerX, upArrowRect.top()); - const QLine lines[3] = { - QLine(centerX - 1, upArrowRect.top() + 1, centerX + 1, upArrowRect.top() + 1), - QLine(centerX - 2, upArrowRect.top() + 2, centerX + 2, upArrowRect.top() + 2), - QLine(centerX - 3, upArrowRect.top() + 3, centerX + 3, upArrowRect.top() + 3) }; - painter->drawLines(lines, 3); - } - if (spinBox->subControls & SC_SpinBoxDown) { - // ........... - // ..XXXXXXX.. - // ...XXXXX... - // ....XXX.... - // .....X..... - // ........... - offset = downSunken ? 1 : 0; - QRect downArrowRect(downRect.center().x() - 3 + offset, downRect.center().y() - 2 + offset + 1, 7, 4); - centerX = downArrowRect.center().x(); - const QLine lines[3] = { - QLine(centerX - 3, downArrowRect.top(), centerX + 3, downArrowRect.top()), - QLine(centerX - 2, downArrowRect.top() + 1, centerX + 2, downArrowRect.top() + 1), - QLine(centerX - 1, downArrowRect.top() + 2, centerX + 1, downArrowRect.top() + 2) }; - painter->drawLines(lines, 3); - painter->drawPoint(centerX, downArrowRect.top() + 3); - } - } - painter->restore(); - } - break; -#endif // QT_NO_SPINBOX -#ifndef QT_NO_COMBOBOX - case CC_ComboBox: - if (const QStyleOptionComboBox *comboBox = qstyleoption_cast(option)) { - bool sunken = comboBox->state & State_On; // play dead if combobox has no items - bool reverse = comboBox->direction == Qt::RightToLeft; - int menuButtonWidth = 16; - int xoffset = sunken ? (reverse ? -1 : 1) : 0; - int yoffset = sunken ? 1 : 0; - QRect rect = comboBox->rect; - QPen oldPen = painter->pen(); - - // Fill - if (comboBox->editable) { - // Button colors - QBrush alphaCornerBrush = qBrushDark(option->palette.button(), 165); - qBrushSetAlphaF(&alphaCornerBrush, 0.5); - QBrush buttonGradientBrush; - QBrush leftLineGradientBrush; - QBrush rightLineGradientBrush; - QBrush sunkenButtonGradientBrush; - QBrush sunkenLeftLineGradientBrush; - QBrush sunkenRightLineGradientBrush; - QBrush button = option->palette.button(); - if (button.gradient() || !button.texture().isNull()) { - buttonGradientBrush = button; - sunkenButtonGradientBrush = qBrushDark(button, 108); - leftLineGradientBrush = qBrushLight(button, 105); - rightLineGradientBrush = qBrushDark(button, 105); - sunkenLeftLineGradientBrush = qBrushDark(button, 110); - sunkenRightLineGradientBrush = qBrushDark(button, 106); - } else { - // Generate gradients - QLinearGradient buttonGradient(option->rect.topLeft(), option->rect.bottomLeft()); - buttonGradient.setColorAt(0.0, button.color().lighter(104)); - buttonGradient.setColorAt(1.0, button.color().darker(110)); - buttonGradientBrush = QBrush(buttonGradient); - - QLinearGradient buttonGradient2(option->rect.topLeft(), option->rect.bottomLeft()); - buttonGradient2.setColorAt(0.0, button.color().darker(113)); - buttonGradient2.setColorAt(1.0, button.color().darker(103)); - sunkenButtonGradientBrush = QBrush(buttonGradient2); - - QLinearGradient buttonGradient3(option->rect.topLeft(), option->rect.bottomLeft()); - buttonGradient3.setColorAt(0.0, button.color().lighter(105)); - buttonGradient3.setColorAt(1.0, button.color()); - leftLineGradientBrush = QBrush(buttonGradient3); - - QLinearGradient buttonGradient4(option->rect.topLeft(), option->rect.bottomLeft()); - buttonGradient4.setColorAt(0.0, button.color()); - buttonGradient4.setColorAt(1.0, button.color().darker(110)); - rightLineGradientBrush = QBrush(buttonGradient4); - - QLinearGradient buttonGradient5(option->rect.topLeft(), option->rect.bottomLeft()); - buttonGradient5.setColorAt(0.0, button.color().darker(113)); - buttonGradient5.setColorAt(1.0, button.color().darker(107)); - sunkenLeftLineGradientBrush = QBrush(buttonGradient5); - - QLinearGradient buttonGradient6(option->rect.topLeft(), option->rect.bottomLeft()); - buttonGradient6.setColorAt(0.0, button.color().darker(108)); - buttonGradient6.setColorAt(1.0, button.color().darker(103)); - sunkenRightLineGradientBrush = QBrush(buttonGradient6); - } - - // ComboBox starts with a lineedit in place already. - QRect buttonRect; - if (!reverse) { - buttonRect.setRect(rect.right() - menuButtonWidth, rect.top(), menuButtonWidth + 1, rect.height()); - } else { - buttonRect.setRect(rect.left(), rect.top(), menuButtonWidth + 1, rect.height()); - } - - Q_D(const QPlastiqueStyle); - d->drawPartialFrame(painter, - option, - proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget), - widget); - - QBrush border = qMapBrushToRect(option->palette.shadow(), buttonRect); - qBrushSetAlphaF(&border, qreal(0.4)); - painter->setPen(QPen(border, 0)); - if (!reverse) - painter->drawLine(buttonRect.topLeft() + QPoint(0, 1), buttonRect.bottomLeft() + QPoint(0, -1)); - else - painter->drawLine(buttonRect.topRight() + QPoint(0, -1), buttonRect.bottomRight() + QPoint(0, 1)); - - // Outline the button border - if (!reverse) { - const QLine lines[3] = { - QLine(buttonRect.left(), buttonRect.top(), - buttonRect.right() - 2, buttonRect.top()), - QLine(buttonRect.right(), buttonRect.top() + 2, - buttonRect.right(), buttonRect.bottom() - 2), - QLine(buttonRect.left(), buttonRect.bottom(), - buttonRect.right() - 2, buttonRect.bottom()) }; - painter->drawLines(lines, 3); - { - const QPoint points[2] = { - QPoint(buttonRect.right() - 1, buttonRect.top() + 1), - QPoint(buttonRect.right() - 1, buttonRect.bottom() - 1) }; - painter->drawPoints(points, 2); - } - - QBrush corner = qMapBrushToRect(option->palette.shadow(), buttonRect); - qBrushSetAlphaF(&corner, qreal(0.16)); - painter->setPen(QPen(corner, 0)); - { - const QPoint points[4] = { - QPoint(buttonRect.right() - 1, buttonRect.top()), - QPoint(buttonRect.right() - 1, buttonRect.bottom()), - QPoint(buttonRect.right(), buttonRect.top() + 1), - QPoint(buttonRect.right(), buttonRect.bottom() - 1) }; - painter->drawPoints(points, 4); - } - } else { - const QLine lines[3] = { - QLine(buttonRect.right(), buttonRect.top(), - buttonRect.left() + 2, buttonRect.top()), - QLine(buttonRect.left(), buttonRect.top() + 2, - buttonRect.left(), buttonRect.bottom() - 2), - QLine(buttonRect.right(), buttonRect.bottom(), - buttonRect.left() + 2, buttonRect.bottom()) }; - painter->drawLines(lines, 3); - { - const QPoint points[2] = { - QPoint(buttonRect.left() + 1, buttonRect.top() + 1), - QPoint(buttonRect.left() + 1, buttonRect.bottom() - 1) }; - painter->drawPoints(points, 2); - } - - QBrush corner = qMapBrushToRect(option->palette.shadow(), buttonRect); - qBrushSetAlphaF(&corner, qreal(0.16)); - painter->setPen(QPen(corner, 0)); - { - const QPoint points[4] = { - QPoint(buttonRect.left() + 1, buttonRect.top()), - QPoint(buttonRect.left() + 1, buttonRect.bottom()), - QPoint(buttonRect.left(), buttonRect.top() + 1), - QPoint(buttonRect.left(), buttonRect.bottom() - 1) }; - painter->drawPoints(points, 4); - } - } - - QRect fillRect = buttonRect.adjusted(2, 2, -2, -2); - // Main fill - painter->fillRect(fillRect, - qMapBrushToRect(sunken ? sunkenButtonGradientBrush - : buttonGradientBrush, option->rect)); - - // Top line - painter->setPen(QPen(qBrushLight(qMapBrushToRect(sunken ? sunkenButtonGradientBrush - : buttonGradientBrush, option->rect), 105), 0)); - if (!reverse) { - painter->drawLine(QPointF(buttonRect.left() + 1, buttonRect.top() + 1), - QPointF(buttonRect.right() - 2, buttonRect.top() + 1)); - } else { - painter->drawLine(QPointF(buttonRect.right() - 1, buttonRect.top() + 1), - QPointF(buttonRect.left() + 2, buttonRect.top() + 1)); - } - - // Bottom line - painter->setPen(QPen(qBrushDark(qMapBrushToRect(sunken ? sunkenButtonGradientBrush - : buttonGradientBrush, option->rect), 105), 0)); - if (!reverse) { - painter->drawLine(QPointF(buttonRect.left() + 1, buttonRect.bottom() - 1), - QPointF(buttonRect.right() - 2, buttonRect.bottom() - 1)); - } else { - painter->drawLine(QPointF(buttonRect.right() - 1, buttonRect.bottom() - 1), - QPointF(buttonRect.left() + 2, buttonRect.bottom() - 1)); - } - - // Left line - painter->setPen(QPen(qMapBrushToRect(sunken ? sunkenLeftLineGradientBrush - : leftLineGradientBrush, option->rect), 1)); - if (!reverse) { - painter->drawLine(QPointF(buttonRect.left() + 1, buttonRect.top() + 2), - QPointF(buttonRect.left() + 1, buttonRect.bottom() - 2)); - } else { - painter->drawLine(QPointF(buttonRect.left() + 1, buttonRect.top() + 2), - QPointF(buttonRect.left() + 1, buttonRect.bottom() - 2)); - } - - // Right line - painter->setPen(QPen(qMapBrushToRect(sunken ? sunkenRightLineGradientBrush - : rightLineGradientBrush, option->rect), 1)); - if (!reverse) { - painter->drawLine(QPointF(buttonRect.right() - 1, buttonRect.top() + 2), - QPointF(buttonRect.right() - 1, buttonRect.bottom() - 2)); - } else { - painter->drawLine(QPointF(buttonRect.right() - 1, buttonRect.top() + 2), - QPointF(buttonRect.right() - 1, buttonRect.bottom() - 2)); - } - } else { - // Start with a standard panel button fill - QStyleOptionButton buttonOption; - buttonOption.QStyleOption::operator=(*comboBox); - if (!sunken) { - buttonOption.state &= ~State_Sunken; - } - proxy()->drawPrimitive(PE_PanelButtonCommand, &buttonOption, painter, widget); - - // Draw the menu button separator line - QBrush border = qMapBrushToRect(option->palette.shadow(), rect); - qBrushSetAlphaF(&border, qreal(0.35)); - painter->setPen(QPen(border, 0)); - if (!reverse) { - painter->drawLine(rect.right() - menuButtonWidth + xoffset, rect.top() + 1, - rect.right() - menuButtonWidth + xoffset, rect.bottom() - 1); - } else { - painter->drawLine(rect.left() + menuButtonWidth + xoffset, rect.top() + 1, - rect.left() + menuButtonWidth + xoffset, rect.bottom() - 1); - } - } - - // Draw the little arrow - if (comboBox->subControls & SC_ComboBoxArrow) { - int left = !reverse ? rect.right() - menuButtonWidth : rect.left(); - int right = !reverse ? rect.right() : rect.left() + menuButtonWidth; - QRect arrowRect((left + right) / 2 - 3 + xoffset, - rect.center().y() - 1 + yoffset, 7, 4); - painter->setPen(QPen(qMapBrushToRect(option->palette.buttonText(), rect), 0)); - const QLine lines[3] = { - QLine(arrowRect.topLeft(), arrowRect.topRight()), - QLine(arrowRect.left() + 1, arrowRect.top() + 1, - arrowRect.right() - 1, arrowRect.top() + 1), - QLine(arrowRect.left() + 2, arrowRect.top() + 2, - arrowRect.right() - 2, arrowRect.top() + 2) }; - painter->drawLines(lines, 3); - painter->drawPoint(arrowRect.center().x(), arrowRect.bottom()); - } - - // Draw the focus rect - if ((option->state & State_HasFocus) && !comboBox->editable - && ((option->state & State_KeyboardFocusChange) || styleHint(SH_UnderlineShortcut, option, widget))) { - QStyleOptionFocusRect focus; - focus.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget) - .adjusted(-2, 0, 2, 0); - proxy()->drawPrimitive(PE_FrameFocusRect, &focus, painter, widget); - } - - painter->setPen(oldPen); - } - break; -#endif // QT_NO_COMBOBOX - case CC_TitleBar: - if (const QStyleOptionTitleBar *titleBar = qstyleoption_cast(option)) { - painter->save(); - bool active = (titleBar->titleBarState & State_Active); - QRect fullRect = titleBar->rect; - - // ### use palette colors instead - QColor titleBarGradientStart(active ? 0x3b508a : 0x6e6e6e); - QColor titleBarGradientStop(active ? 0x5d6e9e : 0x818181); - QColor titleBarFrameBorder(0x393939); - QColor titleBarAlphaCorner(active ? 0x4b5e7f : 0x6a6a6a); - QColor titleBarInnerTopLine(active ? 0x8e98ba : 0xa4a4a4); - QColor titleBarInnerInnerTopLine(active ? 0x57699b : 0x808080); - QColor leftCorner(active ? 0x6f7ea8 : 0x8e8e8e); - QColor rightCorner(active ? 0x44537d : 0x676767); - QColor textColor(active ? 0x282e40 : 0x282e40); - QColor textAlphaColor(active ? 0x3f4862 : 0x3f4862); - - - { - // Fill title bar gradient - qt_plastique_draw_gradient(painter, option->rect.adjusted(1, 1, -1, 0), - titleBarGradientStart, - titleBarGradientStop); - - // Frame and rounded corners - painter->setPen(titleBarFrameBorder); - - // top border line - { - const QLine lines[3] = { - QLine(fullRect.left() + 2, fullRect.top(), fullRect.right() - 2, fullRect.top()), - QLine(fullRect.left(), fullRect.top() + 2, fullRect.left(), fullRect.bottom()), - QLine(fullRect.right(), fullRect.top() + 2, fullRect.right(), fullRect.bottom()) }; - painter->drawLines(lines, 3); - const QPoint points[2] = { - QPoint(fullRect.left() + 1, fullRect.top() + 1), - QPoint(fullRect.right() - 1, fullRect.top() + 1) }; - painter->drawPoints(points, 2); - } - - // alpha corners - painter->setPen(titleBarAlphaCorner); - { - const QPoint points[4] = { - QPoint(fullRect.left() + 2, fullRect.top() + 1), - QPoint(fullRect.left() + 1, fullRect.top() + 2), - QPoint(fullRect.right() - 2, fullRect.top() + 1), - QPoint(fullRect.right() - 1, fullRect.top() + 2) }; - painter->drawPoints(points, 4); - } - - // inner top line - painter->setPen(titleBarInnerTopLine); - painter->drawLine(fullRect.left() + 3, fullRect.top() + 1, fullRect.right() - 3, fullRect.top() + 1); - - // inner inner top line - painter->setPen(titleBarInnerInnerTopLine); - painter->drawLine(fullRect.left() + 2, fullRect.top() + 2, fullRect.right() - 2, fullRect.top() + 2); - - // left and right inner - painter->setPen(leftCorner); - painter->drawLine(fullRect.left() + 1, fullRect.top() + 3, fullRect.left() + 1, fullRect.bottom()); - painter->setPen(rightCorner); - painter->drawLine(fullRect.right() - 1, fullRect.top() + 3, fullRect.right() - 1, fullRect.bottom()); - - if (titleBar->titleBarState & Qt::WindowMinimized) { - painter->setPen(titleBarFrameBorder); - painter->drawLine(fullRect.left() + 2, fullRect.bottom(), fullRect.right() - 2, fullRect.bottom()); - { - const QPoint points[2] = { - QPoint(fullRect.left() + 1, fullRect.bottom() - 1), - QPoint(fullRect.right() - 1, fullRect.bottom() - 1) }; - painter->drawPoints(points, 2); - } - painter->setPen(rightCorner); - painter->drawLine(fullRect.left() + 2, fullRect.bottom() - 1, fullRect.right() - 2, fullRect.bottom() - 1); - painter->setPen(titleBarAlphaCorner); - { - const QPoint points[4] = { - QPoint(fullRect.left() + 1, fullRect.bottom() - 2), - QPoint(fullRect.left() + 2, fullRect.bottom() - 1), - QPoint(fullRect.right() - 1, fullRect.bottom() - 2), - QPoint(fullRect.right() - 2, fullRect.bottom() - 1) }; - painter->drawPoints(points, 4); - } - } - // draw title - QRect textRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarLabel, widget); - - QFont font = painter->font(); - font.setBold(true); - painter->setFont(font); - painter->setPen(titleBar->palette.text().color()); - - // Attempt to align left if there is not enough room for the title - // text. Otherwise, align center. QWorkspace does elliding for us, - // and it doesn't know about the bold title, so we need to work - // around some of the width mismatches. - bool tooWide = (QFontMetrics(font).width(titleBar->text) > textRect.width()); - QTextOption option((tooWide ? Qt::AlignLeft : Qt::AlignHCenter) | Qt::AlignVCenter); - option.setWrapMode(QTextOption::NoWrap); - - painter->drawText(textRect.adjusted(1, 1, 1, 1), titleBar->text, option); - painter->setPen(titleBar->palette.highlightedText().color()); - painter->drawText(textRect, titleBar->text, option); - } - - // min button - if ((titleBar->subControls & SC_TitleBarMinButton) - && (titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) - && !(titleBar->titleBarState & Qt::WindowMinimized)) { - bool hover = (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_Sunken); - - QRect minButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMinButton, widget); - qt_plastique_draw_mdibutton(painter, titleBar, minButtonRect, hover, sunken); - - int xoffset = minButtonRect.width() / 3; - int yoffset = minButtonRect.height() / 3; - - QRect minButtonIconRect(minButtonRect.left() + xoffset, minButtonRect.top() + yoffset, - minButtonRect.width() - xoffset * 2, minButtonRect.height() - yoffset * 2); - - painter->setPen(textColor); - { - const QLine lines[2] = { - QLine(minButtonIconRect.center().x() - 2, - minButtonIconRect.center().y() + 3, - minButtonIconRect.center().x() + 3, - minButtonIconRect.center().y() + 3), - QLine(minButtonIconRect.center().x() - 2, - minButtonIconRect.center().y() + 4, - minButtonIconRect.center().x() + 3, - minButtonIconRect.center().y() + 4) }; - painter->drawLines(lines, 2); - } - painter->setPen(textAlphaColor); - { - const QLine lines[2] = { - QLine(minButtonIconRect.center().x() - 3, - minButtonIconRect.center().y() + 3, - minButtonIconRect.center().x() - 3, - minButtonIconRect.center().y() + 4), - QLine(minButtonIconRect.center().x() + 4, - minButtonIconRect.center().y() + 3, - minButtonIconRect.center().x() + 4, - minButtonIconRect.center().y() + 4) }; - painter->drawLines(lines, 2); - } - } - - // max button - if ((titleBar->subControls & SC_TitleBarMaxButton) - && (titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) - && !(titleBar->titleBarState & Qt::WindowMaximized)) { - bool hover = (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_Sunken); - - QRect maxButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMaxButton, widget); - qt_plastique_draw_mdibutton(painter, titleBar, maxButtonRect, hover, sunken); - - int xoffset = maxButtonRect.width() / 3; - int yoffset = maxButtonRect.height() / 3; - - QRect maxButtonIconRect(maxButtonRect.left() + xoffset, maxButtonRect.top() + yoffset, - maxButtonRect.width() - xoffset * 2, maxButtonRect.height() - yoffset * 2); - - painter->setPen(textColor); - painter->drawRect(maxButtonIconRect.adjusted(0, 0, -1, -1)); - painter->drawLine(maxButtonIconRect.left() + 1, maxButtonIconRect.top() + 1, - maxButtonIconRect.right() - 1, maxButtonIconRect.top() + 1); - painter->setPen(textAlphaColor); - const QPoint points[4] = { - maxButtonIconRect.topLeft(), maxButtonIconRect.topRight(), - maxButtonIconRect.bottomLeft(), maxButtonIconRect.bottomRight() }; - painter->drawPoints(points, 4); - } - - // close button - if (titleBar->subControls & SC_TitleBarCloseButton && titleBar->titleBarFlags & Qt::WindowSystemMenuHint) { - bool hover = (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_Sunken); - - QRect closeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarCloseButton, widget); - qt_plastique_draw_mdibutton(painter, titleBar, closeButtonRect, hover, sunken); - - int xoffset = closeButtonRect.width() / 3; - int yoffset = closeButtonRect.height() / 3; - - QRect closeIconRect(closeButtonRect.left() + xoffset, closeButtonRect.top() + yoffset, - closeButtonRect.width() - xoffset * 2, closeButtonRect.height() - yoffset * 2); - - painter->setPen(textAlphaColor); - { - const QLine lines[4] = { - QLine(closeIconRect.left() + 1, closeIconRect.top(), - closeIconRect.right(), closeIconRect.bottom() - 1), - QLine(closeIconRect.left(), closeIconRect.top() + 1, - closeIconRect.right() - 1, closeIconRect.bottom()), - QLine(closeIconRect.right() - 1, closeIconRect.top(), - closeIconRect.left(), closeIconRect.bottom() - 1), - QLine(closeIconRect.right(), closeIconRect.top() + 1, - closeIconRect.left() + 1, closeIconRect.bottom()) }; - painter->drawLines(lines, 4); - const QPoint points[4] = { - closeIconRect.topLeft(), closeIconRect.topRight(), - closeIconRect.bottomLeft(), closeIconRect.bottomRight() }; - painter->drawPoints(points, 4); - } - painter->setPen(textColor); - { - const QLine lines[2] = { - QLine(closeIconRect.left() + 1, closeIconRect.top() + 1, - closeIconRect.right() - 1, closeIconRect.bottom() - 1), - QLine(closeIconRect.left() + 1, closeIconRect.bottom() - 1, - closeIconRect.right() - 1, closeIconRect.top() + 1) }; - painter->drawLines(lines, 2); - } - } - - // normalize button - if ((titleBar->subControls & SC_TitleBarNormalButton) && - (((titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) && - (titleBar->titleBarState & Qt::WindowMinimized)) || - ((titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) && - (titleBar->titleBarState & Qt::WindowMaximized)))) { - bool hover = (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_Sunken); - - QRect normalButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarNormalButton, widget); - qt_plastique_draw_mdibutton(painter, titleBar, normalButtonRect, hover, sunken); - int xoffset = int(normalButtonRect.width() / 3.5); - int yoffset = int(normalButtonRect.height() / 3.5); - - QRect normalButtonIconRect(normalButtonRect.left() + xoffset, normalButtonRect.top() + yoffset, - normalButtonRect.width() - xoffset * 2, normalButtonRect.height() - yoffset * 2); - - QRect frontWindowRect = normalButtonIconRect.adjusted(0, 3, -3, 0); - painter->setPen(textColor); - painter->drawRect(frontWindowRect.adjusted(0, 0, -1, -1)); - painter->drawLine(frontWindowRect.left() + 1, frontWindowRect.top() + 1, - frontWindowRect.right() - 1, frontWindowRect.top() + 1); - painter->setPen(textAlphaColor); - { - const QPoint points[4] = { - frontWindowRect.topLeft(), frontWindowRect.topRight(), - frontWindowRect.bottomLeft(), frontWindowRect.bottomRight() }; - painter->drawPoints(points, 4); - } - - QRect backWindowRect = normalButtonIconRect.adjusted(3, 0, 0, -3); - QRegion clipRegion = backWindowRect; - clipRegion -= frontWindowRect; - painter->save(); - painter->setClipRegion(clipRegion); - painter->setPen(textColor); - painter->drawRect(backWindowRect.adjusted(0, 0, -1, -1)); - painter->drawLine(backWindowRect.left() + 1, backWindowRect.top() + 1, - backWindowRect.right() - 1, backWindowRect.top() + 1); - painter->setPen(textAlphaColor); - { - const QPoint points[4] = { - backWindowRect.topLeft(), backWindowRect.topRight(), - backWindowRect.bottomLeft(), backWindowRect.bottomRight() }; - painter->drawPoints(points, 4); - } - painter->restore(); - } - - // context help button - if (titleBar->subControls & SC_TitleBarContextHelpButton - && (titleBar->titleBarFlags & Qt::WindowContextHelpButtonHint)) { - bool hover = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_Sunken); - - QRect contextHelpButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarContextHelpButton, widget); - - qt_plastique_draw_mdibutton(painter, titleBar, contextHelpButtonRect, hover, sunken); - - QColor blend; - // ### Use palette colors - if (active) { - blend = mergedColors(QColor(hover ? 0x7d8bb1 : 0x55689a), - QColor(hover ? 0x939ebe : 0x7381ab)); - } else { - blend = mergedColors(QColor(hover ? 0x9e9e9e : 0x818181), - QColor(hover ? 0xababab : 0x929292)); - } - QImage image(qt_titlebar_context_help); - image.setColor(4, textColor.rgba()); - image.setColor(3, mergedColors(blend, textColor, 30).rgba()); - image.setColor(2, mergedColors(blend, textColor, 70).rgba()); - image.setColor(1, mergedColors(blend, textColor, 90).rgba()); - - painter->drawImage(contextHelpButtonRect, image); - } - - // shade button - if (titleBar->subControls & SC_TitleBarShadeButton) { - bool hover = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_Sunken); - - QRect shadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarShadeButton, widget); - qt_plastique_draw_mdibutton(painter, titleBar, shadeButtonRect, hover, sunken); - - int xoffset = shadeButtonRect.width() / 3; - int yoffset = shadeButtonRect.height() / 3; - - QRect shadeButtonIconRect(shadeButtonRect.left() + xoffset, shadeButtonRect.top() + yoffset, - shadeButtonRect.width() - xoffset * 2, shadeButtonRect.height() - yoffset * 2); - - QPainterPath path(shadeButtonIconRect.bottomLeft()); - path.lineTo(shadeButtonIconRect.center().x(), shadeButtonIconRect.bottom() - shadeButtonIconRect.height() / 2); - path.lineTo(shadeButtonIconRect.bottomRight()); - path.lineTo(shadeButtonIconRect.bottomLeft()); - - painter->setPen(textAlphaColor); - painter->setBrush(textColor); - painter->drawPath(path); - } - - // unshade button - if (titleBar->subControls & SC_TitleBarUnshadeButton) { - bool hover = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_Sunken); - - QRect unshadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarUnshadeButton, widget); - qt_plastique_draw_mdibutton(painter, titleBar, unshadeButtonRect, hover, sunken); - - int xoffset = unshadeButtonRect.width() / 3; - int yoffset = unshadeButtonRect.height() / 3; - - QRect unshadeButtonIconRect(unshadeButtonRect.left() + xoffset, unshadeButtonRect.top() + yoffset, - unshadeButtonRect.width() - xoffset * 2, unshadeButtonRect.height() - yoffset * 2); - - int midY = unshadeButtonIconRect.bottom() - unshadeButtonIconRect.height() / 2; - QPainterPath path(QPoint(unshadeButtonIconRect.left(), midY)); - path.lineTo(unshadeButtonIconRect.right(), midY); - path.lineTo(unshadeButtonIconRect.center().x(), unshadeButtonIconRect.bottom()); - path.lineTo(unshadeButtonIconRect.left(), midY); - - painter->setPen(textAlphaColor); - painter->setBrush(textColor); - painter->drawPath(path); - } - - // from qwindowsstyle.cpp - if ((titleBar->subControls & SC_TitleBarSysMenu) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) { - bool hover = (titleBar->activeSubControls & SC_TitleBarSysMenu) && (titleBar->state & State_MouseOver); - bool sunken = (titleBar->activeSubControls & SC_TitleBarSysMenu) && (titleBar->state & State_Sunken); - - QRect iconRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarSysMenu, widget); - if (hover) - qt_plastique_draw_mdibutton(painter, titleBar, iconRect, hover, sunken); - - if (!titleBar->icon.isNull()) { - titleBar->icon.paint(painter, iconRect); - } else { - QStyleOption tool(0); - tool.palette = titleBar->palette; - QPixmap pm = standardPixmap(SP_TitleBarMenuButton, &tool, widget); - tool.rect = iconRect; - painter->save(); - proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm); - painter->restore(); - } - } - painter->restore(); - } - break; -#ifndef QT_NO_DIAL - case CC_Dial: - if (const QStyleOptionSlider *dial = qstyleoption_cast(option)) - QStyleHelper::drawDial(dial, painter); - break; -#endif // QT_NO_DIAL - default: - QWindowsStyle::drawComplexControl(control, option, painter, widget); - break; - } -} - -/*! - \reimp -*/ -QSize QPlastiqueStyle::sizeFromContents(ContentsType type, const QStyleOption *option, - const QSize &size, const QWidget *widget) const -{ - QSize newSize = QWindowsStyle::sizeFromContents(type, option, size, widget); - - switch (type) { - case CT_RadioButton: - ++newSize.rheight(); - ++newSize.rwidth(); - break; -#ifndef QT_NO_SLIDER - case CT_Slider: - if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { - int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); - if (slider->tickPosition & QSlider::TicksBelow) { - if (slider->orientation == Qt::Horizontal) - newSize.rheight() += tickSize; - else - newSize.rwidth() += tickSize; - } - if (slider->tickPosition & QSlider::TicksAbove) { - if (slider->orientation == Qt::Horizontal) - newSize.rheight() += tickSize; - else - newSize.rwidth() += tickSize; - } - } - break; -#endif // QT_NO_SLIDER -#ifndef QT_NO_SCROLLBAR - case CT_ScrollBar: - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - int scrollBarExtent = proxy()->pixelMetric(PM_ScrollBarExtent, option, widget); - int scrollBarSliderMinimum = proxy()->pixelMetric(PM_ScrollBarSliderMin, option, widget); - if (scrollBar->orientation == Qt::Horizontal) { - newSize = QSize(scrollBarExtent * 3 + scrollBarSliderMinimum, scrollBarExtent); - } else { - newSize = QSize(scrollBarExtent, scrollBarExtent * 3 + scrollBarSliderMinimum); - } - } - break; -#endif // QT_NO_SCROLLBAR -#ifndef QT_NO_SPINBOX - case CT_SpinBox: - // Make sure the size is odd - newSize.setHeight(sizeFromContents(CT_LineEdit, option, size, widget).height()); - newSize.rheight() -= ((1 - newSize.rheight()) & 1); - break; -#endif -#ifndef QT_NO_TOOLBUTTON - case CT_ToolButton: - newSize.rheight() += 3; - newSize.rwidth() += 3; - break; -#endif -#ifndef QT_NO_COMBOBOX - case CT_ComboBox: - newSize = sizeFromContents(CT_PushButton, option, size, widget); - newSize.rwidth() += 30; // Make room for drop-down indicator - newSize.rheight() += 4; - break; -#endif - case CT_MenuItem: - if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(option)) { - if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) - newSize.setHeight(menuItem->text.isEmpty() ? 2 : menuItem->fontMetrics.height()); - } - break; - case CT_MenuBarItem: - newSize.setHeight(newSize.height()); - break; - default: - break; - } - - return newSize; -} - -/*! - \reimp -*/ -QRect QPlastiqueStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const -{ - QRect rect; - switch (element) { - case SE_RadioButtonIndicator: - rect = visualRect(option->direction, option->rect, - QWindowsStyle::subElementRect(element, option, widget)).adjusted(0, 0, 1, 1); - break; - case SE_ProgressBarLabel: - case SE_ProgressBarContents: - case SE_ProgressBarGroove: - return option->rect; - default: - return QWindowsStyle::subElementRect(element, option, widget); - } - - return visualRect(option->direction, option->rect, rect); -} - -/*! - \reimp -*/ -QRect QPlastiqueStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, - SubControl subControl, const QWidget *widget) const -{ - QRect rect = QWindowsStyle::subControlRect(control, option, subControl, widget); - - switch (control) { -#ifndef QT_NO_SLIDER - case CC_Slider: - if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { - int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); - - switch (subControl) { - case SC_SliderHandle: - if (slider->orientation == Qt::Horizontal) { - rect.setWidth(11); - rect.setHeight(15); - int centerY = slider->rect.center().y() - rect.height() / 2; - if (slider->tickPosition & QSlider::TicksAbove) - centerY += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - centerY -= tickSize; - rect.moveTop(centerY); - } else { - rect.setWidth(15); - rect.setHeight(11); - int centerX = slider->rect.center().x() - rect.width() / 2; - if (slider->tickPosition & QSlider::TicksAbove) - centerX += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - centerX -= tickSize; - rect.moveLeft(centerX); - } - break; - case SC_SliderGroove: { - QPoint grooveCenter = slider->rect.center(); - if (slider->orientation == Qt::Horizontal) { - rect.setHeight(14); - --grooveCenter.ry(); - if (slider->tickPosition & QSlider::TicksAbove) - grooveCenter.ry() += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - grooveCenter.ry() -= tickSize; - } else { - rect.setWidth(14); - --grooveCenter.rx(); - if (slider->tickPosition & QSlider::TicksAbove) - grooveCenter.rx() += tickSize; - if (slider->tickPosition & QSlider::TicksBelow) - grooveCenter.rx() -= tickSize; - } - rect.moveCenter(grooveCenter); - break; - } - default: - break; - } - } - break; -#endif // QT_NO_SLIDER -#ifndef QT_NO_SCROLLBAR - case CC_ScrollBar: - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - int scrollBarExtent = proxy()->pixelMetric(PM_ScrollBarExtent, scrollBar, widget); - int sliderMaxLength = ((scrollBar->orientation == Qt::Horizontal) ? - scrollBar->rect.width() : scrollBar->rect.height()) - (scrollBarExtent * 3); - int sliderMinLength = proxy()->pixelMetric(PM_ScrollBarSliderMin, scrollBar, widget); - int sliderLength; - - // calculate slider length - if (scrollBar->maximum != scrollBar->minimum) { - uint valueRange = scrollBar->maximum - scrollBar->minimum; - sliderLength = (scrollBar->pageStep * sliderMaxLength) / (valueRange + scrollBar->pageStep); - - if (sliderLength < sliderMinLength || valueRange > INT_MAX / 2) - sliderLength = sliderMinLength; - if (sliderLength > sliderMaxLength) - sliderLength = sliderMaxLength; - } else { - sliderLength = sliderMaxLength; - } - - int sliderStart = scrollBarExtent + sliderPositionFromValue(scrollBar->minimum, - scrollBar->maximum, - scrollBar->sliderPosition, - sliderMaxLength - sliderLength, - scrollBar->upsideDown); - - QRect scrollBarRect = scrollBar->rect; - - switch (subControl) { - case SC_ScrollBarSubLine: // top/left button - if (scrollBar->orientation == Qt::Horizontal) { - rect.setRect(scrollBarRect.left(), scrollBarRect.top(), scrollBarRect.width() - scrollBarExtent, scrollBarRect.height()); - } else { - rect.setRect(scrollBarRect.left(), scrollBarRect.top(), scrollBarRect.width(), scrollBarRect.height() - scrollBarExtent); - } - break; - case SC_ScrollBarAddLine: // bottom/right button - if (scrollBar->orientation == Qt::Horizontal) { - rect.setRect(scrollBarRect.right() - (scrollBarExtent - 1), scrollBarRect.top(), scrollBarExtent, scrollBarRect.height()); - } else { - rect.setRect(scrollBarRect.left(), scrollBarRect.bottom() - (scrollBarExtent - 1), scrollBarRect.width(), scrollBarExtent); - } - break; - case SC_ScrollBarSubPage: - if (scrollBar->orientation == Qt::Horizontal) { - rect.setRect(scrollBarRect.left() + scrollBarExtent, scrollBarRect.top(), - sliderStart - (scrollBarRect.left() + scrollBarExtent), scrollBarRect.height()); - } else { - rect.setRect(scrollBarRect.left(), scrollBarRect.top() + scrollBarExtent, - scrollBarRect.width(), sliderStart - (scrollBarRect.left() + scrollBarExtent)); - } - break; - case SC_ScrollBarAddPage: - if (scrollBar->orientation == Qt::Horizontal) - rect.setRect(sliderStart + sliderLength, 0, - sliderMaxLength - sliderStart - sliderLength + scrollBarExtent, scrollBarRect.height()); - else - rect.setRect(0, sliderStart + sliderLength, - scrollBarRect.width(), sliderMaxLength - sliderStart - sliderLength + scrollBarExtent); - break; - case SC_ScrollBarGroove: - if (scrollBar->orientation == Qt::Horizontal) { - rect = scrollBarRect.adjusted(scrollBarExtent, 0, -2 * scrollBarExtent, 0); - } else { - rect = scrollBarRect.adjusted(0, scrollBarExtent, 0, -2 * scrollBarExtent); - } - break; - case SC_ScrollBarSlider: - if (scrollBar->orientation == Qt::Horizontal) { - rect.setRect(sliderStart, 0, sliderLength, scrollBarRect.height()); - } else { - rect.setRect(0, sliderStart, scrollBarRect.width(), sliderLength); - } - break; - default: - break; - } - rect = visualRect(scrollBar->direction, scrollBarRect, rect); - } - break; -#endif // QT_NO_SCROLLBAR -#ifndef QT_NO_SPINBOX - case CC_SpinBox: - if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast(option)) { - int center = spinBox->rect.height() / 2; - switch (subControl) { - case SC_SpinBoxUp: - if (spinBox->buttonSymbols == QAbstractSpinBox::NoButtons) - return QRect(); - rect = visualRect(spinBox->direction, spinBox->rect, rect); - rect.setRect(spinBox->rect.right() - 16, spinBox->rect.top(), 17, center + 1); - rect = visualRect(spinBox->direction, spinBox->rect, rect); - break; - case SC_SpinBoxDown: - if (spinBox->buttonSymbols == QAbstractSpinBox::NoButtons) - return QRect(); - rect = visualRect(spinBox->direction, spinBox->rect, rect); - rect.setRect(spinBox->rect.right() - 16, spinBox->rect.top() + center, 17, spinBox->rect.height() - center); - rect = visualRect(spinBox->direction, spinBox->rect, rect); - break; - case SC_SpinBoxEditField: - if (spinBox->buttonSymbols != QAbstractSpinBox::NoButtons) { - rect = spinBox->rect.adjusted(0, 0, -16, 0); - } else { - rect = spinBox->rect; - } - rect.adjust(blueFrameWidth, blueFrameWidth, -blueFrameWidth, -blueFrameWidth); - rect = visualRect(spinBox->direction, spinBox->rect, rect); - break; - default: - break; - } - } - break; -#endif // QT_NO_SPINBOX -#ifndef QT_NO_COMBOBOX - case CC_ComboBox: - switch (subControl) { - case SC_ComboBoxArrow: - rect = visualRect(option->direction, option->rect, rect); - rect.setRect(rect.right() - 17, rect.top() - 2, - 19, rect.height() + 4); - rect = visualRect(option->direction, option->rect, rect); - break; - case SC_ComboBoxEditField: { - if (const QStyleOptionComboBox *box = qstyleoption_cast(option)) { - int frameWidth = proxy()->pixelMetric(PM_DefaultFrameWidth); - rect = visualRect(option->direction, option->rect, rect); - - if (box->editable) { - rect = box->rect.adjusted(blueFrameWidth, blueFrameWidth, -blueFrameWidth, -blueFrameWidth); - rect.setRight(rect.right() - 16); // Overlaps the combobox button by 2 pixels - } else { - rect.setRect(option->rect.left() + frameWidth, option->rect.top() + frameWidth, - option->rect.width() - 16 - 2 * frameWidth, - option->rect.height() - 2 * frameWidth); - rect.setLeft(rect.left() + 2); - rect.setRight(rect.right() - 2); - if (box->state & (State_Sunken | State_On)) - rect.translate(1, 1); - } - rect = visualRect(option->direction, option->rect, rect); - } - break; - } - default: - break; - } - break; -#endif // QT_NO_COMBOBOX - case CC_TitleBar: - if (const QStyleOptionTitleBar *tb = qstyleoption_cast(option)) { - SubControl sc = subControl; - QRect &ret = rect; - const int indent = 3; - const int controlTopMargin = 4; - const int controlBottomMargin = 3; - const int controlWidthMargin = 1; - const int controlHeight = tb->rect.height() - controlTopMargin - controlBottomMargin; - const int delta = controlHeight + controlWidthMargin; - int offset = 0; - - bool isMinimized = tb->titleBarState & Qt::WindowMinimized; - bool isMaximized = tb->titleBarState & Qt::WindowMaximized; - - switch (sc) { - case SC_TitleBarLabel: - if (tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) { - ret = tb->rect; - if (tb->titleBarFlags & Qt::WindowSystemMenuHint) - ret.adjust(delta, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) - ret.adjust(0, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) - ret.adjust(0, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowShadeButtonHint) - ret.adjust(0, 0, -delta, 0); - if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) - ret.adjust(0, 0, -delta, 0); - ret.adjusted(indent, 0, -indent, 0); - } - break; - case SC_TitleBarContextHelpButton: - if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) - offset += delta; - case SC_TitleBarMinButton: - if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarMinButton) - break; - case SC_TitleBarNormalButton: - if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)) - offset += delta; - else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarNormalButton) - break; - case SC_TitleBarMaxButton: - if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarMaxButton) - break; - case SC_TitleBarShadeButton: - if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarShadeButton) - break; - case SC_TitleBarUnshadeButton: - if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint)) - offset += delta; - else if (sc == SC_TitleBarUnshadeButton) - break; - case SC_TitleBarCloseButton: - if (tb->titleBarFlags & Qt::WindowSystemMenuHint) - offset += delta; - else if (sc == SC_TitleBarCloseButton) - break; - ret.setRect(tb->rect.right() - indent - offset, tb->rect.top() + controlTopMargin, - controlHeight, controlHeight); - break; - case SC_TitleBarSysMenu: - if (tb->titleBarFlags & Qt::WindowSystemMenuHint) { - ret.setRect(tb->rect.left() + controlWidthMargin + indent, tb->rect.top() + controlTopMargin, - controlHeight, controlHeight); - } - break; - default: - break; - } - ret = visualRect(tb->direction, tb->rect, ret); - } - break; - default: - break; - } - - return rect; -} - -/*! - \reimp -*/ -int QPlastiqueStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, - QStyleHintReturn *returnData) const -{ - int ret = 0; - switch (hint) { - case SH_WindowFrame_Mask: - ret = 1; - if (QStyleHintReturnMask *mask = qstyleoption_cast(returnData)) { - mask->region = option->rect; - mask->region -= QRect(option->rect.left(), option->rect.top(), 2, 1); - mask->region -= QRect(option->rect.right() - 1, option->rect.top(), 2, 1); - mask->region -= QRect(option->rect.left(), option->rect.top() + 1, 1, 1); - mask->region -= QRect(option->rect.right(), option->rect.top() + 1, 1, 1); - - const QStyleOptionTitleBar *titleBar = qstyleoption_cast(option); - if (titleBar && (titleBar->titleBarState & Qt::WindowMinimized)) { - mask->region -= QRect(option->rect.left(), option->rect.bottom(), 2, 1); - mask->region -= QRect(option->rect.right() - 1, option->rect.bottom(), 2, 1); - mask->region -= QRect(option->rect.left(), option->rect.bottom() - 1, 1, 1); - mask->region -= QRect(option->rect.right(), option->rect.bottom() - 1, 1, 1); - } else { - mask->region -= QRect(option->rect.bottomLeft(), QSize(1, 1)); - mask->region -= QRect(option->rect.bottomRight(), QSize(1, 1)); - } - } - break; - case SH_TitleBar_NoBorder: - ret = 1; - break; - case SH_TitleBar_AutoRaise: - ret = 1; - break; - case SH_ItemView_ShowDecorationSelected: - ret = true; - break; - case SH_ToolBox_SelectedPageTitleBold: - case SH_ScrollBar_MiddleClickAbsolutePosition: - ret = true; - break; - case SH_MainWindow_SpaceBelowMenuBar: - ret = 0; - break; - case SH_FormLayoutWrapPolicy: - ret = QFormLayout::DontWrapRows; - break; - case SH_FormLayoutFieldGrowthPolicy: - ret = QFormLayout::ExpandingFieldsGrow; - break; - case SH_FormLayoutFormAlignment: - ret = Qt::AlignLeft | Qt::AlignTop; - break; - case SH_FormLayoutLabelAlignment: - ret = Qt::AlignRight; - break; - case SH_MessageBox_TextInteractionFlags: - ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; - break; - case SH_LineEdit_PasswordCharacter: - ret = QCommonStyle::styleHint(hint, option, widget, returnData); - break; - case SH_ItemView_ArrowKeysNavigateIntoChildren: - ret = true; - break; - case SH_Menu_SubMenuPopupDelay: - ret = 96; // from Plastik - break; - case SH_DialogButtonBox_ButtonsHaveIcons: - if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) - ret = theme->themeHint(QPlatformTheme::DialogButtonBoxButtonsHaveIcons).toBool(); - else - ret = true; - break; -#ifndef Q_OS_WIN - case SH_Menu_AllowActiveAndDisabled: - ret = false; - break; -#endif - default: - ret = QWindowsStyle::styleHint(hint, option, widget, returnData); - break; - } - return ret; -} - -/*! - \reimp -*/ -QStyle::SubControl QPlastiqueStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, - const QPoint &pos, const QWidget *widget) const -{ - SubControl ret = SC_None; - switch (control) { -#ifndef QT_NO_SCROLLBAR - case CC_ScrollBar: - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { - QRect slider = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSlider, widget); - if (slider.contains(pos)) { - ret = SC_ScrollBarSlider; - break; - } - - QRect scrollBarAddLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarAddLine, widget); - if (scrollBarAddLine.contains(pos)) { - ret = SC_ScrollBarAddLine; - break; - } - - QRect scrollBarSubPage = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSubPage, widget); - if (scrollBarSubPage.contains(pos)) { - ret = SC_ScrollBarSubPage; - break; - } - - QRect scrollBarAddPage = proxy()->subControlRect(control, scrollBar, SC_ScrollBarAddPage, widget); - if (scrollBarAddPage.contains(pos)) { - ret = SC_ScrollBarAddPage; - break; - } - - QRect scrollBarSubLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSubLine, widget); - if (scrollBarSubLine.contains(pos)) { - ret = SC_ScrollBarSubLine; - break; - } - } - break; -#endif // QT_NO_SCROLLBAR - default: - break; - } - - return ret != SC_None ? ret : QWindowsStyle::hitTestComplexControl(control, option, pos, widget); -} - -/*! - \reimp -*/ -int QPlastiqueStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const -{ - int ret = -1; - switch (metric) { - case PM_MenuVMargin: - case PM_MenuHMargin: - ret = 0; - break; - case PM_ButtonShiftHorizontal: - case PM_ButtonShiftVertical: - ret = 1; - break; - case PM_ButtonDefaultIndicator: - ret = 0; - break; -#ifndef QT_NO_SLIDER - case PM_SliderThickness: - ret = 15; - break; - case PM_SliderLength: - case PM_SliderControlThickness: - ret = 11; - break; - case PM_SliderTickmarkOffset: - ret = 5; - break; - case PM_SliderSpaceAvailable: - if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { - int size = 15; - if (slider->tickPosition & QSlider::TicksBelow) - ++size; - if (slider->tickPosition & QSlider::TicksAbove) - ++size; - ret = size; - break; - } -#endif // QT_NO_SLIDER - case PM_ScrollBarExtent: - ret = 16; - break; - case PM_ScrollBarSliderMin: - ret = 26; - break; - case PM_ProgressBarChunkWidth: - ret = 1; - break; - case PM_MenuBarItemSpacing: - ret = 3; - break; - case PM_MenuBarVMargin: - ret = 2; - break; - case PM_MenuBarHMargin: - ret = 0; - break; - case PM_MenuBarPanelWidth: - ret = 1; - break; - case PM_ToolBarHandleExtent: - ret = 9; - break; - case PM_ToolBarSeparatorExtent: - ret = 2; - break; - case PM_ToolBarItemSpacing: - ret = 1; - break; - case PM_ToolBarItemMargin: - ret = 1; - break; - case PM_ToolBarFrameWidth: - ret = 2; - break; - case PM_SplitterWidth: - ret = 6; - break; - case PM_DockWidgetSeparatorExtent: - ret = 6; - break; - case PM_DockWidgetHandleExtent: - ret = 20; - break; - case PM_DefaultFrameWidth: -#ifndef QT_NO_MENU - if (qobject_cast(widget)) { - ret = 1; - break; - } -#endif - ret = 2; - break; - case PM_MdiSubWindowFrameWidth: - ret = 4; - break; - case PM_TitleBarHeight: - ret = qMax(widget ? widget->fontMetrics().height() : - (option ? option->fontMetrics.height() : 0), 30); - break; - case PM_MaximumDragDistance: - return -1; - case PM_DockWidgetTitleMargin: - return 2; - case PM_LayoutHorizontalSpacing: - case PM_LayoutVerticalSpacing: - return -1; // rely on layoutHorizontalSpacing() - case PM_LayoutLeftMargin: - case PM_LayoutTopMargin: - case PM_LayoutRightMargin: - case PM_LayoutBottomMargin: - { - bool isWindow = false; - if (option) { - isWindow = (option->state & State_Window); - } else if (widget) { - isWindow = widget->isWindow(); - } - - if (isWindow) { - ret = 11; - } else { - ret = 9; - } - } - default: - break; - } - - return ret != -1 ? ret : QWindowsStyle::pixelMetric(metric, option, widget); -} - -/*! - \reimp -*/ -QPalette QPlastiqueStyle::standardPalette() const -{ - QPalette palette; - - palette.setBrush(QPalette::Disabled, QPalette::WindowText, QColor(QRgb(0xff808080))); - palette.setBrush(QPalette::Disabled, QPalette::Button, QColor(QRgb(0xffdddfe4))); - palette.setBrush(QPalette::Disabled, QPalette::Light, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Disabled, QPalette::Midlight, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Disabled, QPalette::Dark, QColor(QRgb(0xff555555))); - palette.setBrush(QPalette::Disabled, QPalette::Mid, QColor(QRgb(0xffc7c7c7))); - palette.setBrush(QPalette::Disabled, QPalette::Text, QColor(QRgb(0xffc7c7c7))); - palette.setBrush(QPalette::Disabled, QPalette::BrightText, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Disabled, QPalette::ButtonText, QColor(QRgb(0xff808080))); - palette.setBrush(QPalette::Disabled, QPalette::Base, QColor(QRgb(0xffefefef))); - palette.setBrush(QPalette::Disabled, QPalette::AlternateBase, palette.color(QPalette::Disabled, QPalette::Base).darker(110)); - palette.setBrush(QPalette::Disabled, QPalette::Window, QColor(QRgb(0xffefefef))); - palette.setBrush(QPalette::Disabled, QPalette::Shadow, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Disabled, QPalette::Highlight, QColor(QRgb(0xff567594))); - palette.setBrush(QPalette::Disabled, QPalette::HighlightedText, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Disabled, QPalette::Link, QColor(QRgb(0xff0000ee))); - palette.setBrush(QPalette::Disabled, QPalette::LinkVisited, QColor(QRgb(0xff52188b))); - palette.setBrush(QPalette::Active, QPalette::WindowText, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Active, QPalette::Button, QColor(QRgb(0xffdddfe4))); - palette.setBrush(QPalette::Active, QPalette::Light, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Active, QPalette::Midlight, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Active, QPalette::Dark, QColor(QRgb(0xff555555))); - palette.setBrush(QPalette::Active, QPalette::Mid, QColor(QRgb(0xffc7c7c7))); - palette.setBrush(QPalette::Active, QPalette::Text, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Active, QPalette::BrightText, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Active, QPalette::ButtonText, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Active, QPalette::Base, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Active, QPalette::AlternateBase, palette.color(QPalette::Active, QPalette::Base).darker(110)); - palette.setBrush(QPalette::Active, QPalette::Window, QColor(QRgb(0xffefefef))); - palette.setBrush(QPalette::Active, QPalette::Shadow, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Active, QPalette::Highlight, QColor(QRgb(0xff678db2))); - palette.setBrush(QPalette::Active, QPalette::HighlightedText, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Active, QPalette::Link, QColor(QRgb(0xff0000ee))); - palette.setBrush(QPalette::Active, QPalette::LinkVisited, QColor(QRgb(0xff52188b))); - palette.setBrush(QPalette::Inactive, QPalette::WindowText, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Inactive, QPalette::Button, QColor(QRgb(0xffdddfe4))); - palette.setBrush(QPalette::Inactive, QPalette::Light, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Inactive, QPalette::Midlight, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Inactive, QPalette::Dark, QColor(QRgb(0xff555555))); - palette.setBrush(QPalette::Inactive, QPalette::Mid, QColor(QRgb(0xffc7c7c7))); - palette.setBrush(QPalette::Inactive, QPalette::Text, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Inactive, QPalette::BrightText, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Inactive, QPalette::ButtonText, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Inactive, QPalette::Base, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Inactive, QPalette::AlternateBase, palette.color(QPalette::Inactive, QPalette::Base).darker(110)); - palette.setBrush(QPalette::Inactive, QPalette::Window, QColor(QRgb(0xffefefef))); - palette.setBrush(QPalette::Inactive, QPalette::Shadow, QColor(QRgb(0xff000000))); - palette.setBrush(QPalette::Inactive, QPalette::Highlight, QColor(QRgb(0xff678db2))); - palette.setBrush(QPalette::Inactive, QPalette::HighlightedText, QColor(QRgb(0xffffffff))); - palette.setBrush(QPalette::Inactive, QPalette::Link, QColor(QRgb(0xff0000ee))); - palette.setBrush(QPalette::Inactive, QPalette::LinkVisited, QColor(QRgb(0xff52188b))); - return palette; -} - -/*! - \reimp -*/ -void QPlastiqueStyle::polish(QWidget *widget) -{ - if (qobject_cast(widget) -#ifndef QT_NO_COMBOBOX - || qobject_cast(widget) -#endif -#ifndef QT_NO_SPINBOX - || qobject_cast(widget) -#endif - || qobject_cast(widget) -#ifndef QT_NO_GROUPBOX - || qobject_cast(widget) -#endif - || qobject_cast(widget) -#ifndef QT_NO_SPLITTER - || qobject_cast(widget) -#endif -#ifndef QT_NO_TABBAR - || qobject_cast(widget) -#endif - ) { - widget->setAttribute(Qt::WA_Hover); - } - - if (widget->inherits("QDockSeparator") - || widget->inherits("QDockWidgetSeparator")) { - widget->setAttribute(Qt::WA_Hover); - } - - if (false // to simplify the #ifdefs -#ifndef QT_NO_MENUBAR - || qobject_cast(widget) -#endif -#ifndef QT_NO_TOOLBAR - || qobject_cast(widget) - || (widget && qobject_cast(widget->parent())) -#endif - ) { - widget->setBackgroundRole(QPalette::Window); - } - -#if defined QPlastique_MaskButtons - if (qobject_cast(widget) || qobject_cast(widget)) - widget->installEventFilter(this); -#endif -} - -/*! - \reimp -*/ -void QPlastiqueStyle::unpolish(QWidget *widget) -{ - if (qobject_cast(widget) -#ifndef QT_NO_COMBOBOX - || qobject_cast(widget) -#endif -#ifndef QT_NO_SPINBOX - || qobject_cast(widget) -#endif - || qobject_cast(widget) -#ifndef QT_NO_GROUPBOX - || qobject_cast(widget) -#endif -#ifndef QT_NO_SPLITTER - || qobject_cast(widget) -#endif -#ifndef QT_NO_TABBAR - || qobject_cast(widget) -#endif - || qobject_cast(widget)) { - widget->setAttribute(Qt::WA_Hover, false); - } - - if (widget->inherits("QDockSeparator") - || widget->inherits("QDockWidgetSeparator")) { - widget->setAttribute(Qt::WA_Hover, false); - } - - if (false // to simplify the #ifdefs -#ifndef QT_NO_MENUBAR - || qobject_cast(widget) -#endif -#ifndef QT_NO_TOOLBOX - || qobject_cast(widget) -#endif -#ifndef QT_NO_TOOLBAR - || qobject_cast(widget) - || (widget && qobject_cast(widget->parent())) -#endif - ) { - widget->setBackgroundRole(QPalette::Button); - } - -#if defined QPlastique_MaskButtons - if (qobject_cast(widget) || qobject_cast(widget)) - widget->removeEventFilter(this); -#endif -} - -/*! - \reimp -*/ -void QPlastiqueStyle::polish(QApplication *app) -{ - QWindowsStyle::polish(app); -} - -/*! - \reimp -*/ -void QPlastiqueStyle::polish(QPalette &pal) -{ - QWindowsStyle::polish(pal); -#ifdef Q_WS_MAC - pal.setBrush(QPalette::Shadow, Qt::black); -#endif -} - -/*! - \reimp -*/ -void QPlastiqueStyle::unpolish(QApplication *app) -{ - QWindowsStyle::unpolish(app); -} - -/*! - \reimp -*/ -QIcon QPlastiqueStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, - const QWidget *widget) const -{ - return QWindowsStyle::standardIcon(standardIcon, option, widget); -} - -/*! - \reimp -*/ -QPixmap QPlastiqueStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, - const QWidget *widget) const -{ - return QWindowsStyle::standardPixmap(standardPixmap, opt, widget); -} - -// this works as long as we have at most 16 different control types -#define CT1(c) CT2(c, c) -#define CT2(c1, c2) (((uint)c1 << 16) | (uint)c2) - -/*! - \reimp -*/ -int QPlastiqueStyle::layoutSpacing(QSizePolicy::ControlType control1, - QSizePolicy::ControlType control2, - Qt::Orientation orientation, - const QStyleOption * /* option */, - const QWidget * /* widget */) const -{ - const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton; - - if (control2 == QSizePolicy::ButtonBox) - return 11; - - if ((control1 | control2) & ButtonMask) - return (orientation == Qt::Horizontal) ? 10 : 9; - - switch (CT2(control1, control2)) { - case CT1(QSizePolicy::Label): - case CT2(QSizePolicy::Label, QSizePolicy::DefaultType): - case CT2(QSizePolicy::Label, QSizePolicy::CheckBox): - case CT2(QSizePolicy::Label, QSizePolicy::ComboBox): - case CT2(QSizePolicy::Label, QSizePolicy::LineEdit): - case CT2(QSizePolicy::Label, QSizePolicy::RadioButton): - case CT2(QSizePolicy::Label, QSizePolicy::Slider): - case CT2(QSizePolicy::Label, QSizePolicy::SpinBox): - case CT2(QSizePolicy::Label, QSizePolicy::ToolButton): - return 5; - case CT2(QSizePolicy::CheckBox, QSizePolicy::RadioButton): - case CT2(QSizePolicy::RadioButton, QSizePolicy::CheckBox): - case CT1(QSizePolicy::CheckBox): - if (orientation == Qt::Vertical) - return 2; - case CT1(QSizePolicy::RadioButton): - if (orientation == Qt::Vertical) - return 1; - } - - if (orientation == Qt::Horizontal - && (control2 & (QSizePolicy::CheckBox | QSizePolicy::RadioButton))) - return 8; - - if ((control1 | control2) & (QSizePolicy::Frame - | QSizePolicy::GroupBox - | QSizePolicy::TabWidget)) { - return 11; - } - - if ((control1 | control2) & (QSizePolicy::Line | QSizePolicy::Slider - | QSizePolicy::LineEdit | QSizePolicy::ComboBox - | QSizePolicy::SpinBox)) - return 7; - - return 6; -} - -/*! - \reimp -*/ -bool QPlastiqueStyle::eventFilter(QObject *watched, QEvent *event) -{ -#if defined QPlastique_MaskButtons - switch (event->type()) { - case QEvent::Resize: - if (qobject_cast(watched) || qobject_cast(watched)) { - QWidget *widget = qobject_cast(watched); - QRect rect = widget->rect(); - QRegion region(rect); - region -= QRect(rect.left(), rect.top(), 2, 1); - region -= QRect(rect.left(), rect.top() + 1, 1, 1); - region -= QRect(rect.left(), rect.bottom(), 2, 1); - region -= QRect(rect.left(), rect.bottom() - 1, 1, 1); - region -= QRect(rect.right() - 1, rect.top(), 2, 1); - region -= QRect(rect.right(), rect.top() + 1, 1, 1); - region -= QRect(rect.right() - 1, rect.bottom(), 2, 1); - region -= QRect(rect.right(), rect.bottom() - 1, 1, 1); - widget->setMask(region); - } - break; - default: - break; - } -#endif - - return QWindowsStyle::eventFilter(watched, event); -} - -QT_END_NAMESPACE - -#endif // !defined(QT_NO_STYLE_PLASTIQUE) || defined(QT_PLUGIN) diff --git a/src/widgets/styles/qplastiquestyle.h b/src/widgets/styles/qplastiquestyle.h deleted file mode 100644 index bda686e215..0000000000 --- a/src/widgets/styles/qplastiquestyle.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPLASTIQUESTYLE_H -#define QPLASTIQUESTYLE_H - -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - - -#if !defined(QT_NO_STYLE_PLASTIQUE) - -class QPlastiqueStylePrivate; -class Q_WIDGETS_EXPORT QPlastiqueStyle : public QWindowsStyle -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QPlastiqueStyle) -public: - QPlastiqueStyle(); - ~QPlastiqueStyle(); - - void drawPrimitive(PrimitiveElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget = 0) const; - void drawControl(ControlElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget) const; - void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, - QPainter *painter, const QWidget *widget) const; - QSize sizeFromContents(ContentsType type, const QStyleOption *option, - const QSize &size, const QWidget *widget) const; - - QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const; - QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, - SubControl sc, const QWidget *widget) const; - - int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, - QStyleHintReturn *returnData = 0) const; - SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, - const QPoint &pos, const QWidget *widget = 0) const; - - int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const; - - QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, - const QWidget *widget = 0) const; - - void polish(QWidget *widget); - void polish(QApplication *app); - void polish(QPalette &pal); - void unpolish(QWidget *widget); - void unpolish(QApplication *app); - - QPalette standardPalette() const; - - QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt = 0, - const QWidget *widget = 0) const; - int layoutSpacing(QSizePolicy::ControlType control1, - QSizePolicy::ControlType control2, - Qt::Orientation orientation, - const QStyleOption *option = 0, - const QWidget *widget = 0) const; - -protected: - bool eventFilter(QObject *watched, QEvent *event); - -private: - Q_DISABLE_COPY(QPlastiqueStyle) - void *reserved; -}; - -#endif // QT_NO_STYLE_PLASTIQUE - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QPLASTIQUESTYLE_H diff --git a/src/widgets/styles/qstylefactory.cpp b/src/widgets/styles/qstylefactory.cpp index 8f4f014ac8..378448f33c 100644 --- a/src/widgets/styles/qstylefactory.cpp +++ b/src/widgets/styles/qstylefactory.cpp @@ -46,12 +46,6 @@ #include "qapplication.h" #include "qwindowsstyle.h" -#ifndef QT_NO_STYLE_PLASTIQUE -#include "qplastiquestyle.h" -#endif -#ifndef QT_NO_STYLE_CLEANLOOKS -#include "qcleanlooksstyle.h" -#endif #ifndef QT_NO_STYLE_FUSION #include "qfusionstyle.h" #endif @@ -96,9 +90,9 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, plugin (see QStylePlugin). The valid keys can be retrieved using the keys() - function. Typically they include "windows", - "plastique" and "cleanlooks". Depending on the platform, - "windowsxp", "windowsvista" and "macintosh" may be available. + function. Typically they include "windows" and "fusion". + Depending on the platform, "windowsxp", "windowsvista", "gtk" + and "macintosh" may be available. Note that keys are case insensitive. \sa QStyle @@ -144,21 +138,11 @@ QStyle *QStyleFactory::create(const QString& key) ret = new QWindowsVistaStyle; else #endif -#ifndef QT_NO_STYLE_PLASTIQUE - if (style == QLatin1String("plastique")) - ret = new QPlastiqueStyle; - else -#endif #ifndef QT_NO_STYLE_FUSION if (style == QLatin1String("fusion")) ret = new QFusionStyle; else #endif -#ifndef QT_NO_STYLE_CLEANLOOKS - if (style == QLatin1String("cleanlooks")) - ret = new QCleanlooksStyle; - else -#endif #ifndef QT_NO_STYLE_GTK if (style == QLatin1String("gtk") || style == QLatin1String("gtk+")) ret = new QGtkStyle; @@ -222,10 +206,6 @@ QStringList QStyleFactory::keys() (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))) list << QLatin1String("WindowsVista"); #endif -#ifndef QT_NO_STYLE_PLASTIQUE - if (!list.contains(QLatin1String("Plastique"))) - list << QLatin1String("Plastique"); -#endif #ifndef QT_NO_STYLE_GTK if (!list.contains(QLatin1String("GTK+"))) list << QLatin1String("GTK+"); @@ -234,10 +214,6 @@ QStringList QStyleFactory::keys() if (!list.contains(QLatin1String("Fusion"))) list << QLatin1String("Fusion"); #endif -#ifndef QT_NO_STYLE_CLEANLOOKS - if (!list.contains(QLatin1String("Cleanlooks"))) - list << QLatin1String("Cleanlooks"); -#endif #ifndef QT_NO_STYLE_MAC QString mstyle = QLatin1String("Macintosh"); # ifdef Q_WS_MAC diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 4abedb07c8..1c4cad7afe 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include "private/qcssparser_p.h" #include "private/qmath_p.h" #include diff --git a/src/widgets/styles/qstylesheetstyle_default.cpp b/src/widgets/styles/qstylesheetstyle_default.cpp index 843e4adfd3..58dbb1b0b9 100644 --- a/src/widgets/styles/qstylesheetstyle_default.cpp +++ b/src/widgets/styles/qstylesheetstyle_default.cpp @@ -335,11 +335,12 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const } /*QComboBox[style="QPlastiqueStyle"][readOnly="true"], + QComboBox[style="QFusionStyle"][readOnly="true"], QComboBox[style="QCleanlooksStyle"][readOnly="true"] { -qt-background-role: button; }*/ - if (baseStyle()->inherits("QPlastiqueStyle") || baseStyle()->inherits("QCleanlooksStyle")) + if (baseStyle()->inherits("QPlastiqueStyle") || baseStyle()->inherits("QCleanlooksStyle") || baseStyle()->inherits("QFusionStyle")) { SET_ELEMENT_NAME(QLatin1String("QComboBox")); ADD_ATTRIBUTE_SELECTOR(QLatin1String("readOnly"), QLatin1String("true"), AttributeSelector::MatchEqual); diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 301a7ac9ea..6a20f5e9d3 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -204,7 +204,7 @@ bool QWindowsStyle::eventFilter(QObject *o, QEvent *e) This style is Qt's default GUI style on Windows. \image qwindowsstyle.png - \sa QWindowsXPStyle, QMacStyle, QPlastiqueStyle + \sa QWindowsVistaStyle, QMacStyle, QFusionStyle */ /*! diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index d8bf6920ac..d58e76e043 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -154,7 +154,7 @@ bool QWindowsVistaStylePrivate::useVista() \warning This style is only available on the Windows Vista platform because it makes use of Windows Vista's style engine. - \sa QMacStyle, QWindowsXPStyle, QPlastiqueStyle, QCleanlooksStyle + \sa QMacStyle, QWindowsXPStyle, QFusionStyle */ /*! diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index c7517c6e3f..67e5118558 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -1170,7 +1170,7 @@ void QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa sizeFromContents(), are documented here. \image qwindowsxpstyle.png - \sa QMacStyle, QWindowsStyle, QPlastiqueStyle + \sa QMacStyle, QWindowsStyle, QFusionStyle */ /*! diff --git a/src/widgets/styles/styles.pri b/src/widgets/styles/styles.pri index 1aae0d89f3..9c5a790390 100644 --- a/src/widgets/styles/styles.pri +++ b/src/widgets/styles/styles.pri @@ -37,7 +37,7 @@ wince* { } contains( styles, all ) { - styles = mac windows windowsxp windowsvista + styles = fusion mac windows windowsxp windowsvista } !macx-*|ios:styles -= mac @@ -65,6 +65,14 @@ contains( styles, mac ) { DEFINES += QT_NO_STYLE_MAC } +contains( styles, windows ) { + HEADERS += styles/qwindowsstyle.h + SOURCES += styles/qwindowsstyle.cpp + DEFINES += QT_STYLE_WINDOWS +} else { + DEFINES += QT_NO_STYLE_WINDOWS +} + contains( styles, windowsvista ) { HEADERS += styles/qwindowsvistastyle.h HEADERS += styles/qwindowsvistastyle_p.h @@ -72,7 +80,7 @@ contains( styles, windowsvista ) { !contains( styles, windowsxp ) { message( windowsvista requires windowsxp ) styles += windowsxp - DEFINES+= QT_STYLE_WINDOWSXP + DEFINES += QT_STYLE_WINDOWSXP } } else { DEFINES += QT_NO_STYLE_WINDOWSVISTA @@ -83,25 +91,13 @@ contains( styles, windowsxp ) { SOURCES += styles/qwindowsxpstyle.cpp !contains( styles, windows ) { message( windowsxp requires windows ) - styles += windows - DEFINES+= QT_STYLE_WINDOWS + styles += windows + DEFINES += QT_STYLE_WINDOWS } } else { DEFINES += QT_NO_STYLE_WINDOWSXP } -contains( styles, plastique ) { - HEADERS += styles/qplastiquestyle.h - SOURCES += styles/qplastiquestyle.cpp - !contains( styles, windows ) { - message( plastique requires windows ) - styles += windows - DEFINES+= QT_STYLE_WINDOWS - } -} else { - DEFINES += QT_NO_STYLE_PLASTIQUE -} - contains( styles, gtk ) { HEADERS += styles/qgtkstyle.h HEADERS += styles/qgtkpainter_p.h @@ -109,45 +105,17 @@ contains( styles, gtk ) { SOURCES += styles/qgtkstyle.cpp SOURCES += styles/qgtkpainter.cpp SOURCES += styles/qgtkstyle_p.cpp - !contains( styles, cleanlooks ) { - styles += cleanlooks - DEFINES+= QT_STYLE_CLEANLOOKS - } } else { DEFINES += QT_NO_STYLE_GTK } - -contains( styles, cleanlooks ) { - HEADERS += styles/qcleanlooksstyle.h - HEADERS += styles/qcleanlooksstyle_p.h - SOURCES += styles/qcleanlooksstyle.cpp - !contains( styles, windows ) { - styles += windows - DEFINES+= QT_STYLE_WINDOWS - } -} else { - DEFINES += QT_NO_STYLE_CLEANLOOKS -} - contains( styles, fusion ) { HEADERS += styles/qfusionstyle.h HEADERS += styles/qfusionstyle_p.h SOURCES += styles/qfusionstyle.cpp - !contains( styles, windows ) { - styles += windows - DEFINES+= QT_STYLE_WINDOWS - } } else { DEFINES += QT_NO_STYLE_FUSION } -contains( styles, windows ) { - HEADERS += styles/qwindowsstyle.h - SOURCES += styles/qwindowsstyle.cpp -} else { - DEFINES += QT_NO_STYLE_WINDOWS -} - contains( styles, windowsce ) { HEADERS += styles/qwindowscestyle.h SOURCES += styles/qwindowscestyle.cpp diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 516c8b9ae2..e53dc2cac2 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -623,17 +623,6 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti for items in the menu bar are only shown when the \uicontrol{Alt} key is pressed. - \table - - \row \li \inlineimage plastique-menubar.png A menu bar shown in the - Plastique widget style. - - \li The \l{QPlastiqueStyle}{Plastique widget style}, like most - other styles, handles the \uicontrol{Help} menu in the same way as it - handles any other menu. - - \endtable - \section1 QMenuBar on Mac OS X QMenuBar on Mac OS X is a wrapper for using the system-wide menu bar. -- cgit v1.2.3 From ebaed02ae680cf37f014b314baef429a0e642c53 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Mon, 22 Oct 2012 15:09:43 +0200 Subject: Remove softkey API, it was only implemented for Symbian. It is only removed from the documentation for now (I think this should go in the beta 2). That should liberate us to be able to change the API if needed for other platforms that might need a soft keys API. Once this goes in, the plan is to do the actual cleanup. Change-Id: I9a7a3eb45597cd013fe3c4bd479ad08a25ef0b9b Reviewed-by: Janne Anttila Reviewed-by: Marc Mutz Reviewed-by: Lars Knoll --- src/widgets/kernel/qaction.cpp | 7 ++++--- src/widgets/kernel/qaction.h | 9 ++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp index 70a9ab664e..e835f927d0 100644 --- a/src/widgets/kernel/qaction.cpp +++ b/src/widgets/kernel/qaction.cpp @@ -280,7 +280,7 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) File menu in your menubar and the File menu has a submenu, setting the MenuRole for the actions in that submenu have no effect. They will never be moved. */ - +#ifndef qdoc /*! \since 4.6 \enum QAction::SoftKeyRole @@ -300,7 +300,7 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) the action has focus. If no widget currently has focus, the softkey framework will traverse up the widget parent hierarchy looking for a widget containing softkey actions. */ - +#endif /*! Constructs an action with \a parent. If \a parent is an action group the action will be automatically inserted into the group. @@ -1287,6 +1287,7 @@ QAction::MenuRole QAction::menuRole() const return d->menuRole; } +#ifndef qdoc /*! \property QAction::softKeyRole \brief the action's softkey role @@ -1313,7 +1314,7 @@ QAction::SoftKeyRole QAction::softKeyRole() const Q_D(const QAction); return d->softKeyRole; } - +#endif /*! \property QAction::iconVisibleInMenu \brief Whether or not an action should show an icon in a menu diff --git a/src/widgets/kernel/qaction.h b/src/widgets/kernel/qaction.h index d9b518916e..e149975de7 100644 --- a/src/widgets/kernel/qaction.h +++ b/src/widgets/kernel/qaction.h @@ -66,7 +66,9 @@ class Q_WIDGETS_EXPORT QAction : public QObject Q_DECLARE_PRIVATE(QAction) Q_ENUMS(MenuRole) +#ifndef qdoc Q_ENUMS(SoftKeyRole) +#endif Q_ENUMS(Priority) Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY changed) Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled) @@ -85,7 +87,9 @@ class Q_WIDGETS_EXPORT QAction : public QObject #endif Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed) Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed) +#ifndef qdoc Q_PROPERTY(SoftKeyRole softKeyRole READ softKeyRole WRITE setSoftKeyRole NOTIFY changed) +#endif Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed) Q_PROPERTY(Priority priority READ priority WRITE setPriority) @@ -93,8 +97,10 @@ public: // note this is copied into qplatformmenu.h, which must stay in sync enum MenuRole { NoRole = 0, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole, AboutRole, PreferencesRole, QuitRole }; +#ifndef qdoc enum SoftKeyRole { NoSoftKey, PositiveSoftKey, NegativeSoftKey, SelectSoftKey }; +#endif enum Priority { LowPriority = 0, NormalPriority = 128, HighPriority = 256}; @@ -172,9 +178,10 @@ public: void setMenuRole(MenuRole menuRole); MenuRole menuRole() const; +#ifndef qdoc void setSoftKeyRole(SoftKeyRole softKeyRole); SoftKeyRole softKeyRole() const; - +#endif void setIconVisibleInMenu(bool visible); bool isIconVisibleInMenu() const; -- cgit v1.2.3 From d8c8057c03fc906f3bee0905246ca18351bd9e1b Mon Sep 17 00:00:00 2001 From: Julien Brianceau Date: Fri, 19 Oct 2012 11:35:43 +0200 Subject: qpa: Fix drawPixmap rendering using CompositionMode_Source in DirectFB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I646bc7054e1aa17dca4f54ddd3d2668c173773d4 Reviewed-by: Samuel Rødal Reviewed-by: Jørgen Lind --- src/plugins/platforms/directfb/qdirectfbblitter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.cpp b/src/plugins/platforms/directfb/qdirectfbblitter.cpp index 428ee72f9e..cac250fb9d 100644 --- a/src/plugins/platforms/directfb/qdirectfbblitter.cpp +++ b/src/plugins/platforms/directfb/qdirectfbblitter.cpp @@ -197,7 +197,9 @@ void QDirectFbBlitter::drawPixmapOpacity(const QRectF &rect, const QPixmap &pixm m_surface->SetBlittingFlags(m_surface.data(), DFBSurfaceBlittingFlags(blittingFlags)); m_surface->SetPorterDuff(m_surface.data(), porterDuff); - m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA); + + if (cmode == QPainter::CompositionMode_SourceOver) + m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA); if ((sRect.w == dRect.w) && (sRect.h == dRect.h)) result = m_surface->Blit(m_surface.data(), s, &sRect, dRect.x, dRect.y); -- cgit v1.2.3 From 4dbf60d672a24a56e830654c386517b71d83bf85 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 11 Oct 2012 15:24:11 +0200 Subject: Fix mistakes in QNetworkAccessManager docs. Change-Id: I2c797affec9472815003b1a032196c81088e1df6 Reviewed-by: Shane Kearns Reviewed-by: Marc Mutz --- src/network/access/qnetworkaccessmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 3dcb4b8730..1118c3242f 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -205,10 +205,10 @@ static void ensureInitialized() QNetworkAccessManager gained the ability to manage network connections. QNetworkAccessManager can start the network interface if the device is offline and terminates the interface if the current process is the last - one to use the uplink. Note that some platform utilize grace periods from + one to use the uplink. Note that some platforms utilize grace periods from when the last application stops using a uplink until the system actually terminates the connectivity link. Roaming is equally transparent. Any - queued/pending network requests are automatically transferred to new + queued/pending network requests are automatically transferred to the new access point. Clients wanting to utilize this feature should not require any changes. In fact -- cgit v1.2.3 From 6fe8a3d5a1c1f2b963fe25e9032b562f6c6467e6 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Mon, 22 Oct 2012 09:32:24 +0200 Subject: CMake: Make qt5_use_modules a macro, not a function. Because qt5_use_modules is a function that does a find package which finds imported targets, things like this: qt5_use_modules(foo Sql) if (TARGET Qt5::Sql) message("Qt5Sql_FOUND: ${Qt5Sql_FOUND}") endif() will show Qt5Sql as being not found, even though the target is in scope. Fix that by making it a macro instead. Change-Id: If314bd5b4d3f769c6c7df5ff2c924eabd16dcc0e Reviewed-by: Alexander Neundorf Reviewed-by: Stephen Kelly --- src/corelib/Qt5CoreMacros.cmake | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake index 089445a184..614b79ab88 100644 --- a/src/corelib/Qt5CoreMacros.cmake +++ b/src/corelib/Qt5CoreMacros.cmake @@ -217,29 +217,29 @@ endfunction() if (NOT CMAKE_VERSION VERSION_LESS 2.8.9) - function(qt5_use_modules _target _link_type) + macro(qt5_use_modules _target _link_type) if (NOT TARGET ${_target}) message(FATAL_ERROR "The first argument to qt5_use_modules must be an existing target.") endif() if ("${_link_type}" STREQUAL "LINK_PUBLIC" OR "${_link_type}" STREQUAL "LINK_PRIVATE" ) - set(modules ${ARGN}) - set(link_type ${_link_type}) + set(_qt5_modules ${ARGN}) + set(_qt5_link_type ${_link_type}) else() - set(modules ${_link_type} ${ARGN}) + set(_qt5_modules ${_link_type} ${ARGN}) endif() - if ("${modules}" STREQUAL "") + if ("${_qt5_modules}" STREQUAL "") message(FATAL_ERROR "qt5_use_modules requires at least one Qt module to use.") endif() - foreach(_module ${modules}) + foreach(_module ${_qt5_modules}) if (NOT Qt5${_module}_FOUND) find_package(Qt5${_module} PATHS ${_qt5_corelib_install_prefix} NO_DEFAULT_PATH) if (NOT Qt5${_module}_FOUND) message(FATAL_ERROR "Can not use \"${_module}\" module which has not yet been found.") endif() endif() - target_link_libraries(${_target} ${link_type} ${Qt5${_module}_LIBRARIES}) + target_link_libraries(${_target} ${_qt5_link_type} ${Qt5${_module}_LIBRARIES}) set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES ${Qt5${_module}_INCLUDE_DIRS}) set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS ${Qt5${_module}_COMPILE_DEFINITIONS}) set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG) @@ -248,5 +248,5 @@ if (NOT CMAKE_VERSION VERSION_LESS 2.8.9) set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ${Qt5_POSITION_INDEPENDENT_CODE}) endif() endforeach() - endfunction() + endmacro() endif() -- cgit v1.2.3 From bbda968a0a3230b1ddb55b27e4dcc627fc087bbd Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sun, 14 Oct 2012 04:12:35 +0100 Subject: Fix QRegExpValidator::validate docs about the pos parameter The code sets it to input.length() iff the regexp doesn't match the string, while the docs say it's *always* set. Therefore, make the docs match what the code does and add a simple test to enforce it. We're not changing the code to match the docs because 1) it's better to stay conservative (we don't want to break existing behaviour); 2) this behaviour mimics what the int/double validators do (they don't move pos at all). Change-Id: I958074558de6b0fc5944101c6535fc7e00442ae9 Reviewed-by: Marc Mutz --- src/gui/util/qvalidator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index 49945ae5b0..6231a097d3 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -862,7 +862,8 @@ QRegExpValidator::~QRegExpValidator() partially (i.e. could be a valid match if additional valid characters are added), and \l Invalid if \a input is not matched. - The \a pos parameter is set to the length of the \a input parameter. + Additionally, if \a input is not matched, the \a pos parameter is set to + the length of the \a input parameter. For example, if the regular expression is \b{\\w\\d\\d} (word-character, digit, digit) then "A57" is \l Acceptable, -- cgit v1.2.3 From 2e2133247677fbdf81741badf523a00612826a37 Mon Sep 17 00:00:00 2001 From: Thomas McGuire Date: Wed, 17 Oct 2012 10:45:43 +0200 Subject: Blackberry: Fix applicationFilePath() for unpackaged executables Not all executables originate from a BAR package, for example unit tests. Make those use the fallback code for finding the application file path. Change-Id: I5603f329bbe74e37d319ddd190f72bc6f64e1a5c Reviewed-by: Fabian Bumberger Reviewed-by: Kevin Krammer Reviewed-by: Sean Harmer --- src/corelib/kernel/qcoreapplication.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index df0ffce12d..55112af7ec 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1796,8 +1796,6 @@ QString QCoreApplication::applicationFilePath() if (!executables.empty()) { //We assume that there is only one executable in the folder return dir.absoluteFilePath(executables.first()); - } else { - return QString(); } #elif defined(Q_OS_MAC) QString qAppFileName_str = qAppFileName(); -- cgit v1.2.3 From 7abf6234436aee377d15f9f2f1d37ee7daf7464e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 23 Oct 2012 10:53:40 +0200 Subject: QStyleAnimation: fix threaded rendering Change-Id: I00875adf2e4b157a3f8b0b99e5280b1275635026 Reviewed-by: Jens Bache-Wiig --- src/widgets/styles/qcommonstyle.cpp | 5 +---- src/widgets/styles/qstyleanimation.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 0e22a90a4b..990245a113 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -1073,7 +1073,6 @@ void QCommonStylePrivate::startAnimation(QStyleAnimation *animation) const { Q_Q(const QCommonStyle); stopAnimation(animation->target()); - q->connect(animation, SIGNAL(finished()), SLOT(_q_removeAnimation()), Qt::UniqueConnection); q->connect(animation, SIGNAL(destroyed()), SLOT(_q_removeAnimation()), Qt::UniqueConnection); animations.insert(animation->target(), animation); animation->start(); @@ -1096,10 +1095,8 @@ void QCommonStylePrivate::_q_removeAnimation() { Q_Q(QCommonStyle); QObject *animation = q->sender(); - if (animation) { + if (animation) animations.remove(animation->parent()); - animation->deleteLater(); - } } /*! diff --git a/src/widgets/styles/qstyleanimation.cpp b/src/widgets/styles/qstyleanimation.cpp index 6173dc9ddb..9f58c9d51f 100644 --- a/src/widgets/styles/qstyleanimation.cpp +++ b/src/widgets/styles/qstyleanimation.cpp @@ -47,9 +47,14 @@ QT_BEGIN_NAMESPACE -QStyleAnimation::QStyleAnimation(QObject *target) : QAbstractAnimation(target), +QStyleAnimation::QStyleAnimation(QObject *target) : QAbstractAnimation(), _startTime(QTime::currentTime()) { + if (target) { + moveToThread(target->thread()); + setParent(target); + } + connect(this, SIGNAL(finished()), SLOT(deleteLater())); } QStyleAnimation::~QStyleAnimation() -- cgit v1.2.3 From 202ac1cbe7d7e2a30b3c2384ce8d62655ba019c0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 23 Oct 2012 10:11:54 +0200 Subject: QProcess: Include program in destructor warning. Change-Id: Ib6870d2b161197fdeab7fe5140ac4757c79f478e Reviewed-by: Joerg Bornemann --- src/corelib/io/qprocess.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index b115310d63..395effaff9 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -41,8 +41,9 @@ //#define QPROCESS_DEBUG -#if defined QPROCESS_DEBUG #include +#include +#if defined QPROCESS_DEBUG #include #include #if !defined(Q_OS_WINCE) @@ -1147,7 +1148,8 @@ QProcess::~QProcess() { Q_D(QProcess); if (d->processState != NotRunning) { - qWarning("QProcess: Destroyed while process is still running."); + qWarning().nospace() + << "QProcess: Destroyed while process (" << QDir::toNativeSeparators(program()) << ") is still running."; kill(); waitForFinished(); } -- cgit v1.2.3 From 0a6691027db87ef30ee4010740feb7bc9c753bd1 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 22 Oct 2012 16:08:44 +0200 Subject: Fix warning about missing return value in XCB native interface. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If311211076c05ed8d0fb62a9ff1129b93a813850 Reviewed-by: Samuel Rødal --- src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 40f39843e5..2a36fb7369 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -186,6 +186,8 @@ void * QXcbNativeInterface::eglContextForContext(QOpenGLContext *context) #if defined(XCB_USE_EGL) QEGLPlatformContext *eglPlatformContext = static_cast(context->handle()); return eglPlatformContext->eglContext(); +#else + return 0; #endif } -- cgit v1.2.3 From 4835a87fe3a4107a7d7a05b371d8a2a4b3b255de Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 22 Oct 2012 19:15:14 +0200 Subject: Add QStyleAnimation::updateTarget() For example a paused "default button" animation might want to update the target to get "non-default button" looks meanwhile the animation is paused. Change-Id: Ibb854a40f38a8971e7233b1f34a83056e6a9d827 Reviewed-by: Jens Bache-Wiig --- src/widgets/styles/qstyleanimation.cpp | 12 ++++++++---- src/widgets/styles/qstyleanimation_p.h | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qstyleanimation.cpp b/src/widgets/styles/qstyleanimation.cpp index 9f58c9d51f..6b12ca9540 100644 --- a/src/widgets/styles/qstyleanimation.cpp +++ b/src/widgets/styles/qstyleanimation.cpp @@ -81,6 +81,12 @@ void QStyleAnimation::setStartTime(const QTime &time) _startTime = time; } +void QStyleAnimation::updateTarget() +{ + QEvent event(QEvent::StyleAnimationUpdate); + QCoreApplication::sendEvent(target(), &event); +} + bool QStyleAnimation::isUpdateNeeded() const { return true; @@ -95,10 +101,8 @@ void QStyleAnimation::updateCurrentTime(int) stop(); } - if (isUpdateNeeded()) { - QEvent event(QEvent::StyleAnimationUpdate); - QCoreApplication::sendEvent(tgt, &event); - } + if (isUpdateNeeded()) + updateTarget(); } } diff --git a/src/widgets/styles/qstyleanimation_p.h b/src/widgets/styles/qstyleanimation_p.h index 8231abbb40..577b1d7dd4 100644 --- a/src/widgets/styles/qstyleanimation_p.h +++ b/src/widgets/styles/qstyleanimation_p.h @@ -72,6 +72,8 @@ public: QTime startTime() const; void setStartTime(const QTime &time); + void updateTarget(); + protected: virtual bool isUpdateNeeded() const; virtual void updateCurrentTime(int time); -- cgit v1.2.3 From d1ad991bee52e17452cae9dca55b3b340c6f0955 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 23 Oct 2012 17:25:48 +0200 Subject: Fix valgrind warning in QTriangulatingStroker. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize all member variables including m_invScale, which was uninitialized. Change-Id: Id581b1db9411b2f945281e17b7a0407c746761f8 Reviewed-by: Samuel Rødal --- src/gui/opengl/qtriangulatingstroker_p.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/opengl/qtriangulatingstroker_p.h b/src/gui/opengl/qtriangulatingstroker_p.h index ba21c0820f..98b12b0fb3 100644 --- a/src/gui/opengl/qtriangulatingstroker_p.h +++ b/src/gui/opengl/qtriangulatingstroker_p.h @@ -54,7 +54,10 @@ QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QTriangulatingStroker { public: - QTriangulatingStroker() : m_vertices(0) {} + QTriangulatingStroker() : m_vertices(0), m_cx(0), m_cy(0), m_nvx(0), m_nvy(0), m_width(1), m_miter_limit(2), + m_roundness(0), m_sin_theta(0), m_cos_theta(0), m_inv_scale(1), m_curvyness_mul(1), m_curvyness_add(0), + m_join_style(Qt::BevelJoin), m_cap_style(Qt::SquareCap) {} + void process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints); inline int vertexCount() const { return m_vertices.size(); } -- cgit v1.2.3 From 811bf4da67cedea0daa40f2fff805003687e9d6e Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 21 Sep 2012 11:30:55 +0200 Subject: Output leading zeroes for yyyy date formats in QLocale::toString(). Converting the date 1 January 0001 to a string in the format "dd MMMM yyyy" currently results in the string "01 January 1", but it should be "01 January 0001". Task-number: QTBUG-27287 Change-Id: Ia025da7343d1c36aaee34c47c6db551a6e89595f Reviewed-by: Thiago Macieira --- src/corelib/tools/qlocale.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 368cb444a3..97946b52c8 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -2262,7 +2262,7 @@ QString QLocalePrivate::dateTimeToString(const QString &format, const QDate *dat switch (repeat) { case 4: - result.append(longLongToString(date->year())); + result.append(longLongToString(date->year(), -1, 10, 4, QLocalePrivate::ZeroPadded)); break; case 2: result.append(longLongToString(date->year() % 100, -1, 10, 2, -- cgit v1.2.3 From 7cbdac13627b8e6ba9ed1bcd42fdf3f408f02b7d Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 28 Sep 2012 16:23:09 +0200 Subject: Clarify assert on use of const char* as TestData type in tests. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently all C-style strings used as data types in QTest::addColumn will assert at runtime with, e.g.: "expected data of type 'const char*', got 'QString' for element 0 of data with tab 'blah'". This patch makes it clear that C-style strings are disallowed. Change-Id: Iadbb8f10e16607de95c7adb43d9ff3310aac6738 Reviewed-by: Jędrzej Nowacki --- src/testlib/qtestcase.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index 1bfefaf2b0..8529791be4 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -218,6 +219,8 @@ namespace QTest template inline void addColumn(const char *name, T * = 0) { + typedef QtPrivate::is_same QIsSameTConstChar; + Q_STATIC_ASSERT_X(!QIsSameTConstChar::value, "const char* is not allowed as a test data format."); addColumnInternal(qMetaTypeId(), name); } Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag); -- cgit v1.2.3 From 6a7a08b4a873d0bb4602e4095dc62d7124a6f41e Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 15 Oct 2012 18:22:45 +0200 Subject: Improve QDate test coverage. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some statements could not be tested, such as default cases of switches where all possible cases are already handled and some statements where the system locale is used. I also removed some statements that would never be reached and hence will never be able to be covered by tests. Change-Id: I8ea3071f66d942d986e65708732af6751d36b5e3 Reviewed-by: Jędrzej Nowacki --- src/corelib/tools/qdatetime.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index a9d3095224..7561847c96 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -408,8 +408,6 @@ int QDate::daysInMonth() const getDateFromJulianDay(jd, &y, &m, 0); if (m == 2 && isLeapYear(y)) return 29; - else if (m < 1 || m > 12) - return 0; else return monthDays[m]; } @@ -1150,9 +1148,10 @@ QDate QDate::fromString(const QString& s, Qt::DateFormat f) break; } } - } - if (month < 1 || month > 12) { - return QDate(); + if (month == -1) { + // Month name matches neither English nor other localised name. + return QDate(); + } } bool ok; -- cgit v1.2.3 From 8310533975fc3cafd796ca3b1266d6777137b2d0 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 16 Oct 2012 12:05:06 +0200 Subject: Improve QTime test coverage. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If47de3dc047ac4f8a4a1498cf225e03bbbf4110e Reviewed-by: Mitch Curtis Reviewed-by: Jędrzej Nowacki Reviewed-by: Jon Severinsson --- src/corelib/tools/qdatetime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 7561847c96..7845273cb8 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -1804,7 +1804,7 @@ QTime fromStringImpl(const QString &s, Qt::DateFormat f, bool &isMidnight24) if (s.size() == 5) { // Do not need to specify seconds if using ISO format. return QTime(hour, minute, 0, 0); - } else if ((s.size() > 6 && s[5] == QLatin1Char(',')) || s[5] == QLatin1Char('.')) { + } else if ((s.size() > 6) && (s[5] == QLatin1Char(',') || s[5] == QLatin1Char('.'))) { // Possibly specifying fraction of a minute. // We only want 5 digits worth of fraction of minute. This follows the existing -- cgit v1.2.3 From b016597db844d0214734bb301c1e101261f4c724 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 17 Oct 2012 13:56:50 +0200 Subject: Return invalid datetime when calling addMSecs with invalid QDateTime. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is in line with what QTime::addMSecs and QDate::addDays do, for example. Change-Id: I902112486727f74f669a97bde6c42028e0838f8d Reviewed-by: Jon Severinsson Reviewed-by: Jędrzej Nowacki --- src/corelib/tools/qdatetime.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 7845273cb8..7d18e93dce 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -2692,6 +2692,9 @@ QDateTime QDateTime::addYears(int nyears) const QDateTime QDateTimePrivate::addMSecs(const QDateTime &dt, qint64 msecs) { + if (!dt.isValid()) + return QDateTime(); + QDate utcDate; QTime utcTime; dt.d->getUTC(utcDate, utcTime); @@ -2742,6 +2745,8 @@ void QDateTimePrivate::addMSecs(QDate &utcDate, QTime &utcTime, qint64 msecs) later than the datetime of this object (or earlier if \a s is negative). + If this datetime is invalid, an invalid datetime will be returned. + \sa addMSecs(), secsTo(), addDays(), addMonths(), addYears() */ @@ -2755,6 +2760,8 @@ QDateTime QDateTime::addSecs(qint64 s) const later than the datetime of this object (or earlier if \a msecs is negative). + If this datetime is invalid, an invalid datetime will be returned. + \sa addSecs(), msecsTo(), addDays(), addMonths(), addYears() */ QDateTime QDateTime::addMSecs(qint64 msecs) const -- cgit v1.2.3 From 84d09214bc54b4a0cf9860aa27e78ae27bfd69f9 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 23 Oct 2012 17:14:06 +0200 Subject: Quieten warning about uninitialized use of d pointer We had this issue in Qt 4 before: Clang considers the use of d uninitialized in the initializer list for d. This might or might not be legal, the clang devs are divided on that topic. Let's just use a more common form and ignore the issue language lawyers. Change-Id: I3324255963a6d0f4a9057fe0d1d9ae868d3efef7 Reviewed-by: Thiago Macieira --- src/corelib/tools/qsharedpointer_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index d0422175f5..6f3e577e55 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -625,7 +625,7 @@ public: #ifndef QT_NO_QOBJECT template - inline QWeakPointer(X *ptr, bool) : d(ptr ? d->getAndRef(ptr) : 0), value(ptr) + inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : 0), value(ptr) { } #endif -- cgit v1.2.3 From e0c0e83fd5534b24f18d5e02a453182df54933e0 Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Mon, 15 Oct 2012 14:16:51 +0200 Subject: Add ANGLE as a 3rdparty library to Qt. ANGLE is a component that implements the OpenGL ES 2.0 API on top of DirectX 9. See the following for more info: http://code.google.com/p/angleproject/ ANGLE is now the default configuration on Windows. If you want to use desktop OpenGL, you should build Qt with the following configure options: -opengl desktop To configure Qt to use another OpenGL ES 2 implementation, you should use: -opengl es2 -no-angle Task-number: QTBUG-24207 Change-Id: Iefcbeaa37ed920f431729749ab8333b248fe5134 Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/.gitignore | 35 + src/3rdparty/angle/AUTHORS | 30 + src/3rdparty/angle/CONTRIBUTORS | 70 + src/3rdparty/angle/LICENSE | 32 + src/3rdparty/angle/LICENSE.preprocessor | 45 + src/3rdparty/angle/include/EGL/egl.h | 329 + src/3rdparty/angle/include/EGL/eglext.h | 348 + src/3rdparty/angle/include/EGL/eglplatform.h | 129 + src/3rdparty/angle/include/GLES2/gl2.h | 621 ++ src/3rdparty/angle/include/GLES2/gl2ext.h | 1504 +++++ src/3rdparty/angle/include/GLES2/gl2platform.h | 30 + src/3rdparty/angle/include/GLSLANG/ShaderLang.h | 354 + src/3rdparty/angle/include/KHR/khrplatform.h | 269 + src/3rdparty/angle/src/common/RefCountObject.cpp | 47 + src/3rdparty/angle/src/common/RefCountObject.h | 65 + src/3rdparty/angle/src/common/angleutils.h | 26 + src/3rdparty/angle/src/common/debug.cpp | 103 + src/3rdparty/angle/src/common/debug.h | 105 + src/3rdparty/angle/src/common/version.h | 10 + src/3rdparty/angle/src/compiler/BaseTypes.h | 152 + .../angle/src/compiler/BuiltInFunctionEmulator.cpp | 406 ++ .../angle/src/compiler/BuiltInFunctionEmulator.h | 93 + src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp | 34 + src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp | 31 + src/3rdparty/angle/src/compiler/Common.h | 89 + src/3rdparty/angle/src/compiler/Compiler.cpp | 350 + src/3rdparty/angle/src/compiler/ConstantUnion.h | 256 + .../angle/src/compiler/DetectDiscontinuity.cpp | 119 + .../angle/src/compiler/DetectDiscontinuity.h | 50 + .../angle/src/compiler/DetectRecursion.cpp | 125 + src/3rdparty/angle/src/compiler/DetectRecursion.h | 60 + src/3rdparty/angle/src/compiler/Diagnostics.cpp | 63 + src/3rdparty/angle/src/compiler/Diagnostics.h | 44 + .../angle/src/compiler/DirectiveHandler.cpp | 161 + src/3rdparty/angle/src/compiler/DirectiveHandler.h | 46 + .../angle/src/compiler/ExtensionBehavior.h | 37 + src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp | 215 + src/3rdparty/angle/src/compiler/ForLoopUnroll.h | 48 + src/3rdparty/angle/src/compiler/InfoSink.cpp | 59 + src/3rdparty/angle/src/compiler/InfoSink.h | 115 + src/3rdparty/angle/src/compiler/Initialize.cpp | 657 ++ src/3rdparty/angle/src/compiler/Initialize.h | 35 + src/3rdparty/angle/src/compiler/InitializeDll.cpp | 115 + src/3rdparty/angle/src/compiler/InitializeDll.h | 16 + .../angle/src/compiler/InitializeGlobals.h | 15 + .../angle/src/compiler/InitializeParseContext.cpp | 96 + .../angle/src/compiler/InitializeParseContext.h | 26 + src/3rdparty/angle/src/compiler/IntermTraverse.cpp | 293 + src/3rdparty/angle/src/compiler/Intermediate.cpp | 1447 ++++ src/3rdparty/angle/src/compiler/MMap.h | 56 + .../angle/src/compiler/MapLongVariableNames.cpp | 122 + .../angle/src/compiler/MapLongVariableNames.h | 59 + src/3rdparty/angle/src/compiler/OutputESSL.cpp | 22 + src/3rdparty/angle/src/compiler/OutputESSL.h | 21 + src/3rdparty/angle/src/compiler/OutputGLSL.cpp | 17 + src/3rdparty/angle/src/compiler/OutputGLSL.h | 21 + src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp | 720 ++ src/3rdparty/angle/src/compiler/OutputGLSLBase.h | 53 + src/3rdparty/angle/src/compiler/OutputHLSL.cpp | 2664 ++++++++ src/3rdparty/angle/src/compiler/OutputHLSL.h | 152 + src/3rdparty/angle/src/compiler/ParseHelper.cpp | 1528 +++++ src/3rdparty/angle/src/compiler/ParseHelper.h | 140 + src/3rdparty/angle/src/compiler/PoolAlloc.cpp | 310 + src/3rdparty/angle/src/compiler/PoolAlloc.h | 306 + src/3rdparty/angle/src/compiler/Pragma.h | 19 + src/3rdparty/angle/src/compiler/QualifierAlive.cpp | 58 + src/3rdparty/angle/src/compiler/QualifierAlive.h | 7 + src/3rdparty/angle/src/compiler/RemoveTree.cpp | 77 + src/3rdparty/angle/src/compiler/RemoveTree.h | 7 + src/3rdparty/angle/src/compiler/RenameFunction.h | 36 + src/3rdparty/angle/src/compiler/SearchSymbol.cpp | 38 + src/3rdparty/angle/src/compiler/SearchSymbol.h | 33 + src/3rdparty/angle/src/compiler/ShHandle.h | 142 + src/3rdparty/angle/src/compiler/ShaderLang.cpp | 285 + src/3rdparty/angle/src/compiler/SymbolTable.cpp | 279 + src/3rdparty/angle/src/compiler/SymbolTable.h | 359 + src/3rdparty/angle/src/compiler/TranslatorESSL.cpp | 40 + src/3rdparty/angle/src/compiler/TranslatorESSL.h | 23 + src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp | 41 + src/3rdparty/angle/src/compiler/TranslatorGLSL.h | 20 + src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp | 23 + src/3rdparty/angle/src/compiler/TranslatorHLSL.h | 20 + src/3rdparty/angle/src/compiler/Types.h | 318 + .../angle/src/compiler/UnfoldShortCircuit.cpp | 172 + .../angle/src/compiler/UnfoldShortCircuit.h | 39 + .../angle/src/compiler/ValidateLimitations.cpp | 512 ++ .../angle/src/compiler/ValidateLimitations.h | 59 + src/3rdparty/angle/src/compiler/VariableInfo.cpp | 232 + src/3rdparty/angle/src/compiler/VariableInfo.h | 46 + src/3rdparty/angle/src/compiler/VariablePacker.cpp | 297 + src/3rdparty/angle/src/compiler/VariablePacker.h | 41 + src/3rdparty/angle/src/compiler/VersionGLSL.cpp | 140 + src/3rdparty/angle/src/compiler/VersionGLSL.h | 56 + src/3rdparty/angle/src/compiler/debug.cpp | 37 + src/3rdparty/angle/src/compiler/debug.h | 53 + .../src/compiler/depgraph/DependencyGraph.cpp | 97 + .../angle/src/compiler/depgraph/DependencyGraph.h | 212 + .../compiler/depgraph/DependencyGraphBuilder.cpp | 227 + .../src/compiler/depgraph/DependencyGraphBuilder.h | 181 + .../compiler/depgraph/DependencyGraphOutput.cpp | 65 + .../src/compiler/depgraph/DependencyGraphOutput.h | 30 + .../compiler/depgraph/DependencyGraphTraverse.cpp | 69 + src/3rdparty/angle/src/compiler/glslang.h | 16 + src/3rdparty/angle/src/compiler/glslang.l | 511 ++ src/3rdparty/angle/src/compiler/glslang.y | 2142 ++++++ src/3rdparty/angle/src/compiler/intermOut.cpp | 419 ++ src/3rdparty/angle/src/compiler/intermediate.h | 557 ++ .../angle/src/compiler/localintermediate.h | 58 + src/3rdparty/angle/src/compiler/osinclude.h | 72 + src/3rdparty/angle/src/compiler/ossource_nspr.cpp | 43 + src/3rdparty/angle/src/compiler/ossource_posix.cpp | 64 + src/3rdparty/angle/src/compiler/ossource_win.cpp | 57 + src/3rdparty/angle/src/compiler/parseConst.cpp | 238 + .../angle/src/compiler/preprocessor/atom.c | 737 ++ .../angle/src/compiler/preprocessor/atom.h | 63 + .../angle/src/compiler/preprocessor/compile.h | 100 + src/3rdparty/angle/src/compiler/preprocessor/cpp.c | 1118 ++++ src/3rdparty/angle/src/compiler/preprocessor/cpp.h | 86 + .../angle/src/compiler/preprocessor/cppstruct.c | 152 + .../src/compiler/preprocessor/length_limits.h | 21 + .../angle/src/compiler/preprocessor/memory.c | 158 + .../angle/src/compiler/preprocessor/memory.h | 58 + .../src/compiler/preprocessor/new/Diagnostics.cpp | 127 + .../src/compiler/preprocessor/new/Diagnostics.h | 87 + .../compiler/preprocessor/new/DirectiveHandler.cpp | 16 + .../compiler/preprocessor/new/DirectiveHandler.h | 43 + .../compiler/preprocessor/new/DirectiveParser.cpp | 932 +++ .../compiler/preprocessor/new/DirectiveParser.h | 82 + .../compiler/preprocessor/new/ExpressionParser.h | 34 + .../compiler/preprocessor/new/ExpressionParser.y | 279 + .../angle/src/compiler/preprocessor/new/Input.cpp | 55 + .../angle/src/compiler/preprocessor/new/Input.h | 48 + .../angle/src/compiler/preprocessor/new/Lexer.cpp | 16 + .../angle/src/compiler/preprocessor/new/Lexer.h | 25 + .../angle/src/compiler/preprocessor/new/Macro.cpp | 23 + .../angle/src/compiler/preprocessor/new/Macro.h | 44 + .../compiler/preprocessor/new/MacroExpander.cpp | 370 ++ .../src/compiler/preprocessor/new/MacroExpander.h | 75 + .../src/compiler/preprocessor/new/Preprocessor.cpp | 142 + .../src/compiler/preprocessor/new/Preprocessor.h | 49 + .../src/compiler/preprocessor/new/SourceLocation.h | 38 + .../angle/src/compiler/preprocessor/new/Token.cpp | 83 + .../angle/src/compiler/preprocessor/new/Token.h | 106 + .../src/compiler/preprocessor/new/Tokenizer.h | 58 + .../src/compiler/preprocessor/new/Tokenizer.l | 340 + .../src/compiler/preprocessor/new/numeric_lex.h | 61 + .../angle/src/compiler/preprocessor/new/pp_utils.h | 18 + .../angle/src/compiler/preprocessor/parser.h | 93 + .../angle/src/compiler/preprocessor/preprocess.h | 50 + .../angle/src/compiler/preprocessor/scanner.c | 698 ++ .../angle/src/compiler/preprocessor/scanner.h | 81 + .../angle/src/compiler/preprocessor/slglobals.h | 82 + .../angle/src/compiler/preprocessor/symbols.c | 288 + .../angle/src/compiler/preprocessor/symbols.h | 111 + .../angle/src/compiler/preprocessor/tokens.c | 467 ++ .../angle/src/compiler/preprocessor/tokens.h | 90 + .../timing/RestrictFragmentShaderTiming.cpp | 127 + .../compiler/timing/RestrictFragmentShaderTiming.h | 40 + .../compiler/timing/RestrictVertexShaderTiming.cpp | 17 + .../compiler/timing/RestrictVertexShaderTiming.h | 33 + src/3rdparty/angle/src/compiler/util.cpp | 33 + src/3rdparty/angle/src/compiler/util.h | 21 + src/3rdparty/angle/src/libEGL/Config.cpp | 399 ++ src/3rdparty/angle/src/libEGL/Config.h | 118 + src/3rdparty/angle/src/libEGL/Display.cpp | 1292 ++++ src/3rdparty/angle/src/libEGL/Display.h | 167 + src/3rdparty/angle/src/libEGL/ShaderCache.h | 116 + src/3rdparty/angle/src/libEGL/Surface.cpp | 674 ++ src/3rdparty/angle/src/libEGL/Surface.h | 112 + src/3rdparty/angle/src/libEGL/libEGL.cpp | 1181 ++++ src/3rdparty/angle/src/libEGL/libEGL.def | 36 + src/3rdparty/angle/src/libEGL/libEGL.rc | 102 + src/3rdparty/angle/src/libEGL/main.cpp | 165 + src/3rdparty/angle/src/libEGL/main.h | 61 + src/3rdparty/angle/src/libEGL/resource.h | 14 + src/3rdparty/angle/src/libGLESv2/BinaryStream.h | 167 + src/3rdparty/angle/src/libGLESv2/Blit.cpp | 518 ++ src/3rdparty/angle/src/libGLESv2/Blit.h | 94 + src/3rdparty/angle/src/libGLESv2/Buffer.cpp | 117 + src/3rdparty/angle/src/libGLESv2/Buffer.h | 61 + src/3rdparty/angle/src/libGLESv2/Context.cpp | 4501 +++++++++++++ src/3rdparty/angle/src/libGLESv2/Context.h | 685 ++ .../angle/src/libGLESv2/D3DConstantTable.cpp | 231 + .../angle/src/libGLESv2/D3DConstantTable.h | 117 + src/3rdparty/angle/src/libGLESv2/Fence.cpp | 132 + src/3rdparty/angle/src/libGLESv2/Fence.h | 49 + .../angle/src/libGLESv2/Float16ToFloat32.cpp | 2203 ++++++ .../angle/src/libGLESv2/Float16ToFloat32.py | 78 + src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp | 509 ++ src/3rdparty/angle/src/libGLESv2/Framebuffer.h | 98 + .../angle/src/libGLESv2/HandleAllocator.cpp | 63 + src/3rdparty/angle/src/libGLESv2/HandleAllocator.h | 45 + .../angle/src/libGLESv2/IndexDataManager.cpp | 473 ++ .../angle/src/libGLESv2/IndexDataManager.h | 149 + src/3rdparty/angle/src/libGLESv2/Program.cpp | 528 ++ src/3rdparty/angle/src/libGLESv2/Program.h | 121 + src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp | 2794 ++++++++ src/3rdparty/angle/src/libGLESv2/ProgramBinary.h | 235 + src/3rdparty/angle/src/libGLESv2/Query.cpp | 128 + src/3rdparty/angle/src/libGLESv2/Query.h | 48 + src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp | 577 ++ src/3rdparty/angle/src/libGLESv2/Renderbuffer.h | 257 + .../angle/src/libGLESv2/ResourceManager.cpp | 320 + src/3rdparty/angle/src/libGLESv2/ResourceManager.h | 116 + src/3rdparty/angle/src/libGLESv2/Shader.cpp | 584 ++ src/3rdparty/angle/src/libGLESv2/Shader.h | 166 + src/3rdparty/angle/src/libGLESv2/Texture.cpp | 3118 +++++++++ src/3rdparty/angle/src/libGLESv2/Texture.h | 433 ++ src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp | 100 + .../angle/src/libGLESv2/VertexDataManager.cpp | 783 +++ .../angle/src/libGLESv2/VertexDataManager.h | 169 + src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp | 7002 ++++++++++++++++++++ src/3rdparty/angle/src/libGLESv2/libGLESv2.def | 182 + src/3rdparty/angle/src/libGLESv2/libGLESv2.rc | 102 + src/3rdparty/angle/src/libGLESv2/main.cpp | 176 + src/3rdparty/angle/src/libGLESv2/main.h | 50 + src/3rdparty/angle/src/libGLESv2/mathutil.h | 145 + src/3rdparty/angle/src/libGLESv2/resource.h | 14 + src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps | 39 + src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs | 43 + src/3rdparty/angle/src/libGLESv2/utilities.cpp | 1218 ++++ src/3rdparty/angle/src/libGLESv2/utilities.h | 121 + .../angle/src/libGLESv2/vertexconversion.h | 208 + src/angle/README.qt | 29 + src/angle/angle.pro | 19 + .../patches/0003-Fix-Float16ToFloat32.py.patch | 54 + src/angle/src/common/common.pri | 53 + src/angle/src/compiler/compiler.pro | 3 + .../src/compiler/preprocessor/preprocessor.pro | 58 + src/angle/src/compiler/translator_common.pro | 137 + src/angle/src/compiler/translator_hlsl.pro | 25 + src/angle/src/config.pri | 103 + src/angle/src/libEGL/libEGL.pro | 31 + src/angle/src/libGLESv2/libGLESv2.pro | 107 + src/angle/src/src.pro | 3 + .../platforms/windows/qwindowseglcontext.cpp | 2 +- src/src.pro | 7 + 237 files changed, 67172 insertions(+), 1 deletion(-) create mode 100644 src/3rdparty/angle/.gitignore create mode 100644 src/3rdparty/angle/AUTHORS create mode 100644 src/3rdparty/angle/CONTRIBUTORS create mode 100644 src/3rdparty/angle/LICENSE create mode 100644 src/3rdparty/angle/LICENSE.preprocessor create mode 100644 src/3rdparty/angle/include/EGL/egl.h create mode 100644 src/3rdparty/angle/include/EGL/eglext.h create mode 100644 src/3rdparty/angle/include/EGL/eglplatform.h create mode 100644 src/3rdparty/angle/include/GLES2/gl2.h create mode 100644 src/3rdparty/angle/include/GLES2/gl2ext.h create mode 100644 src/3rdparty/angle/include/GLES2/gl2platform.h create mode 100644 src/3rdparty/angle/include/GLSLANG/ShaderLang.h create mode 100644 src/3rdparty/angle/include/KHR/khrplatform.h create mode 100644 src/3rdparty/angle/src/common/RefCountObject.cpp create mode 100644 src/3rdparty/angle/src/common/RefCountObject.h create mode 100644 src/3rdparty/angle/src/common/angleutils.h create mode 100644 src/3rdparty/angle/src/common/debug.cpp create mode 100644 src/3rdparty/angle/src/common/debug.h create mode 100644 src/3rdparty/angle/src/common/version.h create mode 100644 src/3rdparty/angle/src/compiler/BaseTypes.h create mode 100644 src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp create mode 100644 src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h create mode 100644 src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/Common.h create mode 100644 src/3rdparty/angle/src/compiler/Compiler.cpp create mode 100644 src/3rdparty/angle/src/compiler/ConstantUnion.h create mode 100644 src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp create mode 100644 src/3rdparty/angle/src/compiler/DetectDiscontinuity.h create mode 100644 src/3rdparty/angle/src/compiler/DetectRecursion.cpp create mode 100644 src/3rdparty/angle/src/compiler/DetectRecursion.h create mode 100644 src/3rdparty/angle/src/compiler/Diagnostics.cpp create mode 100644 src/3rdparty/angle/src/compiler/Diagnostics.h create mode 100644 src/3rdparty/angle/src/compiler/DirectiveHandler.cpp create mode 100644 src/3rdparty/angle/src/compiler/DirectiveHandler.h create mode 100644 src/3rdparty/angle/src/compiler/ExtensionBehavior.h create mode 100644 src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp create mode 100644 src/3rdparty/angle/src/compiler/ForLoopUnroll.h create mode 100644 src/3rdparty/angle/src/compiler/InfoSink.cpp create mode 100644 src/3rdparty/angle/src/compiler/InfoSink.h create mode 100644 src/3rdparty/angle/src/compiler/Initialize.cpp create mode 100644 src/3rdparty/angle/src/compiler/Initialize.h create mode 100644 src/3rdparty/angle/src/compiler/InitializeDll.cpp create mode 100644 src/3rdparty/angle/src/compiler/InitializeDll.h create mode 100644 src/3rdparty/angle/src/compiler/InitializeGlobals.h create mode 100644 src/3rdparty/angle/src/compiler/InitializeParseContext.cpp create mode 100644 src/3rdparty/angle/src/compiler/InitializeParseContext.h create mode 100644 src/3rdparty/angle/src/compiler/IntermTraverse.cpp create mode 100644 src/3rdparty/angle/src/compiler/Intermediate.cpp create mode 100644 src/3rdparty/angle/src/compiler/MMap.h create mode 100644 src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp create mode 100644 src/3rdparty/angle/src/compiler/MapLongVariableNames.h create mode 100644 src/3rdparty/angle/src/compiler/OutputESSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/OutputESSL.h create mode 100644 src/3rdparty/angle/src/compiler/OutputGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/OutputGLSL.h create mode 100644 src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp create mode 100644 src/3rdparty/angle/src/compiler/OutputGLSLBase.h create mode 100644 src/3rdparty/angle/src/compiler/OutputHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/OutputHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/ParseHelper.cpp create mode 100644 src/3rdparty/angle/src/compiler/ParseHelper.h create mode 100644 src/3rdparty/angle/src/compiler/PoolAlloc.cpp create mode 100644 src/3rdparty/angle/src/compiler/PoolAlloc.h create mode 100644 src/3rdparty/angle/src/compiler/Pragma.h create mode 100644 src/3rdparty/angle/src/compiler/QualifierAlive.cpp create mode 100644 src/3rdparty/angle/src/compiler/QualifierAlive.h create mode 100644 src/3rdparty/angle/src/compiler/RemoveTree.cpp create mode 100644 src/3rdparty/angle/src/compiler/RemoveTree.h create mode 100644 src/3rdparty/angle/src/compiler/RenameFunction.h create mode 100644 src/3rdparty/angle/src/compiler/SearchSymbol.cpp create mode 100644 src/3rdparty/angle/src/compiler/SearchSymbol.h create mode 100644 src/3rdparty/angle/src/compiler/ShHandle.h create mode 100644 src/3rdparty/angle/src/compiler/ShaderLang.cpp create mode 100644 src/3rdparty/angle/src/compiler/SymbolTable.cpp create mode 100644 src/3rdparty/angle/src/compiler/SymbolTable.h create mode 100644 src/3rdparty/angle/src/compiler/TranslatorESSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/TranslatorESSL.h create mode 100644 src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/TranslatorGLSL.h create mode 100644 src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/TranslatorHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/Types.h create mode 100644 src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp create mode 100644 src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h create mode 100644 src/3rdparty/angle/src/compiler/ValidateLimitations.cpp create mode 100644 src/3rdparty/angle/src/compiler/ValidateLimitations.h create mode 100644 src/3rdparty/angle/src/compiler/VariableInfo.cpp create mode 100644 src/3rdparty/angle/src/compiler/VariableInfo.h create mode 100644 src/3rdparty/angle/src/compiler/VariablePacker.cpp create mode 100644 src/3rdparty/angle/src/compiler/VariablePacker.h create mode 100644 src/3rdparty/angle/src/compiler/VersionGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/VersionGLSL.h create mode 100644 src/3rdparty/angle/src/compiler/debug.cpp create mode 100644 src/3rdparty/angle/src/compiler/debug.h create mode 100644 src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp create mode 100644 src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h create mode 100644 src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp create mode 100644 src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h create mode 100644 src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp create mode 100644 src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h create mode 100644 src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp create mode 100644 src/3rdparty/angle/src/compiler/glslang.h create mode 100644 src/3rdparty/angle/src/compiler/glslang.l create mode 100644 src/3rdparty/angle/src/compiler/glslang.y create mode 100644 src/3rdparty/angle/src/compiler/intermOut.cpp create mode 100644 src/3rdparty/angle/src/compiler/intermediate.h create mode 100644 src/3rdparty/angle/src/compiler/localintermediate.h create mode 100644 src/3rdparty/angle/src/compiler/osinclude.h create mode 100644 src/3rdparty/angle/src/compiler/ossource_nspr.cpp create mode 100644 src/3rdparty/angle/src/compiler/ossource_posix.cpp create mode 100644 src/3rdparty/angle/src/compiler/ossource_win.cpp create mode 100644 src/3rdparty/angle/src/compiler/parseConst.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/atom.c create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/atom.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/compile.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/cpp.c create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/cpp.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/length_limits.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/memory.c create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/memory.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Input.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Token.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/parser.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/preprocess.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/scanner.c create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/scanner.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/slglobals.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/symbols.c create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/symbols.h create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/tokens.c create mode 100644 src/3rdparty/angle/src/compiler/preprocessor/tokens.h create mode 100644 src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp create mode 100644 src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h create mode 100644 src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp create mode 100644 src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h create mode 100644 src/3rdparty/angle/src/compiler/util.cpp create mode 100644 src/3rdparty/angle/src/compiler/util.h create mode 100644 src/3rdparty/angle/src/libEGL/Config.cpp create mode 100644 src/3rdparty/angle/src/libEGL/Config.h create mode 100644 src/3rdparty/angle/src/libEGL/Display.cpp create mode 100644 src/3rdparty/angle/src/libEGL/Display.h create mode 100644 src/3rdparty/angle/src/libEGL/ShaderCache.h create mode 100644 src/3rdparty/angle/src/libEGL/Surface.cpp create mode 100644 src/3rdparty/angle/src/libEGL/Surface.h create mode 100644 src/3rdparty/angle/src/libEGL/libEGL.cpp create mode 100644 src/3rdparty/angle/src/libEGL/libEGL.def create mode 100644 src/3rdparty/angle/src/libEGL/libEGL.rc create mode 100644 src/3rdparty/angle/src/libEGL/main.cpp create mode 100644 src/3rdparty/angle/src/libEGL/main.h create mode 100644 src/3rdparty/angle/src/libEGL/resource.h create mode 100644 src/3rdparty/angle/src/libGLESv2/BinaryStream.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Blit.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Blit.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Buffer.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Buffer.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Context.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Context.h create mode 100644 src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Fence.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Fence.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py create mode 100644 src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Framebuffer.h create mode 100644 src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/HandleAllocator.h create mode 100644 src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/IndexDataManager.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Program.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Program.h create mode 100644 src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/ProgramBinary.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Query.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Query.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Renderbuffer.h create mode 100644 src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/ResourceManager.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Shader.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Shader.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Texture.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Texture.h create mode 100644 src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/VertexDataManager.h create mode 100644 src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/libGLESv2.def create mode 100644 src/3rdparty/angle/src/libGLESv2/libGLESv2.rc create mode 100644 src/3rdparty/angle/src/libGLESv2/main.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/main.h create mode 100644 src/3rdparty/angle/src/libGLESv2/mathutil.h create mode 100644 src/3rdparty/angle/src/libGLESv2/resource.h create mode 100644 src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps create mode 100644 src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs create mode 100644 src/3rdparty/angle/src/libGLESv2/utilities.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/utilities.h create mode 100644 src/3rdparty/angle/src/libGLESv2/vertexconversion.h create mode 100644 src/angle/README.qt create mode 100644 src/angle/angle.pro create mode 100644 src/angle/patches/0003-Fix-Float16ToFloat32.py.patch create mode 100644 src/angle/src/common/common.pri create mode 100644 src/angle/src/compiler/compiler.pro create mode 100644 src/angle/src/compiler/preprocessor/preprocessor.pro create mode 100644 src/angle/src/compiler/translator_common.pro create mode 100644 src/angle/src/compiler/translator_hlsl.pro create mode 100644 src/angle/src/config.pri create mode 100644 src/angle/src/libEGL/libEGL.pro create mode 100644 src/angle/src/libGLESv2/libGLESv2.pro create mode 100644 src/angle/src/src.pro (limited to 'src') diff --git a/src/3rdparty/angle/.gitignore b/src/3rdparty/angle/.gitignore new file mode 100644 index 0000000000..cfa07de1ee --- /dev/null +++ b/src/3rdparty/angle/.gitignore @@ -0,0 +1,35 @@ +# This file is used to ignore files which are generated when building ANGLE +# ---------------------------------------------------------------------------- + +# Directories from ANGLE we don't want/need +build +extensions +samples +tests +third_party +src/ipch +.svn + +# Files from ANGLE we don't want/need +DEPS +*.gyp +*.gypi +*.sh +*.bat +codereview.settings + +# Generated by flex/bison +src/compiler/preprocessor/new/Tokenizer.cpp +src/compiler/preprocessor/new/ExpressionParser.cpp +src/compiler/glslang_lex.cpp +src/compiler/glslang_tab.cpp +src/compiler/glslang_tab.h + +# Generated by FXC +src/libGLESv2/shaders/standardvs.h +src/libGLESv2/shaders/flipyvs.h +src/libGLESv2/shaders/luminanceps.h +src/libGLESv2/shaders/componentmaskps.h +src/libGLESv2/shaders/passthroughps.h + + diff --git a/src/3rdparty/angle/AUTHORS b/src/3rdparty/angle/AUTHORS new file mode 100644 index 0000000000..0294632691 --- /dev/null +++ b/src/3rdparty/angle/AUTHORS @@ -0,0 +1,30 @@ +# This is the official list of The ANGLE Project Authors +# for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# Email addresses for individuals are tracked elsewhere to avoid spam. + +Google Inc. +TransGaming Inc. +3DLabs Inc. Ltd. + +Adobe Systems Inc. +Autodesk, Inc. +Cloud Party, Inc. +Intel Corporation +Mozilla Corporation +Turbulenz + +Jacek Caban +Mark Callow +Ginn Chen +James Hauxwell +Sam Hocevar +Pierre Leveille +Boying Lu +Aitor Moreno +Yuri O'Donnell +Josh Soref diff --git a/src/3rdparty/angle/CONTRIBUTORS b/src/3rdparty/angle/CONTRIBUTORS new file mode 100644 index 0000000000..29f9ad3faf --- /dev/null +++ b/src/3rdparty/angle/CONTRIBUTORS @@ -0,0 +1,70 @@ +# This is the official list of people who can contribute +# (and who have contributed) code to the ANGLE project +# repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# + +TransGaming Inc. + Nicolas Capens + Daniel Koch + Andrew Lewycky + Gavriel State + Shannon Woods + +Google Inc. + Brent Austin + Michael Bai + John Bauman + Peter Beverloo + Steve Block + Rachel Blum + Eric Boren + Henry Bridge + Nat Duca + Peter Kasting + Vangelis Kokkevis + Zhenyao Mo + Daniel Nicoara + Alastair Patrick + Alok Priyadarshi + Kenneth Russell + Brian Salomon + Gregg Tavares + Jeff Timanus + Ben Vanik + Adrienne Walker + thestig@chromium.org + +Adobe Systems Inc. + Alexandru Chiculita + Steve Minns + Max Vujovic + +Autodesk, Inc. + Ranger Harke + +Cloud Party, Inc. + Conor Dickinson + +Intel Corporation + Jin Yang + Andy Chen + Josh Triplett + +Mozilla Corp. + Ehsan Akhgari + Jeff Gilbert + Mike Hommey + Benoit Jacob + Makoto Kato + Vladimir Vukicevic + +Turbulenz + Michael Braithwaite + +Ulrik Persson (ddefrostt) +Mark Banner (standard8mbp) +David Kilzer + diff --git a/src/3rdparty/angle/LICENSE b/src/3rdparty/angle/LICENSE new file mode 100644 index 0000000000..0513b7d0f9 --- /dev/null +++ b/src/3rdparty/angle/LICENSE @@ -0,0 +1,32 @@ +// Copyright (C) 2002-2010 The ANGLE Project Authors. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc. +// Ltd., nor the names of their contributors may be used to endorse +// or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. diff --git a/src/3rdparty/angle/LICENSE.preprocessor b/src/3rdparty/angle/LICENSE.preprocessor new file mode 100644 index 0000000000..0ec2123b61 --- /dev/null +++ b/src/3rdparty/angle/LICENSE.preprocessor @@ -0,0 +1,45 @@ +Files in src/compiler/preprocessor are provided under the following license: + +**************************************************************************** +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**************************************************************************** diff --git a/src/3rdparty/angle/include/EGL/egl.h b/src/3rdparty/angle/include/EGL/egl.h new file mode 100644 index 0000000000..99ea342a47 --- /dev/null +++ b/src/3rdparty/angle/include/EGL/egl.h @@ -0,0 +1,329 @@ +/* -*- mode: c; tab-width: 8; -*- */ +/* vi: set sw=4 ts=8: */ +/* Reference version of egl.h for EGL 1.4. + * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $ + */ + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#ifndef __egl_h_ +#define __egl_h_ + +/* All platform-dependent types and macro boilerplate (such as EGLAPI + * and EGLAPIENTRY) should go in eglplatform.h. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* EGL Types */ +/* EGLint is defined in eglplatform.h */ +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDisplay; +typedef void *EGLSurface; +typedef void *EGLClientBuffer; + +/* EGL Versioning */ +#define EGL_VERSION_1_0 1 +#define EGL_VERSION_1_1 1 +#define EGL_VERSION_1_2 1 +#define EGL_VERSION_1_3 1 +#define EGL_VERSION_1_4 1 + +/* EGL Enumerants. Bitmasks and other exceptional cases aside, most + * enums are assigned unique values starting at 0x3000. + */ + +/* EGL aliases */ +#define EGL_FALSE 0 +#define EGL_TRUE 1 + +/* Out-of-band handle values */ +#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) + +/* Out-of-band attribute value */ +#define EGL_DONT_CARE ((EGLint)-1) + +/* Errors / GetError return values */ +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */ + +/* Reserved 0x300F-0x301F for additional errors */ + +/* Config attributes */ +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_NONE 0x3038 /* Attrib list terminator */ +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */ +#define EGL_CONFORMANT 0x3042 + +/* Reserved 0x3041-0x304F for additional config attributes */ + +/* Config attribute values */ +#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */ +#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */ +#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */ +#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */ +#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */ + +/* More config attribute values, for EGL_TEXTURE_FORMAT */ +#define EGL_NO_TEXTURE 0x305C +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_2D 0x305F + +/* Config attribute mask bits */ +#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */ + +#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */ + +/* QueryString targets */ +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_EXTENSIONS 0x3055 +#define EGL_CLIENT_APIS 0x308D + +/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */ +#define EGL_HEIGHT 0x3056 +#define EGL_WIDTH 0x3057 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_VG_COLORSPACE 0x3087 +#define EGL_VG_ALPHA_FORMAT 0x3088 +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_SWAP_BEHAVIOR 0x3093 +#define EGL_MULTISAMPLE_RESOLVE 0x3099 + +/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */ +#define EGL_BACK_BUFFER 0x3084 +#define EGL_SINGLE_BUFFER 0x3085 + +/* OpenVG color spaces */ +#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */ +#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */ + +/* OpenVG alpha formats */ +#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */ +#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */ + +/* Constant scale factor by which fractional display resolutions & + * aspect ratio are scaled when queried as integer values. + */ +#define EGL_DISPLAY_SCALING 10000 + +/* Unknown display resolution/aspect ratio */ +#define EGL_UNKNOWN ((EGLint)-1) + +/* Back buffer swap behaviors */ +#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */ +#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */ + +/* CreatePbufferFromClientBuffer buffer types */ +#define EGL_OPENVG_IMAGE 0x3096 + +/* QueryContext targets */ +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 + +/* CreateContext attributes */ +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 + +/* Multisample resolution behaviors */ +#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */ +#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */ + +/* BindAPI/QueryAPI targets */ +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENVG_API 0x30A1 +#define EGL_OPENGL_API 0x30A2 + +/* GetCurrentSurface targets */ +#define EGL_DRAW 0x3059 +#define EGL_READ 0x305A + +/* WaitNative engines */ +#define EGL_CORE_NATIVE_ENGINE 0x305B + +/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */ +#define EGL_COLORSPACE EGL_VG_COLORSPACE +#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT +#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB +#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR +#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE +#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE + +/* EGL extensions must request enum blocks from the Khronos + * API Registrar, who maintains the enumerant registry. Submit + * a bug in Khronos Bugzilla against task "Registry". + */ + + + +/* EGL Functions */ + +EGLAPI EGLint EGLAPIENTRY eglGetError(void); + +EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id); +EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); + +EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); + +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, + EGLint config_size, EGLint *num_config); +EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + +EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); +EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface); +EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value); + +EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api); +EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void); + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void); + +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void); + +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list); + +EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint value); +EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); + + +EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval); + + +EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); +EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + +EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); +EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); +EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value); + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void); +EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine); +EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); +EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target); + +/* This is a generic function pointer type, whose name indicates it must + * be cast to the proper type *and calling convention* before use. + */ +typedef void (*__eglMustCastToProperFunctionPointerType)(void); + +/* Now, define eglGetProcAddress using the generic function ptr. type */ +EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY + eglGetProcAddress(const char *procname); + +#ifdef __cplusplus +} +#endif + +#endif /* __egl_h_ */ diff --git a/src/3rdparty/angle/include/EGL/eglext.h b/src/3rdparty/angle/include/EGL/eglext.h new file mode 100644 index 0000000000..b670840d12 --- /dev/null +++ b/src/3rdparty/angle/include/EGL/eglext.h @@ -0,0 +1,348 @@ +#ifndef __eglext_h_ +#define __eglext_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2007-2012 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#include + +/*************************************************************/ + +/* Header file version number */ +/* Current version at http://www.khronos.org/registry/egl/ */ +/* $Revision: 16473 $ on $Date: 2012-01-04 02:20:48 -0800 (Wed, 04 Jan 2012) $ */ +#define EGL_EGLEXT_VERSION 11 + +#ifndef EGL_KHR_config_attribs +#define EGL_KHR_config_attribs 1 +#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */ +#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */ +#endif + +#ifndef EGL_KHR_lock_surface +#define EGL_KHR_lock_surface 1 +#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */ +#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */ +#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */ +#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */ +#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */ +#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */ +#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */ +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface); +#endif + +#ifndef EGL_KHR_image +#define EGL_KHR_image 1 +#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */ +typedef void *EGLImageKHR; +#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); +#endif + +#ifndef EGL_KHR_vg_parent_image +#define EGL_KHR_vg_parent_image 1 +#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_2D_image +#define EGL_KHR_gl_texture_2D_image 1 +#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_texture_cubemap_image +#define EGL_KHR_gl_texture_cubemap_image 1 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_3D_image +#define EGL_KHR_gl_texture_3D_image 1 +#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_renderbuffer_image +#define EGL_KHR_gl_renderbuffer_image 1 +#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */ +#endif + +#if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */ +#ifndef EGL_KHR_reusable_sync +#define EGL_KHR_reusable_sync 1 + +typedef void* EGLSyncKHR; +typedef khronos_utime_nanoseconds_t EGLTimeKHR; + +#define EGL_SYNC_STATUS_KHR 0x30F1 +#define EGL_SIGNALED_KHR 0x30F2 +#define EGL_UNSIGNALED_KHR 0x30F3 +#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5 +#define EGL_CONDITION_SATISFIED_KHR 0x30F6 +#define EGL_SYNC_TYPE_KHR 0x30F7 +#define EGL_SYNC_REUSABLE_KHR 0x30FA +#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR bitfield */ +#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull +#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); +EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); +EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync); +typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); +#endif +#endif + +#ifndef EGL_KHR_image_base +#define EGL_KHR_image_base 1 +/* Most interfaces defined by EGL_KHR_image_pixmap above */ +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_image_pixmap +#define EGL_KHR_image_pixmap 1 +/* Interfaces defined by EGL_KHR_image above */ +#endif + +#ifndef EGL_IMG_context_priority +#define EGL_IMG_context_priority 1 +#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100 +#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101 +#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102 +#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103 +#endif + +#ifndef EGL_KHR_lock_surface2 +#define EGL_KHR_lock_surface2 1 +#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 +#endif + +#ifndef EGL_NV_coverage_sample +#define EGL_NV_coverage_sample 1 +#define EGL_COVERAGE_BUFFERS_NV 0x30E0 +#define EGL_COVERAGE_SAMPLES_NV 0x30E1 +#endif + +#ifndef EGL_NV_depth_nonlinear +#define EGL_NV_depth_nonlinear 1 +#define EGL_DEPTH_ENCODING_NV 0x30E2 +#define EGL_DEPTH_ENCODING_NONE_NV 0 +#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3 +#endif + +#if KHRONOS_SUPPORT_INT64 /* EGLTimeNV requires 64-bit uint support */ +#ifndef EGL_NV_sync +#define EGL_NV_sync 1 +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6 +#define EGL_SYNC_STATUS_NV 0x30E7 +#define EGL_SIGNALED_NV 0x30E8 +#define EGL_UNSIGNALED_NV 0x30E9 +#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001 +#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull +#define EGL_ALREADY_SIGNALED_NV 0x30EA +#define EGL_TIMEOUT_EXPIRED_NV 0x30EB +#define EGL_CONDITION_SATISFIED_NV 0x30EC +#define EGL_SYNC_TYPE_NV 0x30ED +#define EGL_SYNC_CONDITION_NV 0x30EE +#define EGL_SYNC_FENCE_NV 0x30EF +#define EGL_NO_SYNC_NV ((EGLSyncNV)0) +typedef void* EGLSyncNV; +typedef khronos_utime_nanoseconds_t EGLTimeNV; +#ifdef EGL_EGLEXT_PROTOTYPES +EGLSyncNV eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); +EGLBoolean eglDestroySyncNV (EGLSyncNV sync); +EGLBoolean eglFenceNV (EGLSyncNV sync); +EGLint eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); +EGLBoolean eglSignalSyncNV (EGLSyncNV sync, EGLenum mode); +EGLBoolean eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync); +typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value); +#endif +#endif + +#if KHRONOS_SUPPORT_INT64 /* Dependent on EGL_KHR_reusable_sync which requires 64-bit uint support */ +#ifndef EGL_KHR_fence_sync +#define EGL_KHR_fence_sync 1 +/* Reuses most tokens and entry points from EGL_KHR_reusable_sync */ +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0 +#define EGL_SYNC_CONDITION_KHR 0x30F8 +#define EGL_SYNC_FENCE_KHR 0x30F9 +#endif +#endif + +#ifndef EGL_HI_clientpixmap +#define EGL_HI_clientpixmap 1 + +/* Surface Attribute */ +#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74 +/* + * Structure representing a client pixmap + * (pixmap's data is in client-space memory). + */ +struct EGLClientPixmapHI +{ + void* pData; + EGLint iWidth; + EGLint iHeight; + EGLint iStride; +}; + +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI(EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap); +#endif /* EGL_HI_clientpixmap */ + +#ifndef EGL_HI_colorformats +#define EGL_HI_colorformats 1 +/* Config Attribute */ +#define EGL_COLOR_FORMAT_HI 0x8F70 +/* Color Formats */ +#define EGL_COLOR_RGB_HI 0x8F71 +#define EGL_COLOR_RGBA_HI 0x8F72 +#define EGL_COLOR_ARGB_HI 0x8F73 +#endif /* EGL_HI_colorformats */ + +#ifndef EGL_MESA_drm_image +#define EGL_MESA_drm_image 1 +#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 /* CreateDRMImageMESA attribute */ +#define EGL_DRM_BUFFER_USE_MESA 0x31D1 /* CreateDRMImageMESA attribute */ +#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2 /* EGL_IMAGE_FORMAT_MESA attribute value */ +#define EGL_DRM_BUFFER_MESA 0x31D3 /* eglCreateImageKHR target */ +#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4 +#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001 /* EGL_DRM_BUFFER_USE_MESA bits */ +#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002 /* EGL_DRM_BUFFER_USE_MESA bits */ +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride); +#endif + +#ifndef EGL_NV_post_sub_buffer +#define EGL_NV_post_sub_buffer 1 +#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); +#endif + +#ifndef EGL_ANGLE_query_surface_pointer +#define EGL_ANGLE_query_surface_pointer 1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); +#endif +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); +#endif + +#ifndef EGL_ANGLE_software_display +#define EGL_ANGLE_software_display 1 +#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1) +#endif + +#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle +#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1 +#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 +#endif + +#ifndef EGL_NV_coverage_sample_resolve +#define EGL_NV_coverage_sample_resolve 1 +#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131 +#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132 +#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133 +#endif + +#if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */ +#ifndef EGL_NV_system_time +#define EGL_NV_system_time 1 + +typedef khronos_utime_nanoseconds_t EGLuint64NV; + +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void); +EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV(void); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void); +typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void); +#endif +#endif + +#ifndef EGL_EXT_create_context_robustness +#define EGL_EXT_create_context_robustness 1 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/3rdparty/angle/include/EGL/eglplatform.h b/src/3rdparty/angle/include/EGL/eglplatform.h new file mode 100644 index 0000000000..34283f2e90 --- /dev/null +++ b/src/3rdparty/angle/include/EGL/eglplatform.h @@ -0,0 +1,129 @@ +#ifndef __eglplatform_h_ +#define __eglplatform_h_ + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Platform-specific types and definitions for egl.h + * $Revision: 12306 $ on $Date: 2010-08-25 09:51:28 -0700 (Wed, 25 Aug 2010) $ + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * You are encouraged to submit all modifications to the Khronos group so that + * they can be included in future versions of this file. Please submit changes + * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) + * by filing a bug against product "EGL" component "Registry". + */ + +#include + +/* Macros used in EGL function prototype declarations. + * + * EGL functions should be prototyped as: + * + * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); + * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); + * + * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h + */ + +#ifndef EGLAPI +#define EGLAPI KHRONOS_APICALL +#endif + +#ifndef EGLAPIENTRY +#define EGLAPIENTRY KHRONOS_APIENTRY +#endif +#define EGLAPIENTRYP EGLAPIENTRY* + +/* The types NativeDisplayType, NativeWindowType, and NativePixmapType + * are aliases of window-system-dependent types, such as X Display * or + * Windows Device Context. They must be defined in platform-specific + * code below. The EGL-prefixed versions of Native*Type are the same + * types, renamed in EGL 1.3 so all types in the API start with "EGL". + * + * Khronos STRONGLY RECOMMENDS that you use the default definitions + * provided below, since these changes affect both binary and source + * portability of applications using EGL running on different EGL + * implementations. + */ + +#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include + +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; + +#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ + +typedef int EGLNativeDisplayType; +typedef void *EGLNativeWindowType; +typedef void *EGLNativePixmapType; + +#elif defined(WL_EGL_PLATFORM) + +typedef struct wl_display *EGLNativeDisplayType; +typedef struct wl_egl_pixmap *EGLNativePixmapType; +typedef struct wl_egl_window *EGLNativeWindowType; + +#elif defined(__unix__) && !defined(ANDROID) + +/* X11 (tentative) */ +#include +#include + +typedef Display *EGLNativeDisplayType; +typedef Pixmap EGLNativePixmapType; +typedef Window EGLNativeWindowType; + +#elif defined(ANDROID) + +struct egl_native_pixmap_t; + +typedef struct ANativeWindow* EGLNativeWindowType; +typedef struct egl_native_pixmap_t* EGLNativePixmapType; +typedef void* EGLNativeDisplayType; + +#else +#error "Platform not recognized" +#endif + +/* EGL 1.2 types, renamed for consistency in EGL 1.3 */ +typedef EGLNativeDisplayType NativeDisplayType; +typedef EGLNativePixmapType NativePixmapType; +typedef EGLNativeWindowType NativeWindowType; + + +/* Define EGLint. This must be a signed integral type large enough to contain + * all legal attribute names and values passed into and out of EGL, whether + * their type is boolean, bitmask, enumerant (symbolic constant), integer, + * handle, or other. While in general a 32-bit integer will suffice, if + * handles are 64 bit types, then EGLint should be defined as a signed 64-bit + * integer type. + */ +typedef khronos_int32_t EGLint; + +#endif /* __eglplatform_h */ diff --git a/src/3rdparty/angle/include/GLES2/gl2.h b/src/3rdparty/angle/include/GLES2/gl2.h new file mode 100644 index 0000000000..e1d3b87cc5 --- /dev/null +++ b/src/3rdparty/angle/include/GLES2/gl2.h @@ -0,0 +1,621 @@ +#ifndef __gl2_h_ +#define __gl2_h_ + +/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This document is licensed under the SGI Free Software B License Version + * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . + */ + +/*------------------------------------------------------------------------- + * Data type definitions + *-----------------------------------------------------------------------*/ + +typedef void GLvoid; +typedef char GLchar; +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef khronos_int8_t GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLsizei; +typedef khronos_uint8_t GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef khronos_int32_t GLfixed; + +/* GL types for handling large vertex buffer objects */ +typedef khronos_intptr_t GLintptr; +typedef khronos_ssize_t GLsizeiptr; + +/* OpenGL ES core versions */ +#define GL_ES_VERSION_2_0 1 + +/* ClearBufferMask */ +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 + +/* Boolean */ +#define GL_FALSE 0 +#define GL_TRUE 1 + +/* BeginMode */ +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 + +/* AlphaFunction (not supported in ES20) */ +/* GL_NEVER */ +/* GL_LESS */ +/* GL_EQUAL */ +/* GL_LEQUAL */ +/* GL_GREATER */ +/* GL_NOTEQUAL */ +/* GL_GEQUAL */ +/* GL_ALWAYS */ + +/* BlendingFactorDest */ +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 + +/* BlendingFactorSrc */ +/* GL_ZERO */ +/* GL_ONE */ +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +/* GL_SRC_ALPHA */ +/* GL_ONE_MINUS_SRC_ALPHA */ +/* GL_DST_ALPHA */ +/* GL_ONE_MINUS_DST_ALPHA */ + +/* BlendEquationSeparate */ +#define GL_FUNC_ADD 0x8006 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */ +#define GL_BLEND_EQUATION_ALPHA 0x883D + +/* BlendSubtract */ +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B + +/* Separate Blend Functions */ +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 + +/* Buffer Objects */ +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 + +#define GL_STREAM_DRAW 0x88E0 +#define GL_STATIC_DRAW 0x88E4 +#define GL_DYNAMIC_DRAW 0x88E8 + +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 + +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 + +/* CullFaceMode */ +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_FRONT_AND_BACK 0x0408 + +/* DepthFunction */ +/* GL_NEVER */ +/* GL_LESS */ +/* GL_EQUAL */ +/* GL_LEQUAL */ +/* GL_GREATER */ +/* GL_NOTEQUAL */ +/* GL_GEQUAL */ +/* GL_ALWAYS */ + +/* EnableCap */ +#define GL_TEXTURE_2D 0x0DE1 +#define GL_CULL_FACE 0x0B44 +#define GL_BLEND 0x0BE2 +#define GL_DITHER 0x0BD0 +#define GL_STENCIL_TEST 0x0B90 +#define GL_DEPTH_TEST 0x0B71 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_COVERAGE 0x80A0 + +/* ErrorCode */ +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 + +/* FrontFaceDirection */ +#define GL_CW 0x0900 +#define GL_CCW 0x0901 + +/* GetPName */ +#define GL_LINE_WIDTH 0x0B21 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VIEWPORT 0x0BA2 +#define GL_SCISSOR_BOX 0x0C10 +/* GL_SCISSOR_TEST */ +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +/* GL_POLYGON_OFFSET_FILL */ +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB + +/* GetTextureParameter */ +/* GL_TEXTURE_MAG_FILTER */ +/* GL_TEXTURE_MIN_FILTER */ +/* GL_TEXTURE_WRAP_S */ +/* GL_TEXTURE_WRAP_T */ + +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 + +/* HintMode */ +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 + +/* HintTarget */ +#define GL_GENERATE_MIPMAP_HINT 0x8192 + +/* DataType */ +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_FIXED 0x140C + +/* PixelFormat */ +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A + +/* PixelType */ +/* GL_UNSIGNED_BYTE */ +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 + +/* Shaders */ +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_SHADER_TYPE 0x8B4F +#define GL_DELETE_STATUS 0x8B80 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D + +/* StencilFunction */ +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 + +/* StencilOp */ +/* GL_ZERO */ +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_INVERT 0x150A +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 + +/* StringName */ +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 + +/* TextureMagFilter */ +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 + +/* TextureMinFilter */ +/* GL_NEAREST */ +/* GL_LINEAR */ +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 + +/* TextureParameterName */ +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 + +/* TextureTarget */ +/* GL_TEXTURE_2D */ +#define GL_TEXTURE 0x1702 + +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C + +/* TextureUnit */ +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 + +/* TextureWrapMode */ +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_MIRRORED_REPEAT 0x8370 + +/* Uniform Types */ +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 + +/* Vertex Arrays */ +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F + +/* Read Format */ +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B + +/* Shader Source */ +#define GL_COMPILE_STATUS 0x8B81 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_COMPILER 0x8DFA + +/* Shader Binary */ +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 + +/* Shader Precision-Specified Types */ +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 + +/* Framebuffer Object. */ +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 + +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGB565 0x8D62 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_STENCIL_INDEX 0x1901 +#define GL_STENCIL_INDEX8 0x8D48 + +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 + +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 + +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 + +#define GL_NONE 0 + +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD + +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 + +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 + +/*------------------------------------------------------------------------- + * GL core functions. + *-----------------------------------------------------------------------*/ + +GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); +GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); +GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name); +GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); +GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode ); +GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); +GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); +GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); +GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); +GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); +GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth); +GL_APICALL void GL_APIENTRY glClearStencil (GLint s); +GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); +GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); +GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); +GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); +GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); +GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers); +GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers); +GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); +GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers); +GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); +GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures); +GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); +GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); +GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar); +GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); +GL_APICALL void GL_APIENTRY glDisable (GLenum cap); +GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); +GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); +GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); +GL_APICALL void GL_APIENTRY glEnable (GLenum cap); +GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); +GL_APICALL void GL_APIENTRY glFinish (void); +GL_APICALL void GL_APIENTRY glFlush (void); +GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); +GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers); +GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); +GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers); +GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers); +GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures); +GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); +GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name); +GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params); +GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params); +GL_APICALL GLenum GL_APIENTRY glGetError (void); +GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog); +GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog); +GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); +GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); +GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name); +GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params); +GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name); +GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer); +GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); +GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); +GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); +GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); +GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); +GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); +GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); +GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); +GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); +GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); +GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); +GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); +GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); +GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length); +GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length); +GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); +GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); +GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); +GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); +GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params); +GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params); +GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); +GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x); +GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x); +GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y); +GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y); +GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z); +GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z); +GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w); +GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); +GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); +GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x); +GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y); +GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z); +GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr); +GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); + +#ifdef __cplusplus +} +#endif + +#endif /* __gl2_h_ */ diff --git a/src/3rdparty/angle/include/GLES2/gl2ext.h b/src/3rdparty/angle/include/GLES2/gl2ext.h new file mode 100644 index 0000000000..e297fbfe87 --- /dev/null +++ b/src/3rdparty/angle/include/GLES2/gl2ext.h @@ -0,0 +1,1504 @@ +#ifndef __gl2ext_h_ +#define __gl2ext_h_ + +/* $Revision: 16482 $ on $Date:: 2012-01-04 13:44:55 -0500 #$ */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This document is licensed under the SGI Free Software B License Version + * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . + */ + +#ifndef GL_APIENTRYP +# define GL_APIENTRYP GL_APIENTRY* +#endif + +/*------------------------------------------------------------------------* + * OES extension tokens + *------------------------------------------------------------------------*/ + +/* GL_OES_compressed_ETC1_RGB8_texture */ +#ifndef GL_OES_compressed_ETC1_RGB8_texture +#define GL_ETC1_RGB8_OES 0x8D64 +#endif + +/* GL_OES_compressed_paletted_texture */ +#ifndef GL_OES_compressed_paletted_texture +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#endif + +/* GL_OES_depth24 */ +#ifndef GL_OES_depth24 +#define GL_DEPTH_COMPONENT24_OES 0x81A6 +#endif + +/* GL_OES_depth32 */ +#ifndef GL_OES_depth32 +#define GL_DEPTH_COMPONENT32_OES 0x81A7 +#endif + +/* GL_OES_depth_texture */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_EGL_image */ +#ifndef GL_OES_EGL_image +typedef void* GLeglImageOES; +#endif + +/* GL_OES_EGL_image_external */ +#ifndef GL_OES_EGL_image_external +/* GLeglImageOES defined in GL_OES_EGL_image already. */ +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#define GL_SAMPLER_EXTERNAL_OES 0x8D66 +#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 +#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 +#endif + +/* GL_OES_element_index_uint */ +#ifndef GL_OES_element_index_uint +#define GL_UNSIGNED_INT 0x1405 +#endif + +/* GL_OES_get_program_binary */ +#ifndef GL_OES_get_program_binary +#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE +#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF +#endif + +/* GL_OES_mapbuffer */ +#ifndef GL_OES_mapbuffer +#define GL_WRITE_ONLY_OES 0x88B9 +#define GL_BUFFER_ACCESS_OES 0x88BB +#define GL_BUFFER_MAPPED_OES 0x88BC +#define GL_BUFFER_MAP_POINTER_OES 0x88BD +#endif + +/* GL_OES_packed_depth_stencil */ +#ifndef GL_OES_packed_depth_stencil +#define GL_DEPTH_STENCIL_OES 0x84F9 +#define GL_UNSIGNED_INT_24_8_OES 0x84FA +#define GL_DEPTH24_STENCIL8_OES 0x88F0 +#endif + +/* GL_OES_rgb8_rgba8 */ +#ifndef GL_OES_rgb8_rgba8 +#define GL_RGB8_OES 0x8051 +#define GL_RGBA8_OES 0x8058 +#endif + +/* GL_OES_standard_derivatives */ +#ifndef GL_OES_standard_derivatives +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B +#endif + +/* GL_OES_stencil1 */ +#ifndef GL_OES_stencil1 +#define GL_STENCIL_INDEX1_OES 0x8D46 +#endif + +/* GL_OES_stencil4 */ +#ifndef GL_OES_stencil4 +#define GL_STENCIL_INDEX4_OES 0x8D47 +#endif + +/* GL_OES_texture_3D */ +#ifndef GL_OES_texture_3D +#define GL_TEXTURE_WRAP_R_OES 0x8072 +#define GL_TEXTURE_3D_OES 0x806F +#define GL_TEXTURE_BINDING_3D_OES 0x806A +#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 +#define GL_SAMPLER_3D_OES 0x8B5F +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 +#endif + +/* GL_OES_texture_float */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_texture_float_linear */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_texture_half_float */ +#ifndef GL_OES_texture_half_float +#define GL_HALF_FLOAT_OES 0x8D61 +#endif + +/* GL_OES_texture_half_float_linear */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_texture_npot */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_vertex_array_object */ +#ifndef GL_OES_vertex_array_object +#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5 +#endif + +/* GL_OES_vertex_half_float */ +/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */ + +/* GL_OES_vertex_type_10_10_10_2 */ +#ifndef GL_OES_vertex_type_10_10_10_2 +#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 +#define GL_INT_10_10_10_2_OES 0x8DF7 +#endif + +/*------------------------------------------------------------------------* + * AMD extension tokens + *------------------------------------------------------------------------*/ + +/* GL_AMD_compressed_3DC_texture */ +#ifndef GL_AMD_compressed_3DC_texture +#define GL_3DC_X_AMD 0x87F9 +#define GL_3DC_XY_AMD 0x87FA +#endif + +/* GL_AMD_compressed_ATC_texture */ +#ifndef GL_AMD_compressed_ATC_texture +#define GL_ATC_RGB_AMD 0x8C92 +#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 +#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE +#endif + +/* GL_AMD_performance_monitor */ +#ifndef GL_AMD_performance_monitor +#define GL_COUNTER_TYPE_AMD 0x8BC0 +#define GL_COUNTER_RANGE_AMD 0x8BC1 +#define GL_UNSIGNED_INT64_AMD 0x8BC2 +#define GL_PERCENTAGE_AMD 0x8BC3 +#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 +#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 +#define GL_PERFMON_RESULT_AMD 0x8BC6 +#endif + +/* GL_AMD_program_binary_Z400 */ +#ifndef GL_AMD_program_binary_Z400 +#define GL_Z400_BINARY_AMD 0x8740 +#endif + +/*------------------------------------------------------------------------* + * ANGLE extension tokens + *------------------------------------------------------------------------*/ + +/* GL_ANGLE_framebuffer_blit */ +#ifndef GL_ANGLE_framebuffer_blit +#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA +#endif + +/* GL_ANGLE_framebuffer_multisample */ +#ifndef GL_ANGLE_framebuffer_multisample +#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56 +#define GL_MAX_SAMPLES_ANGLE 0x8D57 +#endif + +/* GL_ANGLE_pack_reverse_row_order */ +#ifndef GL_ANGLE_pack_reverse_row_order +#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4 +#endif + +/* GL_ANGLE_texture_compression_dxt3 */ +#ifndef GL_ANGLE_texture_compression_dxt3 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2 +#endif + +/* GL_ANGLE_texture_compression_dxt5 */ +#ifndef GL_ANGLE_texture_compression_dxt5 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 +#endif + +/* GL_ANGLE_translated_shader_source */ +#ifndef GL_ANGLE_translated_shader_source +#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 +#endif + +/* GL_ANGLE_texture_usage */ +#ifndef GL_ANGLE_texture_usage +#define GL_TEXTURE_USAGE_ANGLE 0x93A2 +#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 +#endif + +/* GL_ANGLE_instanced_arrays */ +#ifndef GL_ANGLE_instanced_arrays +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE +#endif + +/* GL_ANGLE_program_binary */ +#ifndef GL_ANGLE_program_binary +#define GL_PROGRAM_BINARY_ANGLE 0x93A6 +#endif + +/*------------------------------------------------------------------------* + * APPLE extension tokens + *------------------------------------------------------------------------*/ + +/* GL_APPLE_rgb_422 */ +#ifndef GL_APPLE_rgb_422 +#define GL_RGB_422_APPLE 0x8A1F +#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#endif + +/* GL_APPLE_framebuffer_multisample */ +#ifndef GL_APPLE_framebuffer_multisample +#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56 +#define GL_MAX_SAMPLES_APPLE 0x8D57 +#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA +#endif + +/* GL_APPLE_texture_format_BGRA8888 */ +#ifndef GL_APPLE_texture_format_BGRA8888 +#define GL_BGRA_EXT 0x80E1 +#endif + +/* GL_APPLE_texture_max_level */ +#ifndef GL_APPLE_texture_max_level +#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D +#endif + +/*------------------------------------------------------------------------* + * ARM extension tokens + *------------------------------------------------------------------------*/ + +/* GL_ARM_mali_shader_binary */ +#ifndef GL_ARM_mali_shader_binary +#define GL_MALI_SHADER_BINARY_ARM 0x8F60 +#endif + +/* GL_ARM_rgba8 */ +/* No new tokens introduced by this extension. */ + +/*------------------------------------------------------------------------* + * EXT extension tokens + *------------------------------------------------------------------------*/ + +/* GL_EXT_blend_minmax */ +#ifndef GL_EXT_blend_minmax +#define GL_MIN_EXT 0x8007 +#define GL_MAX_EXT 0x8008 +#endif + +/* GL_EXT_color_buffer_half_float */ +#ifndef GL_EXT_color_buffer_half_float +#define GL_RGBA16F_EXT 0x881A +#define GL_RGB16F_EXT 0x881B +#define GL_RG16F_EXT 0x822F +#define GL_R16F_EXT 0x822D +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211 +#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17 +#endif + +/* GL_EXT_debug_label */ +#ifndef GL_EXT_debug_label +#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define GL_PROGRAM_OBJECT_EXT 0x8B40 +#define GL_SHADER_OBJECT_EXT 0x8B48 +#define GL_BUFFER_OBJECT_EXT 0x9151 +#define GL_QUERY_OBJECT_EXT 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +#endif + +/* GL_EXT_debug_marker */ +/* No new tokens introduced by this extension. */ + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_COLOR_EXT 0x1800 +#define GL_DEPTH_EXT 0x1801 +#define GL_STENCIL_EXT 0x1802 +#endif + +/* GL_EXT_multisampled_render_to_texture */ +#ifndef GL_EXT_multisampled_render_to_texture +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C +#define GL_RENDERBUFFER_SAMPLES_EXT 0x9133 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x9134 +#define GL_MAX_SAMPLES_EXT 0x9135 +#endif + +/* GL_EXT_multi_draw_arrays */ +/* No new tokens introduced by this extension. */ + +/* GL_EXT_occlusion_query_boolean */ +#ifndef GL_EXT_occlusion_query_boolean +#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A +#define GL_CURRENT_QUERY_EXT 0x8865 +#define GL_QUERY_RESULT_EXT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 +#endif + +/* GL_EXT_read_format_bgra */ +#ifndef GL_EXT_read_format_bgra +#define GL_BGRA_EXT 0x80E1 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366 +#endif + +/* GL_EXT_robustness */ +#ifndef GL_EXT_robustness +/* reuse GL_NO_ERROR */ +#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255 +#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3 +#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252 +#define GL_NO_RESET_NOTIFICATION_EXT 0x8261 +#endif + +/* GL_EXT_separate_shader_objects */ +#ifndef GL_EXT_separate_shader_objects +#define GL_VERTEX_SHADER_BIT_EXT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002 +#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE_EXT 0x8258 +#define GL_ACTIVE_PROGRAM_EXT 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A +#endif + +/* GL_EXT_shader_texture_lod */ +/* No new tokens introduced by this extension. */ + +/* GL_EXT_shadow_samplers */ +#ifndef GL_EXT_shadow_samplers +#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C +#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D +#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E +#endif + +/* GL_EXT_sRGB */ +#ifndef GL_EXT_sRGB +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210 +#endif + +/* GL_EXT_texture_compression_dxt1 */ +#ifndef GL_EXT_texture_compression_dxt1 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#endif + +/* GL_EXT_texture_filter_anisotropic */ +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_BGRA_EXT 0x80E1 +#endif + +/* GL_EXT_texture_rg */ +#ifndef GL_EXT_texture_rg +#define GL_RED_EXT 0x1903 +#define GL_RG_EXT 0x8227 +#define GL_R8_EXT 0x8229 +#define GL_RG8_EXT 0x822B +#endif + +/* GL_EXT_texture_storage */ +#ifndef GL_EXT_texture_storage +#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F +#define GL_ALPHA8_EXT 0x803C +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_RGBA32F_EXT 0x8814 +#define GL_RGB32F_EXT 0x8815 +#define GL_ALPHA32F_EXT 0x8816 +#define GL_LUMINANCE32F_EXT 0x8818 +#define GL_LUMINANCE_ALPHA32F_EXT 0x8819 +/* reuse GL_RGBA16F_EXT */ +#define GL_RGB16F_EXT 0x881B +#define GL_ALPHA16F_EXT 0x881C +#define GL_LUMINANCE16F_EXT 0x881E +#define GL_LUMINANCE_ALPHA16F_EXT 0x881F +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGB10_EXT 0x8052 +#define GL_BGRA8_EXT 0x93A1 +#endif + +/* GL_EXT_texture_type_2_10_10_10_REV */ +#ifndef GL_EXT_texture_type_2_10_10_10_REV +#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 +#endif + +/* GL_EXT_unpack_subimage */ +#ifndef GL_EXT_unpack_subimage +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#endif + +/*------------------------------------------------------------------------* + * DMP extension tokens + *------------------------------------------------------------------------*/ + +/* GL_DMP_shader_binary */ +#ifndef GL_DMP_shader_binary +#define GL_SHADER_BINARY_DMP 0x9250 +#endif + +/*------------------------------------------------------------------------* + * IMG extension tokens + *------------------------------------------------------------------------*/ + +/* GL_IMG_program_binary */ +#ifndef GL_IMG_program_binary +#define GL_SGX_PROGRAM_BINARY_IMG 0x9130 +#endif + +/* GL_IMG_read_format */ +#ifndef GL_IMG_read_format +#define GL_BGRA_IMG 0x80E1 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365 +#endif + +/* GL_IMG_shader_binary */ +#ifndef GL_IMG_shader_binary +#define GL_SGX_BINARY_IMG 0x8C0A +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +#endif + +/* GL_IMG_multisampled_render_to_texture */ +#ifndef GL_IMG_multisampled_render_to_texture +#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134 +#define GL_MAX_SAMPLES_IMG 0x9135 +#define GL_TEXTURE_SAMPLES_IMG 0x9136 +#endif + +/*------------------------------------------------------------------------* + * NV extension tokens + *------------------------------------------------------------------------*/ + +/* GL_NV_coverage_sample */ +#ifndef GL_NV_coverage_sample +#define GL_COVERAGE_COMPONENT_NV 0x8ED0 +#define GL_COVERAGE_COMPONENT4_NV 0x8ED1 +#define GL_COVERAGE_ATTACHMENT_NV 0x8ED2 +#define GL_COVERAGE_BUFFERS_NV 0x8ED3 +#define GL_COVERAGE_SAMPLES_NV 0x8ED4 +#define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5 +#define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6 +#define GL_COVERAGE_AUTOMATIC_NV 0x8ED7 +#define GL_COVERAGE_BUFFER_BIT_NV 0x8000 +#endif + +/* GL_NV_depth_nonlinear */ +#ifndef GL_NV_depth_nonlinear +#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C +#endif + +/* GL_NV_draw_buffers */ +#ifndef GL_NV_draw_buffers +#define GL_MAX_DRAW_BUFFERS_NV 0x8824 +#define GL_DRAW_BUFFER0_NV 0x8825 +#define GL_DRAW_BUFFER1_NV 0x8826 +#define GL_DRAW_BUFFER2_NV 0x8827 +#define GL_DRAW_BUFFER3_NV 0x8828 +#define GL_DRAW_BUFFER4_NV 0x8829 +#define GL_DRAW_BUFFER5_NV 0x882A +#define GL_DRAW_BUFFER6_NV 0x882B +#define GL_DRAW_BUFFER7_NV 0x882C +#define GL_DRAW_BUFFER8_NV 0x882D +#define GL_DRAW_BUFFER9_NV 0x882E +#define GL_DRAW_BUFFER10_NV 0x882F +#define GL_DRAW_BUFFER11_NV 0x8830 +#define GL_DRAW_BUFFER12_NV 0x8831 +#define GL_DRAW_BUFFER13_NV 0x8832 +#define GL_DRAW_BUFFER14_NV 0x8833 +#define GL_DRAW_BUFFER15_NV 0x8834 +#define GL_COLOR_ATTACHMENT0_NV 0x8CE0 +#define GL_COLOR_ATTACHMENT1_NV 0x8CE1 +#define GL_COLOR_ATTACHMENT2_NV 0x8CE2 +#define GL_COLOR_ATTACHMENT3_NV 0x8CE3 +#define GL_COLOR_ATTACHMENT4_NV 0x8CE4 +#define GL_COLOR_ATTACHMENT5_NV 0x8CE5 +#define GL_COLOR_ATTACHMENT6_NV 0x8CE6 +#define GL_COLOR_ATTACHMENT7_NV 0x8CE7 +#define GL_COLOR_ATTACHMENT8_NV 0x8CE8 +#define GL_COLOR_ATTACHMENT9_NV 0x8CE9 +#define GL_COLOR_ATTACHMENT10_NV 0x8CEA +#define GL_COLOR_ATTACHMENT11_NV 0x8CEB +#define GL_COLOR_ATTACHMENT12_NV 0x8CEC +#define GL_COLOR_ATTACHMENT13_NV 0x8CED +#define GL_COLOR_ATTACHMENT14_NV 0x8CEE +#define GL_COLOR_ATTACHMENT15_NV 0x8CEF +#endif + +/* GL_NV_fbo_color_attachments */ +#ifndef GL_NV_fbo_color_attachments +#define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF +/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */ +#endif + +/* GL_NV_fence */ +#ifndef GL_NV_fence +#define GL_ALL_COMPLETED_NV 0x84F2 +#define GL_FENCE_STATUS_NV 0x84F3 +#define GL_FENCE_CONDITION_NV 0x84F4 +#endif + +/* GL_NV_read_buffer */ +#ifndef GL_NV_read_buffer +#define GL_READ_BUFFER_NV 0x0C02 +#endif + +/* GL_NV_read_buffer_front */ +/* No new tokens introduced by this extension. */ + +/* GL_NV_read_depth */ +/* No new tokens introduced by this extension. */ + +/* GL_NV_read_depth_stencil */ +/* No new tokens introduced by this extension. */ + +/* GL_NV_read_stencil */ +/* No new tokens introduced by this extension. */ + +/* GL_NV_texture_compression_s3tc_update */ +/* No new tokens introduced by this extension. */ + +/* GL_NV_texture_npot_2D_mipmap */ +/* No new tokens introduced by this extension. */ + +/*------------------------------------------------------------------------* + * QCOM extension tokens + *------------------------------------------------------------------------*/ + +/* GL_QCOM_alpha_test */ +#ifndef GL_QCOM_alpha_test +#define GL_ALPHA_TEST_QCOM 0x0BC0 +#define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1 +#define GL_ALPHA_TEST_REF_QCOM 0x0BC2 +#endif + +/* GL_QCOM_driver_control */ +/* No new tokens introduced by this extension. */ + +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_TEXTURE_WIDTH_QCOM 0x8BD2 +#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3 +#define GL_TEXTURE_DEPTH_QCOM 0x8BD4 +#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5 +#define GL_TEXTURE_FORMAT_QCOM 0x8BD6 +#define GL_TEXTURE_TYPE_QCOM 0x8BD7 +#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8 +#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9 +#define GL_TEXTURE_TARGET_QCOM 0x8BDA +#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB +#define GL_STATE_RESTORE 0x8BDC +#endif + +/* GL_QCOM_extended_get2 */ +/* No new tokens introduced by this extension. */ + +/* GL_QCOM_perfmon_global_mode */ +#ifndef GL_QCOM_perfmon_global_mode +#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0 +#endif + +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_WRITEONLY_RENDERING_QCOM 0x8823 +#endif + +/* GL_QCOM_tiled_rendering */ +#ifndef GL_QCOM_tiled_rendering +#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001 +#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002 +#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004 +#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008 +#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010 +#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020 +#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040 +#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080 +#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100 +#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200 +#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400 +#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800 +#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000 +#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000 +#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000 +#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000 +#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000 +#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000 +#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000 +#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000 +#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000 +#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000 +#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000 +#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000 +#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000 +#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000 +#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000 +#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000 +#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000 +#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000 +#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000 +#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000 +#endif + +/*------------------------------------------------------------------------* + * VIV extension tokens + *------------------------------------------------------------------------*/ + +/* GL_VIV_shader_binary */ +#ifndef GL_VIV_shader_binary +#define GL_SHADER_BINARY_VIV 0x8FC4 +#endif + +/*------------------------------------------------------------------------* + * End of extension tokens, start of corresponding extension functions + *------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------* + * OES extension functions + *------------------------------------------------------------------------*/ + +/* GL_OES_compressed_ETC1_RGB8_texture */ +#ifndef GL_OES_compressed_ETC1_RGB8_texture +#define GL_OES_compressed_ETC1_RGB8_texture 1 +#endif + +/* GL_OES_compressed_paletted_texture */ +#ifndef GL_OES_compressed_paletted_texture +#define GL_OES_compressed_paletted_texture 1 +#endif + +/* GL_OES_depth24 */ +#ifndef GL_OES_depth24 +#define GL_OES_depth24 1 +#endif + +/* GL_OES_depth32 */ +#ifndef GL_OES_depth32 +#define GL_OES_depth32 1 +#endif + +/* GL_OES_depth_texture */ +#ifndef GL_OES_depth_texture +#define GL_OES_depth_texture 1 +#endif + +/* GL_OES_EGL_image */ +#ifndef GL_OES_EGL_image +#define GL_OES_EGL_image 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); +GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image); +#endif +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); +#endif + +/* GL_OES_EGL_image_external */ +#ifndef GL_OES_EGL_image_external +#define GL_OES_EGL_image_external 1 +/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */ +#endif + +/* GL_OES_element_index_uint */ +#ifndef GL_OES_element_index_uint +#define GL_OES_element_index_uint 1 +#endif + +/* GL_OES_fbo_render_mipmap */ +#ifndef GL_OES_fbo_render_mipmap +#define GL_OES_fbo_render_mipmap 1 +#endif + +/* GL_OES_fragment_precision_high */ +#ifndef GL_OES_fragment_precision_high +#define GL_OES_fragment_precision_high 1 +#endif + +/* GL_OES_get_program_binary */ +#ifndef GL_OES_get_program_binary +#define GL_OES_get_program_binary 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length); +#endif +typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length); +#endif + +/* GL_OES_mapbuffer */ +#ifndef GL_OES_mapbuffer +#define GL_OES_mapbuffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access); +GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target); +GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params); +#endif +typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access); +typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params); +#endif + +/* GL_OES_packed_depth_stencil */ +#ifndef GL_OES_packed_depth_stencil +#define GL_OES_packed_depth_stencil 1 +#endif + +/* GL_OES_rgb8_rgba8 */ +#ifndef GL_OES_rgb8_rgba8 +#define GL_OES_rgb8_rgba8 1 +#endif + +/* GL_OES_standard_derivatives */ +#ifndef GL_OES_standard_derivatives +#define GL_OES_standard_derivatives 1 +#endif + +/* GL_OES_stencil1 */ +#ifndef GL_OES_stencil1 +#define GL_OES_stencil1 1 +#endif + +/* GL_OES_stencil4 */ +#ifndef GL_OES_stencil4 +#define GL_OES_stencil4 1 +#endif + +/* GL_OES_texture_3D */ +#ifndef GL_OES_texture_3D +#define GL_OES_texture_3D 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels); +GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); +GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +#endif +typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels); +typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +#endif + +/* GL_OES_texture_float */ +#ifndef GL_OES_texture_float +#define GL_OES_texture_float 1 +#endif + +/* GL_OES_texture_float_linear */ +#ifndef GL_OES_texture_float_linear +#define GL_OES_texture_float_linear 1 +#endif + +/* GL_OES_texture_half_float */ +#ifndef GL_OES_texture_half_float +#define GL_OES_texture_half_float 1 +#endif + +/* GL_OES_texture_half_float_linear */ +#ifndef GL_OES_texture_half_float_linear +#define GL_OES_texture_half_float_linear 1 +#endif + +/* GL_OES_texture_npot */ +#ifndef GL_OES_texture_npot +#define GL_OES_texture_npot 1 +#endif + +/* GL_OES_vertex_array_object */ +#ifndef GL_OES_vertex_array_object +#define GL_OES_vertex_array_object 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array); +GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays); +GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays); +GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array); +#endif +typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array); +typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays); +typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array); +#endif + +/* GL_OES_vertex_half_float */ +#ifndef GL_OES_vertex_half_float +#define GL_OES_vertex_half_float 1 +#endif + +/* GL_OES_vertex_type_10_10_10_2 */ +#ifndef GL_OES_vertex_type_10_10_10_2 +#define GL_OES_vertex_type_10_10_10_2 1 +#endif + +/*------------------------------------------------------------------------* + * AMD extension functions + *------------------------------------------------------------------------*/ + +/* GL_AMD_compressed_3DC_texture */ +#ifndef GL_AMD_compressed_3DC_texture +#define GL_AMD_compressed_3DC_texture 1 +#endif + +/* GL_AMD_compressed_ATC_texture */ +#ifndef GL_AMD_compressed_ATC_texture +#define GL_AMD_compressed_ATC_texture 1 +#endif + +/* AMD_performance_monitor */ +#ifndef GL_AMD_performance_monitor +#define GL_AMD_performance_monitor 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data); +GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); +GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); +GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); +GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor); +GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#endif +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); +typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); +typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); +typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#endif + +/* GL_AMD_program_binary_Z400 */ +#ifndef GL_AMD_program_binary_Z400 +#define GL_AMD_program_binary_Z400 1 +#endif + +/*------------------------------------------------------------------------* + * ANGLE extension functions + *------------------------------------------------------------------------*/ + +/* GL_ANGLE_framebuffer_blit */ +#ifndef GL_ANGLE_framebuffer_blit +#define GL_ANGLE_framebuffer_blit 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif + +/* GL_ANGLE_framebuffer_multisample */ +#ifndef GL_ANGLE_framebuffer_multisample +#define GL_ANGLE_framebuffer_multisample 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#endif +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#endif + +/* GL_ANGLE_pack_reverse_row_order */ +#ifndef GL_ANGLE_pack_reverse_row_order +#define GL_ANGLE_pack_reverse_row_order 1 +#endif + +/* GL_ANGLE_texture_compression_dxt3 */ +#ifndef GL_ANGLE_texture_compression_dxt3 +#define GL_ANGLE_texture_compression_dxt3 1 +#endif + +/* GL_ANGLE_texture_compression_dxt5 */ +#ifndef GL_ANGLE_texture_compression_dxt5 +#define GL_ANGLE_texture_compression_dxt5 1 +#endif + +/* GL_ANGLE_translated_shader_source */ +#ifndef GL_ANGLE_translated_shader_source +#define GL_ANGLE_translated_shader_source 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); +#endif +typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); +#endif + +/* GL_ANGLE_texture_usage */ +#ifndef GL_ANGLE_texture_usage +#define GL_ANGLE_texture_usage 1 +#endif + +/* GL_ANGLE_instanced_arrays */ +#ifndef GL_ANGLE_instanced_arrays +#define GL_ANGLE_instanced_arrays 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor); +GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount); +GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +#endif +typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor); +typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +#endif + +/*------------------------------------------------------------------------* + * APPLE extension functions + *------------------------------------------------------------------------*/ + +/* GL_APPLE_rgb_422 */ +#ifndef GL_APPLE_rgb_422 +#define GL_APPLE_rgb_422 1 +#endif + +/* GL_APPLE_framebuffer_multisample */ +#ifndef GL_APPLE_framebuffer_multisample +#define GL_APPLE_framebuffer_multisample 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei); +GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void); +#endif + +/* GL_APPLE_texture_format_BGRA8888 */ +#ifndef GL_APPLE_texture_format_BGRA8888 +#define GL_APPLE_texture_format_BGRA8888 1 +#endif + +/* GL_APPLE_texture_max_level */ +#ifndef GL_APPLE_texture_max_level +#define GL_APPLE_texture_max_level 1 +#endif + +/*------------------------------------------------------------------------* + * ARM extension functions + *------------------------------------------------------------------------*/ + +/* GL_ARM_mali_shader_binary */ +#ifndef GL_ARM_mali_shader_binary +#define GL_ARM_mali_shader_binary 1 +#endif + +/* GL_ARM_rgba8 */ +#ifndef GL_ARM_rgba8 +#define GL_ARM_rgba8 1 +#endif + +/*------------------------------------------------------------------------* + * EXT extension functions + *------------------------------------------------------------------------*/ + +/* GL_EXT_blend_minmax */ +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#endif + +/* GL_EXT_color_buffer_half_float */ +#ifndef GL_EXT_color_buffer_half_float +#define GL_EXT_color_buffer_half_float 1 +#endif + +/* GL_EXT_debug_label */ +#ifndef GL_EXT_debug_label +#define GL_EXT_debug_label 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); +GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); +typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif + +/* GL_EXT_debug_marker */ +#ifndef GL_EXT_debug_marker +#define GL_EXT_debug_marker 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); +GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); +GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void); +#endif +typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); +#endif + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_EXT_discard_framebuffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif +typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif + +/* GL_EXT_multisampled_render_to_texture */ +#ifndef GL_EXT_multisampled_render_to_texture +#define GL_EXT_multisampled_render_to_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei); +GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); +#endif +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +#endif + +#ifndef GL_EXT_multi_draw_arrays +#define GL_EXT_multi_draw_arrays 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei); +GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); +typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +#endif + +/* GL_EXT_occlusion_query_boolean */ +#ifndef GL_EXT_occlusion_query_boolean +#define GL_EXT_occlusion_query_boolean 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids); +GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids); +GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id); +GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id); +GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target); +GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params); +#endif +typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids); +typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id); +typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id); +typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params); +#endif + +/* GL_EXT_read_format_bgra */ +#ifndef GL_EXT_read_format_bgra +#define GL_EXT_read_format_bgra 1 +#endif + +/* GL_EXT_robustness */ +#ifndef GL_EXT_robustness +#define GL_EXT_robustness 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void); +GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params); +GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params); +#endif +typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void); +typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params); +typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +#endif + +/* GL_EXT_separate_shader_objects */ +#ifndef GL_EXT_separate_shader_objects +#define GL_EXT_separate_shader_objects 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program); +GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program); +GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings); +GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline); +GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines); +GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines); +GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline); +GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); +GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x); +GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y); +GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z); +GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w); +GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x); +GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y); +GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z); +GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline); +GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +#endif +typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program); +typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings); +typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline); +typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines); +typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines); +typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline); +typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline); +typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +#endif + +/* GL_EXT_shader_texture_lod */ +#ifndef GL_EXT_shader_texture_lod +#define GL_EXT_shader_texture_lod 1 +#endif + +/* GL_EXT_shadow_samplers */ +#ifndef GL_EXT_shadow_samplers +#define GL_EXT_shadow_samplers 1 +#endif + +/* GL_EXT_sRGB */ +#ifndef GL_EXT_sRGB +#define GL_EXT_sRGB 1 +#endif + +/* GL_EXT_texture_compression_dxt1 */ +#ifndef GL_EXT_texture_compression_dxt1 +#define GL_EXT_texture_compression_dxt1 1 +#endif + +/* GL_EXT_texture_filter_anisotropic */ +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +#endif + +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_EXT_texture_format_BGRA8888 1 +#endif + +/* GL_EXT_texture_rg */ +#ifndef GL_EXT_texture_rg +#define GL_EXT_texture_rg 1 +#endif + +/* GL_EXT_texture_storage */ +#ifndef GL_EXT_texture_storage +#define GL_EXT_texture_storage 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +#endif +typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +#endif + +/* GL_EXT_texture_type_2_10_10_10_REV */ +#ifndef GL_EXT_texture_type_2_10_10_10_REV +#define GL_EXT_texture_type_2_10_10_10_REV 1 +#endif + +/* GL_EXT_unpack_subimage */ +#ifndef GL_EXT_unpack_subimage +#define GL_EXT_unpack_subimage 1 +#endif + +/*------------------------------------------------------------------------* + * DMP extension functions + *------------------------------------------------------------------------*/ + +/* GL_DMP_shader_binary */ +#ifndef GL_DMP_shader_binary +#define GL_DMP_shader_binary 1 +#endif + +/*------------------------------------------------------------------------* + * IMG extension functions + *------------------------------------------------------------------------*/ + +/* GL_IMG_program_binary */ +#ifndef GL_IMG_program_binary +#define GL_IMG_program_binary 1 +#endif + +/* GL_IMG_read_format */ +#ifndef GL_IMG_read_format +#define GL_IMG_read_format 1 +#endif + +/* GL_IMG_shader_binary */ +#ifndef GL_IMG_shader_binary +#define GL_IMG_shader_binary 1 +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_IMG_texture_compression_pvrtc 1 +#endif + +/* GL_IMG_multisampled_render_to_texture */ +#ifndef GL_IMG_multisampled_render_to_texture +#define GL_IMG_multisampled_render_to_texture 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei); +GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei); +#endif +typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples); +#endif + +/*------------------------------------------------------------------------* + * NV extension functions + *------------------------------------------------------------------------*/ + +/* GL_NV_coverage_sample */ +#ifndef GL_NV_coverage_sample +#define GL_NV_coverage_sample 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask); +GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation); +#endif +typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask); +typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation); +#endif + +/* GL_NV_depth_nonlinear */ +#ifndef GL_NV_depth_nonlinear +#define GL_NV_depth_nonlinear 1 +#endif + +/* GL_NV_draw_buffers */ +#ifndef GL_NV_draw_buffers +#define GL_NV_draw_buffers 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs); +#endif +typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs); +#endif + +/* GL_NV_fbo_color_attachments */ +#ifndef GL_NV_fbo_color_attachments +#define GL_NV_fbo_color_attachments 1 +#endif + +/* GL_NV_fence */ +#ifndef GL_NV_fence +#define GL_NV_fence 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *); +GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *); +GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint); +GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint); +GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *); +GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint); +GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum); +#endif +typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); +typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); +typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); +typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); +typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); +typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); +#endif + +/* GL_NV_read_buffer */ +#ifndef GL_NV_read_buffer +#define GL_NV_read_buffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode); +#endif +typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode); +#endif + +/* GL_NV_read_buffer_front */ +#ifndef GL_NV_read_buffer_front +#define GL_NV_read_buffer_front 1 +#endif + +/* GL_NV_read_depth */ +#ifndef GL_NV_read_depth +#define GL_NV_read_depth 1 +#endif + +/* GL_NV_read_depth_stencil */ +#ifndef GL_NV_read_depth_stencil +#define GL_NV_read_depth_stencil 1 +#endif + +/* GL_NV_read_stencil */ +#ifndef GL_NV_read_stencil +#define GL_NV_read_stencil 1 +#endif + +/* GL_NV_texture_compression_s3tc_update */ +#ifndef GL_NV_texture_compression_s3tc_update +#define GL_NV_texture_compression_s3tc_update 1 +#endif + +/* GL_NV_texture_npot_2D_mipmap */ +#ifndef GL_NV_texture_npot_2D_mipmap +#define GL_NV_texture_npot_2D_mipmap 1 +#endif + +/*------------------------------------------------------------------------* + * QCOM extension functions + *------------------------------------------------------------------------*/ + +/* GL_QCOM_alpha_test */ +#ifndef GL_QCOM_alpha_test +#define GL_QCOM_alpha_test 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref); +#endif +typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref); +#endif + +/* GL_QCOM_driver_control */ +#ifndef GL_QCOM_driver_control +#define GL_QCOM_driver_control 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls); +GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); +GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl); +GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl); +#endif +typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls); +typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString); +typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); +typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); +#endif + +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_QCOM_extended_get 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures); +GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); +GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params); +#endif + +/* GL_QCOM_extended_get2 */ +#ifndef GL_QCOM_extended_get2 +#define GL_QCOM_extended_get2 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders); +GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program); +GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length); +#endif + +/* GL_QCOM_perfmon_global_mode */ +#ifndef GL_QCOM_perfmon_global_mode +#define GL_QCOM_perfmon_global_mode 1 +#endif + +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_QCOM_writeonly_rendering 1 +#endif + +/* GL_QCOM_tiled_rendering */ +#ifndef GL_QCOM_tiled_rendering +#define GL_QCOM_tiled_rendering 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); +GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask); +#endif +typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); +typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask); +#endif + +/*------------------------------------------------------------------------* + * VIV extension tokens + *------------------------------------------------------------------------*/ + +/* GL_VIV_shader_binary */ +#ifndef GL_VIV_shader_binary +#define GL_VIV_shader_binary 1 +#endif + +/* GL_ANGLE_program_binary */ +#ifndef GL_ANGLE_program_binary +#define GL_ANGLE_program_binary 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __gl2ext_h_ */ diff --git a/src/3rdparty/angle/include/GLES2/gl2platform.h b/src/3rdparty/angle/include/GLES2/gl2platform.h new file mode 100644 index 0000000000..c9fa3c4d64 --- /dev/null +++ b/src/3rdparty/angle/include/GLES2/gl2platform.h @@ -0,0 +1,30 @@ +#ifndef __gl2platform_h_ +#define __gl2platform_h_ + +/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */ + +/* + * This document is licensed under the SGI Free Software B License Version + * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . + */ + +/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * You are encouraged to submit all modifications to the Khronos group so that + * they can be included in future versions of this file. Please submit changes + * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) + * by filing a bug against product "OpenGL-ES" component "Registry". + */ + +#include + +#ifndef GL_APICALL +#define GL_APICALL KHRONOS_APICALL +#endif + +#ifndef GL_APIENTRY +#define GL_APIENTRY KHRONOS_APIENTRY +#endif + +#endif /* __gl2platform_h_ */ diff --git a/src/3rdparty/angle/include/GLSLANG/ShaderLang.h b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h new file mode 100644 index 0000000000..d925029a2c --- /dev/null +++ b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h @@ -0,0 +1,354 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#ifndef _COMPILER_INTERFACE_INCLUDED_ +#define _COMPILER_INTERFACE_INCLUDED_ + +#if defined(COMPONENT_BUILD) +#if defined(_WIN32) || defined(_WIN64) + +#if defined(COMPILER_IMPLEMENTATION) +#define COMPILER_EXPORT __declspec(dllexport) +#else +#define COMPILER_EXPORT __declspec(dllimport) +#endif // defined(COMPILER_IMPLEMENTATION) + +#else // defined(WIN32) +#define COMPILER_EXPORT __attribute__((visibility("default"))) +#endif + +#else // defined(COMPONENT_BUILD) +#define COMPILER_EXPORT +#endif + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler. +// + +#ifdef __cplusplus +extern "C" { +#endif + +// Version number for shader translation API. +// It is incremented everytime the API changes. +#define SH_VERSION 107 + +// +// The names of the following enums have been derived by replacing GL prefix +// with SH. For example, SH_INFO_LOG_LENGTH is equivalent to GL_INFO_LOG_LENGTH. +// The enum values are also equal to the values of their GL counterpart. This +// is done to make it easier for applications to use the shader library. +// +typedef enum { + SH_FRAGMENT_SHADER = 0x8B30, + SH_VERTEX_SHADER = 0x8B31 +} ShShaderType; + +typedef enum { + SH_GLES2_SPEC = 0x8B40, + SH_WEBGL_SPEC = 0x8B41, + + // The CSS Shaders spec is a subset of the WebGL spec. + // + // In both CSS vertex and fragment shaders, ANGLE: + // (1) Reserves the "css_" prefix. + // (2) Renames the main function to css_main. + // (3) Disables the gl_MaxDrawBuffers built-in. + // + // In CSS fragment shaders, ANGLE: + // (1) Disables the gl_FragColor built-in. + // (2) Disables the gl_FragData built-in. + // (3) Enables the css_MixColor built-in. + // (4) Enables the css_ColorMatrix built-in. + // + // After passing a CSS shader through ANGLE, the browser is expected to append + // a new main function to it. + // This new main function will call the css_main function. + // It may also perform additional operations like varying assignment, texture + // access, and gl_FragColor assignment in order to implement the CSS Shaders + // blend modes. + // + SH_CSS_SHADERS_SPEC = 0x8B42 +} ShShaderSpec; + +typedef enum { + SH_ESSL_OUTPUT = 0x8B45, + SH_GLSL_OUTPUT = 0x8B46, + SH_HLSL_OUTPUT = 0x8B47 +} ShShaderOutput; + +typedef enum { + SH_NONE = 0, + SH_INT = 0x1404, + SH_FLOAT = 0x1406, + SH_FLOAT_VEC2 = 0x8B50, + SH_FLOAT_VEC3 = 0x8B51, + SH_FLOAT_VEC4 = 0x8B52, + SH_INT_VEC2 = 0x8B53, + SH_INT_VEC3 = 0x8B54, + SH_INT_VEC4 = 0x8B55, + SH_BOOL = 0x8B56, + SH_BOOL_VEC2 = 0x8B57, + SH_BOOL_VEC3 = 0x8B58, + SH_BOOL_VEC4 = 0x8B59, + SH_FLOAT_MAT2 = 0x8B5A, + SH_FLOAT_MAT3 = 0x8B5B, + SH_FLOAT_MAT4 = 0x8B5C, + SH_SAMPLER_2D = 0x8B5E, + SH_SAMPLER_CUBE = 0x8B60, + SH_SAMPLER_2D_RECT_ARB = 0x8B63, + SH_SAMPLER_EXTERNAL_OES = 0x8D66 +} ShDataType; + +typedef enum { + SH_INFO_LOG_LENGTH = 0x8B84, + SH_OBJECT_CODE_LENGTH = 0x8B88, // GL_SHADER_SOURCE_LENGTH + SH_ACTIVE_UNIFORMS = 0x8B86, + SH_ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87, + SH_ACTIVE_ATTRIBUTES = 0x8B89, + SH_ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A, + SH_MAPPED_NAME_MAX_LENGTH = 0x8B8B +} ShShaderInfo; + +// Compile options. +typedef enum { + SH_VALIDATE = 0, + SH_VALIDATE_LOOP_INDEXING = 0x0001, + SH_INTERMEDIATE_TREE = 0x0002, + SH_OBJECT_CODE = 0x0004, + SH_ATTRIBUTES_UNIFORMS = 0x0008, + SH_LINE_DIRECTIVES = 0x0010, + SH_SOURCE_PATH = 0x0020, + SH_MAP_LONG_VARIABLE_NAMES = 0x0040, + SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0080, + + // This is needed only as a workaround for certain OpenGL driver bugs. + SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100, + + // This is an experimental flag to enforce restrictions that aim to prevent + // timing attacks. + // It generates compilation errors for shaders that could expose sensitive + // texture information via the timing channel. + // To use this flag, you must compile the shader under the WebGL spec + // (using the SH_WEBGL_SPEC flag). + SH_TIMING_RESTRICTIONS = 0x0200, + + // This flag prints the dependency graph that is used to enforce timing + // restrictions on fragment shaders. + // This flag only has an effect if all of the following are true: + // - The shader spec is SH_WEBGL_SPEC. + // - The compile options contain the SH_TIMING_RESTRICTIONS flag. + // - The shader type is SH_FRAGMENT_SHADER. + SH_DEPENDENCY_GRAPH = 0x0400, + + // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions. + SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800, +} ShCompileOptions; + +// +// Driver must call this first, once, before doing any other +// compiler operations. +// If the function succeeds, the return value is nonzero, else zero. +// +COMPILER_EXPORT int ShInitialize(); +// +// Driver should call this at shutdown. +// If the function succeeds, the return value is nonzero, else zero. +// +COMPILER_EXPORT int ShFinalize(); + +// +// Implementation dependent built-in resources (constants and extensions). +// The names for these resources has been obtained by stripping gl_/GL_. +// +typedef struct +{ + // Constants. + int MaxVertexAttribs; + int MaxVertexUniformVectors; + int MaxVaryingVectors; + int MaxVertexTextureImageUnits; + int MaxCombinedTextureImageUnits; + int MaxTextureImageUnits; + int MaxFragmentUniformVectors; + int MaxDrawBuffers; + + // Extensions. + // Set to 1 to enable the extension, else 0. + int OES_standard_derivatives; + int OES_EGL_image_external; + int ARB_texture_rectangle; +} ShBuiltInResources; + +// +// Initialize built-in resources with minimum expected values. +// +COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources* resources); + +// +// ShHandle held by but opaque to the driver. It is allocated, +// managed, and de-allocated by the compiler. It's contents +// are defined by and used by the compiler. +// +// If handle creation fails, 0 will be returned. +// +typedef void* ShHandle; + +// +// Driver calls these to create and destroy compiler objects. +// +// Returns the handle of constructed compiler, null if the requested compiler is +// not supported. +// Parameters: +// type: Specifies the type of shader - SH_FRAGMENT_SHADER or SH_VERTEX_SHADER. +// spec: Specifies the language spec the compiler must conform to - +// SH_GLES2_SPEC or SH_WEBGL_SPEC. +// output: Specifies the output code type - SH_ESSL_OUTPUT, SH_GLSL_OUTPUT, +// or SH_HLSL_OUTPUT. +// resources: Specifies the built-in resources. +COMPILER_EXPORT ShHandle ShConstructCompiler( + ShShaderType type, + ShShaderSpec spec, + ShShaderOutput output, + const ShBuiltInResources* resources); +COMPILER_EXPORT void ShDestruct(ShHandle handle); + +// +// Compiles the given shader source. +// If the function succeeds, the return value is nonzero, else zero. +// Parameters: +// handle: Specifies the handle of compiler to be used. +// shaderStrings: Specifies an array of pointers to null-terminated strings +// containing the shader source code. +// numStrings: Specifies the number of elements in shaderStrings array. +// compileOptions: A mask containing the following parameters: +// SH_VALIDATE: Validates shader to ensure that it conforms to the spec +// specified during compiler construction. +// SH_VALIDATE_LOOP_INDEXING: Validates loop and indexing in the shader to +// ensure that they do not exceed the minimum +// functionality mandated in GLSL 1.0 spec, +// Appendix A, Section 4 and 5. +// There is no need to specify this parameter when +// compiling for WebGL - it is implied. +// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log. +// Can be queried by calling ShGetInfoLog(). +// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader. +// Can be queried by calling ShGetObjectCode(). +// SH_ATTRIBUTES_UNIFORMS: Extracts attributes and uniforms. +// Can be queried by calling ShGetActiveAttrib() and +// ShGetActiveUniform(). +// +COMPILER_EXPORT int ShCompile( + const ShHandle handle, + const char* const shaderStrings[], + const int numStrings, + int compileOptions + ); + +// Returns a parameter from a compiled shader. +// Parameters: +// handle: Specifies the compiler +// pname: Specifies the parameter to query. +// The following parameters are defined: +// SH_INFO_LOG_LENGTH: the number of characters in the information log +// including the null termination character. +// SH_OBJECT_CODE_LENGTH: the number of characters in the object code +// including the null termination character. +// SH_ACTIVE_ATTRIBUTES: the number of active attribute variables. +// SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: the length of the longest active attribute +// variable name including the null +// termination character. +// SH_ACTIVE_UNIFORMS: the number of active uniform variables. +// SH_ACTIVE_UNIFORM_MAX_LENGTH: the length of the longest active uniform +// variable name including the null +// termination character. +// SH_MAPPED_NAME_MAX_LENGTH: the length of the mapped variable name including +// the null termination character. +// +// params: Requested parameter +COMPILER_EXPORT void ShGetInfo(const ShHandle handle, + ShShaderInfo pname, + int* params); + +// Returns nul-terminated information log for a compiled shader. +// Parameters: +// handle: Specifies the compiler +// infoLog: Specifies an array of characters that is used to return +// the information log. It is assumed that infoLog has enough memory +// to accomodate the information log. The size of the buffer required +// to store the returned information log can be obtained by calling +// ShGetInfo with SH_INFO_LOG_LENGTH. +COMPILER_EXPORT void ShGetInfoLog(const ShHandle handle, char* infoLog); + +// Returns null-terminated object code for a compiled shader. +// Parameters: +// handle: Specifies the compiler +// infoLog: Specifies an array of characters that is used to return +// the object code. It is assumed that infoLog has enough memory to +// accomodate the object code. The size of the buffer required to +// store the returned object code can be obtained by calling +// ShGetInfo with SH_OBJECT_CODE_LENGTH. +COMPILER_EXPORT void ShGetObjectCode(const ShHandle handle, char* objCode); + +// Returns information about an active attribute variable. +// Parameters: +// handle: Specifies the compiler +// index: Specifies the index of the attribute variable to be queried. +// length: Returns the number of characters actually written in the string +// indicated by name (excluding the null terminator) if a value other +// than NULL is passed. +// size: Returns the size of the attribute variable. +// type: Returns the data type of the attribute variable. +// name: Returns a null terminated string containing the name of the +// attribute variable. It is assumed that name has enough memory to +// accomodate the attribute variable name. The size of the buffer +// required to store the attribute variable name can be obtained by +// calling ShGetInfo with SH_ACTIVE_ATTRIBUTE_MAX_LENGTH. +// mappedName: Returns a null terminated string containing the mapped name of +// the attribute variable, It is assumed that mappedName has enough +// memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care +// about the mapped name. If the name is not mapped, then name and +// mappedName are the same. +COMPILER_EXPORT void ShGetActiveAttrib(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name, + char* mappedName); + +// Returns information about an active uniform variable. +// Parameters: +// handle: Specifies the compiler +// index: Specifies the index of the uniform variable to be queried. +// length: Returns the number of characters actually written in the string +// indicated by name (excluding the null terminator) if a value +// other than NULL is passed. +// size: Returns the size of the uniform variable. +// type: Returns the data type of the uniform variable. +// name: Returns a null terminated string containing the name of the +// uniform variable. It is assumed that name has enough memory to +// accomodate the uniform variable name. The size of the buffer required +// to store the uniform variable name can be obtained by calling +// ShGetInfo with SH_ACTIVE_UNIFORMS_MAX_LENGTH. +// mappedName: Returns a null terminated string containing the mapped name of +// the uniform variable, It is assumed that mappedName has enough +// memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care +// about the mapped name. If the name is not mapped, then name and +// mappedName are the same. +COMPILER_EXPORT void ShGetActiveUniform(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name, + char* mappedName); + +#ifdef __cplusplus +} +#endif + +#endif // _COMPILER_INTERFACE_INCLUDED_ diff --git a/src/3rdparty/angle/include/KHR/khrplatform.h b/src/3rdparty/angle/include/KHR/khrplatform.h new file mode 100644 index 0000000000..8ec0d199ff --- /dev/null +++ b/src/3rdparty/angle/include/KHR/khrplatform.h @@ -0,0 +1,269 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $ + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by sending them to the public Khronos Bugzilla + * (http://khronos.org/bugzilla) by filing a bug against product + * "Khronos (general)" component "Registry". + * + * A predefined template which fills in some of the bug fields can be + * reached using http://tinyurl.com/khrplatform-h-bugreport, but you + * must create a Bugzilla login first. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/src/3rdparty/angle/src/common/RefCountObject.cpp b/src/3rdparty/angle/src/common/RefCountObject.cpp new file mode 100644 index 0000000000..c1ef90cdcc --- /dev/null +++ b/src/3rdparty/angle/src/common/RefCountObject.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RefCountObject.cpp: Defines the gl::RefCountObject base class that provides +// lifecycle support for GL objects using the traditional BindObject scheme, but +// that need to be reference counted for correct cross-context deletion. +// (Concretely, textures, buffers and renderbuffers.) + +#include "RefCountObject.h" + +RefCountObject::RefCountObject(GLuint id) +{ + mId = id; + mRefCount = 0; +} + +RefCountObject::~RefCountObject() +{ + ASSERT(mRefCount == 0); +} + +void RefCountObject::addRef() const +{ + mRefCount++; +} + +void RefCountObject::release() const +{ + ASSERT(mRefCount > 0); + + if (--mRefCount == 0) + { + delete this; + } +} + +void RefCountObjectBindingPointer::set(RefCountObject *newObject) +{ + // addRef first in case newObject == mObject and this is the last reference to it. + if (newObject != NULL) newObject->addRef(); + if (mObject != NULL) mObject->release(); + + mObject = newObject; +} diff --git a/src/3rdparty/angle/src/common/RefCountObject.h b/src/3rdparty/angle/src/common/RefCountObject.h new file mode 100644 index 0000000000..727c71c362 --- /dev/null +++ b/src/3rdparty/angle/src/common/RefCountObject.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RefCountObject.h: Defines the gl::RefCountObject base class that provides +// lifecycle support for GL objects using the traditional BindObject scheme, but +// that need to be reference counted for correct cross-context deletion. +// (Concretely, textures, buffers and renderbuffers.) + +#ifndef COMMON_REFCOUNTOBJECT_H_ +#define COMMON_REFCOUNTOBJECT_H_ + +#include + +#define GL_APICALL +#include + +#include "common/debug.h" + +class RefCountObject +{ + public: + explicit RefCountObject(GLuint id); + virtual ~RefCountObject(); + + virtual void addRef() const; + virtual void release() const; + + GLuint id() const { return mId; } + + private: + GLuint mId; + + mutable std::size_t mRefCount; +}; + +class RefCountObjectBindingPointer +{ + protected: + RefCountObjectBindingPointer() : mObject(NULL) { } + ~RefCountObjectBindingPointer() { ASSERT(mObject == NULL); } // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up. + + void set(RefCountObject *newObject); + RefCountObject *get() const { return mObject; } + + public: + GLuint id() const { return (mObject != NULL) ? mObject->id() : 0; } + bool operator ! () const { return (get() == NULL); } + + private: + RefCountObject *mObject; +}; + +template +class BindingPointer : public RefCountObjectBindingPointer +{ + public: + void set(ObjectType *newObject) { RefCountObjectBindingPointer::set(newObject); } + ObjectType *get() const { return static_cast(RefCountObjectBindingPointer::get()); } + ObjectType *operator -> () const { return get(); } +}; + +#endif // COMMON_REFCOUNTOBJECT_H_ diff --git a/src/3rdparty/angle/src/common/angleutils.h b/src/3rdparty/angle/src/common/angleutils.h new file mode 100644 index 0000000000..ff9730c4da --- /dev/null +++ b/src/3rdparty/angle/src/common/angleutils.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// angleutils.h: Common ANGLE utilities. + +#ifndef COMMON_ANGLEUTILS_H_ +#define COMMON_ANGLEUTILS_H_ + +// A macro to disallow the copy constructor and operator= functions +// This must be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#if defined(_MSC_VER) +#define snprintf _snprintf +#endif + +#define VENDOR_ID_AMD 0x1002 +#define VENDOR_ID_INTEL 0x8086 +#define VENDOR_ID_NVIDIA 0x10DE + +#endif // COMMON_ANGLEUTILS_H_ diff --git a/src/3rdparty/angle/src/common/debug.cpp b/src/3rdparty/angle/src/common/debug.cpp new file mode 100644 index 0000000000..b2238f9708 --- /dev/null +++ b/src/3rdparty/angle/src/common/debug.cpp @@ -0,0 +1,103 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// debug.cpp: Debugging utilities. + +#include "common/debug.h" + +#include +#include +#include +#include + +namespace gl +{ + +typedef void (WINAPI *PerfOutputFunction)(D3DCOLOR, LPCWSTR); + +static void output(bool traceFileDebugOnly, PerfOutputFunction perfFunc, const char *format, va_list vararg) +{ +#if !defined(ANGLE_DISABLE_PERF) + if (perfActive()) + { + char message[32768]; + int len = vsprintf_s(message, format, vararg); + if (len < 0) + { + return; + } + + // There are no ASCII variants of these D3DPERF functions. + wchar_t wideMessage[32768]; + for (int i = 0; i < len; ++i) + { + wideMessage[i] = message[i]; + } + wideMessage[len] = 0; + + perfFunc(0, wideMessage); + } +#endif + +#if !defined(ANGLE_DISABLE_TRACE) +#if defined(NDEBUG) + if (traceFileDebugOnly) + { + return; + } +#endif + + FILE* file = fopen(TRACE_OUTPUT_FILE, "a"); + if (file) + { + vfprintf(file, format, vararg); + fclose(file); + } +#endif +} + +void trace(bool traceFileDebugOnly, const char *format, ...) +{ + va_list vararg; + va_start(vararg, format); +#if defined(ANGLE_DISABLE_PERF) + output(traceFileDebugOnly, NULL, format, vararg); +#else + output(traceFileDebugOnly, D3DPERF_SetMarker, format, vararg); +#endif + va_end(vararg); +} + +bool perfActive() +{ +#if defined(ANGLE_DISABLE_PERF) + return false; +#else + static bool active = D3DPERF_GetStatus() != 0; + return active; +#endif +} + +ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) +{ +#if !defined(ANGLE_DISABLE_PERF) + va_list vararg; + va_start(vararg, format); + output(true, reinterpret_cast(D3DPERF_BeginEvent), format, vararg); + va_end(vararg); +#endif +} + +ScopedPerfEventHelper::~ScopedPerfEventHelper() +{ +#if !defined(ANGLE_DISABLE_PERF) + if (perfActive()) + { + D3DPERF_EndEvent(); + } +#endif +} +} diff --git a/src/3rdparty/angle/src/common/debug.h b/src/3rdparty/angle/src/common/debug.h new file mode 100644 index 0000000000..5f8f60fe61 --- /dev/null +++ b/src/3rdparty/angle/src/common/debug.h @@ -0,0 +1,105 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// debug.h: Debugging utilities. + +#ifndef COMMON_DEBUG_H_ +#define COMMON_DEBUG_H_ + +#include +#include + +#include "common/angleutils.h" + +#if !defined(TRACE_OUTPUT_FILE) +#define TRACE_OUTPUT_FILE "debug.txt" +#endif + +namespace gl +{ + // Outputs text to the debugging log + void trace(bool traceFileDebugOnly, const char *format, ...); + + // Returns whether D3DPERF is active. + bool perfActive(); + + // Pairs a D3D begin event with an end event. + class ScopedPerfEventHelper + { + public: + ScopedPerfEventHelper(const char* format, ...); + ~ScopedPerfEventHelper(); + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedPerfEventHelper); + }; +} + +// A macro to output a trace of a function call and its arguments to the debugging log +#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF) +#define TRACE(message, ...) (void(0)) +#else +#define TRACE(message, ...) gl::trace(true, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#endif + +// A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing. +#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF) +#define FIXME(message, ...) (void(0)) +#else +#define FIXME(message, ...) gl::trace(false, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#endif + +// A macro to output a function call and its arguments to the debugging log, in case of error. +#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF) +#define ERR(message, ...) (void(0)) +#else +#define ERR(message, ...) gl::trace(false, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#endif + +// A macro to log a performance event around a scope. +#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF) +#define EVENT(message, ...) (void(0)) +#elif defined(_MSC_VER) +#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__(__FUNCTION__ message "\n", __VA_ARGS__); +#else +#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper(message "\n", ##__VA_ARGS__); +#endif + +// A macro asserting a condition and outputting failures to the debug log +#if !defined(NDEBUG) +#define ASSERT(expression) do { \ + if(!(expression)) \ + ERR("\t! Assert failed in %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \ + assert(expression); \ + } while(0) +#else +#define ASSERT(expression) (void(0)) +#endif + +// A macro to indicate unimplemented functionality +#if !defined(NDEBUG) +#define UNIMPLEMENTED() do { \ + FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ + } while(0) +#else + #define UNIMPLEMENTED() FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__) +#endif + +// A macro for code which is not expected to be reached under valid assumptions +#if !defined(NDEBUG) +#define UNREACHABLE() do { \ + ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ + } while(0) +#else + #define UNREACHABLE() ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__) +#endif + +// A macro functioning as a compile-time assert to validate constant conditions +#define META_ASSERT(condition) typedef int COMPILE_TIME_ASSERT_##__LINE__[static_cast(condition)?1:-1] + +#endif // COMMON_DEBUG_H_ diff --git a/src/3rdparty/angle/src/common/version.h b/src/3rdparty/angle/src/common/version.h new file mode 100644 index 0000000000..fec98a15c9 --- /dev/null +++ b/src/3rdparty/angle/src/common/version.h @@ -0,0 +1,10 @@ +#define MAJOR_VERSION 1 +#define MINOR_VERSION 0 +#define BUILD_VERSION 0 +#define BUILD_REVISION 1318 + +#define STRINGIFY(x) #x +#define MACRO_STRINGIFY(x) STRINGIFY(x) + +#define REVISION_STRING MACRO_STRINGIFY(BUILD_REVISION) +#define VERSION_STRING MACRO_STRINGIFY(MAJOR_VERSION) "." MACRO_STRINGIFY(MINOR_VERSION) "." MACRO_STRINGIFY(BUILD_VERSION) "." MACRO_STRINGIFY(BUILD_REVISION) diff --git a/src/3rdparty/angle/src/compiler/BaseTypes.h b/src/3rdparty/angle/src/compiler/BaseTypes.h new file mode 100644 index 0000000000..5f83185304 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/BaseTypes.h @@ -0,0 +1,152 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _BASICTYPES_INCLUDED_ +#define _BASICTYPES_INCLUDED_ + +// +// Precision qualifiers +// +enum TPrecision +{ + // These need to be kept sorted + EbpUndefined, + EbpLow, + EbpMedium, + EbpHigh, +}; + +inline const char* getPrecisionString(TPrecision p) +{ + switch(p) + { + case EbpHigh: return "highp"; break; + case EbpMedium: return "mediump"; break; + case EbpLow: return "lowp"; break; + default: return "mediump"; break; // Safest fallback + } +} + +// +// Basic type. Arrays, vectors, etc., are orthogonal to this. +// +enum TBasicType +{ + EbtVoid, + EbtFloat, + EbtInt, + EbtBool, + EbtGuardSamplerBegin, // non type: see implementation of IsSampler() + EbtSampler2D, + EbtSamplerCube, + EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists. + EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists. + EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtStruct, + EbtAddress, // should be deprecated?? + EbtInvariant, // used as a type when qualifying a previously declared variable as being invariant +}; + +inline const char* getBasicString(TBasicType t) +{ + switch (t) + { + case EbtVoid: return "void"; break; + case EbtFloat: return "float"; break; + case EbtInt: return "int"; break; + case EbtBool: return "bool"; break; + case EbtSampler2D: return "sampler2D"; break; + case EbtSamplerCube: return "samplerCube"; break; + case EbtSamplerExternalOES: return "samplerExternalOES"; break; + case EbtSampler2DRect: return "sampler2DRect"; break; + case EbtStruct: return "structure"; break; + default: return "unknown type"; + } +} + +inline bool IsSampler(TBasicType type) +{ + return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd; +} + +// +// Qualifiers and built-ins. These are mainly used to see what can be read +// or written, and by the machine dependent translator to know which registers +// to allocate variables in. Since built-ins tend to go to different registers +// than varying or uniform, it makes sense they are peers, not sub-classes. +// +enum TQualifier +{ + EvqTemporary, // For temporaries (within a function), read/write + EvqGlobal, // For globals read/write + EvqConst, // User defined constants and non-output parameters in functions + EvqAttribute, // Readonly + EvqVaryingIn, // readonly, fragment shaders only + EvqVaryingOut, // vertex shaders only read/write + EvqInvariantVaryingIn, // readonly, fragment shaders only + EvqInvariantVaryingOut, // vertex shaders only read/write + EvqUniform, // Readonly, vertex and fragment + + // pack/unpack input and output + EvqInput, + EvqOutput, + + // parameters + EvqIn, + EvqOut, + EvqInOut, + EvqConstReadOnly, + + // built-ins written by vertex shader + EvqPosition, + EvqPointSize, + + // built-ins read by fragment shader + EvqFragCoord, + EvqFrontFacing, + EvqPointCoord, + + // built-ins written by fragment shader + EvqFragColor, + EvqFragData, + + // end of list + EvqLast, +}; + +// +// This is just for debug print out, carried along with the definitions above. +// +inline const char* getQualifierString(TQualifier q) +{ + switch(q) + { + case EvqTemporary: return "Temporary"; break; + case EvqGlobal: return "Global"; break; + case EvqConst: return "const"; break; + case EvqConstReadOnly: return "const"; break; + case EvqAttribute: return "attribute"; break; + case EvqVaryingIn: return "varying"; break; + case EvqVaryingOut: return "varying"; break; + case EvqInvariantVaryingIn: return "invariant varying"; break; + case EvqInvariantVaryingOut:return "invariant varying"; break; + case EvqUniform: return "uniform"; break; + case EvqIn: return "in"; break; + case EvqOut: return "out"; break; + case EvqInOut: return "inout"; break; + case EvqInput: return "input"; break; + case EvqOutput: return "output"; break; + case EvqPosition: return "Position"; break; + case EvqPointSize: return "PointSize"; break; + case EvqFragCoord: return "FragCoord"; break; + case EvqFrontFacing: return "FrontFacing"; break; + case EvqFragColor: return "FragColor"; break; + case EvqFragData: return "FragData"; break; + default: return "unknown qualifier"; + } +} + +#endif // _BASICTYPES_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp new file mode 100644 index 0000000000..1c4b25f13f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp @@ -0,0 +1,406 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/BuiltInFunctionEmulator.h" + +#include "compiler/SymbolTable.h" + +namespace { + +// we use macros here instead of function definitions to work around more GLSL +// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are +// problematic because if the argument has side-effects they will be repeatedly +// evaluated. This is unlikely to show up in real shaders, but is something to +// consider. +const char* kFunctionEmulationVertexSource[] = { + "#error no emulation for cos(float)", + "#error no emulation for cos(vec2)", + "#error no emulation for cos(vec3)", + "#error no emulation for cos(vec4)", + + "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))", + "#error no emulation for distance(vec2, vec2)", + "#error no emulation for distance(vec3, vec3)", + "#error no emulation for distance(vec4, vec4)", + + "#define webgl_dot_emu(x, y) ((x) * (y))", + "#error no emulation for dot(vec2, vec2)", + "#error no emulation for dot(vec3, vec3)", + "#error no emulation for dot(vec4, vec4)", + + "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", + "#error no emulation for length(vec2)", + "#error no emulation for length(vec3)", + "#error no emulation for length(vec4)", + + "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", + "#error no emulation for normalize(vec2)", + "#error no emulation for normalize(vec3)", + "#error no emulation for normalize(vec4)", + + "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))", + "#error no emulation for reflect(vec2, vec2)", + "#error no emulation for reflect(vec3, vec3)", + "#error no emulation for reflect(vec4, vec4)" +}; + +const char* kFunctionEmulationFragmentSource[] = { + "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }", + "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }", + "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }", + "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }", + + "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))", + "#error no emulation for distance(vec2, vec2)", + "#error no emulation for distance(vec3, vec3)", + "#error no emulation for distance(vec4, vec4)", + + "#define webgl_dot_emu(x, y) ((x) * (y))", + "#error no emulation for dot(vec2, vec2)", + "#error no emulation for dot(vec3, vec3)", + "#error no emulation for dot(vec4, vec4)", + + "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", + "#error no emulation for length(vec2)", + "#error no emulation for length(vec3)", + "#error no emulation for length(vec4)", + + "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", + "#error no emulation for normalize(vec2)", + "#error no emulation for normalize(vec3)", + "#error no emulation for normalize(vec4)", + + "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))", + "#error no emulation for reflect(vec2, vec2)", + "#error no emulation for reflect(vec3, vec3)", + "#error no emulation for reflect(vec4, vec4)" +}; + +const bool kFunctionEmulationVertexMask[] = { +#if defined(__APPLE__) + // Work around ATI driver bugs in Mac. + false, // TFunctionCos1 + false, // TFunctionCos2 + false, // TFunctionCos3 + false, // TFunctionCos4 + true, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + true, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + true, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + true, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + true, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#else + // Work around D3D driver bug in Win. + false, // TFunctionCos1 + false, // TFunctionCos2 + false, // TFunctionCos3 + false, // TFunctionCos4 + false, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + false, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + false, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + false, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + false, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#endif + false // TFunctionUnknown +}; + +const bool kFunctionEmulationFragmentMask[] = { +#if defined(__APPLE__) + // Work around ATI driver bugs in Mac. + true, // TFunctionCos1 + true, // TFunctionCos2 + true, // TFunctionCos3 + true, // TFunctionCos4 + true, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + true, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + true, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + true, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + true, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#else + // Work around D3D driver bug in Win. + false, // TFunctionCos1 + false, // TFunctionCos2 + false, // TFunctionCos3 + false, // TFunctionCos4 + false, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + false, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + false, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + false, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + false, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#endif + false // TFunctionUnknown +}; + +class BuiltInFunctionEmulationMarker : public TIntermTraverser { +public: + BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator) + : mEmulator(emulator) + { + } + + virtual bool visitUnary(Visit visit, TIntermUnary* node) + { + if (visit == PreVisit) { + bool needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), node->getOperand()->getType()); + if (needToEmulate) + node->setUseEmulatedFunction(); + } + return true; + } + + virtual bool visitAggregate(Visit visit, TIntermAggregate* node) + { + if (visit == PreVisit) { + // Here we handle all the built-in functions instead of the ones we + // currently identified as problematic. + switch (node->getOp()) { + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpVectorEqual: + case EOpVectorNotEqual: + case EOpMod: + case EOpPow: + case EOpAtan: + case EOpMin: + case EOpMax: + case EOpClamp: + case EOpMix: + case EOpStep: + case EOpSmoothStep: + case EOpDistance: + case EOpDot: + case EOpCross: + case EOpFaceForward: + case EOpReflect: + case EOpRefract: + case EOpMul: + break; + default: + return true; + }; + const TIntermSequence& sequence = node->getSequence(); + // Right now we only handle built-in functions with two parameters. + if (sequence.size() != 2) + return true; + TIntermTyped* param1 = sequence[0]->getAsTyped(); + TIntermTyped* param2 = sequence[1]->getAsTyped(); + if (!param1 || !param2) + return true; + bool needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType()); + if (needToEmulate) + node->setUseEmulatedFunction(); + } + return true; + } + +private: + BuiltInFunctionEmulator& mEmulator; +}; + +} // anonymous namepsace + +BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType) +{ + if (shaderType == SH_FRAGMENT_SHADER) { + mFunctionMask = kFunctionEmulationFragmentMask; + mFunctionSource = kFunctionEmulationFragmentSource; + } else { + mFunctionMask = kFunctionEmulationVertexMask; + mFunctionSource = kFunctionEmulationVertexSource; + } +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + TOperator op, const TType& param) +{ + TBuiltInFunction function = IdentifyFunction(op, param); + return SetFunctionCalled(function); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2) +{ + TBuiltInFunction function = IdentifyFunction(op, param1, param2); + return SetFunctionCalled(function); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + BuiltInFunctionEmulator::TBuiltInFunction function) { + if (function == TFunctionUnknown || mFunctionMask[function] == false) + return false; + for (size_t i = 0; i < mFunctions.size(); ++i) { + if (mFunctions[i] == function) + return true; + } + mFunctions.push_back(function); + return true; +} + +void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition( + TInfoSinkBase& out, bool withPrecision) const +{ + if (mFunctions.size() == 0) + return; + out << "// BEGIN: Generated code for built-in function emulation\n\n"; + if (withPrecision) { + out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n" + << "#define webgl_emu_precision highp\n" + << "#else\n" + << "#define webgl_emu_precision mediump\n" + << "#endif\n\n"; + } else { + out << "#define webgl_emu_precision\n\n"; + } + for (size_t i = 0; i < mFunctions.size(); ++i) { + out << mFunctionSource[mFunctions[i]] << "\n\n"; + } + out << "// END: Generated code for built-in function emulation\n\n"; +} + +BuiltInFunctionEmulator::TBuiltInFunction +BuiltInFunctionEmulator::IdentifyFunction( + TOperator op, const TType& param) +{ + if (param.getNominalSize() > 4) + return TFunctionUnknown; + unsigned int function = TFunctionUnknown; + switch (op) { + case EOpCos: + function = TFunctionCos1; + break; + case EOpLength: + function = TFunctionLength1; + break; + case EOpNormalize: + function = TFunctionNormalize1; + break; + default: + break; + } + if (function == TFunctionUnknown) + return TFunctionUnknown; + if (param.isVector()) + function += param.getNominalSize() - 1; + return static_cast(function); +} + +BuiltInFunctionEmulator::TBuiltInFunction +BuiltInFunctionEmulator::IdentifyFunction( + TOperator op, const TType& param1, const TType& param2) +{ + // Right now for all the emulated functions with two parameters, the two + // parameters have the same type. + if (param1.isVector() != param2.isVector() || + param1.getNominalSize() != param2.getNominalSize() || + param1.getNominalSize() > 4) + return TFunctionUnknown; + + unsigned int function = TFunctionUnknown; + switch (op) { + case EOpDistance: + function = TFunctionDistance1_1; + break; + case EOpDot: + function = TFunctionDot1_1; + break; + case EOpReflect: + function = TFunctionReflect1_1; + break; + default: + break; + } + if (function == TFunctionUnknown) + return TFunctionUnknown; + if (param1.isVector()) + function += param1.getNominalSize() - 1; + return static_cast(function); +} + +void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( + TIntermNode* root) +{ + ASSERT(root); + + BuiltInFunctionEmulationMarker marker(*this); + root->traverse(&marker); +} + +void BuiltInFunctionEmulator::Cleanup() +{ + mFunctions.clear(); +} + +//static +TString BuiltInFunctionEmulator::GetEmulatedFunctionName( + const TString& name) +{ + ASSERT(name[name.length() - 1] == '('); + return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; +} + diff --git a/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h new file mode 100644 index 0000000000..0d904f41d0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h @@ -0,0 +1,93 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ +#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/InfoSink.h" +#include "compiler/intermediate.h" + +// +// This class decides which built-in functions need to be replaced with the +// emulated ones. +// It's only a workaround for OpenGL driver bugs, and isn't needed in general. +// +class BuiltInFunctionEmulator { +public: + BuiltInFunctionEmulator(ShShaderType shaderType); + // Records that a function is called by the shader and might needs to be + // emulated. If the function's group is not in mFunctionGroupFilter, this + // becomes an no-op. + // Returns true if the function call needs to be replaced with an emulated + // one. + bool SetFunctionCalled(TOperator op, const TType& param); + bool SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2); + + // Output function emulation definition. This should be before any other + // shader source. + void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const; + + void MarkBuiltInFunctionsForEmulation(TIntermNode* root); + + void Cleanup(); + + // "name(" becomes "webgl_name_emu(". + static TString GetEmulatedFunctionName(const TString& name); + +private: + // + // Built-in functions. + // + enum TBuiltInFunction { + TFunctionCos1 = 0, // float cos(float); + TFunctionCos2, // vec2 cos(vec2); + TFunctionCos3, // vec3 cos(vec3); + TFunctionCos4, // vec4 cos(vec4); + + TFunctionDistance1_1, // float distance(float, float); + TFunctionDistance2_2, // vec2 distance(vec2, vec2); + TFunctionDistance3_3, // vec3 distance(vec3, vec3); + TFunctionDistance4_4, // vec4 distance(vec4, vec4); + + TFunctionDot1_1, // float dot(float, float); + TFunctionDot2_2, // vec2 dot(vec2, vec2); + TFunctionDot3_3, // vec3 dot(vec3, vec3); + TFunctionDot4_4, // vec4 dot(vec4, vec4); + + TFunctionLength1, // float length(float); + TFunctionLength2, // float length(vec2); + TFunctionLength3, // float length(vec3); + TFunctionLength4, // float length(vec4); + + TFunctionNormalize1, // float normalize(float); + TFunctionNormalize2, // vec2 normalize(vec2); + TFunctionNormalize3, // vec3 normalize(vec3); + TFunctionNormalize4, // vec4 normalize(vec4); + + TFunctionReflect1_1, // float reflect(float, float); + TFunctionReflect2_2, // vec2 reflect(vec2, vec2); + TFunctionReflect3_3, // vec3 reflect(vec3, vec3); + TFunctionReflect4_4, // vec4 reflect(vec4, vec4); + + TFunctionUnknown + }; + + TBuiltInFunction IdentifyFunction(TOperator op, const TType& param); + TBuiltInFunction IdentifyFunction( + TOperator op, const TType& param1, const TType& param2); + + bool SetFunctionCalled(TBuiltInFunction function); + + std::vector mFunctions; + + const bool* mFunctionMask; // a boolean flag for each function. + const char** mFunctionSource; +}; + +#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp b/src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp new file mode 100644 index 0000000000..226bf8f0fc --- /dev/null +++ b/src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp @@ -0,0 +1,34 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/TranslatorGLSL.h" +#include "compiler/TranslatorESSL.h" + +// +// This function must be provided to create the actual +// compile object used by higher level code. It returns +// a subclass of TCompiler. +// +TCompiler* ConstructCompiler( + ShShaderType type, ShShaderSpec spec, ShShaderOutput output) +{ + switch (output) { + case SH_GLSL_OUTPUT: + return new TranslatorGLSL(type, spec); + case SH_ESSL_OUTPUT: + return new TranslatorESSL(type, spec); + default: + return NULL; + } +} + +// +// Delete the compiler made by ConstructCompiler +// +void DeleteCompiler(TCompiler* compiler) +{ + delete compiler; +} diff --git a/src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp b/src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp new file mode 100644 index 0000000000..f46ff66d40 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/TranslatorHLSL.h" + +// +// This function must be provided to create the actual +// compile object used by higher level code. It returns +// a subclass of TCompiler. +// +TCompiler* ConstructCompiler( + ShShaderType type, ShShaderSpec spec, ShShaderOutput output) +{ + switch (output) { + case SH_HLSL_OUTPUT: + return new TranslatorHLSL(type, spec); + default: + return NULL; + } +} + +// +// Delete the compiler made by ConstructCompiler +// +void DeleteCompiler(TCompiler* compiler) +{ + delete compiler; +} diff --git a/src/3rdparty/angle/src/compiler/Common.h b/src/3rdparty/angle/src/compiler/Common.h new file mode 100644 index 0000000000..27a5598290 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Common.h @@ -0,0 +1,89 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _COMMON_INCLUDED_ +#define _COMMON_INCLUDED_ + +#include +#include +#include +#include + +#include "compiler/PoolAlloc.h" + +// We need two pieces of information to report errors/warnings - string and +// line number. We encode these into a single int so that it can be easily +// incremented/decremented by lexer. The right SOURCE_LOC_LINE_SIZE bits store +// line number while the rest store the string number. Since the shaders are +// usually small, we should not run out of memory. SOURCE_LOC_LINE_SIZE +// can be increased to alleviate this issue. +typedef int TSourceLoc; +const unsigned int SOURCE_LOC_LINE_SIZE = 16; // in bits. +const unsigned int SOURCE_LOC_LINE_MASK = (1 << SOURCE_LOC_LINE_SIZE) - 1; + +inline TSourceLoc EncodeSourceLoc(int string, int line) { + return (string << SOURCE_LOC_LINE_SIZE) | (line & SOURCE_LOC_LINE_MASK); +} + +inline void DecodeSourceLoc(TSourceLoc loc, int* string, int* line) { + if (string) *string = loc >> SOURCE_LOC_LINE_SIZE; + if (line) *line = loc & SOURCE_LOC_LINE_MASK; +} + +// +// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme. +// +#define POOL_ALLOCATOR_NEW_DELETE(A) \ + void* operator new(size_t s) { return (A).allocate(s); } \ + void* operator new(size_t, void *_Where) { return (_Where); } \ + void operator delete(void*) { } \ + void operator delete(void *, void *) { } \ + void* operator new[](size_t s) { return (A).allocate(s); } \ + void* operator new[](size_t, void *_Where) { return (_Where); } \ + void operator delete[](void*) { } \ + void operator delete[](void *, void *) { } + +// +// Pool version of string. +// +typedef pool_allocator TStringAllocator; +typedef std::basic_string , TStringAllocator> TString; +typedef std::basic_ostringstream, TStringAllocator> TStringStream; +inline TString* NewPoolTString(const char* s) +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TString)); + return new(memory) TString(s); +} + +// +// Persistent string memory. Should only be used for strings that survive +// across compiles. +// +#define TPersistString std::string +#define TPersistStringStream std::ostringstream + +// +// Pool allocator versions of vectors, lists, and maps +// +template class TVector : public std::vector > { +public: + typedef typename std::vector >::size_type size_type; + TVector() : std::vector >() {} + TVector(const pool_allocator& a) : std::vector >(a) {} + TVector(size_type i): std::vector >(i) {} +}; + +template > +class TMap : public std::map > > { +public: + typedef pool_allocator > tAllocator; + + TMap() : std::map() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TMap(const tAllocator& a) : std::map(std::map::key_compare(), a) {} +}; + +#endif // _COMMON_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/Compiler.cpp b/src/3rdparty/angle/src/compiler/Compiler.cpp new file mode 100644 index 0000000000..9e7f75c33a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Compiler.cpp @@ -0,0 +1,350 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/BuiltInFunctionEmulator.h" +#include "compiler/DetectRecursion.h" +#include "compiler/ForLoopUnroll.h" +#include "compiler/Initialize.h" +#include "compiler/InitializeParseContext.h" +#include "compiler/MapLongVariableNames.h" +#include "compiler/ParseHelper.h" +#include "compiler/RenameFunction.h" +#include "compiler/ShHandle.h" +#include "compiler/ValidateLimitations.h" +#include "compiler/VariablePacker.h" +#include "compiler/depgraph/DependencyGraph.h" +#include "compiler/depgraph/DependencyGraphOutput.h" +#include "compiler/timing/RestrictFragmentShaderTiming.h" +#include "compiler/timing/RestrictVertexShaderTiming.h" + +bool isWebGLBasedSpec(ShShaderSpec spec) +{ + return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC; +} + +namespace { +bool InitializeSymbolTable( + const TBuiltInStrings& builtInStrings, + ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources, + TInfoSink& infoSink, TSymbolTable& symbolTable) +{ + TIntermediate intermediate(infoSink); + TExtensionBehavior extBehavior; + InitExtensionBehavior(resources, extBehavior); + // The builtins deliberately don't specify precisions for the function + // arguments and return types. For that reason we don't try to check them. + TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink); + + GlobalParseContext = &parseContext; + + assert(symbolTable.isEmpty()); + // + // Parse the built-ins. This should only happen once per + // language symbol table. + // + // Push the symbol table to give it an initial scope. This + // push should not have a corresponding pop, so that built-ins + // are preserved, and the test for an empty table fails. + // + symbolTable.push(); + + for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i) + { + const char* builtInShaders = i->c_str(); + int builtInLengths = static_cast(i->size()); + if (builtInLengths <= 0) + continue; + + if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0) + { + infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); + return false; + } + } + + IdentifyBuiltIns(type, spec, resources, symbolTable); + + return true; +} + +class TScopedPoolAllocator { +public: + TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop) + : mAllocator(allocator), mPushPopAllocator(pushPop) { + if (mPushPopAllocator) mAllocator->push(); + SetGlobalPoolAllocator(mAllocator); + } + ~TScopedPoolAllocator() { + SetGlobalPoolAllocator(NULL); + if (mPushPopAllocator) mAllocator->pop(); + } + +private: + TPoolAllocator* mAllocator; + bool mPushPopAllocator; +}; +} // namespace + +TShHandleBase::TShHandleBase() { + allocator.push(); + SetGlobalPoolAllocator(&allocator); +} + +TShHandleBase::~TShHandleBase() { + SetGlobalPoolAllocator(NULL); + allocator.popAll(); +} + +TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec) + : shaderType(type), + shaderSpec(spec), + builtInFunctionEmulator(type) +{ + longNameMap = LongNameMap::GetInstance(); +} + +TCompiler::~TCompiler() +{ + ASSERT(longNameMap); + longNameMap->Release(); +} + +bool TCompiler::Init(const ShBuiltInResources& resources) +{ + maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ? + resources.MaxVertexUniformVectors : + resources.MaxFragmentUniformVectors; + TScopedPoolAllocator scopedAlloc(&allocator, false); + + // Generate built-in symbol table. + if (!InitBuiltInSymbolTable(resources)) + return false; + InitExtensionBehavior(resources, extensionBehavior); + + return true; +} + +bool TCompiler::compile(const char* const shaderStrings[], + const int numStrings, + int compileOptions) +{ + TScopedPoolAllocator scopedAlloc(&allocator, true); + clearResults(); + + if (numStrings == 0) + return true; + + // If compiling for WebGL, validate loop and indexing as well. + if (isWebGLBasedSpec(shaderSpec)) + compileOptions |= SH_VALIDATE_LOOP_INDEXING; + + // First string is path of source file if flag is set. The actual source follows. + const char* sourcePath = NULL; + int firstSource = 0; + if (compileOptions & SH_SOURCE_PATH) + { + sourcePath = shaderStrings[0]; + ++firstSource; + } + + TIntermediate intermediate(infoSink); + TParseContext parseContext(symbolTable, extensionBehavior, intermediate, + shaderType, shaderSpec, compileOptions, true, + sourcePath, infoSink); + GlobalParseContext = &parseContext; + + // We preserve symbols at the built-in level from compile-to-compile. + // Start pushing the user-defined symbols at global level. + symbolTable.push(); + if (!symbolTable.atGlobalLevel()) + infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); + + // Parse shader. + bool success = + (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && + (parseContext.treeRoot != NULL); + if (success) { + TIntermNode* root = parseContext.treeRoot; + success = intermediate.postProcess(root); + + if (success) + success = detectRecursion(root); + + if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) + success = validateLimitations(root); + + if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) + success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); + + if (success && shaderSpec == SH_CSS_SHADERS_SPEC) + rewriteCSSShader(root); + + // Unroll for-loop markup needs to happen after validateLimitations pass. + if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) + ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root); + + // Built-in function emulation needs to happen after validateLimitations pass. + if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) + builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); + + // Call mapLongVariableNames() before collectAttribsUniforms() so in + // collectAttribsUniforms() we already have the mapped symbol names and + // we could composite mapped and original variable names. + if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES)) + mapLongVariableNames(root); + + if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) { + collectAttribsUniforms(root); + if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { + success = enforcePackingRestrictions(); + if (!success) { + infoSink.info.message(EPrefixError, "too many uniforms"); + } + } + } + + if (success && (compileOptions & SH_INTERMEDIATE_TREE)) + intermediate.outputTree(root); + + if (success && (compileOptions & SH_OBJECT_CODE)) + translate(root); + } + + // Cleanup memory. + intermediate.remove(parseContext.treeRoot); + // Ensure symbol table is returned to the built-in level, + // throwing away all but the built-ins. + while (!symbolTable.atBuiltInLevel()) + symbolTable.pop(); + + return success; +} + +bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources) +{ + TBuiltIns builtIns; + + builtIns.initialize(shaderType, shaderSpec, resources); + return InitializeSymbolTable(builtIns.getBuiltInStrings(), + shaderType, shaderSpec, resources, infoSink, symbolTable); +} + +void TCompiler::clearResults() +{ + infoSink.info.erase(); + infoSink.obj.erase(); + infoSink.debug.erase(); + + attribs.clear(); + uniforms.clear(); + + builtInFunctionEmulator.Cleanup(); +} + +bool TCompiler::detectRecursion(TIntermNode* root) +{ + DetectRecursion detect; + root->traverse(&detect); + switch (detect.detectRecursion()) { + case DetectRecursion::kErrorNone: + return true; + case DetectRecursion::kErrorMissingMain: + infoSink.info.message(EPrefixError, "Missing main()"); + return false; + case DetectRecursion::kErrorRecursion: + infoSink.info.message(EPrefixError, "Function recursion detected"); + return false; + default: + UNREACHABLE(); + return false; + } +} + +void TCompiler::rewriteCSSShader(TIntermNode* root) +{ + RenameFunction renamer("main(", "css_main("); + root->traverse(&renamer); +} + +bool TCompiler::validateLimitations(TIntermNode* root) { + ValidateLimitations validate(shaderType, infoSink.info); + root->traverse(&validate); + return validate.numErrors() == 0; +} + +bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) +{ + if (shaderSpec != SH_WEBGL_SPEC) { + infoSink.info << "Timing restrictions must be enforced under the WebGL spec."; + return false; + } + + if (shaderType == SH_FRAGMENT_SHADER) { + TDependencyGraph graph(root); + + // Output any errors first. + bool success = enforceFragmentShaderTimingRestrictions(graph); + + // Then, output the dependency graph. + if (outputGraph) { + TDependencyGraphOutput output(infoSink.info); + output.outputAllSpanningTrees(graph); + } + + return success; + } + else { + return enforceVertexShaderTimingRestrictions(root); + } +} + +bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) +{ + RestrictFragmentShaderTiming restrictor(infoSink.info); + restrictor.enforceRestrictions(graph); + return restrictor.numErrors() == 0; +} + +bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) +{ + RestrictVertexShaderTiming restrictor(infoSink.info); + restrictor.enforceRestrictions(root); + return restrictor.numErrors() == 0; +} + +void TCompiler::collectAttribsUniforms(TIntermNode* root) +{ + CollectAttribsUniforms collect(attribs, uniforms); + root->traverse(&collect); +} + +bool TCompiler::enforcePackingRestrictions() +{ + VariablePacker packer; + return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms); +} + +void TCompiler::mapLongVariableNames(TIntermNode* root) +{ + ASSERT(longNameMap); + MapLongVariableNames map(longNameMap); + root->traverse(&map); +} + +int TCompiler::getMappedNameMaxLength() const +{ + return MAX_SHORTENED_IDENTIFIER_SIZE + 1; +} + +const TExtensionBehavior& TCompiler::getExtensionBehavior() const +{ + return extensionBehavior; +} + +const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const +{ + return builtInFunctionEmulator; +} diff --git a/src/3rdparty/angle/src/compiler/ConstantUnion.h b/src/3rdparty/angle/src/compiler/ConstantUnion.h new file mode 100644 index 0000000000..fd9d94dc5a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ConstantUnion.h @@ -0,0 +1,256 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _CONSTANT_UNION_INCLUDED_ +#define _CONSTANT_UNION_INCLUDED_ + +#include + +class ConstantUnion { +public: + ConstantUnion() + { + iConst = 0; + } + + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + void setIConst(int i) {iConst = i; type = EbtInt; } + void setFConst(float f) {fConst = f; type = EbtFloat; } + void setBConst(bool b) {bConst = b; type = EbtBool; } + + int getIConst() { return iConst; } + float getFConst() { return fConst; } + bool getBConst() { return bConst; } + int getIConst() const { return iConst; } + float getFConst() const { return fConst; } + bool getBConst() const { return bConst; } + + bool operator==(const int i) const + { + return i == iConst; + } + + bool operator==(const float f) const + { + return f == fConst; + } + + bool operator==(const bool b) const + { + return b == bConst; + } + + bool operator==(const ConstantUnion& constant) const + { + if (constant.type != type) + return false; + + switch (type) { + case EbtInt: + return constant.iConst == iConst; + case EbtFloat: + return constant.fConst == fConst; + case EbtBool: + return constant.bConst == bConst; + default: + return false; + } + } + + bool operator!=(const int i) const + { + return !operator==(i); + } + + bool operator!=(const float f) const + { + return !operator==(f); + } + + bool operator!=(const bool b) const + { + return !operator==(b); + } + + bool operator!=(const ConstantUnion& constant) const + { + return !operator==(constant); + } + + bool operator>(const ConstantUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + return iConst > constant.iConst; + case EbtFloat: + return fConst > constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + } + + bool operator<(const ConstantUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + return iConst < constant.iConst; + case EbtFloat: + return fConst < constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + } + + ConstantUnion operator+(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator-(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator*(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator%(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator>>(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator<<(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator&(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator|(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator^(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator&&(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst && constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator||(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst || constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + TBasicType getType() const { return type; } +private: + + union { + int iConst; // used for ivec, scalar ints + bool bConst; // used for bvec, scalar bools + float fConst; // used for vec, mat, scalar floats + } ; + + TBasicType type; +}; + +#endif // _CONSTANT_UNION_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp new file mode 100644 index 0000000000..472232a75d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp @@ -0,0 +1,119 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Contains analysis utilities for dealing with HLSL's lack of support for +// the use of intrinsic functions which (implicitly or explicitly) compute +// gradients of functions with discontinuities. +// + +#include "compiler/DetectDiscontinuity.h" + +#include "compiler/ParseHelper.h" + +namespace sh +{ +bool DetectLoopDiscontinuity::traverse(TIntermNode *node) +{ + mLoopDiscontinuity = false; + node->traverse(this); + return mLoopDiscontinuity; +} + +bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node) +{ + if (mLoopDiscontinuity) + { + return false; + } + + switch (node->getFlowOp()) + { + case EOpKill: + break; + case EOpBreak: + case EOpContinue: + mLoopDiscontinuity = true; + case EOpReturn: + break; + default: UNREACHABLE(); + } + + return !mLoopDiscontinuity; +} + +bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node) +{ + return !mLoopDiscontinuity; +} + +bool containsLoopDiscontinuity(TIntermNode *node) +{ + DetectLoopDiscontinuity detectLoopDiscontinuity; + return detectLoopDiscontinuity.traverse(node); +} + +bool DetectGradientOperation::traverse(TIntermNode *node) +{ + mGradientOperation = false; + node->traverse(this); + return mGradientOperation; +} + +bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mGradientOperation) + { + return false; + } + + switch (node->getOp()) + { + case EOpDFdx: + case EOpDFdy: + mGradientOperation = true; + default: + break; + } + + return !mGradientOperation; +} + +bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mGradientOperation) + { + return false; + } + + if (node->getOp() == EOpFunctionCall) + { + if (!node->isUserDefined()) + { + TString name = TFunction::unmangleName(node->getName()); + + if (name == "texture2D" || + name == "texture2DProj" || + name == "textureCube") + { + mGradientOperation = true; + } + } + else + { + // When a user defined function is called, we have to + // conservatively assume it to contain gradient operations + mGradientOperation = true; + } + } + + return !mGradientOperation; +} + +bool containsGradientOperation(TIntermNode *node) +{ + DetectGradientOperation detectGradientOperation; + return detectGradientOperation.traverse(node); +} +} diff --git a/src/3rdparty/angle/src/compiler/DetectDiscontinuity.h b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.h new file mode 100644 index 0000000000..8bda4c3dea --- /dev/null +++ b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Contains analysis utilities for dealing with HLSL's lack of support for +// the use of intrinsic functions which (implicitly or explicitly) compute +// gradients of functions with discontinuities. +// + +#ifndef COMPILER_DETECTDISCONTINUITY_H_ +#define COMPILER_DETECTDISCONTINUITY_H_ + +#include "compiler/intermediate.h" + +namespace sh +{ +// Checks whether a loop can run for a variable number of iterations +class DetectLoopDiscontinuity : public TIntermTraverser +{ + public: + bool traverse(TIntermNode *node); + + protected: + bool visitBranch(Visit visit, TIntermBranch *node); + bool visitAggregate(Visit visit, TIntermAggregate *node); + + bool mLoopDiscontinuity; +}; + +bool containsLoopDiscontinuity(TIntermNode *node); + +// Checks for intrinsic functions which compute gradients +class DetectGradientOperation : public TIntermTraverser +{ + public: + bool traverse(TIntermNode *node); + + protected: + bool visitUnary(Visit visit, TIntermUnary *node); + bool visitAggregate(Visit visit, TIntermAggregate *node); + + bool mGradientOperation; +}; + +bool containsGradientOperation(TIntermNode *node); + +} + +#endif // COMPILER_DETECTDISCONTINUITY_H_ diff --git a/src/3rdparty/angle/src/compiler/DetectRecursion.cpp b/src/3rdparty/angle/src/compiler/DetectRecursion.cpp new file mode 100644 index 0000000000..c09780dd92 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/DetectRecursion.cpp @@ -0,0 +1,125 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/DetectRecursion.h" + +DetectRecursion::FunctionNode::FunctionNode(const TString& fname) + : name(fname), + visit(PreVisit) +{ +} + +const TString& DetectRecursion::FunctionNode::getName() const +{ + return name; +} + +void DetectRecursion::FunctionNode::addCallee( + DetectRecursion::FunctionNode* callee) +{ + for (size_t i = 0; i < callees.size(); ++i) { + if (callees[i] == callee) + return; + } + callees.push_back(callee); +} + +bool DetectRecursion::FunctionNode::detectRecursion() +{ + ASSERT(visit == PreVisit); + visit = InVisit; + for (size_t i = 0; i < callees.size(); ++i) { + switch (callees[i]->visit) { + case InVisit: + // cycle detected, i.e., recursion detected. + return true; + case PostVisit: + break; + case PreVisit: { + bool recursion = callees[i]->detectRecursion(); + if (recursion) + return true; + break; + } + default: + UNREACHABLE(); + break; + } + } + visit = PostVisit; + return false; +} + +DetectRecursion::DetectRecursion() + : currentFunction(NULL) +{ +} + +DetectRecursion::~DetectRecursion() +{ + for (size_t i = 0; i < functions.size(); ++i) + delete functions[i]; +} + +bool DetectRecursion::visitAggregate(Visit visit, TIntermAggregate* node) +{ + switch (node->getOp()) + { + case EOpPrototype: + // Function declaration. + // Don't add FunctionNode here because node->getName() is the + // unmangled function name. + break; + case EOpFunction: { + // Function definition. + if (visit == PreVisit) { + currentFunction = findFunctionByName(node->getName()); + if (currentFunction == NULL) { + currentFunction = new FunctionNode(node->getName()); + functions.push_back(currentFunction); + } + } + break; + } + case EOpFunctionCall: { + // Function call. + if (visit == PreVisit) { + ASSERT(currentFunction != NULL); + FunctionNode* func = findFunctionByName(node->getName()); + if (func == NULL) { + func = new FunctionNode(node->getName()); + functions.push_back(func); + } + currentFunction->addCallee(func); + } + break; + } + default: + break; + } + return true; +} + +DetectRecursion::ErrorCode DetectRecursion::detectRecursion() +{ + FunctionNode* main = findFunctionByName("main("); + if (main == NULL) + return kErrorMissingMain; + if (main->detectRecursion()) + return kErrorRecursion; + return kErrorNone; +} + +DetectRecursion::FunctionNode* DetectRecursion::findFunctionByName( + const TString& name) +{ + for (size_t i = 0; i < functions.size(); ++i) { + if (functions[i]->getName() == name) + return functions[i]; + } + return NULL; +} + diff --git a/src/3rdparty/angle/src/compiler/DetectRecursion.h b/src/3rdparty/angle/src/compiler/DetectRecursion.h new file mode 100644 index 0000000000..bbac79dc9c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/DetectRecursion.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DETECT_RECURSION_H_ +#define COMPILER_DETECT_RECURSION_H_ + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/intermediate.h" +#include "compiler/VariableInfo.h" + +// Traverses intermediate tree to detect function recursion. +class DetectRecursion : public TIntermTraverser { +public: + enum ErrorCode { + kErrorMissingMain, + kErrorRecursion, + kErrorNone + }; + + DetectRecursion(); + ~DetectRecursion(); + + virtual bool visitAggregate(Visit, TIntermAggregate*); + + ErrorCode detectRecursion(); + +private: + class FunctionNode { + public: + FunctionNode(const TString& fname); + + const TString& getName() const; + + // If a function is already in the callee list, this becomes a no-op. + void addCallee(FunctionNode* callee); + + // Return true if recursive function calls are detected. + bool detectRecursion(); + + private: + // mangled function name is unique. + TString name; + + // functions that are directly called by this function. + TVector callees; + + Visit visit; + }; + + FunctionNode* findFunctionByName(const TString& name); + + TVector functions; + FunctionNode* currentFunction; +}; + +#endif // COMPILER_DETECT_RECURSION_H_ diff --git a/src/3rdparty/angle/src/compiler/Diagnostics.cpp b/src/3rdparty/angle/src/compiler/Diagnostics.cpp new file mode 100644 index 0000000000..8aa1cb6b24 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Diagnostics.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/Diagnostics.h" + +#include "compiler/debug.h" +#include "compiler/InfoSink.h" +#include "compiler/preprocessor/new/SourceLocation.h" + +TDiagnostics::TDiagnostics(TInfoSink& infoSink) : + mInfoSink(infoSink), + mNumErrors(0), + mNumWarnings(0) +{ +} + +TDiagnostics::~TDiagnostics() +{ +} + +void TDiagnostics::writeInfo(Severity severity, + const pp::SourceLocation& loc, + const std::string& reason, + const std::string& token, + const std::string& extra) +{ + TPrefixType prefix = EPrefixNone; + switch (severity) + { + case ERROR: + ++mNumErrors; + prefix = EPrefixError; + break; + case WARNING: + ++mNumWarnings; + prefix = EPrefixWarning; + break; + default: + UNREACHABLE(); + break; + } + + TInfoSinkBase& sink = mInfoSink.info; + /* VC++ format: file(linenum) : error #: 'token' : extrainfo */ + sink.prefix(prefix); + sink.location(EncodeSourceLoc(loc.file, loc.line)); + sink << "'" << token << "' : " << reason << " " << extra << "\n"; +} + +void TDiagnostics::writeDebug(const std::string& str) +{ + mInfoSink.debug << str; +} + +void TDiagnostics::print(ID id, + const pp::SourceLocation& loc, + const std::string& text) +{ + writeInfo(severity(id), loc, message(id), text, ""); +} diff --git a/src/3rdparty/angle/src/compiler/Diagnostics.h b/src/3rdparty/angle/src/compiler/Diagnostics.h new file mode 100644 index 0000000000..3670414b03 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Diagnostics.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DIAGNOSTICS_H_ +#define COMPILER_DIAGNOSTICS_H_ + +#include "compiler/preprocessor/new/Diagnostics.h" + +class TInfoSink; + +class TDiagnostics : public pp::Diagnostics +{ + public: + TDiagnostics(TInfoSink& infoSink); + virtual ~TDiagnostics(); + + TInfoSink& infoSink() { return mInfoSink; } + + int numErrors() const { return mNumErrors; } + int numWarnings() const { return mNumWarnings; } + + void writeInfo(Severity severity, + const pp::SourceLocation& loc, + const std::string& reason, + const std::string& token, + const std::string& extra); + + void writeDebug(const std::string& str); + + protected: + virtual void print(ID id, + const pp::SourceLocation& loc, + const std::string& text); + + private: + TInfoSink& mInfoSink; + int mNumErrors; + int mNumWarnings; +}; + +#endif // COMPILER_DIAGNOSTICS_H_ diff --git a/src/3rdparty/angle/src/compiler/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/DirectiveHandler.cpp new file mode 100644 index 0000000000..d1f6ab3af5 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/DirectiveHandler.cpp @@ -0,0 +1,161 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/DirectiveHandler.h" + +#include + +#include "compiler/debug.h" +#include "compiler/Diagnostics.h" + +static TBehavior getBehavior(const std::string& str) +{ + static const std::string kRequire("require"); + static const std::string kEnable("enable"); + static const std::string kDisable("disable"); + static const std::string kWarn("warn"); + + if (str == kRequire) return EBhRequire; + else if (str == kEnable) return EBhEnable; + else if (str == kDisable) return EBhDisable; + else if (str == kWarn) return EBhWarn; + return EBhUndefined; +} + +TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior, + TDiagnostics& diagnostics) + : mExtensionBehavior(extBehavior), + mDiagnostics(diagnostics) +{ +} + +TDirectiveHandler::~TDirectiveHandler() +{ +} + +void TDirectiveHandler::handleError(const pp::SourceLocation& loc, + const std::string& msg) +{ + mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, msg, "", ""); +} + +void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, + const std::string& name, + const std::string& value) +{ + static const std::string kSTDGL("STDGL"); + static const std::string kOptimize("optimize"); + static const std::string kDebug("debug"); + static const std::string kOn("on"); + static const std::string kOff("off"); + + bool invalidValue = false; + if (name == kSTDGL) + { + // The STDGL pragma is used to reserve pragmas for use by future + // revisions of GLSL. Ignore it. + return; + } + else if (name == kOptimize) + { + if (value == kOn) mPragma.optimize = true; + else if (value == kOff) mPragma.optimize = false; + else invalidValue = true; + } + else if (name == kDebug) + { + if (value == kOn) mPragma.debug = true; + else if (value == kOff) mPragma.debug = false; + else invalidValue = true; + } + else + { + mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name); + return; + } + + if (invalidValue) + mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, + "invalid pragma value", value, + "'on' or 'off' expected"); +} + +void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, + const std::string& name, + const std::string& behavior) +{ + static const std::string kExtAll("all"); + + TBehavior behaviorVal = getBehavior(behavior); + if (behaviorVal == EBhUndefined) + { + mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, + "behavior", name, "invalid"); + return; + } + + if (name == kExtAll) + { + if (behaviorVal == EBhRequire) + { + mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, + "extension", name, + "cannot have 'require' behavior"); + } + else if (behaviorVal == EBhEnable) + { + mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, + "extension", name, + "cannot have 'enable' behavior"); + } + else + { + for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin(); + iter != mExtensionBehavior.end(); ++iter) + iter->second = behaviorVal; + } + return; + } + + TExtensionBehavior::iterator iter = mExtensionBehavior.find(name); + if (iter != mExtensionBehavior.end()) + { + iter->second = behaviorVal; + return; + } + + pp::Diagnostics::Severity severity = pp::Diagnostics::ERROR; + switch (behaviorVal) { + case EBhRequire: + severity = pp::Diagnostics::ERROR; + break; + case EBhEnable: + case EBhWarn: + case EBhDisable: + severity = pp::Diagnostics::WARNING; + break; + default: + UNREACHABLE(); + break; + } + mDiagnostics.writeInfo(severity, loc, + "extension", name, "is not supported"); +} + +void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc, + int version) +{ + static const int kVersion = 100; + + if (version != kVersion) + { + std::stringstream stream; + stream << version; + std::string str = stream.str(); + mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, + "version number", str, "not supported"); + } +} diff --git a/src/3rdparty/angle/src/compiler/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/DirectiveHandler.h new file mode 100644 index 0000000000..21d3dfc315 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/DirectiveHandler.h @@ -0,0 +1,46 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DIRECTIVE_HANDLER_H_ +#define COMPILER_DIRECTIVE_HANDLER_H_ + +#include "compiler/ExtensionBehavior.h" +#include "compiler/Pragma.h" +#include "compiler/preprocessor/new/DirectiveHandler.h" + +class TDiagnostics; + +class TDirectiveHandler : public pp::DirectiveHandler +{ + public: + TDirectiveHandler(TExtensionBehavior& extBehavior, + TDiagnostics& diagnostics); + virtual ~TDirectiveHandler(); + + const TPragma& pragma() const { return mPragma; } + const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; } + + virtual void handleError(const pp::SourceLocation& loc, + const std::string& msg); + + virtual void handlePragma(const pp::SourceLocation& loc, + const std::string& name, + const std::string& value); + + virtual void handleExtension(const pp::SourceLocation& loc, + const std::string& name, + const std::string& behavior); + + virtual void handleVersion(const pp::SourceLocation& loc, + int version); + + private: + TPragma mPragma; + TExtensionBehavior& mExtensionBehavior; + TDiagnostics& mDiagnostics; +}; + +#endif // COMPILER_DIRECTIVE_HANDLER_H_ diff --git a/src/3rdparty/angle/src/compiler/ExtensionBehavior.h b/src/3rdparty/angle/src/compiler/ExtensionBehavior.h new file mode 100644 index 0000000000..6040980837 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ExtensionBehavior.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _EXTENSION_BEHAVIOR_INCLUDED_ +#define _EXTENSION_BEHAVIOR_INCLUDED_ + +#include +#include + +typedef enum +{ + EBhRequire, + EBhEnable, + EBhWarn, + EBhDisable, + EBhUndefined, +} TBehavior; + +inline const char* getBehaviorString(TBehavior b) +{ + switch(b) + { + case EBhRequire: return "require"; + case EBhEnable: return "enable"; + case EBhWarn: return "warn"; + case EBhDisable: return "disable"; + default: return NULL; + } +} + +// Mapping between extension name and behavior. +typedef std::map TExtensionBehavior; + +#endif // _EXTENSION_TABLE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp b/src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp new file mode 100644 index 0000000000..fdc3f44431 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp @@ -0,0 +1,215 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/ForLoopUnroll.h" + +namespace { + +class IntegerForLoopUnrollMarker : public TIntermTraverser { +public: + + virtual bool visitLoop(Visit, TIntermLoop* node) + { + // This is called after ValidateLimitations pass, so all the ASSERT + // should never fail. + // See ValidateLimitations::validateForLoopInit(). + ASSERT(node); + ASSERT(node->getType() == ELoopFor); + ASSERT(node->getInit()); + TIntermAggregate* decl = node->getInit()->getAsAggregate(); + ASSERT(decl && decl->getOp() == EOpDeclaration); + TIntermSequence& declSeq = decl->getSequence(); + ASSERT(declSeq.size() == 1); + TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); + ASSERT(declInit && declInit->getOp() == EOpInitialize); + ASSERT(declInit->getLeft()); + TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); + ASSERT(symbol); + TBasicType type = symbol->getBasicType(); + ASSERT(type == EbtInt || type == EbtFloat); + if (type == EbtInt) + node->setUnrollFlag(true); + return true; + } + +}; + +} // anonymous namepsace + +void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info) +{ + ASSERT(node->getType() == ELoopFor); + ASSERT(node->getUnrollFlag()); + + TIntermNode* init = node->getInit(); + ASSERT(init != NULL); + TIntermAggregate* decl = init->getAsAggregate(); + ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration)); + TIntermSequence& declSeq = decl->getSequence(); + ASSERT(declSeq.size() == 1); + TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); + ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize)); + TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); + ASSERT(symbol != NULL); + ASSERT(symbol->getBasicType() == EbtInt); + + info.id = symbol->getId(); + + ASSERT(declInit->getRight() != NULL); + TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); + ASSERT(initNode != NULL); + + info.initValue = evaluateIntConstant(initNode); + info.currentValue = info.initValue; + + TIntermNode* cond = node->getCondition(); + ASSERT(cond != NULL); + TIntermBinary* binOp = cond->getAsBinaryNode(); + ASSERT(binOp != NULL); + ASSERT(binOp->getRight() != NULL); + ASSERT(binOp->getRight()->getAsConstantUnion() != NULL); + + info.incrementValue = getLoopIncrement(node); + info.stopValue = evaluateIntConstant( + binOp->getRight()->getAsConstantUnion()); + info.op = binOp->getOp(); +} + +void ForLoopUnroll::Step() +{ + ASSERT(mLoopIndexStack.size() > 0); + TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1]; + info.currentValue += info.incrementValue; +} + +bool ForLoopUnroll::SatisfiesLoopCondition() +{ + ASSERT(mLoopIndexStack.size() > 0); + TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1]; + // Relational operator is one of: > >= < <= == or !=. + switch (info.op) { + case EOpEqual: + return (info.currentValue == info.stopValue); + case EOpNotEqual: + return (info.currentValue != info.stopValue); + case EOpLessThan: + return (info.currentValue < info.stopValue); + case EOpGreaterThan: + return (info.currentValue > info.stopValue); + case EOpLessThanEqual: + return (info.currentValue <= info.stopValue); + case EOpGreaterThanEqual: + return (info.currentValue >= info.stopValue); + default: + UNREACHABLE(); + } + return false; +} + +bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol) +{ + for (TVector::iterator i = mLoopIndexStack.begin(); + i != mLoopIndexStack.end(); + ++i) { + if (i->id == symbol->getId()) + return true; + } + return false; +} + +int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol) +{ + for (TVector::iterator i = mLoopIndexStack.begin(); + i != mLoopIndexStack.end(); + ++i) { + if (i->id == symbol->getId()) + return i->currentValue; + } + UNREACHABLE(); + return false; +} + +void ForLoopUnroll::Push(TLoopIndexInfo& info) +{ + mLoopIndexStack.push_back(info); +} + +void ForLoopUnroll::Pop() +{ + mLoopIndexStack.pop_back(); +} + +// static +void ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling( + TIntermNode* root) +{ + ASSERT(root); + + IntegerForLoopUnrollMarker marker; + root->traverse(&marker); +} + +int ForLoopUnroll::getLoopIncrement(TIntermLoop* node) +{ + TIntermNode* expr = node->getExpression(); + ASSERT(expr != NULL); + // for expression has one of the following forms: + // loop_index++ + // loop_index-- + // loop_index += constant_expression + // loop_index -= constant_expression + // ++loop_index + // --loop_index + // The last two forms are not specified in the spec, but I am assuming + // its an oversight. + TIntermUnary* unOp = expr->getAsUnaryNode(); + TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode(); + + TOperator op = EOpNull; + TIntermConstantUnion* incrementNode = NULL; + if (unOp != NULL) { + op = unOp->getOp(); + } else if (binOp != NULL) { + op = binOp->getOp(); + ASSERT(binOp->getRight() != NULL); + incrementNode = binOp->getRight()->getAsConstantUnion(); + ASSERT(incrementNode != NULL); + } + + int increment = 0; + // The operator is one of: ++ -- += -=. + switch (op) { + case EOpPostIncrement: + case EOpPreIncrement: + ASSERT((unOp != NULL) && (binOp == NULL)); + increment = 1; + break; + case EOpPostDecrement: + case EOpPreDecrement: + ASSERT((unOp != NULL) && (binOp == NULL)); + increment = -1; + break; + case EOpAddAssign: + ASSERT((unOp == NULL) && (binOp != NULL)); + increment = evaluateIntConstant(incrementNode); + break; + case EOpSubAssign: + ASSERT((unOp == NULL) && (binOp != NULL)); + increment = - evaluateIntConstant(incrementNode); + break; + default: + ASSERT(false); + } + + return increment; +} + +int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node) +{ + ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL)); + return node->getUnionArrayPointer()->getIConst(); +} + diff --git a/src/3rdparty/angle/src/compiler/ForLoopUnroll.h b/src/3rdparty/angle/src/compiler/ForLoopUnroll.h new file mode 100644 index 0000000000..e800e25b1f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ForLoopUnroll.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/intermediate.h" + +struct TLoopIndexInfo { + int id; + int initValue; + int stopValue; + int incrementValue; + TOperator op; + int currentValue; +}; + +class ForLoopUnroll { +public: + ForLoopUnroll() { } + + void FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info); + + // Update the info.currentValue for the next loop iteration. + void Step(); + + // Return false if loop condition is no longer satisfied. + bool SatisfiesLoopCondition(); + + // Check if the symbol is the index of a loop that's unrolled. + bool NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol); + + // Return the current value of a given loop index symbol. + int GetLoopIndexValue(TIntermSymbol* symbol); + + void Push(TLoopIndexInfo& info); + void Pop(); + + static void MarkForLoopsWithIntegerIndicesForUnrolling(TIntermNode* root); + +private: + int getLoopIncrement(TIntermLoop* node); + + int evaluateIntConstant(TIntermConstantUnion* node); + + TVector mLoopIndexStack; +}; + diff --git a/src/3rdparty/angle/src/compiler/InfoSink.cpp b/src/3rdparty/angle/src/compiler/InfoSink.cpp new file mode 100644 index 0000000000..ba32f781f5 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/InfoSink.cpp @@ -0,0 +1,59 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/InfoSink.h" + +void TInfoSinkBase::prefix(TPrefixType message) { + switch(message) { + case EPrefixNone: + break; + case EPrefixWarning: + sink.append("WARNING: "); + break; + case EPrefixError: + sink.append("ERROR: "); + break; + case EPrefixInternalError: + sink.append("INTERNAL ERROR: "); + break; + case EPrefixUnimplemented: + sink.append("UNIMPLEMENTED: "); + break; + case EPrefixNote: + sink.append("NOTE: "); + break; + default: + sink.append("UNKOWN ERROR: "); + break; + } +} + +void TInfoSinkBase::location(TSourceLoc loc) { + int string = 0, line = 0; + DecodeSourceLoc(loc, &string, &line); + + TPersistStringStream stream; + if (line) + stream << string << ":" << line; + else + stream << string << ":? "; + stream << ": "; + + sink.append(stream.str()); +} + +void TInfoSinkBase::message(TPrefixType message, const char* s) { + prefix(message); + sink.append(s); + sink.append("\n"); +} + +void TInfoSinkBase::message(TPrefixType message, const char* s, TSourceLoc loc) { + prefix(message); + location(loc); + sink.append(s); + sink.append("\n"); +} diff --git a/src/3rdparty/angle/src/compiler/InfoSink.h b/src/3rdparty/angle/src/compiler/InfoSink.h new file mode 100644 index 0000000000..e2224e918d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/InfoSink.h @@ -0,0 +1,115 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _INFOSINK_INCLUDED_ +#define _INFOSINK_INCLUDED_ + +#include +#include "compiler/Common.h" + +// Returns the fractional part of the given floating-point number. +inline float fractionalPart(float f) { + float intPart = 0.0f; + return modff(f, &intPart); +} + +// +// TPrefixType is used to centralize how info log messages start. +// See below. +// +enum TPrefixType { + EPrefixNone, + EPrefixWarning, + EPrefixError, + EPrefixInternalError, + EPrefixUnimplemented, + EPrefixNote +}; + +// +// Encapsulate info logs for all objects that have them. +// +// The methods are a general set of tools for getting a variety of +// messages and types inserted into the log. +// +class TInfoSinkBase { +public: + TInfoSinkBase() {} + + template + TInfoSinkBase& operator<<(const T& t) { + TPersistStringStream stream; + stream << t; + sink.append(stream.str()); + return *this; + } + // Override << operator for specific types. It is faster to append strings + // and characters directly to the sink. + TInfoSinkBase& operator<<(char c) { + sink.append(1, c); + return *this; + } + TInfoSinkBase& operator<<(const char* str) { + sink.append(str); + return *this; + } + TInfoSinkBase& operator<<(const TPersistString& str) { + sink.append(str); + return *this; + } + TInfoSinkBase& operator<<(const TString& str) { + sink.append(str.c_str()); + return *this; + } + // Make sure floats are written with correct precision. + TInfoSinkBase& operator<<(float f) { + // Make sure that at least one decimal point is written. If a number + // does not have a fractional part, the default precision format does + // not write the decimal portion which gets interpreted as integer by + // the compiler. + TPersistStringStream stream; + if (fractionalPart(f) == 0.0f) { + stream.precision(1); + stream << std::showpoint << std::fixed << f; + } else { + stream.unsetf(std::ios::fixed); + stream.unsetf(std::ios::scientific); + stream.precision(8); + stream << f; + } + sink.append(stream.str()); + return *this; + } + // Write boolean values as their names instead of integral value. + TInfoSinkBase& operator<<(bool b) { + const char* str = b ? "true" : "false"; + sink.append(str); + return *this; + } + + void erase() { sink.clear(); } + int size() { return static_cast(sink.size()); } + + const TPersistString& str() const { return sink; } + const char* c_str() const { return sink.c_str(); } + + void prefix(TPrefixType message); + void location(TSourceLoc loc); + void message(TPrefixType message, const char* s); + void message(TPrefixType message, const char* s, TSourceLoc loc); + +private: + TPersistString sink; +}; + +class TInfoSink { +public: + TInfoSinkBase info; + TInfoSinkBase debug; + TInfoSinkBase obj; +}; + +#endif // _INFOSINK_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/Initialize.cpp b/src/3rdparty/angle/src/compiler/Initialize.cpp new file mode 100644 index 0000000000..3e94ce7ba8 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Initialize.cpp @@ -0,0 +1,657 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Create strings that declare built-in definitions, add built-ins that +// cannot be expressed in the files, and establish mappings between +// built-in functions and operators. +// + +#include "compiler/Initialize.h" + +#include "compiler/intermediate.h" + +//============================================================================ +// +// Prototypes for built-in functions seen by both vertex and fragment shaders. +// +//============================================================================ +static TString BuiltInFunctionsCommon(const ShBuiltInResources& resources) +{ + TString s; + + // + // Angle and Trigonometric Functions. + // + s.append(TString("float radians(float degrees);")); + s.append(TString("vec2 radians(vec2 degrees);")); + s.append(TString("vec3 radians(vec3 degrees);")); + s.append(TString("vec4 radians(vec4 degrees);")); + + s.append(TString("float degrees(float radians);")); + s.append(TString("vec2 degrees(vec2 radians);")); + s.append(TString("vec3 degrees(vec3 radians);")); + s.append(TString("vec4 degrees(vec4 radians);")); + + s.append(TString("float sin(float angle);")); + s.append(TString("vec2 sin(vec2 angle);")); + s.append(TString("vec3 sin(vec3 angle);")); + s.append(TString("vec4 sin(vec4 angle);")); + + s.append(TString("float cos(float angle);")); + s.append(TString("vec2 cos(vec2 angle);")); + s.append(TString("vec3 cos(vec3 angle);")); + s.append(TString("vec4 cos(vec4 angle);")); + + s.append(TString("float tan(float angle);")); + s.append(TString("vec2 tan(vec2 angle);")); + s.append(TString("vec3 tan(vec3 angle);")); + s.append(TString("vec4 tan(vec4 angle);")); + + s.append(TString("float asin(float x);")); + s.append(TString("vec2 asin(vec2 x);")); + s.append(TString("vec3 asin(vec3 x);")); + s.append(TString("vec4 asin(vec4 x);")); + + s.append(TString("float acos(float x);")); + s.append(TString("vec2 acos(vec2 x);")); + s.append(TString("vec3 acos(vec3 x);")); + s.append(TString("vec4 acos(vec4 x);")); + + s.append(TString("float atan(float y, float x);")); + s.append(TString("vec2 atan(vec2 y, vec2 x);")); + s.append(TString("vec3 atan(vec3 y, vec3 x);")); + s.append(TString("vec4 atan(vec4 y, vec4 x);")); + + s.append(TString("float atan(float y_over_x);")); + s.append(TString("vec2 atan(vec2 y_over_x);")); + s.append(TString("vec3 atan(vec3 y_over_x);")); + s.append(TString("vec4 atan(vec4 y_over_x);")); + + // + // Exponential Functions. + // + s.append(TString("float pow(float x, float y);")); + s.append(TString("vec2 pow(vec2 x, vec2 y);")); + s.append(TString("vec3 pow(vec3 x, vec3 y);")); + s.append(TString("vec4 pow(vec4 x, vec4 y);")); + + s.append(TString("float exp(float x);")); + s.append(TString("vec2 exp(vec2 x);")); + s.append(TString("vec3 exp(vec3 x);")); + s.append(TString("vec4 exp(vec4 x);")); + + s.append(TString("float log(float x);")); + s.append(TString("vec2 log(vec2 x);")); + s.append(TString("vec3 log(vec3 x);")); + s.append(TString("vec4 log(vec4 x);")); + + s.append(TString("float exp2(float x);")); + s.append(TString("vec2 exp2(vec2 x);")); + s.append(TString("vec3 exp2(vec3 x);")); + s.append(TString("vec4 exp2(vec4 x);")); + + s.append(TString("float log2(float x);")); + s.append(TString("vec2 log2(vec2 x);")); + s.append(TString("vec3 log2(vec3 x);")); + s.append(TString("vec4 log2(vec4 x);")); + + s.append(TString("float sqrt(float x);")); + s.append(TString("vec2 sqrt(vec2 x);")); + s.append(TString("vec3 sqrt(vec3 x);")); + s.append(TString("vec4 sqrt(vec4 x);")); + + s.append(TString("float inversesqrt(float x);")); + s.append(TString("vec2 inversesqrt(vec2 x);")); + s.append(TString("vec3 inversesqrt(vec3 x);")); + s.append(TString("vec4 inversesqrt(vec4 x);")); + + // + // Common Functions. + // + s.append(TString("float abs(float x);")); + s.append(TString("vec2 abs(vec2 x);")); + s.append(TString("vec3 abs(vec3 x);")); + s.append(TString("vec4 abs(vec4 x);")); + + s.append(TString("float sign(float x);")); + s.append(TString("vec2 sign(vec2 x);")); + s.append(TString("vec3 sign(vec3 x);")); + s.append(TString("vec4 sign(vec4 x);")); + + s.append(TString("float floor(float x);")); + s.append(TString("vec2 floor(vec2 x);")); + s.append(TString("vec3 floor(vec3 x);")); + s.append(TString("vec4 floor(vec4 x);")); + + s.append(TString("float ceil(float x);")); + s.append(TString("vec2 ceil(vec2 x);")); + s.append(TString("vec3 ceil(vec3 x);")); + s.append(TString("vec4 ceil(vec4 x);")); + + s.append(TString("float fract(float x);")); + s.append(TString("vec2 fract(vec2 x);")); + s.append(TString("vec3 fract(vec3 x);")); + s.append(TString("vec4 fract(vec4 x);")); + + s.append(TString("float mod(float x, float y);")); + s.append(TString("vec2 mod(vec2 x, float y);")); + s.append(TString("vec3 mod(vec3 x, float y);")); + s.append(TString("vec4 mod(vec4 x, float y);")); + s.append(TString("vec2 mod(vec2 x, vec2 y);")); + s.append(TString("vec3 mod(vec3 x, vec3 y);")); + s.append(TString("vec4 mod(vec4 x, vec4 y);")); + + s.append(TString("float min(float x, float y);")); + s.append(TString("vec2 min(vec2 x, float y);")); + s.append(TString("vec3 min(vec3 x, float y);")); + s.append(TString("vec4 min(vec4 x, float y);")); + s.append(TString("vec2 min(vec2 x, vec2 y);")); + s.append(TString("vec3 min(vec3 x, vec3 y);")); + s.append(TString("vec4 min(vec4 x, vec4 y);")); + + s.append(TString("float max(float x, float y);")); + s.append(TString("vec2 max(vec2 x, float y);")); + s.append(TString("vec3 max(vec3 x, float y);")); + s.append(TString("vec4 max(vec4 x, float y);")); + s.append(TString("vec2 max(vec2 x, vec2 y);")); + s.append(TString("vec3 max(vec3 x, vec3 y);")); + s.append(TString("vec4 max(vec4 x, vec4 y);")); + + s.append(TString("float clamp(float x, float minVal, float maxVal);")); + s.append(TString("vec2 clamp(vec2 x, float minVal, float maxVal);")); + s.append(TString("vec3 clamp(vec3 x, float minVal, float maxVal);")); + s.append(TString("vec4 clamp(vec4 x, float minVal, float maxVal);")); + s.append(TString("vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal);")); + s.append(TString("vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal);")); + s.append(TString("vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal);")); + + s.append(TString("float mix(float x, float y, float a);")); + s.append(TString("vec2 mix(vec2 x, vec2 y, float a);")); + s.append(TString("vec3 mix(vec3 x, vec3 y, float a);")); + s.append(TString("vec4 mix(vec4 x, vec4 y, float a);")); + s.append(TString("vec2 mix(vec2 x, vec2 y, vec2 a);")); + s.append(TString("vec3 mix(vec3 x, vec3 y, vec3 a);")); + s.append(TString("vec4 mix(vec4 x, vec4 y, vec4 a);")); + + s.append(TString("float step(float edge, float x);")); + s.append(TString("vec2 step(vec2 edge, vec2 x);")); + s.append(TString("vec3 step(vec3 edge, vec3 x);")); + s.append(TString("vec4 step(vec4 edge, vec4 x);")); + s.append(TString("vec2 step(float edge, vec2 x);")); + s.append(TString("vec3 step(float edge, vec3 x);")); + s.append(TString("vec4 step(float edge, vec4 x);")); + + s.append(TString("float smoothstep(float edge0, float edge1, float x);")); + s.append(TString("vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x);")); + s.append(TString("vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x);")); + s.append(TString("vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x);")); + s.append(TString("vec2 smoothstep(float edge0, float edge1, vec2 x);")); + s.append(TString("vec3 smoothstep(float edge0, float edge1, vec3 x);")); + s.append(TString("vec4 smoothstep(float edge0, float edge1, vec4 x);")); + + // + // Geometric Functions. + // + s.append(TString("float length(float x);")); + s.append(TString("float length(vec2 x);")); + s.append(TString("float length(vec3 x);")); + s.append(TString("float length(vec4 x);")); + + s.append(TString("float distance(float p0, float p1);")); + s.append(TString("float distance(vec2 p0, vec2 p1);")); + s.append(TString("float distance(vec3 p0, vec3 p1);")); + s.append(TString("float distance(vec4 p0, vec4 p1);")); + + s.append(TString("float dot(float x, float y);")); + s.append(TString("float dot(vec2 x, vec2 y);")); + s.append(TString("float dot(vec3 x, vec3 y);")); + s.append(TString("float dot(vec4 x, vec4 y);")); + + s.append(TString("vec3 cross(vec3 x, vec3 y);")); + s.append(TString("float normalize(float x);")); + s.append(TString("vec2 normalize(vec2 x);")); + s.append(TString("vec3 normalize(vec3 x);")); + s.append(TString("vec4 normalize(vec4 x);")); + + s.append(TString("float faceforward(float N, float I, float Nref);")); + s.append(TString("vec2 faceforward(vec2 N, vec2 I, vec2 Nref);")); + s.append(TString("vec3 faceforward(vec3 N, vec3 I, vec3 Nref);")); + s.append(TString("vec4 faceforward(vec4 N, vec4 I, vec4 Nref);")); + + s.append(TString("float reflect(float I, float N);")); + s.append(TString("vec2 reflect(vec2 I, vec2 N);")); + s.append(TString("vec3 reflect(vec3 I, vec3 N);")); + s.append(TString("vec4 reflect(vec4 I, vec4 N);")); + + s.append(TString("float refract(float I, float N, float eta);")); + s.append(TString("vec2 refract(vec2 I, vec2 N, float eta);")); + s.append(TString("vec3 refract(vec3 I, vec3 N, float eta);")); + s.append(TString("vec4 refract(vec4 I, vec4 N, float eta);")); + + // + // Matrix Functions. + // + s.append(TString("mat2 matrixCompMult(mat2 x, mat2 y);")); + s.append(TString("mat3 matrixCompMult(mat3 x, mat3 y);")); + s.append(TString("mat4 matrixCompMult(mat4 x, mat4 y);")); + + // + // Vector relational functions. + // + s.append(TString("bvec2 lessThan(vec2 x, vec2 y);")); + s.append(TString("bvec3 lessThan(vec3 x, vec3 y);")); + s.append(TString("bvec4 lessThan(vec4 x, vec4 y);")); + + s.append(TString("bvec2 lessThan(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 lessThan(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 lessThan(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 lessThanEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 lessThanEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 lessThanEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 lessThanEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 lessThanEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 lessThanEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 greaterThan(vec2 x, vec2 y);")); + s.append(TString("bvec3 greaterThan(vec3 x, vec3 y);")); + s.append(TString("bvec4 greaterThan(vec4 x, vec4 y);")); + + s.append(TString("bvec2 greaterThan(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 greaterThan(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 greaterThan(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 greaterThanEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 greaterThanEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 greaterThanEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 greaterThanEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 greaterThanEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 greaterThanEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 equal(vec2 x, vec2 y);")); + s.append(TString("bvec3 equal(vec3 x, vec3 y);")); + s.append(TString("bvec4 equal(vec4 x, vec4 y);")); + + s.append(TString("bvec2 equal(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 equal(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 equal(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 equal(bvec2 x, bvec2 y);")); + s.append(TString("bvec3 equal(bvec3 x, bvec3 y);")); + s.append(TString("bvec4 equal(bvec4 x, bvec4 y);")); + + s.append(TString("bvec2 notEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 notEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 notEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 notEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 notEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 notEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 notEqual(bvec2 x, bvec2 y);")); + s.append(TString("bvec3 notEqual(bvec3 x, bvec3 y);")); + s.append(TString("bvec4 notEqual(bvec4 x, bvec4 y);")); + + s.append(TString("bool any(bvec2 x);")); + s.append(TString("bool any(bvec3 x);")); + s.append(TString("bool any(bvec4 x);")); + + s.append(TString("bool all(bvec2 x);")); + s.append(TString("bool all(bvec3 x);")); + s.append(TString("bool all(bvec4 x);")); + + s.append(TString("bvec2 not(bvec2 x);")); + s.append(TString("bvec3 not(bvec3 x);")); + s.append(TString("bvec4 not(bvec4 x);")); + + // + // Texture Functions. + // + s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord);")); + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord);")); + + if (resources.OES_EGL_image_external) { + s.append(TString("vec4 texture2D(samplerExternalOES sampler, vec2 coord);")); + s.append(TString("vec4 texture2DProj(samplerExternalOES sampler, vec3 coord);")); + s.append(TString("vec4 texture2DProj(samplerExternalOES sampler, vec4 coord);")); + } + + if (resources.ARB_texture_rectangle) { + s.append(TString("vec4 texture2DRect(sampler2DRect sampler, vec2 coord);")); + s.append(TString("vec4 texture2DRectProj(sampler2DRect sampler, vec3 coord);")); + s.append(TString("vec4 texture2DRectProj(sampler2DRect sampler, vec4 coord);")); + } + + // + // Noise functions. + // + //s.append(TString("float noise1(float x);")); + //s.append(TString("float noise1(vec2 x);")); + //s.append(TString("float noise1(vec3 x);")); + //s.append(TString("float noise1(vec4 x);")); + + //s.append(TString("vec2 noise2(float x);")); + //s.append(TString("vec2 noise2(vec2 x);")); + //s.append(TString("vec2 noise2(vec3 x);")); + //s.append(TString("vec2 noise2(vec4 x);")); + + //s.append(TString("vec3 noise3(float x);")); + //s.append(TString("vec3 noise3(vec2 x);")); + //s.append(TString("vec3 noise3(vec3 x);")); + //s.append(TString("vec3 noise3(vec4 x);")); + + //s.append(TString("vec4 noise4(float x);")); + //s.append(TString("vec4 noise4(vec2 x);")); + //s.append(TString("vec4 noise4(vec3 x);")); + //s.append(TString("vec4 noise4(vec4 x);")); + + return s; +} + +//============================================================================ +// +// Prototypes for built-in functions seen by vertex shaders only. +// +//============================================================================ +static TString BuiltInFunctionsVertex(const ShBuiltInResources& resources) +{ + TString s; + + // + // Geometric Functions. + // + //s.append(TString("vec4 ftransform();")); + + // + // Texture Functions. + // + s.append(TString("vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod);")); + s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod);")); + s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod);")); + s.append(TString("vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);")); + + return s; +} + +//============================================================================ +// +// Prototypes for built-in functions seen by fragment shaders only. +// +//============================================================================ +static TString BuiltInFunctionsFragment(const ShBuiltInResources& resources) +{ + TString s; + + // + // Texture Functions. + // + s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord, float bias);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias);")); + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord, float bias);")); + + if (resources.OES_standard_derivatives) { + s.append(TString("float dFdx(float p);")); + s.append(TString("vec2 dFdx(vec2 p);")); + s.append(TString("vec3 dFdx(vec3 p);")); + s.append(TString("vec4 dFdx(vec4 p);")); + + s.append(TString("float dFdy(float p);")); + s.append(TString("vec2 dFdy(vec2 p);")); + s.append(TString("vec3 dFdy(vec3 p);")); + s.append(TString("vec4 dFdy(vec4 p);")); + + s.append(TString("float fwidth(float p);")); + s.append(TString("vec2 fwidth(vec2 p);")); + s.append(TString("vec3 fwidth(vec3 p);")); + s.append(TString("vec4 fwidth(vec4 p);")); + } + + return s; +} + +//============================================================================ +// +// Standard uniforms. +// +//============================================================================ +static TString StandardUniforms() +{ + TString s; + + // + // Depth range in window coordinates + // + s.append(TString("struct gl_DepthRangeParameters {")); + s.append(TString(" highp float near;")); // n + s.append(TString(" highp float far;")); // f + s.append(TString(" highp float diff;")); // f - n + s.append(TString("};")); + s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;")); + + return s; +} + +//============================================================================ +// +// Default precision for vertex shaders. +// +//============================================================================ +static TString DefaultPrecisionVertex() +{ + TString s; + + s.append(TString("precision highp int;")); + s.append(TString("precision highp float;")); + + return s; +} + +//============================================================================ +// +// Default precision for fragment shaders. +// +//============================================================================ +static TString DefaultPrecisionFragment() +{ + TString s; + + s.append(TString("precision mediump int;")); + // No default precision for float in fragment shaders + + return s; +} + +//============================================================================ +// +// Implementation dependent built-in constants. +// +//============================================================================ +static TString BuiltInConstants(ShShaderSpec spec, const ShBuiltInResources &resources) +{ + TStringStream s; + + s << "const int gl_MaxVertexAttribs = " << resources.MaxVertexAttribs << ";"; + s << "const int gl_MaxVertexUniformVectors = " << resources.MaxVertexUniformVectors << ";"; + + s << "const int gl_MaxVaryingVectors = " << resources.MaxVaryingVectors << ";"; + s << "const int gl_MaxVertexTextureImageUnits = " << resources.MaxVertexTextureImageUnits << ";"; + s << "const int gl_MaxCombinedTextureImageUnits = " << resources.MaxCombinedTextureImageUnits << ";"; + s << "const int gl_MaxTextureImageUnits = " << resources.MaxTextureImageUnits << ";"; + s << "const int gl_MaxFragmentUniformVectors = " << resources.MaxFragmentUniformVectors << ";"; + + if (spec != SH_CSS_SHADERS_SPEC) + s << "const int gl_MaxDrawBuffers = " << resources.MaxDrawBuffers << ";"; + + return s.str(); +} + +void TBuiltIns::initialize(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources) +{ + switch (type) { + case SH_FRAGMENT_SHADER: + builtInStrings.push_back(DefaultPrecisionFragment()); + builtInStrings.push_back(BuiltInFunctionsCommon(resources)); + builtInStrings.push_back(BuiltInFunctionsFragment(resources)); + builtInStrings.push_back(StandardUniforms()); + break; + + case SH_VERTEX_SHADER: + builtInStrings.push_back(DefaultPrecisionVertex()); + builtInStrings.push_back(BuiltInFunctionsCommon(resources)); + builtInStrings.push_back(BuiltInFunctionsVertex(resources)); + builtInStrings.push_back(StandardUniforms()); + break; + + default: assert(false && "Language not supported"); + } + + builtInStrings.push_back(BuiltInConstants(spec, resources)); +} + +void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources, + TSymbolTable& symbolTable) +{ + // + // First, insert some special built-in variables that are not in + // the built-in header files. + // + switch(type) { + case SH_FRAGMENT_SHADER: + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); + + // + // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available. + // Instead, css_MixColor and css_ColorMatrix are available. + // + if (spec != SH_CSS_SHADERS_SPEC) { + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4))); + } else { + symbolTable.insert(*new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, true))); + } + + break; + + case SH_VERTEX_SHADER: + symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1))); + break; + + default: assert(false && "Language not supported"); + } + + // + // Next, identify which built-ins from the already loaded headers have + // a mapping to an operator. Those that are not identified as such are + // expected to be resolved through a library of functions, versus as + // operations. + // + symbolTable.relateToOperator("not", EOpVectorLogicalNot); + + symbolTable.relateToOperator("matrixCompMult", EOpMul); + + symbolTable.relateToOperator("equal", EOpVectorEqual); + symbolTable.relateToOperator("notEqual", EOpVectorNotEqual); + symbolTable.relateToOperator("lessThan", EOpLessThan); + symbolTable.relateToOperator("greaterThan", EOpGreaterThan); + symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual); + symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual); + + symbolTable.relateToOperator("radians", EOpRadians); + symbolTable.relateToOperator("degrees", EOpDegrees); + symbolTable.relateToOperator("sin", EOpSin); + symbolTable.relateToOperator("cos", EOpCos); + symbolTable.relateToOperator("tan", EOpTan); + symbolTable.relateToOperator("asin", EOpAsin); + symbolTable.relateToOperator("acos", EOpAcos); + symbolTable.relateToOperator("atan", EOpAtan); + + symbolTable.relateToOperator("pow", EOpPow); + symbolTable.relateToOperator("exp2", EOpExp2); + symbolTable.relateToOperator("log", EOpLog); + symbolTable.relateToOperator("exp", EOpExp); + symbolTable.relateToOperator("log2", EOpLog2); + symbolTable.relateToOperator("sqrt", EOpSqrt); + symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt); + + symbolTable.relateToOperator("abs", EOpAbs); + symbolTable.relateToOperator("sign", EOpSign); + symbolTable.relateToOperator("floor", EOpFloor); + symbolTable.relateToOperator("ceil", EOpCeil); + symbolTable.relateToOperator("fract", EOpFract); + symbolTable.relateToOperator("mod", EOpMod); + symbolTable.relateToOperator("min", EOpMin); + symbolTable.relateToOperator("max", EOpMax); + symbolTable.relateToOperator("clamp", EOpClamp); + symbolTable.relateToOperator("mix", EOpMix); + symbolTable.relateToOperator("step", EOpStep); + symbolTable.relateToOperator("smoothstep", EOpSmoothStep); + + symbolTable.relateToOperator("length", EOpLength); + symbolTable.relateToOperator("distance", EOpDistance); + symbolTable.relateToOperator("dot", EOpDot); + symbolTable.relateToOperator("cross", EOpCross); + symbolTable.relateToOperator("normalize", EOpNormalize); + symbolTable.relateToOperator("faceforward", EOpFaceForward); + symbolTable.relateToOperator("reflect", EOpReflect); + symbolTable.relateToOperator("refract", EOpRefract); + + symbolTable.relateToOperator("any", EOpAny); + symbolTable.relateToOperator("all", EOpAll); + + // Map language-specific operators. + switch(type) { + case SH_VERTEX_SHADER: + break; + case SH_FRAGMENT_SHADER: + if (resources.OES_standard_derivatives) { + symbolTable.relateToOperator("dFdx", EOpDFdx); + symbolTable.relateToOperator("dFdy", EOpDFdy); + symbolTable.relateToOperator("fwidth", EOpFwidth); + + symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives"); + } + break; + default: break; + } + + // Finally add resource-specific variables. + switch(type) { + case SH_FRAGMENT_SHADER: + if (spec != SH_CSS_SHADERS_SPEC) { + // Set up gl_FragData. The array size. + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true); + fragData.setArraySize(resources.MaxDrawBuffers); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); + } + break; + default: break; + } +} + +void InitExtensionBehavior(const ShBuiltInResources& resources, + TExtensionBehavior& extBehavior) +{ + if (resources.OES_standard_derivatives) + extBehavior["GL_OES_standard_derivatives"] = EBhUndefined; + if (resources.OES_EGL_image_external) + extBehavior["GL_OES_EGL_image_external"] = EBhUndefined; + if (resources.ARB_texture_rectangle) + extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined; +} diff --git a/src/3rdparty/angle/src/compiler/Initialize.h b/src/3rdparty/angle/src/compiler/Initialize.h new file mode 100644 index 0000000000..8b0adc6b4c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Initialize.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _INITIALIZE_INCLUDED_ +#define _INITIALIZE_INCLUDED_ + +#include "compiler/Common.h" +#include "compiler/ShHandle.h" +#include "compiler/SymbolTable.h" + +typedef TVector TBuiltInStrings; + +class TBuiltIns { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + void initialize(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources); + const TBuiltInStrings& getBuiltInStrings() { return builtInStrings; } + +protected: + TBuiltInStrings builtInStrings; +}; + +void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources, + TSymbolTable& symbolTable); + +void InitExtensionBehavior(const ShBuiltInResources& resources, + TExtensionBehavior& extensionBehavior); + +#endif // _INITIALIZE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/InitializeDll.cpp b/src/3rdparty/angle/src/compiler/InitializeDll.cpp new file mode 100644 index 0000000000..8763cfeea8 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/InitializeDll.cpp @@ -0,0 +1,115 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/InitializeDll.h" + +#include "compiler/InitializeGlobals.h" +#include "compiler/InitializeParseContext.h" +#include "compiler/osinclude.h" + +OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + +bool InitProcess() +{ + if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) { + // + // Function is re-entrant. + // + return true; + } + + ThreadInitializeIndex = OS_AllocTLSIndex(); + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitProcess(): Failed to allocate TLS area for init flag"); + return false; + } + + + if (!InitializePoolIndex()) { + assert(0 && "InitProcess(): Failed to initalize global pool"); + return false; + } + + if (!InitializeParseContextIndex()) { + assert(0 && "InitProcess(): Failed to initalize parse context"); + return false; + } + + return InitThread(); +} + +bool DetachProcess() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + success = DetachThread(); + + if (!FreeParseContextIndex()) + success = false; + + FreePoolIndex(); + + OS_FreeTLSIndex(ThreadInitializeIndex); + ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + + return success; +} + +bool InitThread() +{ + // + // This function is re-entrant + // + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitThread(): Process hasn't been initalised."); + return false; + } + + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) + return true; + + InitializeGlobalPools(); + + if (!InitializeGlobalParseContext()) + return false; + + if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) { + assert(0 && "InitThread(): Unable to set init flag."); + return false; + } + + return true; +} + +bool DetachThread() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + // + // Function is re-entrant and this thread may not have been initalised. + // + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) { + if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) { + assert(0 && "DetachThread(): Unable to clear init flag."); + success = false; + } + + if (!FreeParseContext()) + success = false; + + FreeGlobalPools(); + } + + return success; +} + diff --git a/src/3rdparty/angle/src/compiler/InitializeDll.h b/src/3rdparty/angle/src/compiler/InitializeDll.h new file mode 100644 index 0000000000..857238eeae --- /dev/null +++ b/src/3rdparty/angle/src/compiler/InitializeDll.h @@ -0,0 +1,16 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#ifndef __INITIALIZEDLL_H +#define __INITIALIZEDLL_H + +bool InitProcess(); +bool DetachProcess(); + +bool InitThread(); +bool DetachThread(); + +#endif // __INITIALIZEDLL_H + diff --git a/src/3rdparty/angle/src/compiler/InitializeGlobals.h b/src/3rdparty/angle/src/compiler/InitializeGlobals.h new file mode 100644 index 0000000000..842a45281d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/InitializeGlobals.h @@ -0,0 +1,15 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef __INITIALIZE_GLOBALS_INCLUDED_ +#define __INITIALIZE_GLOBALS_INCLUDED_ + +void InitializeGlobalPools(); +void FreeGlobalPools(); +bool InitializePoolIndex(); +void FreePoolIndex(); + +#endif // __INITIALIZE_GLOBALS_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/InitializeParseContext.cpp b/src/3rdparty/angle/src/compiler/InitializeParseContext.cpp new file mode 100644 index 0000000000..1f40cf5800 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/InitializeParseContext.cpp @@ -0,0 +1,96 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/InitializeParseContext.h" + +#include "compiler/osinclude.h" + +OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + +bool InitializeParseContextIndex() +{ + if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalized"); + return false; + } + + // + // Allocate a TLS index. + // + GlobalParseContextIndex = OS_AllocTLSIndex(); + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalized"); + return false; + } + + return true; +} + +bool FreeParseContextIndex() +{ + OS_TLSIndex tlsiIndex = GlobalParseContextIndex; + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContextIndex(): Parse Context index not initalized"); + return false; + } + + GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + + return OS_FreeTLSIndex(tlsiIndex); +} + +bool InitializeGlobalParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalized"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext != 0) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalized"); + return false; + } + + TThreadParseContext *lpThreadData = new TThreadParseContext(); + if (lpThreadData == 0) { + assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context"); + return false; + } + + lpThreadData->lpGlobalParseContext = 0; + OS_SetTLSValue(GlobalParseContextIndex, lpThreadData); + + return true; +} + +bool FreeParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContext(): Parse Context index not initalized"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext) + delete lpParseContext; + + return true; +} + +TParseContextPointer& GetGlobalParseContext() +{ + // + // Minimal error checking for speed + // + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + + return lpParseContext->lpGlobalParseContext; +} + diff --git a/src/3rdparty/angle/src/compiler/InitializeParseContext.h b/src/3rdparty/angle/src/compiler/InitializeParseContext.h new file mode 100644 index 0000000000..aa53b735d4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/InitializeParseContext.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_ + +bool InitializeParseContextIndex(); +bool FreeParseContextIndex(); + +bool InitializeGlobalParseContext(); +bool FreeParseContext(); + +struct TParseContext; +typedef TParseContext* TParseContextPointer; +extern TParseContextPointer& GetGlobalParseContext(); +#define GlobalParseContext GetGlobalParseContext() + +typedef struct TThreadParseContextRec +{ + TParseContext *lpGlobalParseContext; +} TThreadParseContext; + +#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/IntermTraverse.cpp b/src/3rdparty/angle/src/compiler/IntermTraverse.cpp new file mode 100644 index 0000000000..a13877f18f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/IntermTraverse.cpp @@ -0,0 +1,293 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/intermediate.h" + +// +// Traverse the intermediate representation tree, and +// call a node type specific function for each node. +// Done recursively through the member function Traverse(). +// Node types can be skipped if their function to call is 0, +// but their subtree will still be traversed. +// Nodes with children can have their whole subtree skipped +// if preVisit is turned on and the type specific function +// returns false. +// +// preVisit, postVisit, and rightToLeft control what order +// nodes are visited in. +// + +// +// Traversal functions for terminals are straighforward.... +// +void TIntermSymbol::traverse(TIntermTraverser* it) +{ + it->visitSymbol(this); +} + +void TIntermConstantUnion::traverse(TIntermTraverser* it) +{ + it->visitConstantUnion(this); +} + +// +// Traverse a binary node. +// +void TIntermBinary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + // + // visit the node before children if pre-visiting. + // + if(it->preVisit) + { + visit = it->visitBinary(PreVisit, this); + } + + // + // Visit the children, in the right order. + // + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + if(right) + { + right->traverse(it); + } + + if(it->inVisit) + { + visit = it->visitBinary(InVisit, this); + } + + if(visit && left) + { + left->traverse(it); + } + } + else + { + if(left) + { + left->traverse(it); + } + + if(it->inVisit) + { + visit = it->visitBinary(InVisit, this); + } + + if(visit && right) + { + right->traverse(it); + } + } + + it->decrementDepth(); + } + + // + // Visit the node after the children, if requested and the traversal + // hasn't been cancelled yet. + // + if(visit && it->postVisit) + { + it->visitBinary(PostVisit, this); + } +} + +// +// Traverse a unary node. Same comments in binary node apply here. +// +void TIntermUnary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitUnary(PreVisit, this); + + if (visit) { + it->incrementDepth(); + operand->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitUnary(PostVisit, this); +} + +// +// Traverse an aggregate node. Same comments in binary node apply here. +// +void TIntermAggregate::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if(it->preVisit) + { + visit = it->visitAggregate(PreVisit, this); + } + + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + for(TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++) + { + (*sit)->traverse(it); + + if(visit && it->inVisit) + { + if(*sit != sequence.front()) + { + visit = it->visitAggregate(InVisit, this); + } + } + } + } + else + { + for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + (*sit)->traverse(it); + + if(visit && it->inVisit) + { + if(*sit != sequence.back()) + { + visit = it->visitAggregate(InVisit, this); + } + } + } + } + + it->decrementDepth(); + } + + if(visit && it->postVisit) + { + it->visitAggregate(PostVisit, this); + } +} + +// +// Traverse a selection node. Same comments in binary node apply here. +// +void TIntermSelection::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitSelection(PreVisit, this); + + if (visit) { + it->incrementDepth(); + if (it->rightToLeft) { + if (falseBlock) + falseBlock->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + condition->traverse(it); + } else { + condition->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + if (falseBlock) + falseBlock->traverse(it); + } + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitSelection(PostVisit, this); +} + +// +// Traverse a loop node. Same comments in binary node apply here. +// +void TIntermLoop::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if(it->preVisit) + { + visit = it->visitLoop(PreVisit, this); + } + + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + if(expr) + { + expr->traverse(it); + } + + if(body) + { + body->traverse(it); + } + + if(cond) + { + cond->traverse(it); + } + } + else + { + if(cond) + { + cond->traverse(it); + } + + if(body) + { + body->traverse(it); + } + + if(expr) + { + expr->traverse(it); + } + } + + it->decrementDepth(); + } + + if(visit && it->postVisit) + { + it->visitLoop(PostVisit, this); + } +} + +// +// Traverse a branch node. Same comments in binary node apply here. +// +void TIntermBranch::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitBranch(PreVisit, this); + + if (visit && expression) { + it->incrementDepth(); + expression->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitBranch(PostVisit, this); +} + diff --git a/src/3rdparty/angle/src/compiler/Intermediate.cpp b/src/3rdparty/angle/src/compiler/Intermediate.cpp new file mode 100644 index 0000000000..92c450530e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Intermediate.cpp @@ -0,0 +1,1447 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Build the intermediate representation. +// + +#include +#include +#include + +#include "compiler/localintermediate.h" +#include "compiler/QualifierAlive.h" +#include "compiler/RemoveTree.h" + +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); + +static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){ + return left > right ? left : right; +} + +const char* getOperatorString(TOperator op) { + switch (op) { + case EOpInitialize: return "="; + case EOpAssign: return "="; + case EOpAddAssign: return "+="; + case EOpSubAssign: return "-="; + case EOpDivAssign: return "/="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: return "*="; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: return "[]"; + + case EOpIndexDirectStruct: return "."; + case EOpVectorSwizzle: return "."; + case EOpAdd: return "+"; + case EOpSub: return "-"; + case EOpMul: return "*"; + case EOpDiv: return "/"; + case EOpMod: UNIMPLEMENTED(); break; + case EOpEqual: return "=="; + case EOpNotEqual: return "!="; + case EOpLessThan: return "<"; + case EOpGreaterThan: return ">"; + case EOpLessThanEqual: return "<="; + case EOpGreaterThanEqual: return ">="; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: return "*"; + + case EOpLogicalOr: return "||"; + case EOpLogicalXor: return "^^"; + case EOpLogicalAnd: return "&&"; + case EOpNegative: return "-"; + case EOpVectorLogicalNot: return "not"; + case EOpLogicalNot: return "!"; + case EOpPostIncrement: return "++"; + case EOpPostDecrement: return "--"; + case EOpPreIncrement: return "++"; + case EOpPreDecrement: return "--"; + + // Fall-through. + case EOpConvIntToBool: + case EOpConvFloatToBool: return "bool"; + + // Fall-through. + case EOpConvBoolToFloat: + case EOpConvIntToFloat: return "float"; + + // Fall-through. + case EOpConvFloatToInt: + case EOpConvBoolToInt: return "int"; + + case EOpRadians: return "radians"; + case EOpDegrees: return "degrees"; + case EOpSin: return "sin"; + case EOpCos: return "cos"; + case EOpTan: return "tan"; + case EOpAsin: return "asin"; + case EOpAcos: return "acos"; + case EOpAtan: return "atan"; + case EOpExp: return "exp"; + case EOpLog: return "log"; + case EOpExp2: return "exp2"; + case EOpLog2: return "log2"; + case EOpSqrt: return "sqrt"; + case EOpInverseSqrt: return "inversesqrt"; + case EOpAbs: return "abs"; + case EOpSign: return "sign"; + case EOpFloor: return "floor"; + case EOpCeil: return "ceil"; + case EOpFract: return "fract"; + case EOpLength: return "length"; + case EOpNormalize: return "normalize"; + case EOpDFdx: return "dFdx"; + case EOpDFdy: return "dFdy"; + case EOpFwidth: return "fwidth"; + case EOpAny: return "any"; + case EOpAll: return "all"; + + default: break; + } + return ""; +} + +//////////////////////////////////////////////////////////////////////////// +// +// First set of functions are to help build the intermediate representation. +// These functions are not member functions of the nodes. +// They are called from parser productions. +// +///////////////////////////////////////////////////////////////////////////// + +// +// Add a terminal node for an identifier in an expression. +// +// Returns the added node. +// +TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line) +{ + TIntermSymbol* node = new TIntermSymbol(id, name, type); + node->setLine(line); + + return node; +} + +// +// Connect two nodes with a new parent that does a binary operation on the nodes. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable) +{ + switch (op) { + case EOpEqual: + case EOpNotEqual: + if (left->isArray()) + return 0; + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { + return 0; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { + return 0; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + return 0; + default: break; + } + + // + // First try converting the children to compatible types. + // + if (left->getType().getStruct() && right->getType().getStruct()) { + if (left->getType() != right->getType()) + return 0; + } else { + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child) + right = child; + else { + child = addConversion(op, right->getType(), left); + if (child) + left = child; + else + return 0; + } + } + + // + // Need a new node holding things together then. Make + // one and promote it to the right type. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = right->getLine(); + node->setLine(line); + + node->setLeft(left); + node->setRight(right); + if (!node->promote(infoSink)) + return 0; + + // + // See if we can fold constants. + // + TIntermTyped* typedReturnNode = 0; + TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); + TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); + if (leftTempConstant && rightTempConstant) { + typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); + + if (typedReturnNode) + return typedReturnNode; + } + + return node; +} + +// +// Connect two nodes through an assignment. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + // + // Like adding binary math, except the conversion can only go + // from right to left. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = left->getLine(); + node->setLine(line); + + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child == 0) + return 0; + + node->setLeft(left); + node->setRight(child); + if (! node->promote(infoSink)) + return 0; + + return node; +} + +// +// Connect two nodes through an index operator, where the left node is the base +// of an array or struct, and the right node is a direct or indirect offset. +// +// Returns the added node. +// The caller should set the type of the returned node. +// +TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line) +{ + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = index->getLine(); + node->setLine(line); + node->setLeft(base); + node->setRight(index); + + // caller should set the type + + return node; +} + +// +// Add one node as the parent of another that it operates on. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable) +{ + TIntermUnary* node; + TIntermTyped* child = childNode->getAsTyped(); + + if (child == 0) { + infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); + return 0; + } + + switch (op) { + case EOpLogicalNot: + if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { + return 0; + } + break; + + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) + return 0; + default: break; + } + + // + // Do we need to promote the operand? + // + // Note: Implicit promotions were removed from the language. + // + TBasicType newType = EbtVoid; + switch (op) { + case EOpConstructInt: newType = EbtInt; break; + case EOpConstructBool: newType = EbtBool; break; + case EOpConstructFloat: newType = EbtFloat; break; + default: break; + } + + if (newType != EbtVoid) { + child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, + child->getNominalSize(), + child->isMatrix(), + child->isArray()), + child); + if (child == 0) + return 0; + } + + // + // For constructors, we are now done, it's all in the conversion. + // + switch (op) { + case EOpConstructInt: + case EOpConstructBool: + case EOpConstructFloat: + return child; + default: break; + } + + TIntermConstantUnion *childTempConstant = 0; + if (child->getAsConstantUnion()) + childTempConstant = child->getAsConstantUnion(); + + // + // Make a new node for the operator. + // + node = new TIntermUnary(op); + if (line == 0) + line = child->getLine(); + node->setLine(line); + node->setOperand(child); + + if (! node->promote(infoSink)) + return 0; + + if (childTempConstant) { + TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); + + if (newChild) + return newChild; + } + + return node; +} + +// +// This is the safe way to change the operator on an aggregate, as it +// does lots of error checking and fixing. Especially for establishing +// a function call's operation on it's set of parameters. Sequences +// of instructions are also aggregates, but they just direnctly set +// their operator to EOpSequence. +// +// Returns an aggregate node, which could be the one passed in if +// it was already an aggregate but no operator was set. +// +TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line) +{ + TIntermAggregate* aggNode; + + // + // Make sure we have an aggregate. If not turn it into one. + // + if (node) { + aggNode = node->getAsAggregate(); + if (aggNode == 0 || aggNode->getOp() != EOpNull) { + // + // Make an aggregate containing this node. + // + aggNode = new TIntermAggregate(); + aggNode->getSequence().push_back(node); + if (line == 0) + line = node->getLine(); + } + } else + aggNode = new TIntermAggregate(); + + // + // Set the operator. + // + aggNode->setOp(op); + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// Convert one type to another. +// +// Returns the node representing the conversion, which could be the same +// node passed in if no conversion was needed. +// +// Return 0 if a conversion can't be done. +// +TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) +{ + // + // Does the base type allow operation? + // + switch (node->getBasicType()) { + case EbtVoid: + case EbtSampler2D: + case EbtSamplerCube: + return 0; + default: break; + } + + // + // Otherwise, if types are identical, no problem + // + if (type == node->getType()) + return node; + + // + // If one's a structure, then no conversions. + // + if (type.getStruct() || node->getType().getStruct()) + return 0; + + // + // If one's an array, then no conversions. + // + if (type.isArray() || node->getType().isArray()) + return 0; + + TBasicType promoteTo; + + switch (op) { + // + // Explicit conversions + // + case EOpConstructBool: + promoteTo = EbtBool; + break; + case EOpConstructFloat: + promoteTo = EbtFloat; + break; + case EOpConstructInt: + promoteTo = EbtInt; + break; + default: + // + // implicit conversions were removed from the language. + // + if (type.getBasicType() != node->getType().getBasicType()) + return 0; + // + // Size and structure could still differ, but that's + // handled by operator promotion. + // + return node; + } + + if (node->getAsConstantUnion()) { + + return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); + } else { + + // + // Add a new newNode for the conversion. + // + TIntermUnary* newNode = 0; + + TOperator newOp = EOpNull; + switch (promoteTo) { + case EbtFloat: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToFloat; break; + case EbtBool: newOp = EOpConvBoolToFloat; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToBool; break; + case EbtFloat: newOp = EOpConvFloatToBool; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getBasicType()) { + case EbtBool: newOp = EOpConvBoolToInt; break; + case EbtFloat: newOp = EOpConvFloatToInt; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine()); + return 0; + } + + TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); + newNode = new TIntermUnary(newOp, type); + newNode->setLine(node->getLine()); + newNode->setOperand(node); + + return newNode; + } +} + +// +// Safe way to combine two nodes into an aggregate. Works with null pointers, +// a node that's not a aggregate yet, etc. +// +// Returns the resulting aggregate, unless 0 was passed in for +// both existing nodes. +// +TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line) +{ + if (left == 0 && right == 0) + return 0; + + TIntermAggregate* aggNode = 0; + if (left) + aggNode = left->getAsAggregate(); + if (!aggNode || aggNode->getOp() != EOpNull) { + aggNode = new TIntermAggregate; + if (left) + aggNode->getSequence().push_back(left); + } + + if (right) + aggNode->getSequence().push_back(right); + + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// Turn an existing node into an aggregate. +// +// Returns an aggregate, unless 0 was passed in for the existing node. +// +TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggNode = new TIntermAggregate; + aggNode->getSequence().push_back(node); + + if (line != 0) + aggNode->setLine(line); + else + aggNode->setLine(node->getLine()); + + return aggNode; +} + +// +// For "if" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are in the +// nodePair. +// +// Returns the selection node created. +// +TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line) +{ + // + // For compile time constant selections, prune the code and + // test now. + // + + if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { + if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst() == true) + return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + else + return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + } + + TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); + node->setLine(line); + + return node; +} + + +TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { + return right; + } else { + TIntermTyped *commaAggregate = growAggregate(left, right, line); + commaAggregate->getAsAggregate()->setOp(EOpComma); + commaAggregate->setType(right->getType()); + commaAggregate->getTypePointer()->setQualifier(EvqTemporary); + return commaAggregate; + } +} + +// +// For "?:" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are specified +// as separate parameters. +// +// Returns the selection node created, or 0 if one could not be. +// +TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line) +{ + // + // Get compatible types. + // + TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); + if (child) + falseBlock = child; + else { + child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); + if (child) + trueBlock = child; + else + return 0; + } + + // + // See if all the operands are constant, then fold it otherwise not. + // + + if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { + if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst()) + return trueBlock; + else + return falseBlock; + } + + // + // Make a selection node. + // + TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); + node->getTypePointer()->setQualifier(EvqTemporary); + node->setLine(line); + + return node; +} + +// +// Constant terminal nodes. Has a union that contains bool, float or int constants +// +// Returns the constant union node created. +// + +TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, TSourceLoc line) +{ + TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); + node->setLine(line); + + return node; +} + +TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line) +{ + + TIntermAggregate* node = new TIntermAggregate(EOpSequence); + + node->setLine(line); + TIntermConstantUnion* constIntNode; + TIntermSequence &sequenceVector = node->getSequence(); + ConstantUnion* unionArray; + + for (int i = 0; i < fields.num; i++) { + unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.offsets[i]); + constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); + sequenceVector.push_back(constIntNode); + } + + return node; +} + +// +// Create loop nodes. +// +TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, TSourceLoc line) +{ + TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); + node->setLine(line); + + return node; +} + +// +// Add branches. +// +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line) +{ + return addBranch(branchOp, 0, line); +} + +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line) +{ + TIntermBranch* node = new TIntermBranch(branchOp, expression); + node->setLine(line); + + return node; +} + +// +// This is to be executed once the final root is put on top by the parsing +// process. +// +bool TIntermediate::postProcess(TIntermNode* root) +{ + if (root == 0) + return true; + + // + // First, finish off the top level sequence, if any + // + TIntermAggregate* aggRoot = root->getAsAggregate(); + if (aggRoot && aggRoot->getOp() == EOpNull) + aggRoot->setOp(EOpSequence); + + return true; +} + +// +// This deletes the tree. +// +void TIntermediate::remove(TIntermNode* root) +{ + if (root) + RemoveAllTreeNodes(root); +} + +//////////////////////////////////////////////////////////////// +// +// Member functions of the nodes used for building the tree. +// +//////////////////////////////////////////////////////////////// + +// +// Say whether or not an operation node changes the value of a variable. +// +// Returns true if state is modified. +// +bool TIntermOperator::modifiesState() const +{ + switch (op) { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + return true; + default: + return false; + } +} + +// +// returns true if the operator is for one of the constructors +// +bool TIntermOperator::isConstructor() const +{ + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + case EOpConstructStruct: + return true; + default: + return false; + } +} +// +// Make sure the type of a unary operator is appropriate for its +// combination of operation and operand type. +// +// Returns false in nothing makes sense. +// +bool TIntermUnary::promote(TInfoSink&) +{ + switch (op) { + case EOpLogicalNot: + if (operand->getBasicType() != EbtBool) + return false; + break; + case EOpNegative: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (operand->getBasicType() == EbtBool) + return false; + break; + + // operators for built-ins are already type checked against their prototype + case EOpAny: + case EOpAll: + case EOpVectorLogicalNot: + return true; + + default: + if (operand->getBasicType() != EbtFloat) + return false; + } + + setType(operand->getType()); + + return true; +} + +// +// Establishes the type of the resultant operation, as well as +// makes the operator the correct one for the operands. +// +// Returns false if operator can't work on operands. +// +bool TIntermBinary::promote(TInfoSink& infoSink) +{ + // This function only handles scalars, vectors, and matrices. + if (left->isArray() || right->isArray()) { + infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine()); + return false; + } + + // GLSL ES 2.0 does not support implicit type casting. + // So the basic type should always match. + if (left->getBasicType() != right->getBasicType()) + return false; + + // + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + // + setType(left->getType()); + + // The result gets promoted to the highest precision. + TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); + getTypePointer()->setPrecision(higherPrecision); + + // Binary operations results in temporary variables unless both + // operands are const. + if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) { + getTypePointer()->setQualifier(EvqTemporary); + } + + int size = std::max(left->getNominalSize(), right->getNominalSize()); + + // + // All scalars. Code after this test assumes this case is removed! + // + if (size == 1) { + switch (op) { + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool, EbpUndefined)); + break; + + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + // Both operands must be of type bool. + if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) + return false; + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + break; + } + return true; + } + + // If we reach here, at least one of the operands is vector or matrix. + // The other operand could be a scalar, vector, or matrix. + // Are the sizes compatible? + // + if (left->getNominalSize() != right->getNominalSize()) { + // If the nominal size of operands do not match: + // One of them must be scalar. + if (left->getNominalSize() != 1 && right->getNominalSize() != 1) + return false; + // Operator cannot be of type pure assignment. + if (op == EOpAssign || op == EOpInitialize) + return false; + } + + // + // Can these two operands be combined? + // + TBasicType basicType = left->getBasicType(); + switch (op) { + case EOpMul: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrix; + else { + op = EOpMatrixTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, size, true)); + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + op = EOpMatrixTimesVector; + setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); + } else { + op = EOpMatrixTimesScalar; + } + } else if (left->isMatrix() && right->isMatrix()) { + op = EOpMatrixTimesMatrix; + } else if (!left->isMatrix() && !right->isMatrix()) { + if (left->isVector() && right->isVector()) { + // leave as component product + } else if (left->isVector() || right->isVector()) { + op = EOpVectorTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + case EOpMulAssign: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrixAssign; + else { + return false; + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + return false; + } else { + op = EOpMatrixTimesScalarAssign; + } + } else if (left->isMatrix() && right->isMatrix()) { + op = EOpMatrixTimesMatrixAssign; + } else if (!left->isMatrix() && !right->isMatrix()) { + if (left->isVector() && right->isVector()) { + // leave as component product + } else if (left->isVector() || right->isVector()) { + if (! left->isVector()) + return false; + op = EOpVectorTimesScalarAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + + case EOpAssign: + case EOpInitialize: + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + if ((left->isMatrix() && right->isVector()) || + (left->isVector() && right->isMatrix())) + return false; + setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix())); + break; + + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if ((left->isMatrix() && right->isVector()) || + (left->isVector() && right->isMatrix())) + return false; + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + return false; + } + + return true; +} + +bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) +{ + const TTypeList* fields = leftNodeType.getStruct(); + + size_t structSize = fields->size(); + int index = 0; + + for (size_t j = 0; j < structSize; j++) { + int size = (*fields)[j].type->getObjectSize(); + for (int i = 0; i < size; i++) { + if ((*fields)[j].type->getBasicType() == EbtStruct) { + if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index])) + return false; + } else { + if (leftUnionArray[index] != rightUnionArray[index]) + return false; + index++; + } + + } + } + return true; +} + +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) +{ + if (leftNodeType.isArray()) { + TType typeWithoutArrayness = leftNodeType; + typeWithoutArrayness.clearArrayness(); + + int arraySize = leftNodeType.getArraySize(); + + for (int i = 0; i < arraySize; ++i) { + int offset = typeWithoutArrayness.getObjectSize() * i; + if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) + return false; + } + } else + return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + + return true; +} + +// +// The fold functions see if an operation on a constant can be done in place, +// without generating run-time code. +// +// Returns the node to keep using, which may or may not be the node passed in. +// + +TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) +{ + ConstantUnion *unionArray = getUnionArrayPointer(); + int objectSize = getType().getObjectSize(); + + if (constantNode) { // binary operations + TIntermConstantUnion *node = constantNode->getAsConstantUnion(); + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + TType returnType = getType(); + + // for a case like float f = 1.2 + vec4(2,3,4,5); + if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { + rightUnionArray = new ConstantUnion[objectSize]; + for (int i = 0; i < objectSize; ++i) + rightUnionArray[i] = *node->getUnionArrayPointer(); + returnType = getType(); + } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { + // for a case like float f = vec4(2,3,4,5) + 1.2; + unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; + for (int i = 0; i < constantNode->getType().getObjectSize(); ++i) + unionArray[i] = *getUnionArrayPointer(); + returnType = node->getType(); + objectSize = constantNode->getType().getObjectSize(); + } + + ConstantUnion* tempConstArray = 0; + TIntermConstantUnion *tempNode; + + bool boolNodeFlag = false; + switch(op) { + case EOpAdd: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] + rightUnionArray[i]; + } + break; + case EOpSub: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] - rightUnionArray[i]; + } + break; + + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] * rightUnionArray[i]; + } + break; + case EOpMatrixTimesMatrix: + if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine()); + return 0; + } + {// support MSVC++6.0 + int size = getNominalSize(); + tempConstArray = new ConstantUnion[size*size]; + for (int row = 0; row < size; row++) { + for (int column = 0; column < size; column++) { + tempConstArray[size * column + row].setFConst(0.0f); + for (int i = 0; i < size; i++) { + tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); + } + } + } + } + break; + case EOpDiv: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) { + switch (getType().getBasicType()) { + case EbtFloat: + if (rightUnionArray[i] == 0.0f) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); + tempConstArray[i].setFConst(FLT_MAX); + } else + tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); + break; + + case EbtInt: + if (rightUnionArray[i] == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); + tempConstArray[i].setIConst(INT_MAX); + } else + tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); + break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine()); + return 0; + } + } + } + break; + + case EOpMatrixTimesVector: + if (node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine()); + return 0; + } + tempConstArray = new ConstantUnion[getNominalSize()]; + + {// support MSVC++6.0 + for (int size = getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].setFConst(0.0f); + for (int j = 0; j < size; j++) { + tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); + } + } + } + + tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); + tempNode->setLine(getLine()); + + return tempNode; + + case EOpVectorTimesMatrix: + if (getType().getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine()); + return 0; + } + + tempConstArray = new ConstantUnion[getNominalSize()]; + {// support MSVC++6.0 + for (int size = getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].setFConst(0.0f); + for (int j = 0; j < size; j++) { + tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); + } + } + } + break; + + case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + } + break; + + case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + } + break; + + case EOpLogicalXor: + tempConstArray = new ConstantUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + switch (getType().getBasicType()) { + case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; + default: assert(false && "Default missing"); + } + } + break; + + case EOpLessThan: + assert(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + case EOpGreaterThan: + assert(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray > *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + case EOpLessThanEqual: + { + assert(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray > *rightUnionArray); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + } + case EOpGreaterThanEqual: + { + assert(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray < *rightUnionArray); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + } + + case EOpEqual: + if (getType().getBasicType() == EbtStruct) { + if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } else { + for (int i = 0; i < objectSize; i++) { + if (unionArray[i] != rightUnionArray[i]) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + case EOpNotEqual: + if (getType().getBasicType() == EbtStruct) { + if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } else { + for (int i = 0; i < objectSize; i++) { + if (unionArray[i] == rightUnionArray[i]) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + default: + infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine()); + return 0; + } + tempNode = new TIntermConstantUnion(tempConstArray, returnType); + tempNode->setLine(getLine()); + + return tempNode; + } else { + // + // Do unary operations + // + TIntermConstantUnion *newNode = 0; + ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; + for (int i = 0; i < objectSize; i++) { + switch(op) { + case EOpNegative: + switch (getType().getBasicType()) { + case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; + case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); + return 0; + } + break; + case EOpLogicalNot: // this code is written for possible future use, will not get executed currently + switch (getType().getBasicType()) { + case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); + return 0; + } + break; + default: + return 0; + } + } + newNode = new TIntermConstantUnion(tempConstArray, getType()); + newNode->setLine(getLine()); + return newNode; + } +} + +TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) +{ + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + int size = node->getType().getObjectSize(); + + ConstantUnion *leftUnionArray = new ConstantUnion[size]; + + for (int i=0; i < size; i++) { + + switch (promoteTo) { + case EbtFloat: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setFConst(static_cast(rightUnionArray[i].getIConst())); + break; + case EbtBool: + leftUnionArray[i].setFConst(static_cast(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + leftUnionArray[i] = rightUnionArray[i]; + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i] = rightUnionArray[i]; + break; + case EbtBool: + leftUnionArray[i].setIConst(static_cast(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + leftUnionArray[i].setIConst(static_cast(rightUnionArray[i].getFConst())); + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0); + break; + case EbtBool: + leftUnionArray[i] = rightUnionArray[i]; + break; + case EbtFloat: + leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f); + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + + break; + default: + infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine()); + return 0; + } + + } + + const TType& t = node->getType(); + + return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); +} + diff --git a/src/3rdparty/angle/src/compiler/MMap.h b/src/3rdparty/angle/src/compiler/MMap.h new file mode 100644 index 0000000000..a308671514 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/MMap.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _MMAP_INCLUDED_ +#define _MMAP_INCLUDED_ + +// +// Encapsulate memory mapped files +// + +class TMMap { +public: + TMMap(const char* fileName) : + fSize(-1), // -1 is the error value returned by GetFileSize() + fp(NULL), + fBuff(0) // 0 is the error value returned by MapViewOfFile() + { + if ((fp = fopen(fileName, "r")) == NULL) + return; + char c = getc(fp); + fSize = 0; + while (c != EOF) { + fSize++; + c = getc(fp); + } + if (c == EOF) + fSize++; + rewind(fp); + fBuff = (char*)malloc(sizeof(char) * fSize); + int count = 0; + c = getc(fp); + while (c != EOF) { + fBuff[count++] = c; + c = getc(fp); + } + fBuff[count++] = c; + } + + char* getData() { return fBuff; } + int getSize() { return fSize; } + + ~TMMap() { + if (fp != NULL) + fclose(fp); + } + +private: + int fSize; // size of file to map in + FILE *fp; + char* fBuff; // the actual data; +}; + +#endif // _MMAP_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp b/src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp new file mode 100644 index 0000000000..a50310154d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp @@ -0,0 +1,122 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/MapLongVariableNames.h" + +namespace { + +TString mapLongName(int id, const TString& name, bool isGlobal) +{ + ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE); + TStringStream stream; + stream << "webgl_"; + if (isGlobal) + stream << "g"; + stream << id; + if (name[0] != '_') + stream << "_"; + stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size()); + return stream.str(); +} + +LongNameMap* gLongNameMapInstance = NULL; + +} // anonymous namespace + +LongNameMap::LongNameMap() + : refCount(0) +{ +} + +LongNameMap::~LongNameMap() +{ +} + +// static +LongNameMap* LongNameMap::GetInstance() +{ + if (gLongNameMapInstance == NULL) + gLongNameMapInstance = new LongNameMap; + gLongNameMapInstance->refCount++; + return gLongNameMapInstance; +} + +void LongNameMap::Release() +{ + ASSERT(gLongNameMapInstance == this); + ASSERT(refCount > 0); + refCount--; + if (refCount == 0) { + delete gLongNameMapInstance; + gLongNameMapInstance = NULL; + } +} + +const char* LongNameMap::Find(const char* originalName) const +{ + std::map::const_iterator it = mLongNameMap.find( + originalName); + if (it != mLongNameMap.end()) + return (*it).second.c_str(); + return NULL; +} + +void LongNameMap::Insert(const char* originalName, const char* mappedName) +{ + mLongNameMap.insert(std::map::value_type( + originalName, mappedName)); +} + +int LongNameMap::Size() const +{ + return mLongNameMap.size(); +} + +MapLongVariableNames::MapLongVariableNames(LongNameMap* globalMap) +{ + ASSERT(globalMap); + mGlobalMap = globalMap; +} + +void MapLongVariableNames::visitSymbol(TIntermSymbol* symbol) +{ + ASSERT(symbol != NULL); + if (symbol->getSymbol().size() > MAX_SHORTENED_IDENTIFIER_SIZE) { + switch (symbol->getQualifier()) { + case EvqVaryingIn: + case EvqVaryingOut: + case EvqInvariantVaryingIn: + case EvqInvariantVaryingOut: + case EvqUniform: + symbol->setSymbol( + mapGlobalLongName(symbol->getSymbol())); + break; + default: + symbol->setSymbol( + mapLongName(symbol->getId(), symbol->getSymbol(), false)); + break; + }; + } +} + +bool MapLongVariableNames::visitLoop(Visit, TIntermLoop* node) +{ + if (node->getInit()) + node->getInit()->traverse(this); + return true; +} + +TString MapLongVariableNames::mapGlobalLongName(const TString& name) +{ + ASSERT(mGlobalMap); + const char* mappedName = mGlobalMap->Find(name.c_str()); + if (mappedName != NULL) + return mappedName; + int id = mGlobalMap->Size(); + TString rt = mapLongName(id, name, true); + mGlobalMap->Insert(name.c_str(), rt.c_str()); + return rt; +} diff --git a/src/3rdparty/angle/src/compiler/MapLongVariableNames.h b/src/3rdparty/angle/src/compiler/MapLongVariableNames.h new file mode 100644 index 0000000000..fb2c7e81cb --- /dev/null +++ b/src/3rdparty/angle/src/compiler/MapLongVariableNames.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_MAP_LONG_VARIABLE_NAMES_H_ +#define COMPILER_MAP_LONG_VARIABLE_NAMES_H_ + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/intermediate.h" +#include "compiler/VariableInfo.h" + +// This size does not include '\0' in the end. +#define MAX_SHORTENED_IDENTIFIER_SIZE 32 + +// This is a ref-counted singleton. GetInstance() returns a pointer to the +// singleton, and after use, call Release(). GetInstance() and Release() should +// be paired. +class LongNameMap { +public: + static LongNameMap* GetInstance(); + void Release(); + + // Return the mapped name if is in the map; + // otherwise, return NULL. + const char* Find(const char* originalName) const; + + // Insert a pair into the map. + void Insert(const char* originalName, const char* mappedName); + + // Return the number of entries in the map. + int Size() const; + +private: + LongNameMap(); + ~LongNameMap(); + + size_t refCount; + std::map mLongNameMap; +}; + +// Traverses intermediate tree to map attributes and uniforms names that are +// longer than MAX_SHORTENED_IDENTIFIER_SIZE to MAX_SHORTENED_IDENTIFIER_SIZE. +class MapLongVariableNames : public TIntermTraverser { +public: + MapLongVariableNames(LongNameMap* globalMap); + + virtual void visitSymbol(TIntermSymbol*); + virtual bool visitLoop(Visit, TIntermLoop*); + +private: + TString mapGlobalLongName(const TString& name); + + LongNameMap* mGlobalMap; +}; + +#endif // COMPILER_MAP_LONG_VARIABLE_NAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/OutputESSL.cpp b/src/3rdparty/angle/src/compiler/OutputESSL.cpp new file mode 100644 index 0000000000..64ee92d44e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputESSL.cpp @@ -0,0 +1,22 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/OutputESSL.h" + +TOutputESSL::TOutputESSL(TInfoSinkBase& objSink) + : TOutputGLSLBase(objSink) +{ +} + +bool TOutputESSL::writeVariablePrecision(TPrecision precision) +{ + if (precision == EbpUndefined) + return false; + + TInfoSinkBase& out = objSink(); + out << getPrecisionString(precision); + return true; +} diff --git a/src/3rdparty/angle/src/compiler/OutputESSL.h b/src/3rdparty/angle/src/compiler/OutputESSL.h new file mode 100644 index 0000000000..4fa73c8047 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputESSL.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_ +#define CROSSCOMPILERGLSL_OUTPUTESSL_H_ + +#include "compiler/OutputGLSLBase.h" + +class TOutputESSL : public TOutputGLSLBase +{ +public: + TOutputESSL(TInfoSinkBase& objSink); + +protected: + virtual bool writeVariablePrecision(TPrecision precision); +}; + +#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/OutputGLSL.cpp b/src/3rdparty/angle/src/compiler/OutputGLSL.cpp new file mode 100644 index 0000000000..dd31b4b58b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputGLSL.cpp @@ -0,0 +1,17 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/OutputGLSL.h" + +TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink) + : TOutputGLSLBase(objSink) +{ +} + +bool TOutputGLSL::writeVariablePrecision(TPrecision) +{ + return false; +} diff --git a/src/3rdparty/angle/src/compiler/OutputGLSL.h b/src/3rdparty/angle/src/compiler/OutputGLSL.h new file mode 100644 index 0000000000..0fe2356eb7 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputGLSL.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_ +#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_ + +#include "compiler/OutputGLSLBase.h" + +class TOutputGLSL : public TOutputGLSLBase +{ +public: + TOutputGLSL(TInfoSinkBase& objSink); + +protected: + virtual bool writeVariablePrecision(TPrecision); +}; + +#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp b/src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp new file mode 100644 index 0000000000..552fa5066d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp @@ -0,0 +1,720 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/OutputGLSLBase.h" +#include "compiler/debug.h" + +namespace +{ +TString getTypeName(const TType& type) +{ + TInfoSinkBase out; + if (type.isMatrix()) + { + out << "mat"; + out << type.getNominalSize(); + } + else if (type.isVector()) + { + switch (type.getBasicType()) + { + case EbtFloat: out << "vec"; break; + case EbtInt: out << "ivec"; break; + case EbtBool: out << "bvec"; break; + default: UNREACHABLE(); break; + } + out << type.getNominalSize(); + } + else + { + if (type.getBasicType() == EbtStruct) + out << type.getTypeName(); + else + out << type.getBasicString(); + } + return TString(out.c_str()); +} + +TString arrayBrackets(const TType& type) +{ + ASSERT(type.isArray()); + TInfoSinkBase out; + out << "[" << type.getArraySize() << "]"; + return TString(out.c_str()); +} + +bool isSingleStatement(TIntermNode* node) { + if (const TIntermAggregate* aggregate = node->getAsAggregate()) + { + return (aggregate->getOp() != EOpFunction) && + (aggregate->getOp() != EOpSequence); + } + else if (const TIntermSelection* selection = node->getAsSelectionNode()) + { + // Ternary operators are usually part of an assignment operator. + // This handles those rare cases in which they are all by themselves. + return selection->usesTernaryOperator(); + } + else if (node->getAsLoopNode()) + { + return false; + } + return true; +} +} // namespace + +TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink) + : TIntermTraverser(true, true, true), + mObjSink(objSink), + mDeclaringVariables(false) +{ +} + +void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr) +{ + TInfoSinkBase& out = objSink(); + if (visit == PreVisit && preStr) + { + out << preStr; + } + else if (visit == InVisit && inStr) + { + out << inStr; + } + else if (visit == PostVisit && postStr) + { + out << postStr; + } +} + +void TOutputGLSLBase::writeVariableType(const TType& type) +{ + TInfoSinkBase& out = objSink(); + TQualifier qualifier = type.getQualifier(); + // TODO(alokp): Validate qualifier for variable declarations. + if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal)) + out << type.getQualifierString() << " "; + // Declare the struct if we have not done so already. + if ((type.getBasicType() == EbtStruct) && + (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end())) + { + out << "struct " << type.getTypeName() << "{\n"; + const TTypeList* structure = type.getStruct(); + ASSERT(structure != NULL); + for (size_t i = 0; i < structure->size(); ++i) + { + const TType* fieldType = (*structure)[i].type; + ASSERT(fieldType != NULL); + if (writeVariablePrecision(fieldType->getPrecision())) + out << " "; + out << getTypeName(*fieldType) << " " << fieldType->getFieldName(); + if (fieldType->isArray()) + out << arrayBrackets(*fieldType); + out << ";\n"; + } + out << "}"; + mDeclaredStructs.insert(type.getTypeName()); + } + else + { + if (writeVariablePrecision(type.getPrecision())) + out << " "; + out << getTypeName(type); + } +} + +void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args) +{ + TInfoSinkBase& out = objSink(); + for (TIntermSequence::const_iterator iter = args.begin(); + iter != args.end(); ++iter) + { + const TIntermSymbol* arg = (*iter)->getAsSymbolNode(); + ASSERT(arg != NULL); + + const TType& type = arg->getType(); + writeVariableType(type); + + const TString& name = arg->getSymbol(); + if (!name.empty()) + out << " " << name; + if (type.isArray()) + out << arrayBrackets(type); + + // Put a comma if this is not the last argument. + if (iter != args.end() - 1) + out << ", "; + } +} + +const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type, + const ConstantUnion* pConstUnion) +{ + TInfoSinkBase& out = objSink(); + + if (type.getBasicType() == EbtStruct) + { + out << type.getTypeName() << "("; + const TTypeList* structure = type.getStruct(); + ASSERT(structure != NULL); + for (size_t i = 0; i < structure->size(); ++i) + { + const TType* fieldType = (*structure)[i].type; + ASSERT(fieldType != NULL); + pConstUnion = writeConstantUnion(*fieldType, pConstUnion); + if (i != structure->size() - 1) out << ", "; + } + out << ")"; + } + else + { + int size = type.getObjectSize(); + bool writeType = size > 1; + if (writeType) out << getTypeName(type) << "("; + for (int i = 0; i < size; ++i, ++pConstUnion) + { + switch (pConstUnion->getType()) + { + case EbtFloat: out << pConstUnion->getFConst(); break; + case EbtInt: out << pConstUnion->getIConst(); break; + case EbtBool: out << pConstUnion->getBConst(); break; + default: UNREACHABLE(); + } + if (i != size - 1) out << ", "; + } + if (writeType) out << ")"; + } + return pConstUnion; +} + +void TOutputGLSLBase::visitSymbol(TIntermSymbol* node) +{ + TInfoSinkBase& out = objSink(); + if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node)) + out << mLoopUnroll.GetLoopIndexValue(node); + else + out << node->getSymbol(); + + if (mDeclaringVariables && node->getType().isArray()) + out << arrayBrackets(node->getType()); +} + +void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node) +{ + writeConstantUnion(node->getType(), node->getUnionArrayPointer()); +} + +bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node) +{ + bool visitChildren = true; + TInfoSinkBase& out = objSink(); + switch (node->getOp()) + { + case EOpInitialize: + if (visit == InVisit) + { + out << " = "; + // RHS of initialize is not being declared. + mDeclaringVariables = false; + } + break; + case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break; + case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break; + case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break; + case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; + // Notice the fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + writeTriplet(visit, "(", " *= ", ")"); + break; + + case EOpIndexDirect: + case EOpIndexIndirect: + writeTriplet(visit, NULL, "[", "]"); + break; + case EOpIndexDirectStruct: + if (visit == InVisit) + { + out << "."; + // TODO(alokp): ASSERT + out << node->getType().getFieldName(); + visitChildren = false; + } + break; + case EOpVectorSwizzle: + if (visit == InVisit) + { + out << "."; + TIntermAggregate* rightChild = node->getRight()->getAsAggregate(); + TIntermSequence& sequence = rightChild->getSequence(); + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit) + { + TIntermConstantUnion* element = (*sit)->getAsConstantUnion(); + ASSERT(element->getBasicType() == EbtInt); + ASSERT(element->getNominalSize() == 1); + const ConstantUnion& data = element->getUnionArrayPointer()[0]; + ASSERT(data.getType() == EbtInt); + switch (data.getIConst()) + { + case 0: out << "x"; break; + case 1: out << "y"; break; + case 2: out << "z"; break; + case 3: out << "w"; break; + default: UNREACHABLE(); break; + } + } + visitChildren = false; + } + break; + + case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break; + case EOpSub: writeTriplet(visit, "(", " - ", ")"); break; + case EOpMul: writeTriplet(visit, "(", " * ", ")"); break; + case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; + case EOpMod: UNIMPLEMENTED(); break; + case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; + case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break; + case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break; + case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break; + case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break; + case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break; + + // Notice the fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + writeTriplet(visit, "(", " * ", ")"); + break; + + case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break; + case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break; + case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break; + default: UNREACHABLE(); break; + } + + return visitChildren; +} + +bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node) +{ + TString preString; + TString postString = ")"; + + switch (node->getOp()) + { + case EOpNegative: preString = "(-"; break; + case EOpVectorLogicalNot: preString = "not("; break; + case EOpLogicalNot: preString = "(!"; break; + + case EOpPostIncrement: preString = "("; postString = "++)"; break; + case EOpPostDecrement: preString = "("; postString = "--)"; break; + case EOpPreIncrement: preString = "(++"; break; + case EOpPreDecrement: preString = "(--"; break; + + case EOpConvIntToBool: + case EOpConvFloatToBool: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: preString = "bool("; break; + case 2: preString = "bvec2("; break; + case 3: preString = "bvec3("; break; + case 4: preString = "bvec4("; break; + default: UNREACHABLE(); + } + break; + case EOpConvBoolToFloat: + case EOpConvIntToFloat: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: preString = "float("; break; + case 2: preString = "vec2("; break; + case 3: preString = "vec3("; break; + case 4: preString = "vec4("; break; + default: UNREACHABLE(); + } + break; + case EOpConvFloatToInt: + case EOpConvBoolToInt: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: preString = "int("; break; + case 2: preString = "ivec2("; break; + case 3: preString = "ivec3("; break; + case 4: preString = "ivec4("; break; + default: UNREACHABLE(); + } + break; + + case EOpRadians: preString = "radians("; break; + case EOpDegrees: preString = "degrees("; break; + case EOpSin: preString = "sin("; break; + case EOpCos: preString = "cos("; break; + case EOpTan: preString = "tan("; break; + case EOpAsin: preString = "asin("; break; + case EOpAcos: preString = "acos("; break; + case EOpAtan: preString = "atan("; break; + + case EOpExp: preString = "exp("; break; + case EOpLog: preString = "log("; break; + case EOpExp2: preString = "exp2("; break; + case EOpLog2: preString = "log2("; break; + case EOpSqrt: preString = "sqrt("; break; + case EOpInverseSqrt: preString = "inversesqrt("; break; + + case EOpAbs: preString = "abs("; break; + case EOpSign: preString = "sign("; break; + case EOpFloor: preString = "floor("; break; + case EOpCeil: preString = "ceil("; break; + case EOpFract: preString = "fract("; break; + + case EOpLength: preString = "length("; break; + case EOpNormalize: preString = "normalize("; break; + + case EOpDFdx: preString = "dFdx("; break; + case EOpDFdy: preString = "dFdy("; break; + case EOpFwidth: preString = "fwidth("; break; + + case EOpAny: preString = "any("; break; + case EOpAll: preString = "all("; break; + + default: UNREACHABLE(); break; + } + + if (visit == PreVisit && node->getUseEmulatedFunction()) + preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString); + writeTriplet(visit, preString.c_str(), NULL, postString.c_str()); + + return true; +} + +bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node) +{ + TInfoSinkBase& out = objSink(); + + if (node->usesTernaryOperator()) + { + // Notice two brackets at the beginning and end. The outer ones + // encapsulate the whole ternary expression. This preserves the + // order of precedence when ternary expressions are used in a + // compound expression, i.e., c = 2 * (a < b ? 1 : 2). + out << "(("; + node->getCondition()->traverse(this); + out << ") ? ("; + node->getTrueBlock()->traverse(this); + out << ") : ("; + node->getFalseBlock()->traverse(this); + out << "))"; + } + else + { + out << "if ("; + node->getCondition()->traverse(this); + out << ")\n"; + + incrementDepth(); + visitCodeBlock(node->getTrueBlock()); + + if (node->getFalseBlock()) + { + out << "else\n"; + visitCodeBlock(node->getFalseBlock()); + } + decrementDepth(); + } + return false; +} + +bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node) +{ + bool visitChildren = true; + TInfoSinkBase& out = objSink(); + TString preString; + bool delayedWrite = false; + switch (node->getOp()) + { + case EOpSequence: { + // Scope the sequences except when at the global scope. + if (depth > 0) out << "{\n"; + + incrementDepth(); + const TIntermSequence& sequence = node->getSequence(); + for (TIntermSequence::const_iterator iter = sequence.begin(); + iter != sequence.end(); ++iter) + { + TIntermNode* node = *iter; + ASSERT(node != NULL); + node->traverse(this); + + if (isSingleStatement(node)) + out << ";\n"; + } + decrementDepth(); + + // Scope the sequences except when at the global scope. + if (depth > 0) out << "}\n"; + visitChildren = false; + break; + } + case EOpPrototype: { + // Function declaration. + ASSERT(visit == PreVisit); + writeVariableType(node->getType()); + out << " " << node->getName(); + + out << "("; + writeFunctionParameters(node->getSequence()); + out << ")"; + + visitChildren = false; + break; + } + case EOpFunction: { + // Function definition. + ASSERT(visit == PreVisit); + writeVariableType(node->getType()); + out << " " << TFunction::unmangleName(node->getName()); + + incrementDepth(); + // Function definition node contains one or two children nodes + // representing function parameters and function body. The latter + // is not present in case of empty function bodies. + const TIntermSequence& sequence = node->getSequence(); + ASSERT((sequence.size() == 1) || (sequence.size() == 2)); + TIntermSequence::const_iterator seqIter = sequence.begin(); + + // Traverse function parameters. + TIntermAggregate* params = (*seqIter)->getAsAggregate(); + ASSERT(params != NULL); + ASSERT(params->getOp() == EOpParameters); + params->traverse(this); + + // Traverse function body. + TIntermAggregate* body = ++seqIter != sequence.end() ? + (*seqIter)->getAsAggregate() : NULL; + visitCodeBlock(body); + decrementDepth(); + + // Fully processed; no need to visit children. + visitChildren = false; + break; + } + case EOpFunctionCall: + // Function call. + if (visit == PreVisit) + { + TString functionName = TFunction::unmangleName(node->getName()); + out << functionName << "("; + } + else if (visit == InVisit) + { + out << ", "; + } + else + { + out << ")"; + } + break; + case EOpParameters: { + // Function parameters. + ASSERT(visit == PreVisit); + out << "("; + writeFunctionParameters(node->getSequence()); + out << ")"; + visitChildren = false; + break; + } + case EOpDeclaration: { + // Variable declaration. + if (visit == PreVisit) + { + const TIntermSequence& sequence = node->getSequence(); + const TIntermTyped* variable = sequence.front()->getAsTyped(); + writeVariableType(variable->getType()); + out << " "; + mDeclaringVariables = true; + } + else if (visit == InVisit) + { + out << ", "; + mDeclaringVariables = true; + } + else + { + mDeclaringVariables = false; + } + break; + } + case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break; + case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break; + case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break; + case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break; + case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break; + case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break; + case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break; + case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break; + case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break; + case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break; + case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break; + case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break; + case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break; + case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break; + case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break; + case EOpConstructStruct: + if (visit == PreVisit) + { + const TType& type = node->getType(); + ASSERT(type.getBasicType() == EbtStruct); + out << type.getTypeName() << "("; + } + else if (visit == InVisit) + { + out << ", "; + } + else + { + out << ")"; + } + break; + + case EOpLessThan: preString = "lessThan("; delayedWrite = true; break; + case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break; + case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break; + case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break; + case EOpVectorEqual: preString = "equal("; delayedWrite = true; break; + case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break; + case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break; + + case EOpMod: preString = "mod("; delayedWrite = true; break; + case EOpPow: preString = "pow("; delayedWrite = true; break; + case EOpAtan: preString = "atan("; delayedWrite = true; break; + case EOpMin: preString = "min("; delayedWrite = true; break; + case EOpMax: preString = "max("; delayedWrite = true; break; + case EOpClamp: preString = "clamp("; delayedWrite = true; break; + case EOpMix: preString = "mix("; delayedWrite = true; break; + case EOpStep: preString = "step("; delayedWrite = true; break; + case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break; + + case EOpDistance: preString = "distance("; delayedWrite = true; break; + case EOpDot: preString = "dot("; delayedWrite = true; break; + case EOpCross: preString = "cross("; delayedWrite = true; break; + case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break; + case EOpReflect: preString = "reflect("; delayedWrite = true; break; + case EOpRefract: preString = "refract("; delayedWrite = true; break; + case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break; + + default: UNREACHABLE(); break; + } + if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction()) + preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString); + if (delayedWrite) + writeTriplet(visit, preString.c_str(), ", ", ")"); + return visitChildren; +} + +bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node) +{ + TInfoSinkBase& out = objSink(); + + incrementDepth(); + // Loop header. + TLoopType loopType = node->getType(); + if (loopType == ELoopFor) // for loop + { + if (!node->getUnrollFlag()) { + out << "for ("; + if (node->getInit()) + node->getInit()->traverse(this); + out << "; "; + + if (node->getCondition()) + node->getCondition()->traverse(this); + out << "; "; + + if (node->getExpression()) + node->getExpression()->traverse(this); + out << ")\n"; + } + } + else if (loopType == ELoopWhile) // while loop + { + out << "while ("; + ASSERT(node->getCondition() != NULL); + node->getCondition()->traverse(this); + out << ")\n"; + } + else // do-while loop + { + ASSERT(loopType == ELoopDoWhile); + out << "do\n"; + } + + // Loop body. + if (node->getUnrollFlag()) + { + TLoopIndexInfo indexInfo; + mLoopUnroll.FillLoopIndexInfo(node, indexInfo); + mLoopUnroll.Push(indexInfo); + while (mLoopUnroll.SatisfiesLoopCondition()) + { + visitCodeBlock(node->getBody()); + mLoopUnroll.Step(); + } + mLoopUnroll.Pop(); + } + else + { + visitCodeBlock(node->getBody()); + } + + // Loop footer. + if (loopType == ELoopDoWhile) // do-while loop + { + out << "while ("; + ASSERT(node->getCondition() != NULL); + node->getCondition()->traverse(this); + out << ");\n"; + } + decrementDepth(); + + // No need to visit children. They have been already processed in + // this function. + return false; +} + +bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node) +{ + switch (node->getFlowOp()) + { + case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break; + case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break; + case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break; + case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break; + default: UNREACHABLE(); break; + } + + return true; +} + +void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) { + TInfoSinkBase &out = objSink(); + if (node != NULL) + { + node->traverse(this); + // Single statements not part of a sequence need to be terminated + // with semi-colon. + if (isSingleStatement(node)) + out << ";\n"; + } + else + { + out << "{\n}\n"; // Empty code block. + } +} diff --git a/src/3rdparty/angle/src/compiler/OutputGLSLBase.h b/src/3rdparty/angle/src/compiler/OutputGLSLBase.h new file mode 100644 index 0000000000..efd0b5fc2d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputGLSLBase.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ +#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ + +#include + +#include "compiler/ForLoopUnroll.h" +#include "compiler/intermediate.h" +#include "compiler/ParseHelper.h" + +class TOutputGLSLBase : public TIntermTraverser +{ +public: + TOutputGLSLBase(TInfoSinkBase& objSink); + +protected: + TInfoSinkBase& objSink() { return mObjSink; } + void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr); + void writeVariableType(const TType& type); + virtual bool writeVariablePrecision(TPrecision precision) = 0; + void writeFunctionParameters(const TIntermSequence& args); + const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion); + + virtual void visitSymbol(TIntermSymbol* node); + virtual void visitConstantUnion(TIntermConstantUnion* node); + virtual bool visitBinary(Visit visit, TIntermBinary* node); + virtual bool visitUnary(Visit visit, TIntermUnary* node); + virtual bool visitSelection(Visit visit, TIntermSelection* node); + virtual bool visitAggregate(Visit visit, TIntermAggregate* node); + virtual bool visitLoop(Visit visit, TIntermLoop* node); + virtual bool visitBranch(Visit visit, TIntermBranch* node); + + void visitCodeBlock(TIntermNode* node); + +private: + TInfoSinkBase& mObjSink; + bool mDeclaringVariables; + + // Structs are declared as the tree is traversed. This set contains all + // the structs already declared. It is maintained so that a struct is + // declared only once. + typedef std::set DeclaredStructs; + DeclaredStructs mDeclaredStructs; + + ForLoopUnroll mLoopUnroll; +}; + +#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/OutputHLSL.cpp new file mode 100644 index 0000000000..a430695744 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputHLSL.cpp @@ -0,0 +1,2664 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/OutputHLSL.h" + +#include "common/angleutils.h" +#include "compiler/debug.h" +#include "compiler/InfoSink.h" +#include "compiler/UnfoldShortCircuit.h" +#include "compiler/SearchSymbol.h" +#include "compiler/DetectDiscontinuity.h" + +#include +#include + +namespace sh +{ +// Integer to TString conversion +TString str(int i) +{ + char buffer[20]; + snprintf(buffer, sizeof(buffer), "%d", i); + return buffer; +} + +OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context) +{ + mUnfoldShortCircuit = new UnfoldShortCircuit(context, this); + mInsideFunction = false; + + mUsesTexture2D = false; + mUsesTexture2D_bias = false; + mUsesTexture2DProj = false; + mUsesTexture2DProj_bias = false; + mUsesTexture2DProjLod = false; + mUsesTexture2DLod = false; + mUsesTextureCube = false; + mUsesTextureCube_bias = false; + mUsesTextureCubeLod = false; + mUsesTexture2DLod0 = false; + mUsesTexture2DLod0_bias = false; + mUsesTexture2DProjLod0 = false; + mUsesTexture2DProjLod0_bias = false; + mUsesTextureCubeLod0 = false; + mUsesTextureCubeLod0_bias = false; + mUsesDepthRange = false; + mUsesFragCoord = false; + mUsesPointCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesXor = false; + mUsesMod1 = false; + mUsesMod2v = false; + mUsesMod2f = false; + mUsesMod3v = false; + mUsesMod3f = false; + mUsesMod4v = false; + mUsesMod4f = false; + mUsesFaceforward1 = false; + mUsesFaceforward2 = false; + mUsesFaceforward3 = false; + mUsesFaceforward4 = false; + mUsesEqualMat2 = false; + mUsesEqualMat3 = false; + mUsesEqualMat4 = false; + mUsesEqualVec2 = false; + mUsesEqualVec3 = false; + mUsesEqualVec4 = false; + mUsesEqualIVec2 = false; + mUsesEqualIVec3 = false; + mUsesEqualIVec4 = false; + mUsesEqualBVec2 = false; + mUsesEqualBVec3 = false; + mUsesEqualBVec4 = false; + mUsesAtan2_1 = false; + mUsesAtan2_2 = false; + mUsesAtan2_3 = false; + mUsesAtan2_4 = false; + + mScopeDepth = 0; + + mUniqueIndex = 0; + + mContainsLoopDiscontinuity = false; + mOutputLod0Function = false; + mInsideDiscontinuousLoop = false; + + mExcessiveLoopIndex = NULL; +} + +OutputHLSL::~OutputHLSL() +{ + delete mUnfoldShortCircuit; +} + +void OutputHLSL::output() +{ + mContainsLoopDiscontinuity = containsLoopDiscontinuity(mContext.treeRoot); + + mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header + header(); + + mContext.infoSink().obj << mHeader.c_str(); + mContext.infoSink().obj << mBody.c_str(); +} + +TInfoSinkBase &OutputHLSL::getBodyStream() +{ + return mBody; +} + +int OutputHLSL::vectorSize(const TType &type) const +{ + int elementSize = type.isMatrix() ? type.getNominalSize() : 1; + int arraySize = type.isArray() ? type.getArraySize() : 1; + + return elementSize * arraySize; +} + +void OutputHLSL::header() +{ + ShShaderType shaderType = mContext.shaderType; + TInfoSinkBase &out = mHeader; + + for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++) + { + out << *structDeclaration; + } + + for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++) + { + out << *constructor; + } + + if (shaderType == SH_FRAGMENT_SHADER) + { + TString uniforms; + TString varyings; + + TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel(); + int semanticIndex = 0; + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + + if (symbol->isVariable()) + { + const TVariable *variable = static_cast(symbol); + const TType &type = variable->getType(); + TQualifier qualifier = type.getQualifier(); + + if (qualifier == EvqUniform) + { + if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end()) + { + uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n"; + } + } + else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn) + { + if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end()) + { + // Program linking depends on this exact format + varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; + + semanticIndex += type.isArray() ? type.getArraySize() : 1; + } + } + else if (qualifier == EvqGlobal || qualifier == EvqTemporary) + { + // Globals are declared and intialized as an aggregate node + } + else if (qualifier == EvqConst) + { + // Constants are repeated as literals where used + } + else UNREACHABLE(); + } + } + + out << "// Varyings\n"; + out << varyings; + out << "\n" + "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n"; + + if (mUsesFragCoord) + { + out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"; + } + + if (mUsesPointCoord) + { + out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n"; + } + + if (mUsesFrontFacing) + { + out << "static bool gl_FrontFacing = false;\n"; + } + + out << "\n"; + + if (mUsesFragCoord) + { + out << "uniform float4 dx_Coord;\n" + "uniform float2 dx_Depth;\n"; + } + + if (mUsesFrontFacing) + { + out << "uniform bool dx_PointsOrLines;\n" + "uniform bool dx_FrontCCW;\n"; + } + + out << "\n"; + out << uniforms; + out << "\n"; + + if (mUsesTexture2D) + { + out << "float4 gl_texture2D(sampler2D s, float2 t)\n" + "{\n" + " return tex2D(s, t);\n" + "}\n" + "\n"; + } + + if (mUsesTexture2D_bias) + { + out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n" + "{\n" + " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DProj) + { + out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n" + "{\n" + " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n" + "}\n" + "\n" + "float4 gl_texture2DProj(sampler2D s, float4 t)\n" + "{\n" + " return tex2Dproj(s, t);\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DProj_bias) + { + out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n" + "{\n" + " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n" + "}\n" + "\n" + "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n" + "{\n" + " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n" + "}\n" + "\n"; + } + + if (mUsesTextureCube) + { + out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n" + "{\n" + " return texCUBE(s, t);\n" + "}\n" + "\n"; + } + + if (mUsesTextureCube_bias) + { + out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n" + "{\n" + " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n" + "}\n" + "\n"; + } + + // These *Lod0 intrinsics are not available in GL fragment shaders. + // They are used to sample using discontinuous texture coordinates. + if (mUsesTexture2DLod0) + { + out << "float4 gl_texture2DLod0(sampler2D s, float2 t)\n" + "{\n" + " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DLod0_bias) + { + out << "float4 gl_texture2DLod0(sampler2D s, float2 t, float bias)\n" + "{\n" + " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DProjLod0) + { + out << "float4 gl_texture2DProjLod0(sampler2D s, float3 t)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" + "}\n" + "\n" + "float4 gl_texture2DProjLod(sampler2D s, float4 t)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DProjLod0_bias) + { + out << "float4 gl_texture2DProjLod0_bias(sampler2D s, float3 t, float bias)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" + "}\n" + "\n" + "float4 gl_texture2DProjLod_bias(sampler2D s, float4 t, float bias)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTextureCubeLod0) + { + out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t)\n" + "{\n" + " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTextureCubeLod0_bias) + { + out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t, float bias)\n" + "{\n" + " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" + "}\n" + "\n"; + } + } + else // Vertex shader + { + TString uniforms; + TString attributes; + TString varyings; + + TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel(); + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + + if (symbol->isVariable()) + { + const TVariable *variable = static_cast(symbol); + const TType &type = variable->getType(); + TQualifier qualifier = type.getQualifier(); + + if (qualifier == EvqUniform) + { + if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end()) + { + uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n"; + } + } + else if (qualifier == EvqAttribute) + { + if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end()) + { + attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; + } + } + else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut) + { + if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end()) + { + // Program linking depends on this exact format + varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; + } + } + else if (qualifier == EvqGlobal || qualifier == EvqTemporary) + { + // Globals are declared and intialized as an aggregate node + } + else if (qualifier == EvqConst) + { + // Constants are repeated as literals where used + } + else UNREACHABLE(); + } + } + + out << "// Attributes\n"; + out << attributes; + out << "\n" + "static float4 gl_Position = float4(0, 0, 0, 0);\n"; + + if (mUsesPointSize) + { + out << "static float gl_PointSize = float(1);\n"; + } + + out << "\n" + "// Varyings\n"; + out << varyings; + out << "\n" + "uniform float2 dx_HalfPixelSize;\n" + "\n"; + out << uniforms; + out << "\n"; + + if (mUsesTexture2D) + { + out << "float4 gl_texture2D(sampler2D s, float2 t)\n" + "{\n" + " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DLod) + { + out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n" + "{\n" + " return tex2Dlod(s, float4(t.x, t.y, 0, lod));\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DProj) + { + out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n" + "}\n" + "\n" + "float4 gl_texture2DProj(sampler2D s, float4 t)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTexture2DProjLod) + { + out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, lod));\n" + "}\n" + "\n" + "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n" + "{\n" + " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, lod));\n" + "}\n" + "\n"; + } + + if (mUsesTextureCube) + { + out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n" + "{\n" + " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n" + "}\n" + "\n"; + } + + if (mUsesTextureCubeLod) + { + out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n" + "{\n" + " return texCUBElod(s, float4(t.x, t.y, t.z, lod));\n" + "}\n" + "\n"; + } + } + + if (mUsesFragCoord) + { + out << "#define GL_USES_FRAG_COORD\n"; + } + + if (mUsesPointCoord) + { + out << "#define GL_USES_POINT_COORD\n"; + } + + if (mUsesFrontFacing) + { + out << "#define GL_USES_FRONT_FACING\n"; + } + + if (mUsesPointSize) + { + out << "#define GL_USES_POINT_SIZE\n"; + } + + if (mUsesDepthRange) + { + out << "struct gl_DepthRangeParameters\n" + "{\n" + " float near;\n" + " float far;\n" + " float diff;\n" + "};\n" + "\n" + "uniform float3 dx_DepthRange;" + "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" + "\n"; + } + + if (mUsesXor) + { + out << "bool xor(bool p, bool q)\n" + "{\n" + " return (p || q) && !(p && q);\n" + "}\n" + "\n"; + } + + if (mUsesMod1) + { + out << "float mod(float x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod2v) + { + out << "float2 mod(float2 x, float2 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod2f) + { + out << "float2 mod(float2 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod3v) + { + out << "float3 mod(float3 x, float3 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod3f) + { + out << "float3 mod(float3 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod4v) + { + out << "float4 mod(float4 x, float4 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod4f) + { + out << "float4 mod(float4 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward1) + { + out << "float faceforward(float N, float I, float Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward2) + { + out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward3) + { + out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward4) + { + out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesEqualMat2) + { + out << "bool equal(float2x2 m, float2x2 n)\n" + "{\n" + " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n" + " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n" + "}\n"; + } + + if (mUsesEqualMat3) + { + out << "bool equal(float3x3 m, float3x3 n)\n" + "{\n" + " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n" + " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n" + " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n" + "}\n"; + } + + if (mUsesEqualMat4) + { + out << "bool equal(float4x4 m, float4x4 n)\n" + "{\n" + " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] && m[0][3] == n[0][3] &&\n" + " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] && m[1][3] == n[1][3] &&\n" + " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2] && m[2][3] == n[2][3] &&\n" + " m[3][0] == n[3][0] && m[3][1] == n[3][1] && m[3][2] == n[3][2] && m[3][3] == n[3][3];\n" + "}\n"; + } + + if (mUsesEqualVec2) + { + out << "bool equal(float2 v, float2 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y;\n" + "}\n"; + } + + if (mUsesEqualVec3) + { + out << "bool equal(float3 v, float3 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y && v.z == u.z;\n" + "}\n"; + } + + if (mUsesEqualVec4) + { + out << "bool equal(float4 v, float4 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n" + "}\n"; + } + + if (mUsesEqualIVec2) + { + out << "bool equal(int2 v, int2 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y;\n" + "}\n"; + } + + if (mUsesEqualIVec3) + { + out << "bool equal(int3 v, int3 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y && v.z == u.z;\n" + "}\n"; + } + + if (mUsesEqualIVec4) + { + out << "bool equal(int4 v, int4 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n" + "}\n"; + } + + if (mUsesEqualBVec2) + { + out << "bool equal(bool2 v, bool2 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y;\n" + "}\n"; + } + + if (mUsesEqualBVec3) + { + out << "bool equal(bool3 v, bool3 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y && v.z == u.z;\n" + "}\n"; + } + + if (mUsesEqualBVec4) + { + out << "bool equal(bool4 v, bool4 u)\n" + "{\n" + " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n" + "}\n"; + } + + if (mUsesAtan2_1) + { + out << "float atanyx(float y, float x)\n" + "{\n" + " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN + " return atan2(y, x);\n" + "}\n"; + } + + if (mUsesAtan2_2) + { + out << "float2 atanyx(float2 y, float2 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" + "}\n"; + } + + if (mUsesAtan2_3) + { + out << "float3 atanyx(float3 y, float3 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" + "}\n"; + } + + if (mUsesAtan2_4) + { + out << "float4 atanyx(float4 y, float4 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" + " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n" + "}\n"; + } +} + +void OutputHLSL::visitSymbol(TIntermSymbol *node) +{ + TInfoSinkBase &out = mBody; + + TString name = node->getSymbol(); + + if (name == "gl_FragColor") + { + out << "gl_Color[0]"; + } + else if (name == "gl_FragData") + { + out << "gl_Color"; + } + else if (name == "gl_DepthRange") + { + mUsesDepthRange = true; + out << name; + } + else if (name == "gl_FragCoord") + { + mUsesFragCoord = true; + out << name; + } + else if (name == "gl_PointCoord") + { + mUsesPointCoord = true; + out << name; + } + else if (name == "gl_FrontFacing") + { + mUsesFrontFacing = true; + out << name; + } + else if (name == "gl_PointSize") + { + mUsesPointSize = true; + out << name; + } + else + { + TQualifier qualifier = node->getQualifier(); + + if (qualifier == EvqUniform) + { + mReferencedUniforms.insert(name.c_str()); + out << decorateUniform(name, node->getType()); + } + else if (qualifier == EvqAttribute) + { + mReferencedAttributes.insert(name.c_str()); + out << decorate(name); + } + else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn) + { + mReferencedVaryings.insert(name.c_str()); + out << decorate(name); + } + else + { + out << decorate(name); + } + } +} + +bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = mBody; + + switch (node->getOp()) + { + case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; + case EOpInitialize: + if (visit == PreVisit) + { + // GLSL allows to write things like "float x = x;" where a new variable x is defined + // and the value of an existing variable x is assigned. HLSL uses C semantics (the + // new variable is created before the assignment is evaluated), so we need to convert + // this to "float t = x, x = t;". + + TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); + TIntermTyped *expression = node->getRight(); + + sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); + expression->traverse(&searchSymbol); + bool sameSymbol = searchSymbol.foundMatch(); + + if (sameSymbol) + { + // Type already printed + out << "t" + str(mUniqueIndex) + " = "; + expression->traverse(this); + out << ", "; + symbolNode->traverse(this); + out << " = t" + str(mUniqueIndex); + + mUniqueIndex++; + return false; + } + } + else if (visit == InVisit) + { + out << " = "; + } + break; + case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break; + case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break; + case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break; + case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break; + case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break; + case EOpVectorTimesMatrixAssign: + if (visit == PreVisit) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = mul("; + node->getLeft()->traverse(this); + out << ", transpose("; + } + else + { + out << ")))"; + } + break; + case EOpMatrixTimesMatrixAssign: + if (visit == PreVisit) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = mul("; + node->getLeft()->traverse(this); + out << ", "; + } + else + { + out << "))"; + } + break; + case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break; + case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break; + case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break; + case EOpIndexDirectStruct: + if (visit == InVisit) + { + out << "." + decorateField(node->getType().getFieldName(), node->getLeft()->getType()); + + return false; + } + break; + case EOpVectorSwizzle: + if (visit == InVisit) + { + out << "."; + + TIntermAggregate *swizzle = node->getRight()->getAsAggregate(); + + if (swizzle) + { + TIntermSequence &sequence = swizzle->getSequence(); + + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); + + if (element) + { + int i = element->getUnionArrayPointer()[0].getIConst(); + + switch (i) + { + case 0: out << "x"; break; + case 1: out << "y"; break; + case 2: out << "z"; break; + case 3: out << "w"; break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + } + else UNREACHABLE(); + + return false; // Fully processed + } + break; + case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break; + case EOpSub: outputTriplet(visit, "(", " - ", ")"); break; + case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; + case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break; + case EOpEqual: + case EOpNotEqual: + if (node->getLeft()->isScalar()) + { + if (node->getOp() == EOpEqual) + { + outputTriplet(visit, "(", " == ", ")"); + } + else + { + outputTriplet(visit, "(", " != ", ")"); + } + } + else if (node->getLeft()->getBasicType() == EbtStruct) + { + if (node->getOp() == EOpEqual) + { + out << "("; + } + else + { + out << "!("; + } + + const TTypeList *fields = node->getLeft()->getType().getStruct(); + + for (size_t i = 0; i < fields->size(); i++) + { + const TType *fieldType = (*fields)[i].type; + + node->getLeft()->traverse(this); + out << "." + decorateField(fieldType->getFieldName(), node->getLeft()->getType()) + " == "; + node->getRight()->traverse(this); + out << "." + decorateField(fieldType->getFieldName(), node->getLeft()->getType()); + + if (i < fields->size() - 1) + { + out << " && "; + } + } + + out << ")"; + + return false; + } + else + { + if (node->getLeft()->isMatrix()) + { + switch (node->getLeft()->getNominalSize()) + { + case 2: mUsesEqualMat2 = true; break; + case 3: mUsesEqualMat3 = true; break; + case 4: mUsesEqualMat4 = true; break; + default: UNREACHABLE(); + } + } + else if (node->getLeft()->isVector()) + { + switch (node->getLeft()->getBasicType()) + { + case EbtFloat: + switch (node->getLeft()->getNominalSize()) + { + case 2: mUsesEqualVec2 = true; break; + case 3: mUsesEqualVec3 = true; break; + case 4: mUsesEqualVec4 = true; break; + default: UNREACHABLE(); + } + break; + case EbtInt: + switch (node->getLeft()->getNominalSize()) + { + case 2: mUsesEqualIVec2 = true; break; + case 3: mUsesEqualIVec3 = true; break; + case 4: mUsesEqualIVec4 = true; break; + default: UNREACHABLE(); + } + break; + case EbtBool: + switch (node->getLeft()->getNominalSize()) + { + case 2: mUsesEqualBVec2 = true; break; + case 3: mUsesEqualBVec3 = true; break; + case 4: mUsesEqualBVec4 = true; break; + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + + if (node->getOp() == EOpEqual) + { + outputTriplet(visit, "equal(", ", ", ")"); + } + else + { + outputTriplet(visit, "!equal(", ", ", ")"); + } + } + break; + case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; + case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; + case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; + case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; + case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break; + case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break; + case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break; + case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break; + case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break; + case EOpLogicalOr: + out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); + return false; + case EOpLogicalXor: + mUsesXor = true; + outputTriplet(visit, "xor(", ", ", ")"); + break; + case EOpLogicalAnd: + out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); + return false; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) +{ + switch (node->getOp()) + { + case EOpNegative: outputTriplet(visit, "(-", "", ")"); break; + case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; + case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break; + case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break; + case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break; + case EOpConvIntToBool: + case EOpConvFloatToBool: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "bool(", "", ")"); break; + case 2: outputTriplet(visit, "bool2(", "", ")"); break; + case 3: outputTriplet(visit, "bool3(", "", ")"); break; + case 4: outputTriplet(visit, "bool4(", "", ")"); break; + default: UNREACHABLE(); + } + break; + case EOpConvBoolToFloat: + case EOpConvIntToFloat: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "float(", "", ")"); break; + case 2: outputTriplet(visit, "float2(", "", ")"); break; + case 3: outputTriplet(visit, "float3(", "", ")"); break; + case 4: outputTriplet(visit, "float4(", "", ")"); break; + default: UNREACHABLE(); + } + break; + case EOpConvFloatToInt: + case EOpConvBoolToInt: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "int(", "", ")"); break; + case 2: outputTriplet(visit, "int2(", "", ")"); break; + case 3: outputTriplet(visit, "int3(", "", ")"); break; + case 4: outputTriplet(visit, "int4(", "", ")"); break; + default: UNREACHABLE(); + } + break; + case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break; + case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break; + case EOpSin: outputTriplet(visit, "sin(", "", ")"); break; + case EOpCos: outputTriplet(visit, "cos(", "", ")"); break; + case EOpTan: outputTriplet(visit, "tan(", "", ")"); break; + case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break; + case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break; + case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break; + case EOpExp: outputTriplet(visit, "exp(", "", ")"); break; + case EOpLog: outputTriplet(visit, "log(", "", ")"); break; + case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break; + case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break; + case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break; + case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break; + case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break; + case EOpSign: outputTriplet(visit, "sign(", "", ")"); break; + case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break; + case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break; + case EOpFract: outputTriplet(visit, "frac(", "", ")"); break; + case EOpLength: outputTriplet(visit, "length(", "", ")"); break; + case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break; + case EOpDFdx: + if(mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(visit, "ddx(", "", ")"); + } + break; + case EOpDFdy: + if(mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(visit, "ddy(", "", ")"); + } + break; + case EOpFwidth: + if(mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(visit, "fwidth(", "", ")"); + } + break; + case EOpAny: outputTriplet(visit, "any(", "", ")"); break; + case EOpAll: outputTriplet(visit, "all(", "", ")"); break; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) +{ + TInfoSinkBase &out = mBody; + + switch (node->getOp()) + { + case EOpSequence: + { + if (mInsideFunction) + { + outputLineDirective(node->getLine()); + out << "{\n"; + + mScopeDepth++; + + if (mScopeBracket.size() < mScopeDepth) + { + mScopeBracket.push_back(0); // New scope level + } + else + { + mScopeBracket[mScopeDepth - 1]++; // New scope at existing level + } + } + + for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++) + { + outputLineDirective((*sit)->getLine()); + + traverseStatements(*sit); + + out << ";\n"; + } + + if (mInsideFunction) + { + outputLineDirective(node->getEndLine()); + out << "}\n"; + + mScopeDepth--; + } + + return false; + } + case EOpDeclaration: + if (visit == PreVisit) + { + TIntermSequence &sequence = node->getSequence(); + TIntermTyped *variable = sequence[0]->getAsTyped(); + bool visit = true; + + if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal)) + { + if (variable->getType().getStruct()) + { + addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL); + } + + if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration + { + if (!mInsideFunction) + { + out << "static "; + } + + out << typeString(variable->getType()) + " "; + + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); + + if (symbol) + { + symbol->traverse(this); + out << arrayString(symbol->getType()); + out << " = " + initializer(variable->getType()); + } + else + { + (*sit)->traverse(this); + } + + if (visit && this->inVisit) + { + if (*sit != sequence.back()) + { + visit = this->visitAggregate(InVisit, node); + } + } + } + + if (visit && this->postVisit) + { + this->visitAggregate(PostVisit, node); + } + } + else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration + { + // Already added to constructor map + } + else UNREACHABLE(); + } + + return false; + } + else if (visit == InVisit) + { + out << ", "; + } + break; + case EOpPrototype: + if (visit == PreVisit) + { + out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "("); + + TIntermSequence &arguments = node->getSequence(); + + for (unsigned int i = 0; i < arguments.size(); i++) + { + TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); + + if (symbol) + { + out << argumentString(symbol); + + if (i < arguments.size() - 1) + { + out << ", "; + } + } + else UNREACHABLE(); + } + + out << ");\n"; + + // Also prototype the Lod0 variant if needed + if (mContainsLoopDiscontinuity && !mOutputLod0Function) + { + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } + + return false; + } + break; + case EOpComma: outputTriplet(visit, "(", ", ", ")"); break; + case EOpFunction: + { + TString name = TFunction::unmangleName(node->getName()); + + out << typeString(node->getType()) << " "; + + if (name == "main") + { + out << "gl_main("; + } + else + { + out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "("); + } + + TIntermSequence &sequence = node->getSequence(); + TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence(); + + for (unsigned int i = 0; i < arguments.size(); i++) + { + TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); + + if (symbol) + { + if (symbol->getType().getStruct()) + { + addConstructor(symbol->getType(), scopedStruct(symbol->getType().getTypeName()), NULL); + } + + out << argumentString(symbol); + + if (i < arguments.size() - 1) + { + out << ", "; + } + } + else UNREACHABLE(); + } + + out << ")\n" + "{\n"; + + if (sequence.size() > 1) + { + mInsideFunction = true; + sequence[1]->traverse(this); + mInsideFunction = false; + } + + out << "}\n"; + + if (mContainsLoopDiscontinuity && !mOutputLod0Function) + { + if (name != "main") + { + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } + } + + return false; + } + break; + case EOpFunctionCall: + { + if (visit == PreVisit) + { + TString name = TFunction::unmangleName(node->getName()); + bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function; + + if (node->isUserDefined()) + { + out << decorate(name) << (lod0 ? "Lod0(" : "("); + } + else + { + if (name == "texture2D") + { + if (!lod0) + { + if (node->getSequence().size() == 2) + { + mUsesTexture2D = true; + } + else if (node->getSequence().size() == 3) + { + mUsesTexture2D_bias = true; + } + else UNREACHABLE(); + + out << "gl_texture2D("; + } + else + { + if (node->getSequence().size() == 2) + { + mUsesTexture2DLod0 = true; + } + else if (node->getSequence().size() == 3) + { + mUsesTexture2DLod0_bias = true; + } + else UNREACHABLE(); + + out << "gl_texture2DLod0("; + } + } + else if (name == "texture2DProj") + { + if (!lod0) + { + if (node->getSequence().size() == 2) + { + mUsesTexture2DProj = true; + } + else if (node->getSequence().size() == 3) + { + mUsesTexture2DProj_bias = true; + } + else UNREACHABLE(); + + out << "gl_texture2DProj("; + } + else + { + if (node->getSequence().size() == 2) + { + mUsesTexture2DProjLod0 = true; + } + else if (node->getSequence().size() == 3) + { + mUsesTexture2DProjLod0_bias = true; + } + else UNREACHABLE(); + + out << "gl_texture2DProjLod0("; + } + } + else if (name == "textureCube") + { + if (!lod0) + { + if (node->getSequence().size() == 2) + { + mUsesTextureCube = true; + } + else if (node->getSequence().size() == 3) + { + mUsesTextureCube_bias = true; + } + else UNREACHABLE(); + + out << "gl_textureCube("; + } + else + { + if (node->getSequence().size() == 2) + { + mUsesTextureCubeLod0 = true; + } + else if (node->getSequence().size() == 3) + { + mUsesTextureCubeLod0_bias = true; + } + else UNREACHABLE(); + + out << "gl_textureCubeLod0("; + } + } + else if (name == "texture2DLod") + { + if (node->getSequence().size() == 3) + { + mUsesTexture2DLod = true; + } + else UNREACHABLE(); + + out << "gl_texture2DLod("; + } + else if (name == "texture2DProjLod") + { + if (node->getSequence().size() == 3) + { + mUsesTexture2DProjLod = true; + } + else UNREACHABLE(); + + out << "gl_texture2DProjLod("; + } + else if (name == "textureCubeLod") + { + if (node->getSequence().size() == 3) + { + mUsesTextureCubeLod = true; + } + else UNREACHABLE(); + + out << "gl_textureCubeLod("; + } + else UNREACHABLE(); + } + } + else if (visit == InVisit) + { + out << ", "; + } + else + { + out << ")"; + } + } + break; + case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break; + case EOpConstructFloat: + addConstructor(node->getType(), "vec1", &node->getSequence()); + outputTriplet(visit, "vec1(", "", ")"); + break; + case EOpConstructVec2: + addConstructor(node->getType(), "vec2", &node->getSequence()); + outputTriplet(visit, "vec2(", ", ", ")"); + break; + case EOpConstructVec3: + addConstructor(node->getType(), "vec3", &node->getSequence()); + outputTriplet(visit, "vec3(", ", ", ")"); + break; + case EOpConstructVec4: + addConstructor(node->getType(), "vec4", &node->getSequence()); + outputTriplet(visit, "vec4(", ", ", ")"); + break; + case EOpConstructBool: + addConstructor(node->getType(), "bvec1", &node->getSequence()); + outputTriplet(visit, "bvec1(", "", ")"); + break; + case EOpConstructBVec2: + addConstructor(node->getType(), "bvec2", &node->getSequence()); + outputTriplet(visit, "bvec2(", ", ", ")"); + break; + case EOpConstructBVec3: + addConstructor(node->getType(), "bvec3", &node->getSequence()); + outputTriplet(visit, "bvec3(", ", ", ")"); + break; + case EOpConstructBVec4: + addConstructor(node->getType(), "bvec4", &node->getSequence()); + outputTriplet(visit, "bvec4(", ", ", ")"); + break; + case EOpConstructInt: + addConstructor(node->getType(), "ivec1", &node->getSequence()); + outputTriplet(visit, "ivec1(", "", ")"); + break; + case EOpConstructIVec2: + addConstructor(node->getType(), "ivec2", &node->getSequence()); + outputTriplet(visit, "ivec2(", ", ", ")"); + break; + case EOpConstructIVec3: + addConstructor(node->getType(), "ivec3", &node->getSequence()); + outputTriplet(visit, "ivec3(", ", ", ")"); + break; + case EOpConstructIVec4: + addConstructor(node->getType(), "ivec4", &node->getSequence()); + outputTriplet(visit, "ivec4(", ", ", ")"); + break; + case EOpConstructMat2: + addConstructor(node->getType(), "mat2", &node->getSequence()); + outputTriplet(visit, "mat2(", ", ", ")"); + break; + case EOpConstructMat3: + addConstructor(node->getType(), "mat3", &node->getSequence()); + outputTriplet(visit, "mat3(", ", ", ")"); + break; + case EOpConstructMat4: + addConstructor(node->getType(), "mat4", &node->getSequence()); + outputTriplet(visit, "mat4(", ", ", ")"); + break; + case EOpConstructStruct: + addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence()); + outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")"); + break; + case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; + case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; + case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; + case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; + case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break; + case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break; + case EOpMod: + { + // We need to look at the number of components in both arguments + switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10 + + node->getSequence()[1]->getAsTyped()->getNominalSize()) + { + case 11: mUsesMod1 = true; break; + case 22: mUsesMod2v = true; break; + case 21: mUsesMod2f = true; break; + case 33: mUsesMod3v = true; break; + case 31: mUsesMod3f = true; break; + case 44: mUsesMod4v = true; break; + case 41: mUsesMod4f = true; break; + default: UNREACHABLE(); + } + + outputTriplet(visit, "mod(", ", ", ")"); + } + break; + case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break; + case EOpAtan: + ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator + switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) + { + case 1: mUsesAtan2_1 = true; break; + case 2: mUsesAtan2_2 = true; break; + case 3: mUsesAtan2_3 = true; break; + case 4: mUsesAtan2_4 = true; break; + default: UNREACHABLE(); + } + outputTriplet(visit, "atanyx(", ", ", ")"); + break; + case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break; + case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break; + case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break; + case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break; + case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break; + case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break; + case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break; + case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break; + case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break; + case EOpFaceForward: + { + switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument + { + case 1: mUsesFaceforward1 = true; break; + case 2: mUsesFaceforward2 = true; break; + case 3: mUsesFaceforward3 = true; break; + case 4: mUsesFaceforward4 = true; break; + default: UNREACHABLE(); + } + + outputTriplet(visit, "faceforward(", ", ", ")"); + } + break; + case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break; + case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break; + case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) +{ + TInfoSinkBase &out = mBody; + + if (node->usesTernaryOperator()) + { + out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); + } + else // if/else statement + { + mUnfoldShortCircuit->traverse(node->getCondition()); + + out << "if("; + + node->getCondition()->traverse(this); + + out << ")\n"; + + outputLineDirective(node->getLine()); + out << "{\n"; + + if (node->getTrueBlock()) + { + traverseStatements(node->getTrueBlock()); + } + + outputLineDirective(node->getLine()); + out << ";\n}\n"; + + if (node->getFalseBlock()) + { + out << "else\n"; + + outputLineDirective(node->getFalseBlock()->getLine()); + out << "{\n"; + + outputLineDirective(node->getFalseBlock()->getLine()); + traverseStatements(node->getFalseBlock()); + + outputLineDirective(node->getFalseBlock()->getLine()); + out << ";\n}\n"; + } + } + + return false; +} + +void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) +{ + writeConstantUnion(node->getType(), node->getUnionArrayPointer()); +} + +bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) +{ + bool wasDiscontinuous = mInsideDiscontinuousLoop; + + if (!mInsideDiscontinuousLoop) + { + mInsideDiscontinuousLoop = containsLoopDiscontinuity(node); + } + + if (handleExcessiveLoop(node)) + { + return false; + } + + TInfoSinkBase &out = mBody; + + if (node->getType() == ELoopDoWhile) + { + out << "{do\n"; + + outputLineDirective(node->getLine()); + out << "{\n"; + } + else + { + out << "{for("; + + if (node->getInit()) + { + node->getInit()->traverse(this); + } + + out << "; "; + + if (node->getCondition()) + { + node->getCondition()->traverse(this); + } + + out << "; "; + + if (node->getExpression()) + { + node->getExpression()->traverse(this); + } + + out << ")\n"; + + outputLineDirective(node->getLine()); + out << "{\n"; + } + + if (node->getBody()) + { + traverseStatements(node->getBody()); + } + + outputLineDirective(node->getLine()); + out << ";}\n"; + + if (node->getType() == ELoopDoWhile) + { + outputLineDirective(node->getCondition()->getLine()); + out << "while(\n"; + + node->getCondition()->traverse(this); + + out << ");"; + } + + out << "}\n"; + + mInsideDiscontinuousLoop = wasDiscontinuous; + + return false; +} + +bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) +{ + TInfoSinkBase &out = mBody; + + switch (node->getFlowOp()) + { + case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break; + case EOpBreak: + if (visit == PreVisit) + { + if (mExcessiveLoopIndex) + { + out << "{Break"; + mExcessiveLoopIndex->traverse(this); + out << " = true; break;}\n"; + } + else + { + out << "break;\n"; + } + } + break; + case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break; + case EOpReturn: + if (visit == PreVisit) + { + if (node->getExpression()) + { + out << "return "; + } + else + { + out << "return;\n"; + } + } + else if (visit == PostVisit) + { + if (node->getExpression()) + { + out << ";\n"; + } + } + break; + default: UNREACHABLE(); + } + + return true; +} + +void OutputHLSL::traverseStatements(TIntermNode *node) +{ + if (isSingleStatement(node)) + { + mUnfoldShortCircuit->traverse(node); + } + + node->traverse(this); +} + +bool OutputHLSL::isSingleStatement(TIntermNode *node) +{ + TIntermAggregate *aggregate = node->getAsAggregate(); + + if (aggregate) + { + if (aggregate->getOp() == EOpSequence) + { + return false; + } + else + { + for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++) + { + if (!isSingleStatement(*sit)) + { + return false; + } + } + + return true; + } + } + + return true; +} + +// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them +// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254). +bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) +{ + const int MAX_LOOP_ITERATIONS = 254; + TInfoSinkBase &out = mBody; + + // Parse loops of the form: + // for(int index = initial; index [comparator] limit; index += increment) + TIntermSymbol *index = NULL; + TOperator comparator = EOpNull; + int initial = 0; + int limit = 0; + int increment = 0; + + // Parse index name and intial value + if (node->getInit()) + { + TIntermAggregate *init = node->getInit()->getAsAggregate(); + + if (init) + { + TIntermSequence &sequence = init->getSequence(); + TIntermTyped *variable = sequence[0]->getAsTyped(); + + if (variable && variable->getQualifier() == EvqTemporary) + { + TIntermBinary *assign = variable->getAsBinaryNode(); + + if (assign->getOp() == EOpInitialize) + { + TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode(); + TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion(); + + if (symbol && constant) + { + if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) + { + index = symbol; + initial = constant->getUnionArrayPointer()[0].getIConst(); + } + } + } + } + } + } + + // Parse comparator and limit value + if (index != NULL && node->getCondition()) + { + TIntermBinary *test = node->getCondition()->getAsBinaryNode(); + + if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId()) + { + TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion(); + + if (constant) + { + if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) + { + comparator = test->getOp(); + limit = constant->getUnionArrayPointer()[0].getIConst(); + } + } + } + } + + // Parse increment + if (index != NULL && comparator != EOpNull && node->getExpression()) + { + TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode(); + TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode(); + + if (binaryTerminal) + { + TOperator op = binaryTerminal->getOp(); + TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion(); + + if (constant) + { + if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1) + { + int value = constant->getUnionArrayPointer()[0].getIConst(); + + switch (op) + { + case EOpAddAssign: increment = value; break; + case EOpSubAssign: increment = -value; break; + default: UNIMPLEMENTED(); + } + } + } + } + else if (unaryTerminal) + { + TOperator op = unaryTerminal->getOp(); + + switch (op) + { + case EOpPostIncrement: increment = 1; break; + case EOpPostDecrement: increment = -1; break; + case EOpPreIncrement: increment = 1; break; + case EOpPreDecrement: increment = -1; break; + default: UNIMPLEMENTED(); + } + } + } + + if (index != NULL && comparator != EOpNull && increment != 0) + { + if (comparator == EOpLessThanEqual) + { + comparator = EOpLessThan; + limit += 1; + } + + if (comparator == EOpLessThan) + { + int iterations = (limit - initial) / increment; + + if (iterations <= MAX_LOOP_ITERATIONS) + { + return false; // Not an excessive loop + } + + TIntermSymbol *restoreIndex = mExcessiveLoopIndex; + mExcessiveLoopIndex = index; + + out << "{int "; + index->traverse(this); + out << ";\n" + "bool Break"; + index->traverse(this); + out << " = false;\n"; + + bool firstLoopFragment = true; + + while (iterations > 0) + { + int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations); + + if (!firstLoopFragment) + { + out << "if(!Break"; + index->traverse(this); + out << ") {\n"; + } + + if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment + { + mExcessiveLoopIndex = NULL; // Stops setting the Break flag + } + + // for(int index = initial; index < clampedLimit; index += increment) + + out << "for("; + index->traverse(this); + out << " = "; + out << initial; + + out << "; "; + index->traverse(this); + out << " < "; + out << clampedLimit; + + out << "; "; + index->traverse(this); + out << " += "; + out << increment; + out << ")\n"; + + outputLineDirective(node->getLine()); + out << "{\n"; + + if (node->getBody()) + { + node->getBody()->traverse(this); + } + + outputLineDirective(node->getLine()); + out << ";}\n"; + + if (!firstLoopFragment) + { + out << "}\n"; + } + + firstLoopFragment = false; + + initial += MAX_LOOP_ITERATIONS * increment; + iterations -= MAX_LOOP_ITERATIONS; + } + + out << "}"; + + mExcessiveLoopIndex = restoreIndex; + + return true; + } + else UNIMPLEMENTED(); + } + + return false; // Not handled as an excessive loop +} + +void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString) +{ + TInfoSinkBase &out = mBody; + + if (visit == PreVisit) + { + out << preString; + } + else if (visit == InVisit) + { + out << inString; + } + else if (visit == PostVisit) + { + out << postString; + } +} + +void OutputHLSL::outputLineDirective(int line) +{ + if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0)) + { + mBody << "\n"; + mBody << "#line " << line; + + if (mContext.sourcePath) + { + mBody << " \"" << mContext.sourcePath << "\""; + } + + mBody << "\n"; + } +} + +TString OutputHLSL::argumentString(const TIntermSymbol *symbol) +{ + TQualifier qualifier = symbol->getQualifier(); + const TType &type = symbol->getType(); + TString name = symbol->getSymbol(); + + if (name.empty()) // HLSL demands named arguments, also for prototypes + { + name = "x" + str(mUniqueIndex++); + } + else + { + name = decorate(name); + } + + return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type); +} + +TString OutputHLSL::qualifierString(TQualifier qualifier) +{ + switch(qualifier) + { + case EvqIn: return "in"; + case EvqOut: return "out"; + case EvqInOut: return "inout"; + case EvqConstReadOnly: return "const"; + default: UNREACHABLE(); + } + + return ""; +} + +TString OutputHLSL::typeString(const TType &type) +{ + if (type.getBasicType() == EbtStruct) + { + if (type.getTypeName() != "") + { + return structLookup(type.getTypeName()); + } + else // Nameless structure, define in place + { + const TTypeList &fields = *type.getStruct(); + + TString string = "struct\n" + "{\n"; + + for (unsigned int i = 0; i < fields.size(); i++) + { + const TType &field = *fields[i].type; + + string += " " + typeString(field) + " " + decorate(field.getFieldName()) + arrayString(field) + ";\n"; + } + + string += "} "; + + return string; + } + } + else if (type.isMatrix()) + { + switch (type.getNominalSize()) + { + case 2: return "float2x2"; + case 3: return "float3x3"; + case 4: return "float4x4"; + } + } + else + { + switch (type.getBasicType()) + { + case EbtFloat: + switch (type.getNominalSize()) + { + case 1: return "float"; + case 2: return "float2"; + case 3: return "float3"; + case 4: return "float4"; + } + case EbtInt: + switch (type.getNominalSize()) + { + case 1: return "int"; + case 2: return "int2"; + case 3: return "int3"; + case 4: return "int4"; + } + case EbtBool: + switch (type.getNominalSize()) + { + case 1: return "bool"; + case 2: return "bool2"; + case 3: return "bool3"; + case 4: return "bool4"; + } + case EbtVoid: + return "void"; + case EbtSampler2D: + return "sampler2D"; + case EbtSamplerCube: + return "samplerCUBE"; + case EbtSamplerExternalOES: + return "sampler2D"; + default: + break; + } + } + + UNIMPLEMENTED(); // FIXME + return ""; +} + +TString OutputHLSL::arrayString(const TType &type) +{ + if (!type.isArray()) + { + return ""; + } + + return "[" + str(type.getArraySize()) + "]"; +} + +TString OutputHLSL::initializer(const TType &type) +{ + TString string; + + for (int component = 0; component < type.getObjectSize(); component++) + { + string += "0"; + + if (component < type.getObjectSize() - 1) + { + string += ", "; + } + } + + return "{" + string + "}"; +} + +void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) +{ + if (name == "") + { + return; // Nameless structures don't have constructors + } + + if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end()) + { + return; // Already added + } + + TType ctorType = type; + ctorType.clearArrayness(); + ctorType.setPrecision(EbpHigh); + ctorType.setQualifier(EvqTemporary); + + TString ctorName = type.getStruct() ? decorate(name) : name; + + typedef std::vector ParameterArray; + ParameterArray ctorParameters; + + if (type.getStruct()) + { + mStructNames.insert(decorate(name)); + + TString structure; + structure += "struct " + decorate(name) + "\n" + "{\n"; + + const TTypeList &fields = *type.getStruct(); + + for (unsigned int i = 0; i < fields.size(); i++) + { + const TType &field = *fields[i].type; + + structure += " " + typeString(field) + " " + decorateField(field.getFieldName(), type) + arrayString(field) + ";\n"; + } + + structure += "};\n"; + + if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end()) + { + mStructDeclarations.push_back(structure); + } + + for (unsigned int i = 0; i < fields.size(); i++) + { + ctorParameters.push_back(*fields[i].type); + } + } + else if (parameters) + { + for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) + { + ctorParameters.push_back((*parameter)->getAsTyped()->getType()); + } + } + else UNREACHABLE(); + + TString constructor; + + if (ctorType.getStruct()) + { + constructor += ctorName + " " + ctorName + "_ctor("; + } + else // Built-in type + { + constructor += typeString(ctorType) + " " + ctorName + "("; + } + + for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) + { + const TType &type = ctorParameters[parameter]; + + constructor += typeString(type) + " x" + str(parameter) + arrayString(type); + + if (parameter < ctorParameters.size() - 1) + { + constructor += ", "; + } + } + + constructor += ")\n" + "{\n"; + + if (ctorType.getStruct()) + { + constructor += " " + ctorName + " structure = {"; + } + else + { + constructor += " return " + typeString(ctorType) + "("; + } + + if (ctorType.isMatrix() && ctorParameters.size() == 1) + { + int dim = ctorType.getNominalSize(); + const TType ¶meter = ctorParameters[0]; + + if (parameter.isScalar()) + { + for (int row = 0; row < dim; row++) + { + for (int col = 0; col < dim; col++) + { + constructor += TString((row == col) ? "x0" : "0.0"); + + if (row < dim - 1 || col < dim - 1) + { + constructor += ", "; + } + } + } + } + else if (parameter.isMatrix()) + { + for (int row = 0; row < dim; row++) + { + for (int col = 0; col < dim; col++) + { + if (row < parameter.getNominalSize() && col < parameter.getNominalSize()) + { + constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]"; + } + else + { + constructor += TString((row == col) ? "1.0" : "0.0"); + } + + if (row < dim - 1 || col < dim - 1) + { + constructor += ", "; + } + } + } + } + else UNREACHABLE(); + } + else + { + int remainingComponents = ctorType.getObjectSize(); + int parameterIndex = 0; + + while (remainingComponents > 0) + { + const TType ¶meter = ctorParameters[parameterIndex]; + bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1; + + constructor += "x" + str(parameterIndex); + + if (parameter.isScalar()) + { + remainingComponents -= parameter.getObjectSize(); + } + else if (parameter.isVector()) + { + if (remainingComponents == parameter.getObjectSize() || moreParameters) + { + remainingComponents -= parameter.getObjectSize(); + } + else if (remainingComponents < parameter.getNominalSize()) + { + switch (remainingComponents) + { + case 1: constructor += ".x"; break; + case 2: constructor += ".xy"; break; + case 3: constructor += ".xyz"; break; + case 4: constructor += ".xyzw"; break; + default: UNREACHABLE(); + } + + remainingComponents = 0; + } + else UNREACHABLE(); + } + else if (parameter.isMatrix() || parameter.getStruct()) + { + ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters); + + remainingComponents -= parameter.getObjectSize(); + } + else UNREACHABLE(); + + if (moreParameters) + { + parameterIndex++; + } + + if (remainingComponents) + { + constructor += ", "; + } + } + } + + if (ctorType.getStruct()) + { + constructor += "};\n" + " return structure;\n" + "}\n"; + } + else + { + constructor += ");\n" + "}\n"; + } + + mConstructors.insert(constructor); +} + +const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion) +{ + TInfoSinkBase &out = mBody; + + if (type.getBasicType() == EbtStruct) + { + out << structLookup(type.getTypeName()) + "_ctor("; + + const TTypeList *structure = type.getStruct(); + + for (size_t i = 0; i < structure->size(); i++) + { + const TType *fieldType = (*structure)[i].type; + + constUnion = writeConstantUnion(*fieldType, constUnion); + + if (i != structure->size() - 1) + { + out << ", "; + } + } + + out << ")"; + } + else + { + int size = type.getObjectSize(); + bool writeType = size > 1; + + if (writeType) + { + out << typeString(type) << "("; + } + + for (int i = 0; i < size; i++, constUnion++) + { + switch (constUnion->getType()) + { + case EbtFloat: out << constUnion->getFConst(); break; + case EbtInt: out << constUnion->getIConst(); break; + case EbtBool: out << constUnion->getBConst(); break; + default: UNREACHABLE(); + } + + if (i != size - 1) + { + out << ", "; + } + } + + if (writeType) + { + out << ")"; + } + } + + return constUnion; +} + +TString OutputHLSL::scopeString(unsigned int depthLimit) +{ + TString string; + + for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++) + { + string += "_" + str(i); + } + + return string; +} + +TString OutputHLSL::scopedStruct(const TString &typeName) +{ + if (typeName == "") + { + return typeName; + } + + return typeName + scopeString(mScopeDepth); +} + +TString OutputHLSL::structLookup(const TString &typeName) +{ + for (int depth = mScopeDepth; depth >= 0; depth--) + { + TString scopedName = decorate(typeName + scopeString(depth)); + + for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++) + { + if (*structName == scopedName) + { + return scopedName; + } + } + } + + UNREACHABLE(); // Should have found a matching constructor + + return typeName; +} + +TString OutputHLSL::decorate(const TString &string) +{ + if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0) + { + return "_" + string; + } + + return string; +} + +TString OutputHLSL::decorateUniform(const TString &string, const TType &type) +{ + if (type.isArray()) + { + return "ar_" + string; // Allows identifying arrays of size 1 + } + else if (type.getBasicType() == EbtSamplerExternalOES) + { + return "ex_" + string; + } + + return decorate(string); +} + +TString OutputHLSL::decorateField(const TString &string, const TType &structure) +{ + if (structure.getTypeName().compare(0, 3, "gl_") != 0) + { + return decorate(string); + } + + return string; +} +} diff --git a/src/3rdparty/angle/src/compiler/OutputHLSL.h b/src/3rdparty/angle/src/compiler/OutputHLSL.h new file mode 100644 index 0000000000..dc843fb366 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/OutputHLSL.h @@ -0,0 +1,152 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_OUTPUTHLSL_H_ +#define COMPILER_OUTPUTHLSL_H_ + +#include +#include + +#include "compiler/intermediate.h" +#include "compiler/ParseHelper.h" + +namespace sh +{ +class UnfoldShortCircuit; + +class OutputHLSL : public TIntermTraverser +{ + public: + explicit OutputHLSL(TParseContext &context); + ~OutputHLSL(); + + void output(); + + TInfoSinkBase &getBodyStream(); + + TString typeString(const TType &type); + static TString qualifierString(TQualifier qualifier); + static TString arrayString(const TType &type); + static TString initializer(const TType &type); + static TString decorate(const TString &string); // Prepends an underscore to avoid naming clashes + static TString decorateUniform(const TString &string, const TType &type); + static TString decorateField(const TString &string, const TType &structure); + + protected: + void header(); + + // Visit AST nodes and output their code to the body stream + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); + + void traverseStatements(TIntermNode *node); + bool isSingleStatement(TIntermNode *node); + bool handleExcessiveLoop(TIntermLoop *node); + void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString); + void outputLineDirective(int line); + TString argumentString(const TIntermSymbol *symbol); + int vectorSize(const TType &type) const; + + void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters); + const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion); + + TString scopeString(unsigned int depthLimit); + TString scopedStruct(const TString &typeName); + TString structLookup(const TString &typeName); + + TParseContext &mContext; + UnfoldShortCircuit *mUnfoldShortCircuit; + bool mInsideFunction; + + // Output streams + TInfoSinkBase mHeader; + TInfoSinkBase mBody; + TInfoSinkBase mFooter; + + std::set mReferencedUniforms; + std::set mReferencedAttributes; + std::set mReferencedVaryings; + + // Parameters determining what goes in the header output + bool mUsesTexture2D; + bool mUsesTexture2D_bias; + bool mUsesTexture2DLod; + bool mUsesTexture2DProj; + bool mUsesTexture2DProj_bias; + bool mUsesTexture2DProjLod; + bool mUsesTextureCube; + bool mUsesTextureCube_bias; + bool mUsesTextureCubeLod; + bool mUsesTexture2DLod0; + bool mUsesTexture2DLod0_bias; + bool mUsesTexture2DProjLod0; + bool mUsesTexture2DProjLod0_bias; + bool mUsesTextureCubeLod0; + bool mUsesTextureCubeLod0_bias; + bool mUsesDepthRange; + bool mUsesFragCoord; + bool mUsesPointCoord; + bool mUsesFrontFacing; + bool mUsesPointSize; + bool mUsesXor; + bool mUsesMod1; + bool mUsesMod2v; + bool mUsesMod2f; + bool mUsesMod3v; + bool mUsesMod3f; + bool mUsesMod4v; + bool mUsesMod4f; + bool mUsesFaceforward1; + bool mUsesFaceforward2; + bool mUsesFaceforward3; + bool mUsesFaceforward4; + bool mUsesEqualMat2; + bool mUsesEqualMat3; + bool mUsesEqualMat4; + bool mUsesEqualVec2; + bool mUsesEqualVec3; + bool mUsesEqualVec4; + bool mUsesEqualIVec2; + bool mUsesEqualIVec3; + bool mUsesEqualIVec4; + bool mUsesEqualBVec2; + bool mUsesEqualBVec3; + bool mUsesEqualBVec4; + bool mUsesAtan2_1; + bool mUsesAtan2_2; + bool mUsesAtan2_3; + bool mUsesAtan2_4; + + typedef std::set Constructors; + Constructors mConstructors; + + typedef std::set StructNames; + StructNames mStructNames; + + typedef std::list StructDeclarations; + StructDeclarations mStructDeclarations; + + typedef std::vector ScopeBracket; + ScopeBracket mScopeBracket; + unsigned int mScopeDepth; + + int mUniqueIndex; // For creating unique names + + bool mContainsLoopDiscontinuity; + bool mOutputLod0Function; + bool mInsideDiscontinuousLoop; + + TIntermSymbol *mExcessiveLoopIndex; +}; +} + +#endif // COMPILER_OUTPUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/ParseHelper.cpp b/src/3rdparty/angle/src/compiler/ParseHelper.cpp new file mode 100644 index 0000000000..508f1726a7 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ParseHelper.cpp @@ -0,0 +1,1528 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/ParseHelper.h" + +#include +#include + +#include "compiler/glslang.h" +#include "compiler/preprocessor/new/SourceLocation.h" + +/////////////////////////////////////////////////////////////////////// +// +// Sub- vector and matrix fields +// +//////////////////////////////////////////////////////////////////////// + +// +// Look at a '.' field selector string and change it into offsets +// for a vector. +// +bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, int line) +{ + fields.num = (int) compString.size(); + if (fields.num > 4) { + error(line, "illegal vector field selection", compString.c_str()); + return false; + } + + enum { + exyzw, + ergba, + estpq, + } fieldSet[4]; + + for (int i = 0; i < fields.num; ++i) { + switch (compString[i]) { + case 'x': + fields.offsets[i] = 0; + fieldSet[i] = exyzw; + break; + case 'r': + fields.offsets[i] = 0; + fieldSet[i] = ergba; + break; + case 's': + fields.offsets[i] = 0; + fieldSet[i] = estpq; + break; + case 'y': + fields.offsets[i] = 1; + fieldSet[i] = exyzw; + break; + case 'g': + fields.offsets[i] = 1; + fieldSet[i] = ergba; + break; + case 't': + fields.offsets[i] = 1; + fieldSet[i] = estpq; + break; + case 'z': + fields.offsets[i] = 2; + fieldSet[i] = exyzw; + break; + case 'b': + fields.offsets[i] = 2; + fieldSet[i] = ergba; + break; + case 'p': + fields.offsets[i] = 2; + fieldSet[i] = estpq; + break; + + case 'w': + fields.offsets[i] = 3; + fieldSet[i] = exyzw; + break; + case 'a': + fields.offsets[i] = 3; + fieldSet[i] = ergba; + break; + case 'q': + fields.offsets[i] = 3; + fieldSet[i] = estpq; + break; + default: + error(line, "illegal vector field selection", compString.c_str()); + return false; + } + } + + for (int i = 0; i < fields.num; ++i) { + if (fields.offsets[i] >= vecSize) { + error(line, "vector field selection out of range", compString.c_str()); + return false; + } + + if (i > 0) { + if (fieldSet[i] != fieldSet[i-1]) { + error(line, "illegal - vector component fields not from the same set", compString.c_str()); + return false; + } + } + } + + return true; +} + + +// +// Look at a '.' field selector string and change it into offsets +// for a matrix. +// +bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, int line) +{ + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = -1; + fields.col = -1; + + if (compString.size() != 2) { + error(line, "illegal length of matrix field selection", compString.c_str()); + return false; + } + + if (compString[0] == '_') { + if (compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.wholeCol = true; + fields.col = compString[1] - '0'; + } else if (compString[1] == '_') { + if (compString[0] < '0' || compString[0] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.wholeRow = true; + fields.row = compString[0] - '0'; + } else { + if (compString[0] < '0' || compString[0] > '3' || + compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.row = compString[0] - '0'; + fields.col = compString[1] - '0'; + } + + if (fields.row >= matSize || fields.col >= matSize) { + error(line, "matrix field selection out of range", compString.c_str()); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////// +// +// Errors +// +//////////////////////////////////////////////////////////////////////// + +// +// Track whether errors have occurred. +// +void TParseContext::recover() +{ +} + +// +// Used by flex/bison to output all syntax and parsing errors. +// +void TParseContext::error(TSourceLoc loc, + const char* reason, const char* token, + const char* extraInfo) +{ + pp::SourceLocation srcLoc; + DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line); + diagnostics.writeInfo(pp::Diagnostics::ERROR, + srcLoc, reason, token, extraInfo); + +} + +void TParseContext::warning(TSourceLoc loc, + const char* reason, const char* token, + const char* extraInfo) { + pp::SourceLocation srcLoc; + DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line); + diagnostics.writeInfo(pp::Diagnostics::WARNING, + srcLoc, reason, token, extraInfo); +} + +void TParseContext::trace(const char* str) +{ + diagnostics.writeDebug(str); +} + +// +// Same error message for all places assignments don't work. +// +void TParseContext::assignError(int line, const char* op, TString left, TString right) +{ + std::stringstream extraInfoStream; + extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", op, extraInfo.c_str()); +} + +// +// Same error message for all places unary operations don't work. +// +void TParseContext::unaryOpError(int line, const char* op, TString operand) +{ + std::stringstream extraInfoStream; + extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand + << " (or there is no acceptable conversion)"; + std::string extraInfo = extraInfoStream.str(); + error(line, " wrong operand type", op, extraInfo.c_str()); +} + +// +// Same error message for all binary operations don't work. +// +void TParseContext::binaryOpError(int line, const char* op, TString left, TString right) +{ + std::stringstream extraInfoStream; + extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left + << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)"; + std::string extraInfo = extraInfoStream.str(); + error(line, " wrong operand types ", op, extraInfo.c_str()); +} + +bool TParseContext::precisionErrorCheck(int line, TPrecision precision, TBasicType type){ + if (!checksPrecisionErrors) + return false; + switch( type ){ + case EbtFloat: + if( precision == EbpUndefined ){ + error( line, "No precision specified for (float)", "" ); + return true; + } + break; + case EbtInt: + if( precision == EbpUndefined ){ + error( line, "No precision specified (int)", "" ); + return true; + } + break; + default: + return false; + } + return false; +} + +// +// Both test and if necessary, spit out an error, to see if the node is really +// an l-value that can be operated on this way. +// +// Returns true if the was an error. +// +bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* node) +{ + TIntermSymbol* symNode = node->getAsSymbolNode(); + TIntermBinary* binaryNode = node->getAsBinaryNode(); + + if (binaryNode) { + bool errorReturn; + + switch(binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + return lValueErrorCheck(line, op, binaryNode->getLeft()); + case EOpVectorSwizzle: + errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); + if (!errorReturn) { + int offset[4] = {0,0,0,0}; + + TIntermTyped* rightNode = binaryNode->getRight(); + TIntermAggregate *aggrNode = rightNode->getAsAggregate(); + + for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); + p != aggrNode->getSequence().end(); p++) { + int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); + offset[value]++; + if (offset[value] > 1) { + error(line, " l-value of swizzle cannot have duplicate components", op); + + return true; + } + } + } + + return errorReturn; + default: + break; + } + error(line, " l-value required", op); + + return true; + } + + + const char* symbol = 0; + if (symNode != 0) + symbol = symNode->getSymbol().c_str(); + + const char* message = 0; + switch (node->getQualifier()) { + case EvqConst: message = "can't modify a const"; break; + case EvqConstReadOnly: message = "can't modify a const"; break; + case EvqAttribute: message = "can't modify an attribute"; break; + case EvqUniform: message = "can't modify a uniform"; break; + case EvqVaryingIn: message = "can't modify a varying"; break; + case EvqInput: message = "can't modify an input"; break; + case EvqFragCoord: message = "can't modify gl_FragCoord"; break; + case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break; + case EvqPointCoord: message = "can't modify gl_PointCoord"; break; + default: + + // + // Type that can't be written to? + // + switch (node->getBasicType()) { + case EbtSampler2D: + case EbtSamplerCube: + message = "can't modify a sampler"; + break; + case EbtVoid: + message = "can't modify void"; + break; + default: + break; + } + } + + if (message == 0 && binaryNode == 0 && symNode == 0) { + error(line, " l-value required", op); + + return true; + } + + + // + // Everything else is okay, no error. + // + if (message == 0) + return false; + + // + // If we get here, we have an error and a message. + // + if (symNode) { + std::stringstream extraInfoStream; + extraInfoStream << "\"" << symbol << "\" (" << message << ")"; + std::string extraInfo = extraInfoStream.str(); + error(line, " l-value required", op, extraInfo.c_str()); + } + else { + std::stringstream extraInfoStream; + extraInfoStream << "(" << message << ")"; + std::string extraInfo = extraInfoStream.str(); + error(line, " l-value required", op, extraInfo.c_str()); + } + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// a constant. +// +// Returns true if the was an error. +// +bool TParseContext::constErrorCheck(TIntermTyped* node) +{ + if (node->getQualifier() == EvqConst) + return false; + + error(node->getLine(), "constant expression required", ""); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// an integer. +// +// Returns true if the was an error. +// +bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token) +{ + if (node->getBasicType() == EbtInt && node->getNominalSize() == 1) + return false; + + error(node->getLine(), "integer expression required", token); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if we are currently +// globally scoped. +// +// Returns true if the was an error. +// +bool TParseContext::globalErrorCheck(int line, bool global, const char* token) +{ + if (global) + return false; + + error(line, "only allowed at global scope", token); + + return true; +} + +// +// For now, keep it simple: if it starts "gl_", it's reserved, independent +// of scope. Except, if the symbol table is at the built-in push-level, +// which is when we are parsing built-ins. +// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a +// webgl shader. +// +// Returns true if there was an error. +// +bool TParseContext::reservedErrorCheck(int line, const TString& identifier) +{ + static const char* reservedErrMsg = "reserved built-in name"; + if (!symbolTable.atBuiltInLevel()) { + if (identifier.compare(0, 3, "gl_") == 0) { + error(line, reservedErrMsg, "gl_"); + return true; + } + if (isWebGLBasedSpec(shaderSpec)) { + if (identifier.compare(0, 6, "webgl_") == 0) { + error(line, reservedErrMsg, "webgl_"); + return true; + } + if (identifier.compare(0, 7, "_webgl_") == 0) { + error(line, reservedErrMsg, "_webgl_"); + return true; + } + if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) { + error(line, reservedErrMsg, "css_"); + return true; + } + } + if (identifier.find("__") != TString::npos) { + error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str()); + return true; + } + } + + return false; +} + +// +// Make sure there is enough data provided to the constructor to build +// something of the type of the constructor. Also returns the type of +// the constructor. +// +// Returns true if there was an error in construction. +// +bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction& function, TOperator op, TType* type) +{ + *type = function.getReturnType(); + + bool constructingMatrix = false; + switch(op) { + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + constructingMatrix = true; + break; + default: + break; + } + + // + // Note: It's okay to have too many components available, but not okay to have unused + // arguments. 'full' will go to true when enough args have been seen. If we loop + // again, there is an extra argument, so 'overfull' will become true. + // + + int size = 0; + bool constType = true; + bool full = false; + bool overFull = false; + bool matrixInMatrix = false; + bool arrayArg = false; + for (int i = 0; i < function.getParamCount(); ++i) { + const TParameter& param = function.getParam(i); + size += param.type->getObjectSize(); + + if (constructingMatrix && param.type->isMatrix()) + matrixInMatrix = true; + if (full) + overFull = true; + if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) + full = true; + if (param.type->getQualifier() != EvqConst) + constType = false; + if (param.type->isArray()) + arrayArg = true; + } + + if (constType) + type->setQualifier(EvqConst); + + if (type->isArray() && type->getArraySize() != function.getParamCount()) { + error(line, "array constructor needs one argument per array element", "constructor"); + return true; + } + + if (arrayArg && op != EOpConstructStruct) { + error(line, "constructing from a non-dereferenced array", "constructor"); + return true; + } + + if (matrixInMatrix && !type->isArray()) { + if (function.getParamCount() != 1) { + error(line, "constructing matrix from matrix can only take one argument", "constructor"); + return true; + } + } + + if (overFull) { + error(line, "too many arguments", "constructor"); + return true; + } + + if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->size()) != function.getParamCount()) { + error(line, "Number of constructor parameters does not match the number of structure fields", "constructor"); + return true; + } + + if (!type->isMatrix() || !matrixInMatrix) { + if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || + (op == EOpConstructStruct && size < type->getObjectSize())) { + error(line, "not enough data provided for construction", "constructor"); + return true; + } + } + + TIntermTyped *typed = node ? node->getAsTyped() : 0; + if (typed == 0) { + error(line, "constructor argument does not have a type", "constructor"); + return true; + } + if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) { + error(line, "cannot convert a sampler", "constructor"); + return true; + } + if (typed->getBasicType() == EbtVoid) { + error(line, "cannot convert a void", "constructor"); + return true; + } + + return false; +} + +// This function checks to see if a void variable has been declared and raise an error message for such a case +// +// returns true in case of an error +// +bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TPublicType& pubType) +{ + if (pubType.type == EbtVoid) { + error(line, "illegal use of type 'void'", identifier.c_str()); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(int line, const TIntermTyped* type) +{ + if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) { + error(line, "boolean expression expected", ""); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(int line, const TPublicType& pType) +{ + if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) { + error(line, "boolean expression expected", ""); + return true; + } + + return false; +} + +bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const char* reason) +{ + if (pType.type == EbtStruct) { + if (containsSampler(*pType.userDef)) { + error(line, reason, getBasicString(pType.type), "(structure contains a sampler)"); + + return true; + } + + return false; + } else if (IsSampler(pType.type)) { + error(line, reason, getBasicString(pType.type)); + + return true; + } + + return false; +} + +bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType) +{ + if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) && + pType.type == EbtStruct) { + error(line, "cannot be used with a structure", getQualifierString(pType.qualifier)); + + return true; + } + + if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform")) + return true; + + return false; +} + +bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type) +{ + if ((qualifier == EvqOut || qualifier == EvqInOut) && + type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) { + error(line, "samplers cannot be output parameters", type.getBasicString()); + return true; + } + + return false; +} + +bool TParseContext::containsSampler(TType& type) +{ + if (IsSampler(type.getBasicType())) + return true; + + if (type.getBasicType() == EbtStruct) { + TTypeList& structure = *type.getStruct(); + for (unsigned int i = 0; i < structure.size(); ++i) { + if (containsSampler(*structure[i].type)) + return true; + } + } + + return false; +} + +// +// Do size checking for an array type's size. +// +// Returns true if there was an error. +// +bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size) +{ + TIntermConstantUnion* constant = expr->getAsConstantUnion(); + if (constant == 0 || constant->getBasicType() != EbtInt) { + error(line, "array size must be a constant integer expression", ""); + return true; + } + + size = constant->getUnionArrayPointer()->getIConst(); + + if (size <= 0) { + error(line, "array size must be a positive integer", ""); + size = 1; + return true; + } + + return false; +} + +// +// See if this qualifier can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type) +{ + if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) { + error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str()); + return true; + } + + return false; +} + +// +// See if this type can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayTypeErrorCheck(int line, TPublicType type) +{ + // + // Can the type be an array? + // + if (type.array) { + error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str()); + return true; + } + + return false; +} + +// +// Do all the semantic checking for declaring an array, with and +// without a size, and make the right changes to the symbol table. +// +// size == 0 means no specified size. +// +// Returns true if there was an error. +// +bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable) +{ + // + // Don't check for reserved word use until after we know it's not in the symbol table, + // because reserved arrays can be redeclared. + // + + bool builtIn = false; + bool sameScope = false; + TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope); + if (symbol == 0 || !sameScope) { + if (reservedErrorCheck(line, identifier)) + return true; + + variable = new TVariable(&identifier, TType(type)); + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + + if (! symbolTable.insert(*variable)) { + delete variable; + error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str()); + return true; + } + } else { + if (! symbol->isVariable()) { + error(line, "variable expected", identifier.c_str()); + return true; + } + + variable = static_cast(symbol); + if (! variable->getType().isArray()) { + error(line, "redeclaring non-array as array", identifier.c_str()); + return true; + } + if (variable->getType().getArraySize() > 0) { + error(line, "redeclaration of array with size", identifier.c_str()); + return true; + } + + if (! variable->getType().sameElementType(TType(type))) { + error(line, "redeclaration of array with a different type", identifier.c_str()); + return true; + } + + TType* t = variable->getArrayInformationType(); + while (t != 0) { + if (t->getMaxArraySize() > type.arraySize) { + error(line, "higher index value already used for the array", identifier.c_str()); + return true; + } + t->setArraySize(type.arraySize); + t = t->getArrayInformationType(); + } + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line) +{ + bool builtIn = false; + TSymbol* symbol = symbolTable.find(node->getSymbol(), &builtIn); + if (symbol == 0) { + error(line, " undeclared identifier", node->getSymbol().c_str()); + return true; + } + TVariable* variable = static_cast(symbol); + + type->setArrayInformationType(variable->getArrayInformationType()); + variable->updateArrayInformationType(type); + + // special casing to test index value of gl_FragData. If the accessed index is >= gl_MaxDrawBuffers + // its an error + if (node->getSymbol() == "gl_FragData") { + TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers", &builtIn); + ASSERT(fragData); + + int fragDataValue = static_cast(fragData)->getConstPointer()[0].getIConst(); + if (fragDataValue <= size) { + error(line, "", "[", "gl_FragData can only have a max array size of up to gl_MaxDrawBuffers"); + return true; + } + } + + // we dont want to update the maxArraySize when this flag is not set, we just want to include this + // node type in the chain of node types so that its updated when a higher maxArraySize comes in. + if (!updateFlag) + return false; + + size++; + variable->getType().setMaxArraySize(size); + type->setMaxArraySize(size); + TType* tt = type; + + while(tt->getArrayInformationType() != 0) { + tt = tt->getArrayInformationType(); + tt->setMaxArraySize(size); + } + + return false; +} + +// +// Enforce non-initializer type/qualifier rules. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type, bool array) +{ + if (type.qualifier == EvqConst) + { + // Make the qualifier make sense. + type.qualifier = EvqTemporary; + + if (array) + { + error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str()); + } + else if (type.isStructureContainingArrays()) + { + error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str()); + } + else + { + error(line, "variables with qualifier 'const' must be initialized", identifier.c_str()); + } + + return true; + } + + return false; +} + +// +// Do semantic checking for a variable declaration that has no initializer, +// and update the symbol table. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable) +{ + if (reservedErrorCheck(line, identifier)) + recover(); + + variable = new TVariable(&identifier, TType(type)); + + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str()); + delete variable; + variable = 0; + return true; + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type) +{ + if (qualifier != EvqConst && qualifier != EvqTemporary) { + error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier)); + return true; + } + if (qualifier == EvqConst && paramQualifier != EvqIn) { + error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier)); + return true; + } + + if (qualifier == EvqConst) + type->setQualifier(EvqConstReadOnly); + else + type->setQualifier(paramQualifier); + + return false; +} + +bool TParseContext::extensionErrorCheck(int line, const TString& extension) +{ + const TExtensionBehavior& extBehavior = extensionBehavior(); + TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str()); + if (iter == extBehavior.end()) { + error(line, "extension", extension.c_str(), "is not supported"); + return true; + } + // In GLSL ES, an extension's default behavior is "disable". + if (iter->second == EBhDisable || iter->second == EBhUndefined) { + error(line, "extension", extension.c_str(), "is disabled"); + return true; + } + if (iter->second == EBhWarn) { + warning(line, "extension", extension.c_str(), "is being used"); + return false; + } + + return false; +} + +bool TParseContext::supportsExtension(const char* extension) +{ + const TExtensionBehavior& extbehavior = extensionBehavior(); + TExtensionBehavior::const_iterator iter = extbehavior.find(extension); + return (iter != extbehavior.end()); +} + +void TParseContext::handleExtensionDirective(int line, const char* extName, const char* behavior) +{ + pp::SourceLocation loc; + DecodeSourceLoc(line, &loc.file, &loc.line); + directiveHandler.handleExtension(loc, extName, behavior); +} + +void TParseContext::handlePragmaDirective(int line, const char* name, const char* value) +{ + pp::SourceLocation loc; + DecodeSourceLoc(line, &loc.file, &loc.line); + directiveHandler.handlePragma(loc, name, value); +} + +///////////////////////////////////////////////////////////////////////////////// +// +// Non-Errors. +// +///////////////////////////////////////////////////////////////////////////////// + +// +// Look up a function name in the symbol table, and make sure it is a function. +// +// Return the function symbol if found, otherwise 0. +// +const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *builtIn) +{ + // First find by unmangled name to check whether the function name has been + // hidden by a variable name or struct typename. + const TSymbol* symbol = symbolTable.find(call->getName(), builtIn); + if (symbol == 0) { + symbol = symbolTable.find(call->getMangledName(), builtIn); + } + + if (symbol == 0) { + error(line, "no matching overloaded function found", call->getName().c_str()); + return 0; + } + + if (!symbol->isFunction()) { + error(line, "function name expected", call->getName().c_str()); + return 0; + } + + return static_cast(symbol); +} + +// +// Initializers show up in several places in the grammar. Have one set of +// code to handle them here. +// +bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) +{ + TType type = TType(pType); + + if (variable == 0) { + if (reservedErrorCheck(line, identifier)) + return true; + + if (voidErrorCheck(line, identifier, pType)) + return true; + + // + // add variable to symbol table + // + variable = new TVariable(&identifier, type); + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str()); + return true; + // don't delete variable, it's used by error recovery, and the pool + // pop will take care of the memory + } + } + + // + // identifier must be of type constant, a global, or a temporary + // + TQualifier qualifier = variable->getType().getQualifier(); + if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) { + error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString()); + return true; + } + // + // test for and propagate constant + // + + if (qualifier == EvqConst) { + if (qualifier != initializer->getType().getQualifier()) { + std::stringstream extraInfoStream; + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, " assigning non-constant to", "=", extraInfo.c_str()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + if (type != initializer->getType()) { + error(line, " non-matching types for const initializer ", + variable->getType().getQualifierString()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + if (initializer->getAsConstantUnion()) { + ConstantUnion* unionArray = variable->getConstPointer(); + + if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) { + *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0]; + } else { + variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); + } + } else if (initializer->getAsSymbolNode()) { + const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol()); + const TVariable* tVar = static_cast(symbol); + + ConstantUnion* constArray = tVar->getConstPointer(); + variable->shareConstPointer(constArray); + } else { + std::stringstream extraInfoStream; + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, " cannot assign to", "=", extraInfo.c_str()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + } + + if (qualifier != EvqConst) { + TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); + intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); + if (intermNode == 0) { + assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); + return true; + } + } else + intermNode = 0; + + return false; +} + +bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) +{ + ASSERT(aggrNode != NULL); + if (!aggrNode->isConstructor()) + return false; + + bool allConstant = true; + + // check if all the child nodes are constants so that they can be inserted into + // the parent node + TIntermSequence &sequence = aggrNode->getSequence() ; + for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) { + if (!(*p)->getAsTyped()->getAsConstantUnion()) + return false; + } + + return allConstant; +} + +// This function is used to test for the correctness of the parameters passed to various constructor functions +// and also convert them to the right datatype if it is allowed and required. +// +// Returns 0 for an error or the constructed node (aggregate or typed) for no error. +// +TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggrNode = node->getAsAggregate(); + + TTypeList::const_iterator memberTypes; + if (op == EOpConstructStruct) + memberTypes = type->getStruct()->begin(); + + TType elementType = *type; + if (type->isArray()) + elementType.clearArrayness(); + + bool singleArg; + if (aggrNode) { + if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) + singleArg = true; + else + singleArg = false; + } else + singleArg = true; + + TIntermTyped *newNode; + if (singleArg) { + // If structure constructor or array constructor is being called + // for only one parameter inside the structure, we need to call constructStruct function once. + if (type->isArray()) + newNode = constructStruct(node, &elementType, 1, node->getLine(), false); + else if (op == EOpConstructStruct) + newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false); + else + newNode = constructBuiltIn(type, op, node, node->getLine(), false); + + if (newNode && newNode->getAsAggregate()) { + TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + } + + return newNode; + } + + // + // Handle list of arguments. + // + TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor + // if the structure constructor contains more than one parameter, then construct + // each parameter + + int paramCount = 0; // keeps a track of the constructor parameter number being checked + + // for each parameter to the constructor call, check to see if the right type is passed or convert them + // to the right type if possible (and allowed). + // for structure constructors, just check if the right type is passed, no conversion is allowed. + + for (TIntermSequence::iterator p = sequenceVector.begin(); + p != sequenceVector.end(); p++, paramCount++) { + if (type->isArray()) + newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true); + else if (op == EOpConstructStruct) + newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true); + else + newNode = constructBuiltIn(type, op, *p, node->getLine(), true); + + if (newNode) { + *p = newNode; + } + } + + TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line); + TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + + return constructor; +} + +TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) +{ + bool canBeFolded = areAllChildConst(aggrNode); + aggrNode->setType(type); + if (canBeFolded) { + bool returnVal = false; + ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()]; + if (aggrNode->getSequence().size() == 1) { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true); + } + else { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type); + } + if (returnVal) + return 0; + + return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); + } + + return 0; +} + +// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value +// for the parameter to the constructor (passed to this function). Essentially, it converts +// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a +// float, then float is converted to int. +// +// Returns 0 for an error or the constructed node. +// +TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, TSourceLoc line, bool subset) +{ + TIntermTyped* newNode; + TOperator basicOp; + + // + // First, convert types as needed. + // + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + basicOp = EOpConstructFloat; + break; + + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + basicOp = EOpConstructInt; + break; + + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + basicOp = EOpConstructBool; + break; + + default: + error(line, "unsupported construction", ""); + recover(); + + return 0; + } + newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable); + if (newNode == 0) { + error(line, "can't convert", "constructor"); + return 0; + } + + // + // Now, if there still isn't an operation to do the construction, and we need one, add one. + // + + // Otherwise, skip out early. + if (subset || (newNode != node && newNode->getType() == *type)) + return newNode; + + // setAggregateOperator will insert a new node for the constructor, as needed. + return intermediate.setAggregateOperator(newNode, op, line); +} + +// This function tests for the type of the parameters to the structures constructors. Raises +// an error message if the expected type does not match the parameter passed to the constructor. +// +// Returns 0 for an error or the input node itself if the expected and the given parameter types match. +// +TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset) +{ + if (*type == node->getAsTyped()->getType()) { + if (subset) + return node->getAsTyped(); + else + return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line); + } else { + std::stringstream extraInfoStream; + extraInfoStream << "cannot convert parameter " << paramCount + << " from '" << node->getAsTyped()->getType().getBasicString() + << "' to '" << type->getBasicString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "constructor", extraInfo.c_str()); + recover(); + } + + return 0; +} + +// +// This function returns the tree representation for the vector field(s) being accessed from contant vector. +// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is +// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol +// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of +// a constant matrix. +// +TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + ConstantUnion *unionArray; + if (tempConstantNode) { + unionArray = tempConstantNode->getUnionArrayPointer(); + ASSERT(unionArray); + + if (!unionArray) { + return node; + } + } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error + error(line, "Cannot offset into the vector", "Error"); + recover(); + + return 0; + } + + ConstantUnion* constArray = new ConstantUnion[fields.num]; + + for (int i = 0; i < fields.num; i++) { + if (fields.offsets[i] >= node->getType().getObjectSize()) { + std::stringstream extraInfoStream; + extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + fields.offsets[i] = 0; + } + + constArray[i] = unionArray[fields.offsets[i]]; + + } + typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); + return typedNode; +} + +// +// This function returns the column being accessed from a constant matrix. The values are retrieved from +// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input +// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a +// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + if (index >= node->getType().getNominalSize()) { + std::stringstream extraInfoStream; + extraInfoStream << "matrix field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + index = 0; + } + + if (tempConstantNode) { + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + int size = tempConstantNode->getType().getNominalSize(); + typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the matrix", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns an element of an array accessed from a constant array. The values are retrieved from +// the symbol table and parse-tree is built for the type of the element. The input +// to the function could either be a symbol node (a[0] where a is a constant array)that represents a +// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + TType arrayElementType = node->getType(); + arrayElementType.clearArrayness(); + + if (index >= node->getType().getArraySize()) { + std::stringstream extraInfoStream; + extraInfoStream << "array field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + index = 0; + } + + int arrayElementSize = arrayElementType.getObjectSize(); + + if (tempConstantNode) { + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the array", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns the value of a particular field inside a constant structure from the symbol table. +// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr +// function and returns the parse-tree with the values of the embedded/nested struct. +// +TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line) +{ + const TTypeList* fields = node->getType().getStruct(); + TIntermTyped *typedNode; + int instanceSize = 0; + unsigned int index = 0; + TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); + + for ( index = 0; index < fields->size(); ++index) { + if ((*fields)[index].type->getFieldName() == identifier) { + break; + } else { + instanceSize += (*fields)[index].type->getObjectSize(); + } + } + + if (tempConstantNode) { + ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer(); + + typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function + } else { + error(line, "Cannot offset into the structure", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + +bool TParseContext::enterStructDeclaration(int line, const TString& identifier) +{ + ++structNestingLevel; + + // Embedded structure definitions are not supported per GLSL ES spec. + // They aren't allowed in GLSL either, but we need to detect this here + // so we don't rely on the GLSL compiler to catch it. + if (structNestingLevel > 1) { + error(line, "", "Embedded struct definitions are not allowed"); + return true; + } + + return false; +} + +void TParseContext::exitStructDeclaration() +{ + --structNestingLevel; +} + +namespace { + +const int kWebGLMaxStructNesting = 4; + +} // namespace + +bool TParseContext::structNestingErrorCheck(TSourceLoc line, const TType& fieldType) +{ + if (!isWebGLBasedSpec(shaderSpec)) { + return false; + } + + if (fieldType.getBasicType() != EbtStruct) { + return false; + } + + // We're already inside a structure definition at this point, so add + // one to the field's struct nesting. + if (1 + fieldType.getDeepestStructNesting() > kWebGLMaxStructNesting) { + std::stringstream extraInfoStream; + extraInfoStream << "Reference of struct type " << fieldType.getTypeName() + << " exceeds maximum struct nesting of " << kWebGLMaxStructNesting; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "", extraInfo.c_str()); + return true; + } + + return false; +} + +// +// Parse an array of strings using yyparse. +// +// Returns 0 for success. +// +int PaParseStrings(int count, const char* const string[], const int length[], + TParseContext* context) { + if ((count == 0) || (string == NULL)) + return 1; + + if (glslang_initialize(context)) + return 1; + + int error = glslang_scan(count, string, length, context); + if (!error) + error = glslang_parse(context); + + glslang_finalize(context); + + return (error == 0) && (context->numErrors() == 0) ? 0 : 1; +} + + + diff --git a/src/3rdparty/angle/src/compiler/ParseHelper.h b/src/3rdparty/angle/src/compiler/ParseHelper.h new file mode 100644 index 0000000000..824ee00f39 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ParseHelper.h @@ -0,0 +1,140 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#ifndef _PARSER_HELPER_INCLUDED_ +#define _PARSER_HELPER_INCLUDED_ + +#include "compiler/Diagnostics.h" +#include "compiler/DirectiveHandler.h" +#include "compiler/localintermediate.h" +#include "compiler/preprocessor/new/Preprocessor.h" +#include "compiler/ShHandle.h" +#include "compiler/SymbolTable.h" + +struct TMatrixFields { + bool wholeRow; + bool wholeCol; + int row; + int col; +}; + +// +// The following are extra variables needed during parsing, grouped together so +// they can be passed to the parser without needing a global. +// +struct TParseContext { + TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) : + intermediate(interm), + symbolTable(symt), + shaderType(type), + shaderSpec(spec), + compileOptions(options), + sourcePath(sourcePath), + treeRoot(0), + lexAfterType(false), + loopNestingLevel(0), + structNestingLevel(0), + inTypeParen(false), + currentFunctionType(NULL), + functionReturnsValue(false), + checksPrecisionErrors(checksPrecErrors), + diagnostics(is), + directiveHandler(ext, diagnostics), + preprocessor(&diagnostics, &directiveHandler), + scanner(NULL) { } + TIntermediate& intermediate; // to hold and build a parse tree + TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed + ShShaderType shaderType; // vertex or fragment language (future: pack or unpack) + ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + int compileOptions; + const char* sourcePath; // Path of source file or NULL. + TIntermNode* treeRoot; // root of parse tree being created + bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier + int loopNestingLevel; // 0 if outside all loops + int structNestingLevel; // incremented while parsing a struct declaration + bool inTypeParen; // true if in parentheses, looking only for an identifier + const TType* currentFunctionType; // the return type of the function that's currently being parsed + bool functionReturnsValue; // true if a non-void function has a return + bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit. + TString HashErrMsg; + bool AfterEOF; + TDiagnostics diagnostics; + TDirectiveHandler directiveHandler; + pp::Preprocessor preprocessor; + void* scanner; + + int numErrors() const { return diagnostics.numErrors(); } + TInfoSink& infoSink() { return diagnostics.infoSink(); } + void error(TSourceLoc loc, const char *reason, const char* token, + const char* extraInfo=""); + void warning(TSourceLoc loc, const char* reason, const char* token, + const char* extraInfo=""); + void trace(const char* str); + void recover(); + + bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line); + bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, int line); + + bool reservedErrorCheck(int line, const TString& identifier); + void assignError(int line, const char* op, TString left, TString right); + void unaryOpError(int line, const char* op, TString operand); + void binaryOpError(int line, const char* op, TString left, TString right); + bool precisionErrorCheck(int line, TPrecision precision, TBasicType type); + bool lValueErrorCheck(int line, const char* op, TIntermTyped*); + bool constErrorCheck(TIntermTyped* node); + bool integerErrorCheck(TIntermTyped* node, const char* token); + bool globalErrorCheck(int line, bool global, const char* token); + bool constructorErrorCheck(int line, TIntermNode*, TFunction&, TOperator, TType*); + bool arraySizeErrorCheck(int line, TIntermTyped* expr, int& size); + bool arrayQualifierErrorCheck(int line, TPublicType type); + bool arrayTypeErrorCheck(int line, TPublicType type); + bool arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable); + bool voidErrorCheck(int, const TString&, const TPublicType&); + bool boolErrorCheck(int, const TIntermTyped*); + bool boolErrorCheck(int, const TPublicType&); + bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason); + bool structQualifierErrorCheck(int line, const TPublicType& pType); + bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type); + bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type, bool array); + bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable); + bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type); + bool extensionErrorCheck(int line, const TString&); + + const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); } + bool supportsExtension(const char* extension); + void handleExtensionDirective(int line, const char* extName, const char* behavior); + + const TPragma& pragma() const { return directiveHandler.pragma(); } + void handlePragmaDirective(int line, const char* name, const char* value); + + bool containsSampler(TType& type); + bool areAllChildConst(TIntermAggregate* aggrNode); + const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0); + bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); + bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc); + + TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc); + TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); + TIntermTyped* constructStruct(TIntermNode*, TType*, int, TSourceLoc, bool subset); + TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, TSourceLoc, bool subset); + TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc); + TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc); + TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line); + TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc); + + // Performs an error check for embedded struct declarations. + // Returns true if an error was raised due to the declaration of + // this struct. + bool enterStructDeclaration(TSourceLoc line, const TString& identifier); + void exitStructDeclaration(); + + bool structNestingErrorCheck(TSourceLoc line, const TType& fieldType); +}; + +int PaParseStrings(int count, const char* const string[], const int length[], + TParseContext* context); + +#endif // _PARSER_HELPER_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/PoolAlloc.cpp b/src/3rdparty/angle/src/compiler/PoolAlloc.cpp new file mode 100644 index 0000000000..9ef4f59f5c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/PoolAlloc.cpp @@ -0,0 +1,310 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/PoolAlloc.h" + +#ifndef _MSC_VER +#include +#endif +#include + +#include "common/angleutils.h" +#include "compiler/InitializeGlobals.h" +#include "compiler/osinclude.h" + +OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX; + +void InitializeGlobalPools() +{ + TThreadGlobalPools* globalPools= static_cast(OS_GetTLSValue(PoolIndex)); + if (globalPools) + return; + + TThreadGlobalPools* threadData = new TThreadGlobalPools(); + threadData->globalPoolAllocator = 0; + + OS_SetTLSValue(PoolIndex, threadData); +} + +void FreeGlobalPools() +{ + // Release the allocated memory for this thread. + TThreadGlobalPools* globalPools= static_cast(OS_GetTLSValue(PoolIndex)); + if (!globalPools) + return; + + delete globalPools; +} + +bool InitializePoolIndex() +{ + // Allocate a TLS index. + if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX) + return false; + + return true; +} + +void FreePoolIndex() +{ + // Release the TLS index. + OS_FreeTLSIndex(PoolIndex); +} + +TPoolAllocator& GetGlobalPoolAllocator() +{ + TThreadGlobalPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); + + return *threadData->globalPoolAllocator; +} + +void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) +{ + TThreadGlobalPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); + + threadData->globalPoolAllocator = poolAllocator; +} + +// +// Implement the functionality of the TPoolAllocator class, which +// is documented in PoolAlloc.h. +// +TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : + pageSize(growthIncrement), + alignment(allocationAlignment), + freeList(0), + inUseList(0), + numCalls(0), + totalBytes(0) +{ + // + // Don't allow page sizes we know are smaller than all common + // OS page sizes. + // + if (pageSize < 4*1024) + pageSize = 4*1024; + + // + // A large currentPageOffset indicates a new page needs to + // be obtained to allocate memory. + // + currentPageOffset = pageSize; + + // + // Adjust alignment to be at least pointer aligned and + // power of 2. + // + size_t minAlign = sizeof(void*); + alignment &= ~(minAlign - 1); + if (alignment < minAlign) + alignment = minAlign; + size_t a = 1; + while (a < alignment) + a <<= 1; + alignment = a; + alignmentMask = a - 1; + + // + // Align header skip + // + headerSkip = minAlign; + if (headerSkip < sizeof(tHeader)) { + headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask; + } +} + +TPoolAllocator::~TPoolAllocator() +{ + while (inUseList) { + tHeader* next = inUseList->nextPage; + inUseList->~tHeader(); + delete [] reinterpret_cast(inUseList); + inUseList = next; + } + + // We should not check the guard blocks + // here, because we did it already when the block was + // placed into the free list. + // + while (freeList) { + tHeader* next = freeList->nextPage; + delete [] reinterpret_cast(freeList); + freeList = next; + } +} + +// Support MSVC++ 6.0 +const unsigned char TAllocation::guardBlockBeginVal = 0xfb; +const unsigned char TAllocation::guardBlockEndVal = 0xfe; +const unsigned char TAllocation::userDataFill = 0xcd; + +#ifdef GUARD_BLOCKS + const size_t TAllocation::guardBlockSize = 16; +#else + const size_t TAllocation::guardBlockSize = 0; +#endif + +// +// Check a single guard block for damage +// +void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const +{ +#ifdef GUARD_BLOCKS + for (size_t x = 0; x < guardBlockSize; x++) { + if (blockMem[x] != val) { + char assertMsg[80]; + + // We don't print the assert message. It's here just to be helpful. +#if defined(_MSC_VER) + snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n", + locText, size, data()); +#else + snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", + locText, size, data()); +#endif + assert(0 && "PoolAlloc: Damage in guard block"); + } + } +#endif +} + + +void TPoolAllocator::push() +{ + tAllocState state = { currentPageOffset, inUseList }; + + stack.push_back(state); + + // + // Indicate there is no current page to allocate from. + // + currentPageOffset = pageSize; +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred since the last push(), or since the +// last pop(), or since the object's creation. +// +// The deallocated pages are saved for future allocations. +// +void TPoolAllocator::pop() +{ + if (stack.size() < 1) + return; + + tHeader* page = stack.back().page; + currentPageOffset = stack.back().offset; + + while (inUseList != page) { + // invoke destructor to free allocation list + inUseList->~tHeader(); + + tHeader* nextInUse = inUseList->nextPage; + if (inUseList->pageCount > 1) + delete [] reinterpret_cast(inUseList); + else { + inUseList->nextPage = freeList; + freeList = inUseList; + } + inUseList = nextInUse; + } + + stack.pop_back(); +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred. +// +void TPoolAllocator::popAll() +{ + while (stack.size() > 0) + pop(); +} + +void* TPoolAllocator::allocate(size_t numBytes) +{ + // If we are using guard blocks, all allocations are bracketed by + // them: [guardblock][allocation][guardblock]. numBytes is how + // much memory the caller asked for. allocationSize is the total + // size including guard blocks. In release build, + // guardBlockSize=0 and this all gets optimized away. + size_t allocationSize = TAllocation::allocationSize(numBytes); + + // + // Just keep some interesting statistics. + // + ++numCalls; + totalBytes += numBytes; + + // + // Do the allocation, most likely case first, for efficiency. + // This step could be moved to be inline sometime. + // + if (currentPageOffset + allocationSize <= pageSize) { + // + // Safe to allocate from currentPageOffset. + // + unsigned char* memory = reinterpret_cast(inUseList) + currentPageOffset; + currentPageOffset += allocationSize; + currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, memory, numBytes); + } + + if (allocationSize + headerSkip > pageSize) { + // + // Do a multi-page allocation. Don't mix these with the others. + // The OS is efficient and allocating and free-ing multiple pages. + // + size_t numBytesToAlloc = allocationSize + headerSkip; + tHeader* memory = reinterpret_cast(::new char[numBytesToAlloc]); + if (memory == 0) + return 0; + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); + inUseList = memory; + + currentPageOffset = pageSize; // make next allocation come from a new page + + // No guard blocks for multi-page allocations (yet) + return reinterpret_cast(reinterpret_cast(memory) + headerSkip); + } + + // + // Need a simple page to allocate from. + // + tHeader* memory; + if (freeList) { + memory = freeList; + freeList = freeList->nextPage; + } else { + memory = reinterpret_cast(::new char[pageSize]); + if (memory == 0) + return 0; + } + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, 1); + inUseList = memory; + + unsigned char* ret = reinterpret_cast(inUseList) + headerSkip; + currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, ret, numBytes); +} + + +// +// Check all allocations in a list for damage by calling check on each. +// +void TAllocation::checkAllocList() const +{ + for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) + alloc->check(); +} diff --git a/src/3rdparty/angle/src/compiler/PoolAlloc.h b/src/3rdparty/angle/src/compiler/PoolAlloc.h new file mode 100644 index 0000000000..a8a59c69ac --- /dev/null +++ b/src/3rdparty/angle/src/compiler/PoolAlloc.h @@ -0,0 +1,306 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _POOLALLOC_INCLUDED_ +#define _POOLALLOC_INCLUDED_ + +#ifdef _DEBUG +#define GUARD_BLOCKS // define to enable guard block sanity checking +#endif + +// +// This header defines an allocator that can be used to efficiently +// allocate a large number of small requests for heap memory, with the +// intention that they are not individually deallocated, but rather +// collectively deallocated at one time. +// +// This simultaneously +// +// * Makes each individual allocation much more efficient; the +// typical allocation is trivial. +// * Completely avoids the cost of doing individual deallocation. +// * Saves the trouble of tracking down and plugging a large class of leaks. +// +// Individual classes can use this allocator by supplying their own +// new and delete methods. +// +// STL containers can use this allocator by using the pool_allocator +// class as the allocator (second) template argument. +// + +#include +#include +#include + +// If we are using guard blocks, we must track each indivual +// allocation. If we aren't using guard blocks, these +// never get instantiated, so won't have any impact. +// + +class TAllocation { +public: + TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) : + size(size), mem(mem), prevAlloc(prev) { + // Allocations are bracketed: + // [allocationHeader][initialGuardBlock][userData][finalGuardBlock] + // This would be cleaner with if (guardBlockSize)..., but that + // makes the compiler print warnings about 0 length memsets, + // even with the if() protecting them. +#ifdef GUARD_BLOCKS + memset(preGuard(), guardBlockBeginVal, guardBlockSize); + memset(data(), userDataFill, size); + memset(postGuard(), guardBlockEndVal, guardBlockSize); +#endif + } + + void check() const { + checkGuardBlock(preGuard(), guardBlockBeginVal, "before"); + checkGuardBlock(postGuard(), guardBlockEndVal, "after"); + } + + void checkAllocList() const; + + // Return total size needed to accomodate user buffer of 'size', + // plus our tracking data. + inline static size_t allocationSize(size_t size) { + return size + 2 * guardBlockSize + headerSize(); + } + + // Offset from surrounding buffer to get to user data buffer. + inline static unsigned char* offsetAllocation(unsigned char* m) { + return m + guardBlockSize + headerSize(); + } + +private: + void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const; + + // Find offsets to pre and post guard blocks, and user data buffer + unsigned char* preGuard() const { return mem + headerSize(); } + unsigned char* data() const { return preGuard() + guardBlockSize; } + unsigned char* postGuard() const { return data() + size; } + + size_t size; // size of the user data area + unsigned char* mem; // beginning of our allocation (pts to header) + TAllocation* prevAlloc; // prior allocation in the chain + + // Support MSVC++ 6.0 + const static unsigned char guardBlockBeginVal; + const static unsigned char guardBlockEndVal; + const static unsigned char userDataFill; + + const static size_t guardBlockSize; +#ifdef GUARD_BLOCKS + inline static size_t headerSize() { return sizeof(TAllocation); } +#else + inline static size_t headerSize() { return 0; } +#endif +}; + +// +// There are several stacks. One is to track the pushing and popping +// of the user, and not yet implemented. The others are simply a +// repositories of free pages or used pages. +// +// Page stacks are linked together with a simple header at the beginning +// of each allocation obtained from the underlying OS. Multi-page allocations +// are returned to the OS. Individual page allocations are kept for future +// re-use. +// +// The "page size" used is not, nor must it match, the underlying OS +// page size. But, having it be about that size or equal to a set of +// pages is likely most optimal. +// +class TPoolAllocator { +public: + TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16); + + // + // Don't call the destructor just to free up the memory, call pop() + // + ~TPoolAllocator(); + + // + // Call push() to establish a new place to pop memory too. Does not + // have to be called to get things started. + // + void push(); + + // + // Call pop() to free all memory allocated since the last call to push(), + // or if no last call to push, frees all memory since first allocation. + // + void pop(); + + // + // Call popAll() to free all memory allocated. + // + void popAll(); + + // + // Call allocate() to actually acquire memory. Returns 0 if no memory + // available, otherwise a properly aligned pointer to 'numBytes' of memory. + // + void* allocate(size_t numBytes); + + // + // There is no deallocate. The point of this class is that + // deallocation can be skipped by the user of it, as the model + // of use is to simultaneously deallocate everything at once + // by calling pop(), and to not have to solve memory leak problems. + // + +protected: + friend struct tHeader; + + struct tHeader { + tHeader(tHeader* nextPage, size_t pageCount) : + nextPage(nextPage), + pageCount(pageCount) +#ifdef GUARD_BLOCKS + , lastAllocation(0) +#endif + { } + + ~tHeader() { +#ifdef GUARD_BLOCKS + if (lastAllocation) + lastAllocation->checkAllocList(); +#endif + } + + tHeader* nextPage; + size_t pageCount; +#ifdef GUARD_BLOCKS + TAllocation* lastAllocation; +#endif + }; + + struct tAllocState { + size_t offset; + tHeader* page; + }; + typedef std::vector tAllocStack; + + // Track allocations if and only if we're using guard blocks + void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) { +#ifdef GUARD_BLOCKS + new(memory) TAllocation(numBytes, memory, block->lastAllocation); + block->lastAllocation = reinterpret_cast(memory); +#endif + // This is optimized entirely away if GUARD_BLOCKS is not defined. + return TAllocation::offsetAllocation(memory); + } + + size_t pageSize; // granularity of allocation from the OS + size_t alignment; // all returned allocations will be aligned at + // this granularity, which will be a power of 2 + size_t alignmentMask; + size_t headerSkip; // amount of memory to skip to make room for the + // header (basically, size of header, rounded + // up to make it aligned + size_t currentPageOffset; // next offset in top of inUseList to allocate from + tHeader* freeList; // list of popped memory + tHeader* inUseList; // list of all memory currently being used + tAllocStack stack; // stack of where to allocate from, to partition pool + + int numCalls; // just an interesting statistic + size_t totalBytes; // just an interesting statistic +private: + TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator + TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor +}; + + +// +// There could potentially be many pools with pops happening at +// different times. But a simple use is to have a global pop +// with everyone using the same global allocator. +// +extern TPoolAllocator& GetGlobalPoolAllocator(); +extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator); +#define GlobalPoolAllocator GetGlobalPoolAllocator() + +struct TThreadGlobalPools +{ + TPoolAllocator* globalPoolAllocator; +}; + +// +// This STL compatible allocator is intended to be used as the allocator +// parameter to templatized STL containers, like vector and map. +// +// It will use the pools for allocation, and not +// do any deallocation, but will still do destruction. +// +template +class pool_allocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template + struct rebind { + typedef pool_allocator other; + }; + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pool_allocator() : allocator(&GlobalPoolAllocator) { } + pool_allocator(TPoolAllocator& a) : allocator(&a) { } + pool_allocator(const pool_allocator& p) : allocator(p.allocator) { } + + template + pool_allocator& operator=(const pool_allocator& p) { + allocator = p.allocator; + return *this; + } + + template + pool_allocator(const pool_allocator& p) : allocator(&p.getAllocator()) { } + +#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR) + // libCStd on some platforms have a different allocate/deallocate interface. + // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be + // allocated, not the number of elements. + void* allocate(size_type n) { + return getAllocator().allocate(n); + } + void* allocate(size_type n, const void*) { + return getAllocator().allocate(n); + } + void deallocate(void*, size_type) {} +#else + pointer allocate(size_type n) { + return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); + } + pointer allocate(size_type n, const void*) { + return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); + } + void deallocate(pointer, size_type) {} +#endif // _RWSTD_ALLOCATOR + + void construct(pointer p, const T& val) { new ((void *)p) T(val); } + void destroy(pointer p) { p->T::~T(); } + + bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); } + bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); } + + size_type max_size() const { return static_cast(-1) / sizeof(T); } + size_type max_size(int size) const { return static_cast(-1) / size; } + + void setAllocator(TPoolAllocator* a) { allocator = a; } + TPoolAllocator& getAllocator() const { return *allocator; } + +protected: + TPoolAllocator* allocator; +}; + +#endif // _POOLALLOC_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/Pragma.h b/src/3rdparty/angle/src/compiler/Pragma.h new file mode 100644 index 0000000000..2f744123b8 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Pragma.h @@ -0,0 +1,19 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PRAGMA_H_ +#define COMPILER_PRAGMA_H_ + +struct TPragma { + // By default optimization is turned on and debug is turned off. + TPragma() : optimize(true), debug(false) { } + TPragma(bool o, bool d) : optimize(o), debug(d) { } + + bool optimize; + bool debug; +}; + +#endif // COMPILER_PRAGMA_H_ diff --git a/src/3rdparty/angle/src/compiler/QualifierAlive.cpp b/src/3rdparty/angle/src/compiler/QualifierAlive.cpp new file mode 100644 index 0000000000..92a6874eb7 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/QualifierAlive.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/intermediate.h" + +class TAliveTraverser : public TIntermTraverser { +public: + TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q) + { + } + + bool wasFound() { return found; } + +protected: + bool found; + TQualifier qualifier; + + void visitSymbol(TIntermSymbol*); + bool visitSelection(Visit, TIntermSelection*); +}; + +// +// Report whether or not a variable of the given qualifier type +// is guaranteed written. Not always possible to determine if +// it is written conditionally. +// +// ?? It does not do this well yet, this is just a place holder +// that simply determines if it was reference at all, anywhere. +// +bool QualifierWritten(TIntermNode* node, TQualifier qualifier) +{ + TAliveTraverser it(qualifier); + + if (node) + node->traverse(&it); + + return it.wasFound(); +} + +void TAliveTraverser::visitSymbol(TIntermSymbol* node) +{ + // + // If it's what we're looking for, record it. + // + if (node->getQualifier() == qualifier) + found = true; +} + +bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node) +{ + if (wasFound()) + return false; + + return true; +} diff --git a/src/3rdparty/angle/src/compiler/QualifierAlive.h b/src/3rdparty/angle/src/compiler/QualifierAlive.h new file mode 100644 index 0000000000..872a06f721 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/QualifierAlive.h @@ -0,0 +1,7 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +bool QualifierWritten(TIntermNode* root, TQualifier); diff --git a/src/3rdparty/angle/src/compiler/RemoveTree.cpp b/src/3rdparty/angle/src/compiler/RemoveTree.cpp new file mode 100644 index 0000000000..a4b8c1e63e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/RemoveTree.cpp @@ -0,0 +1,77 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/intermediate.h" +#include "compiler/RemoveTree.h" + +// +// Code to recursively delete the intermediate tree. +// + +class RemoveTree : public TIntermTraverser +{ +public: + RemoveTree() : TIntermTraverser(false, false, true) + { + } + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); +}; + +void RemoveTree::visitSymbol(TIntermSymbol* node) +{ + delete node; +} + +bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node) +{ + delete node; + + return true; +} + +void RemoveTree::visitConstantUnion(TIntermConstantUnion* node) +{ + delete node; +} + +// +// Entry point. +// +void RemoveAllTreeNodes(TIntermNode* root) +{ + RemoveTree it; + + root->traverse(&it); +} + diff --git a/src/3rdparty/angle/src/compiler/RemoveTree.h b/src/3rdparty/angle/src/compiler/RemoveTree.h new file mode 100644 index 0000000000..97a821679c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/RemoveTree.h @@ -0,0 +1,7 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +void RemoveAllTreeNodes(TIntermNode*); diff --git a/src/3rdparty/angle/src/compiler/RenameFunction.h b/src/3rdparty/angle/src/compiler/RenameFunction.h new file mode 100644 index 0000000000..3908bfddb8 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/RenameFunction.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_RENAME_FUNCTION +#define COMPILER_RENAME_FUNCTION + +#include "compiler/intermediate.h" + +// +// Renames a function, including its declaration and any calls to it. +// +class RenameFunction : public TIntermTraverser +{ +public: + RenameFunction(const TString& oldFunctionName, const TString& newFunctionName) + : TIntermTraverser(true, false, false) + , mOldFunctionName(oldFunctionName) + , mNewFunctionName(newFunctionName) {} + + virtual bool visitAggregate(Visit visit, TIntermAggregate* node) + { + TOperator op = node->getOp(); + if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName) + node->setName(mNewFunctionName); + return true; + } + +private: + const TString mOldFunctionName; + const TString mNewFunctionName; +}; + +#endif // COMPILER_RENAME_FUNCTION diff --git a/src/3rdparty/angle/src/compiler/SearchSymbol.cpp b/src/3rdparty/angle/src/compiler/SearchSymbol.cpp new file mode 100644 index 0000000000..9368f1a4fa --- /dev/null +++ b/src/3rdparty/angle/src/compiler/SearchSymbol.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SearchSymbol is an AST traverser to detect the use of a given symbol name +// + +#include "compiler/SearchSymbol.h" + +#include "compiler/InfoSink.h" +#include "compiler/OutputHLSL.h" + +namespace sh +{ +SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol) +{ + match = false; +} + +void SearchSymbol::traverse(TIntermNode *node) +{ + node->traverse(this); +} + +void SearchSymbol::visitSymbol(TIntermSymbol *symbolNode) +{ + if (symbolNode->getSymbol() == mSymbol) + { + match = true; + } +} + +bool SearchSymbol::foundMatch() const +{ + return match; +} +} diff --git a/src/3rdparty/angle/src/compiler/SearchSymbol.h b/src/3rdparty/angle/src/compiler/SearchSymbol.h new file mode 100644 index 0000000000..6bc0b90feb --- /dev/null +++ b/src/3rdparty/angle/src/compiler/SearchSymbol.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SearchSymbol is an AST traverser to detect the use of a given symbol name +// + +#ifndef COMPILER_SEARCHSYMBOL_H_ +#define COMPILER_SEARCHSYMBOL_H_ + +#include "compiler/intermediate.h" +#include "compiler/ParseHelper.h" + +namespace sh +{ +class SearchSymbol : public TIntermTraverser +{ + public: + SearchSymbol(const TString &symbol); + + void traverse(TIntermNode *node); + void visitSymbol(TIntermSymbol *symbolNode); + + bool foundMatch() const; + + protected: + const TString &mSymbol; + bool match; +}; +} + +#endif // COMPILER_SEARCHSYMBOL_H_ diff --git a/src/3rdparty/angle/src/compiler/ShHandle.h b/src/3rdparty/angle/src/compiler/ShHandle.h new file mode 100644 index 0000000000..6ba302ad04 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ShHandle.h @@ -0,0 +1,142 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _SHHANDLE_INCLUDED_ +#define _SHHANDLE_INCLUDED_ + +// +// Machine independent part of the compiler private objects +// sent as ShHandle to the driver. +// +// This should not be included by driver code. +// + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/BuiltInFunctionEmulator.h" +#include "compiler/ExtensionBehavior.h" +#include "compiler/InfoSink.h" +#include "compiler/SymbolTable.h" +#include "compiler/VariableInfo.h" + +class LongNameMap; +class TCompiler; +class TDependencyGraph; + +// +// Helper function to identify specs that are based on the WebGL spec, +// like the CSS Shaders spec. +// +bool isWebGLBasedSpec(ShShaderSpec spec); + +// +// The base class used to back handles returned to the driver. +// +class TShHandleBase { +public: + TShHandleBase(); + virtual ~TShHandleBase(); + virtual TCompiler* getAsCompiler() { return 0; } + +protected: + // Memory allocator. Allocates and tracks memory required by the compiler. + // Deallocates all memory when compiler is destructed. + TPoolAllocator allocator; +}; + +// +// The base class for the machine dependent compiler to derive from +// for managing object code from the compile. +// +class TCompiler : public TShHandleBase { +public: + TCompiler(ShShaderType type, ShShaderSpec spec); + virtual ~TCompiler(); + virtual TCompiler* getAsCompiler() { return this; } + + bool Init(const ShBuiltInResources& resources); + bool compile(const char* const shaderStrings[], + const int numStrings, + int compileOptions); + + // Get results of the last compilation. + TInfoSink& getInfoSink() { return infoSink; } + const TVariableInfoList& getAttribs() const { return attribs; } + const TVariableInfoList& getUniforms() const { return uniforms; } + int getMappedNameMaxLength() const; + +protected: + ShShaderType getShaderType() const { return shaderType; } + ShShaderSpec getShaderSpec() const { return shaderSpec; } + // Initialize symbol-table with built-in symbols. + bool InitBuiltInSymbolTable(const ShBuiltInResources& resources); + // Clears the results from the previous compilation. + void clearResults(); + // Return true if function recursion is detected. + bool detectRecursion(TIntermNode* root); + // Rewrites a shader's intermediate tree according to the CSS Shaders spec. + void rewriteCSSShader(TIntermNode* root); + // Returns true if the given shader does not exceed the minimum + // functionality mandated in GLSL 1.0 spec Appendix A. + bool validateLimitations(TIntermNode* root); + // Collect info for all attribs and uniforms. + void collectAttribsUniforms(TIntermNode* root); + // Map long variable names into shorter ones. + void mapLongVariableNames(TIntermNode* root); + // Translate to object code. + virtual void translate(TIntermNode* root) = 0; + // Returns true if, after applying the packing rules in the GLSL 1.017 spec + // Appendix A, section 7, the shader does not use too many uniforms. + bool enforcePackingRestrictions(); + // Returns true if the shader passes the restrictions that aim to prevent timing attacks. + bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph); + // Returns true if the shader does not use samplers. + bool enforceVertexShaderTimingRestrictions(TIntermNode* root); + // Returns true if the shader does not use sampler dependent values to affect control + // flow or in operations whose time can depend on the input values. + bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph); + // Get built-in extensions with default behavior. + const TExtensionBehavior& getExtensionBehavior() const; + + const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const; + +private: + ShShaderType shaderType; + ShShaderSpec shaderSpec; + + int maxUniformVectors; + + // Built-in symbol table for the given language, spec, and resources. + // It is preserved from compile-to-compile. + TSymbolTable symbolTable; + // Built-in extensions with default behavior. + TExtensionBehavior extensionBehavior; + + BuiltInFunctionEmulator builtInFunctionEmulator; + + // Results of compilation. + TInfoSink infoSink; // Output sink. + TVariableInfoList attribs; // Active attributes in the compiled shader. + TVariableInfoList uniforms; // Active uniforms in the compiled shader. + + // Cached copy of the ref-counted singleton. + LongNameMap* longNameMap; +}; + +// +// This is the interface between the machine independent code +// and the machine dependent code. +// +// The machine dependent code should derive from the classes +// above. Then Construct*() and Delete*() will create and +// destroy the machine dependent objects, which contain the +// above machine independent information. +// +TCompiler* ConstructCompiler( + ShShaderType type, ShShaderSpec spec, ShShaderOutput output); +void DeleteCompiler(TCompiler*); + +#endif // _SHHANDLE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/ShaderLang.cpp new file mode 100644 index 0000000000..56f5c7f2ec --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ShaderLang.cpp @@ -0,0 +1,285 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Implement the top-level of interface to the compiler, +// as defined in ShaderLang.h +// + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/InitializeDll.h" +#include "compiler/preprocessor/length_limits.h" +#include "compiler/ShHandle.h" + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler. +// + +static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle, + int expectedValue) +{ + int activeUniformLimit = 0; + ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit); + int activeAttribLimit = 0; + ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit); + return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit); +} + +static bool checkMappedNameMaxLength(const ShHandle handle, int expectedValue) +{ + int mappedNameMaxLength = 0; + ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength); + return (expectedValue == mappedNameMaxLength); +} + +static void getVariableInfo(ShShaderInfo varType, + const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name, + char* mappedName) +{ + if (!handle || !size || !type || !name) + return; + ASSERT((varType == SH_ACTIVE_ATTRIBUTES) || + (varType == SH_ACTIVE_UNIFORMS)); + + TShHandleBase* base = reinterpret_cast(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return; + + const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ? + compiler->getAttribs() : compiler->getUniforms(); + if (index < 0 || index >= static_cast(varList.size())) + return; + + const TVariableInfo& varInfo = varList[index]; + if (length) *length = varInfo.name.size(); + *size = varInfo.size; + *type = varInfo.type; + + // This size must match that queried by + // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH + // in ShGetInfo, below. + int activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN; + ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength)); + strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength); + name[activeUniformAndAttribLength - 1] = 0; + if (mappedName) { + // This size must match that queried by + // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below. + int maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN; + ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength)); + strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength); + mappedName[maxMappedNameLength - 1] = 0; + } +} + +// +// Driver must call this first, once, before doing any other +// compiler operations. +// +int ShInitialize() +{ + if (!InitProcess()) + return 0; + + return 1; +} + +// +// Cleanup symbol tables +// +int ShFinalize() +{ + if (!DetachProcess()) + return 0; + + return 1; +} + +// +// Initialize built-in resources with minimum expected values. +// +void ShInitBuiltInResources(ShBuiltInResources* resources) +{ + // Constants. + resources->MaxVertexAttribs = 8; + resources->MaxVertexUniformVectors = 128; + resources->MaxVaryingVectors = 8; + resources->MaxVertexTextureImageUnits = 0; + resources->MaxCombinedTextureImageUnits = 8; + resources->MaxTextureImageUnits = 8; + resources->MaxFragmentUniformVectors = 16; + resources->MaxDrawBuffers = 1; + + // Extensions. + resources->OES_standard_derivatives = 0; + resources->OES_EGL_image_external = 0; + resources->ARB_texture_rectangle = 0; +} + +// +// Driver calls these to create and destroy compiler objects. +// +ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec, + ShShaderOutput output, + const ShBuiltInResources* resources) +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast(ConstructCompiler(type, spec, output)); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + // Generate built-in symbol table. + if (!compiler->Init(*resources)) { + ShDestruct(base); + return 0; + } + + return reinterpret_cast(base); +} + +void ShDestruct(ShHandle handle) +{ + if (handle == 0) + return; + + TShHandleBase* base = static_cast(handle); + + if (base->getAsCompiler()) + DeleteCompiler(base->getAsCompiler()); +} + +// +// Do an actual compile on the given strings. The result is left +// in the given compile object. +// +// Return: The return value of ShCompile is really boolean, indicating +// success or failure. +// +int ShCompile( + const ShHandle handle, + const char* const shaderStrings[], + const int numStrings, + int compileOptions) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + bool success = compiler->compile(shaderStrings, numStrings, compileOptions); + return success ? 1 : 0; +} + +void ShGetInfo(const ShHandle handle, ShShaderInfo pname, int* params) +{ + if (!handle || !params) + return; + + TShHandleBase* base = static_cast(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + switch(pname) + { + case SH_INFO_LOG_LENGTH: + *params = compiler->getInfoSink().info.size() + 1; + break; + case SH_OBJECT_CODE_LENGTH: + *params = compiler->getInfoSink().obj.size() + 1; + break; + case SH_ACTIVE_UNIFORMS: + *params = compiler->getUniforms().size(); + break; + case SH_ACTIVE_UNIFORM_MAX_LENGTH: + *params = 1 + MAX_SYMBOL_NAME_LEN; + break; + case SH_ACTIVE_ATTRIBUTES: + *params = compiler->getAttribs().size(); + break; + case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = 1 + MAX_SYMBOL_NAME_LEN; + break; + case SH_MAPPED_NAME_MAX_LENGTH: + // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to + // handle array and struct dereferences. + *params = 1 + MAX_SYMBOL_NAME_LEN; + break; + default: UNREACHABLE(); + } +} + +// +// Return any compiler log of messages for the application. +// +void ShGetInfoLog(const ShHandle handle, char* infoLog) +{ + if (!handle || !infoLog) + return; + + TShHandleBase* base = static_cast(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + TInfoSink& infoSink = compiler->getInfoSink(); + strcpy(infoLog, infoSink.info.c_str()); +} + +// +// Return any object code. +// +void ShGetObjectCode(const ShHandle handle, char* objCode) +{ + if (!handle || !objCode) + return; + + TShHandleBase* base = static_cast(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + TInfoSink& infoSink = compiler->getInfoSink(); + strcpy(objCode, infoSink.obj.c_str()); +} + +void ShGetActiveAttrib(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name, + char* mappedName) +{ + getVariableInfo(SH_ACTIVE_ATTRIBUTES, + handle, index, length, size, type, name, mappedName); +} + +void ShGetActiveUniform(const ShHandle handle, + int index, + int* length, + int* size, + ShDataType* type, + char* name, + char* mappedName) +{ + getVariableInfo(SH_ACTIVE_UNIFORMS, + handle, index, length, size, type, name, mappedName); +} diff --git a/src/3rdparty/angle/src/compiler/SymbolTable.cpp b/src/3rdparty/angle/src/compiler/SymbolTable.cpp new file mode 100644 index 0000000000..847c1e4085 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/SymbolTable.cpp @@ -0,0 +1,279 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Symbol table for parsing. Most functionaliy and main ideas +// are documented in the header file. +// + +#if defined(_MSC_VER) +#pragma warning(disable: 4718) +#endif + +#include "compiler/SymbolTable.h" + +#include +#include + +#include "common/angleutils.h" + +TType::TType(const TPublicType &p) : + type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), + maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0) +{ + if (p.userDef) { + structure = p.userDef->getStruct(); + typeName = NewPoolTString(p.userDef->getTypeName().c_str()); + computeDeepestStructNesting(); + } +} + +// +// Recursively generate mangled names. +// +void TType::buildMangledName(TString& mangledName) +{ + if (isMatrix()) + mangledName += 'm'; + else if (isVector()) + mangledName += 'v'; + + switch (type) { + case EbtFloat: mangledName += 'f'; break; + case EbtInt: mangledName += 'i'; break; + case EbtBool: mangledName += 'b'; break; + case EbtSampler2D: mangledName += "s2"; break; + case EbtSamplerCube: mangledName += "sC"; break; + case EbtStruct: + mangledName += "struct-"; + if (typeName) + mangledName += *typeName; + {// support MSVC++6.0 + for (unsigned int i = 0; i < structure->size(); ++i) { + mangledName += '-'; + (*structure)[i].type->buildMangledName(mangledName); + } + } + default: + break; + } + + mangledName += static_cast('0' + getNominalSize()); + if (isArray()) { + char buf[20]; + snprintf(buf, sizeof(buf), "%d", arraySize); + mangledName += '['; + mangledName += buf; + mangledName += ']'; + } +} + +int TType::getStructSize() const +{ + if (!getStruct()) { + assert(false && "Not a struct"); + return 0; + } + + if (structureSize == 0) + for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++) + structureSize += ((*tl).type)->getObjectSize(); + + return structureSize; +} + +void TType::computeDeepestStructNesting() +{ + if (!getStruct()) { + return; + } + + int maxNesting = 0; + for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); ++tl) { + maxNesting = std::max(maxNesting, ((*tl).type)->getDeepestStructNesting()); + } + + deepestStructNesting = 1 + maxNesting; +} + +bool TType::isStructureContainingArrays() const +{ + if (!structure) + { + return false; + } + + for (TTypeList::const_iterator member = structure->begin(); member != structure->end(); member++) + { + if (member->type->isArray() || + member->type->isStructureContainingArrays()) + { + return true; + } + } + + return false; +} + +// +// Dump functions. +// + +void TVariable::dump(TInfoSink& infoSink) const +{ + infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString(); + if (type.isArray()) { + infoSink.debug << "[0]"; + } + infoSink.debug << "\n"; +} + +void TFunction::dump(TInfoSink &infoSink) const +{ + infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n"; +} + +void TSymbolTableLevel::dump(TInfoSink &infoSink) const +{ + tLevel::const_iterator it; + for (it = level.begin(); it != level.end(); ++it) + (*it).second->dump(infoSink); +} + +void TSymbolTable::dump(TInfoSink &infoSink) const +{ + for (int level = currentLevel(); level >= 0; --level) { + infoSink.debug << "LEVEL " << level << "\n"; + table[level]->dump(infoSink); + } +} + +// +// Functions have buried pointers to delete. +// +TFunction::~TFunction() +{ + for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i) + delete (*i).type; +} + +// +// Symbol table levels are a map of pointers to symbols that have to be deleted. +// +TSymbolTableLevel::~TSymbolTableLevel() +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + delete (*it).second; +} + +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in operation. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToOperator(const char* name, TOperator op) +{ + tLevel::iterator it; + for (it = level.begin(); it != level.end(); ++it) { + if ((*it).second->isFunction()) { + TFunction* function = static_cast((*it).second); + if (function->getName() == name) + function->relateToOperator(op); + } + } +} + +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in extension. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext) +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) { + if (it->second->isFunction()) { + TFunction* function = static_cast(it->second); + if (function->getName() == name) + function->relateToExtension(ext); + } + } +} + +TSymbol::TSymbol(const TSymbol& copyOf) +{ + name = NewPoolTString(copyOf.name->c_str()); + uniqueId = copyOf.uniqueId; +} + +TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol(copyOf) +{ + type.copyType(copyOf.type, remapper); + userType = copyOf.userType; + // for builtIn symbol table level, unionArray and arrayInformation pointers should be NULL + assert(copyOf.arrayInformationType == 0); + arrayInformationType = 0; + + if (copyOf.unionArray) { + assert(!copyOf.type.getStruct()); + assert(copyOf.type.getObjectSize() == 1); + unionArray = new ConstantUnion[1]; + unionArray[0] = copyOf.unionArray[0]; + } else + unionArray = 0; +} + +TVariable* TVariable::clone(TStructureMap& remapper) +{ + TVariable *variable = new TVariable(*this, remapper); + + return variable; +} + +TFunction::TFunction(const TFunction& copyOf, TStructureMap& remapper) : TSymbol(copyOf) +{ + for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) { + TParameter param; + parameters.push_back(param); + parameters.back().copyParam(copyOf.parameters[i], remapper); + } + + returnType.copyType(copyOf.returnType, remapper); + mangledName = copyOf.mangledName; + op = copyOf.op; + defined = copyOf.defined; +} + +TFunction* TFunction::clone(TStructureMap& remapper) +{ + TFunction *function = new TFunction(*this, remapper); + + return function; +} + +TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper) +{ + TSymbolTableLevel *symTableLevel = new TSymbolTableLevel(); + tLevel::iterator iter; + for (iter = level.begin(); iter != level.end(); ++iter) { + symTableLevel->insert(*iter->second->clone(remapper)); + } + + return symTableLevel; +} + +void TSymbolTable::copyTable(const TSymbolTable& copyOf) +{ + TStructureMap remapper; + uniqueId = copyOf.uniqueId; + for (unsigned int i = 0; i < copyOf.table.size(); ++i) { + table.push_back(copyOf.table[i]->clone(remapper)); + } + for( unsigned int i = 0; i < copyOf.precisionStack.size(); i++) { + precisionStack.push_back( copyOf.precisionStack[i] ); + } +} diff --git a/src/3rdparty/angle/src/compiler/SymbolTable.h b/src/3rdparty/angle/src/compiler/SymbolTable.h new file mode 100644 index 0000000000..a89499e4f4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/SymbolTable.h @@ -0,0 +1,359 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _SYMBOL_TABLE_INCLUDED_ +#define _SYMBOL_TABLE_INCLUDED_ + +// +// Symbol table for parsing. Has these design characteristics: +// +// * Same symbol table can be used to compile many shaders, to preserve +// effort of creating and loading with the large numbers of built-in +// symbols. +// +// * Name mangling will be used to give each function a unique name +// so that symbol table lookups are never ambiguous. This allows +// a simpler symbol table structure. +// +// * Pushing and popping of scope, so symbol table will really be a stack +// of symbol tables. Searched from the top, with new inserts going into +// the top. +// +// * Constants: Compile time constant symbols will keep their values +// in the symbol table. The parser can substitute constants at parse +// time, including doing constant folding and constant propagation. +// +// * No temporaries: Temporaries made from operations (+, --, .xy, etc.) +// are tracked in the intermediate representation, not the symbol table. +// + +#include + +#include "compiler/InfoSink.h" +#include "compiler/intermediate.h" + +// +// Symbol base class. (Can build functions or variables out of these...) +// +class TSymbol { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TSymbol(const TString *n) : name(n) { } + virtual ~TSymbol() { /* don't delete name, it's from the pool */ } + const TString& getName() const { return *name; } + virtual const TString& getMangledName() const { return getName(); } + virtual bool isFunction() const { return false; } + virtual bool isVariable() const { return false; } + void setUniqueId(int id) { uniqueId = id; } + int getUniqueId() const { return uniqueId; } + virtual void dump(TInfoSink &infoSink) const = 0; + TSymbol(const TSymbol&); + virtual TSymbol* clone(TStructureMap& remapper) = 0; + +protected: + const TString *name; + unsigned int uniqueId; // For real comparing during code generation +}; + +// +// Variable class, meaning a symbol that's not a function. +// +// There could be a separate class heirarchy for Constant variables; +// Only one of int, bool, or float, (or none) is correct for +// any particular use, but it's easy to do this way, and doesn't +// seem worth having separate classes, and "getConst" can't simply return +// different values for different types polymorphically, so this is +// just simple and pragmatic. +// +class TVariable : public TSymbol { +public: + TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { } + virtual ~TVariable() { } + virtual bool isVariable() const { return true; } + TType& getType() { return type; } + const TType& getType() const { return type; } + bool isUserType() const { return userType; } + void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); } + void updateArrayInformationType(TType *t) { arrayInformationType = t; } + TType* getArrayInformationType() { return arrayInformationType; } + + virtual void dump(TInfoSink &infoSink) const; + + ConstantUnion* getConstPointer() + { + if (!unionArray) + unionArray = new ConstantUnion[type.getObjectSize()]; + + return unionArray; + } + + ConstantUnion* getConstPointer() const { return unionArray; } + + void shareConstPointer( ConstantUnion *constArray) + { + if (unionArray == constArray) + return; + + delete[] unionArray; + unionArray = constArray; + } + TVariable(const TVariable&, TStructureMap& remapper); // copy constructor + virtual TVariable* clone(TStructureMap& remapper); + +protected: + TType type; + bool userType; + // we are assuming that Pool Allocator will free the memory allocated to unionArray + // when this object is destroyed + ConstantUnion *unionArray; + TType *arrayInformationType; // this is used for updating maxArraySize in all the references to a given symbol +}; + +// +// The function sub-class of symbols and the parser will need to +// share this definition of a function parameter. +// +struct TParameter { + TString *name; + TType* type; + void copyParam(const TParameter& param, TStructureMap& remapper) + { + name = NewPoolTString(param.name->c_str()); + type = param.type->clone(remapper); + } +}; + +// +// The function sub-class of a symbol. +// +class TFunction : public TSymbol { +public: + TFunction(TOperator o) : + TSymbol(0), + returnType(TType(EbtVoid, EbpUndefined)), + op(o), + defined(false) { } + TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : + TSymbol(name), + returnType(retType), + mangledName(TFunction::mangleName(*name)), + op(tOp), + defined(false) { } + virtual ~TFunction(); + virtual bool isFunction() const { return true; } + + static TString mangleName(const TString& name) { return name + '('; } + static TString unmangleName(const TString& mangledName) + { + return TString(mangledName.c_str(), mangledName.find_first_of('(')); + } + + void addParameter(TParameter& p) + { + parameters.push_back(p); + mangledName = mangledName + p.type->getMangledName(); + } + + const TString& getMangledName() const { return mangledName; } + const TType& getReturnType() const { return returnType; } + + void relateToOperator(TOperator o) { op = o; } + TOperator getBuiltInOp() const { return op; } + + void relateToExtension(const TString& ext) { extension = ext; } + const TString& getExtension() const { return extension; } + + void setDefined() { defined = true; } + bool isDefined() { return defined; } + + int getParamCount() const { return static_cast(parameters.size()); } + const TParameter& getParam(int i) const { return parameters[i]; } + + virtual void dump(TInfoSink &infoSink) const; + TFunction(const TFunction&, TStructureMap& remapper); + virtual TFunction* clone(TStructureMap& remapper); + +protected: + typedef TVector TParamList; + TParamList parameters; + TType returnType; + TString mangledName; + TOperator op; + TString extension; + bool defined; +}; + + +class TSymbolTableLevel { +public: + typedef TMap tLevel; + typedef tLevel::const_iterator const_iterator; + typedef const tLevel::value_type tLevelPair; + typedef std::pair tInsertResult; + + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TSymbolTableLevel() { } + ~TSymbolTableLevel(); + + bool insert(TSymbol& symbol) + { + // + // returning true means symbol was added to the table + // + tInsertResult result; + result = level.insert(tLevelPair(symbol.getMangledName(), &symbol)); + + return result.second; + } + + TSymbol* find(const TString& name) const + { + tLevel::const_iterator it = level.find(name); + if (it == level.end()) + return 0; + else + return (*it).second; + } + + const_iterator begin() const + { + return level.begin(); + } + + const_iterator end() const + { + return level.end(); + } + + void relateToOperator(const char* name, TOperator op); + void relateToExtension(const char* name, const TString& ext); + void dump(TInfoSink &infoSink) const; + TSymbolTableLevel* clone(TStructureMap& remapper); + +protected: + tLevel level; +}; + +class TSymbolTable { +public: + TSymbolTable() : uniqueId(0) + { + // + // The symbol table cannot be used until push() is called, but + // the lack of an initial call to push() can be used to detect + // that the symbol table has not been preloaded with built-ins. + // + } + + ~TSymbolTable() + { + // level 0 is always built In symbols, so we never pop that out + while (table.size() > 1) + pop(); + } + + // + // When the symbol table is initialized with the built-ins, there should + // 'push' calls, so that built-ins are at level 0 and the shader + // globals are at level 1. + // + bool isEmpty() { return table.size() == 0; } + bool atBuiltInLevel() { return table.size() == 1; } + bool atGlobalLevel() { return table.size() <= 2; } + void push() + { + table.push_back(new TSymbolTableLevel); + precisionStack.push_back( PrecisionStackLevel() ); + } + + void pop() + { + delete table[currentLevel()]; + table.pop_back(); + precisionStack.pop_back(); + } + + bool insert(TSymbol& symbol) + { + symbol.setUniqueId(++uniqueId); + return table[currentLevel()]->insert(symbol); + } + + TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) + { + int level = currentLevel(); + TSymbol* symbol; + do { + symbol = table[level]->find(name); + --level; + } while (symbol == 0 && level >= 0); + level++; + if (builtIn) + *builtIn = level == 0; + if (sameScope) + *sameScope = level == currentLevel(); + return symbol; + } + + TSymbol *findBuiltIn(const TString &name) + { + return table[0]->find(name); + } + + TSymbolTableLevel* getGlobalLevel() { + assert(table.size() >= 2); + return table[1]; + } + + TSymbolTableLevel* getOuterLevel() { + assert(table.size() >= 2); + return table[currentLevel() - 1]; + } + + void relateToOperator(const char* name, TOperator op) { + table[0]->relateToOperator(name, op); + } + void relateToExtension(const char* name, const TString& ext) { + table[0]->relateToExtension(name, ext); + } + int getMaxSymbolId() { return uniqueId; } + void dump(TInfoSink &infoSink) const; + void copyTable(const TSymbolTable& copyOf); + + void setDefaultPrecision( TBasicType type, TPrecision prec ){ + if( type != EbtFloat && type != EbtInt ) return; // Only set default precision for int/float + int indexOfLastElement = static_cast(precisionStack.size()) - 1; + precisionStack[indexOfLastElement][type] = prec; // Uses map operator [], overwrites the current value + } + + // Searches down the precisionStack for a precision qualifier for the specified TBasicType + TPrecision getDefaultPrecision( TBasicType type){ + if( type != EbtFloat && type != EbtInt ) return EbpUndefined; + int level = static_cast(precisionStack.size()) - 1; + assert( level >= 0); // Just to be safe. Should not happen. + PrecisionStackLevel::iterator it; + TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this? + while( level >= 0 ){ + it = precisionStack[level].find( type ); + if( it != precisionStack[level].end() ){ + prec = (*it).second; + break; + } + level--; + } + return prec; + } + +protected: + int currentLevel() const { return static_cast(table.size()) - 1; } + + std::vector table; + typedef std::map< TBasicType, TPrecision > PrecisionStackLevel; + std::vector< PrecisionStackLevel > precisionStack; + int uniqueId; // for unique identification in code generation +}; + +#endif // _SYMBOL_TABLE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/TranslatorESSL.cpp new file mode 100644 index 0000000000..e3a2c2a802 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/TranslatorESSL.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/TranslatorESSL.h" + +#include "compiler/OutputESSL.h" + +TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec) + : TCompiler(type, spec) { +} + +void TranslatorESSL::translate(TIntermNode* root) { + TInfoSinkBase& sink = getInfoSink().obj; + + // Write built-in extension behaviors. + writeExtensionBehavior(); + + // Write emulated built-in functions if needed. + getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( + sink, getShaderType() == SH_FRAGMENT_SHADER); + + // Write translated shader. + TOutputESSL outputESSL(sink); + root->traverse(&outputESSL); +} + +void TranslatorESSL::writeExtensionBehavior() { + TInfoSinkBase& sink = getInfoSink().obj; + const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); + iter != extensionBehavior.end(); ++iter) { + if (iter->second != EBhUndefined) { + sink << "#extension " << iter->first << " : " + << getBehaviorString(iter->second) << "\n"; + } + } +} diff --git a/src/3rdparty/angle/src/compiler/TranslatorESSL.h b/src/3rdparty/angle/src/compiler/TranslatorESSL.h new file mode 100644 index 0000000000..a1196bd001 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/TranslatorESSL.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TRANSLATORESSL_H_ +#define COMPILER_TRANSLATORESSL_H_ + +#include "compiler/ShHandle.h" + +class TranslatorESSL : public TCompiler { +public: + TranslatorESSL(ShShaderType type, ShShaderSpec spec); + +protected: + virtual void translate(TIntermNode* root); + +private: + void writeExtensionBehavior(); +}; + +#endif // COMPILER_TRANSLATORESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp new file mode 100644 index 0000000000..bb07a1eb4e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp @@ -0,0 +1,41 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/TranslatorGLSL.h" + +#include "compiler/OutputGLSL.h" +#include "compiler/VersionGLSL.h" + +static void writeVersion(ShShaderType type, TIntermNode* root, + TInfoSinkBase& sink) { + TVersionGLSL versionGLSL(type); + root->traverse(&versionGLSL); + int version = versionGLSL.getVersion(); + // We need to write version directive only if it is greater than 110. + // If there is no version directive in the shader, 110 is implied. + if (version > 110) { + sink << "#version " << version << "\n"; + } +} + +TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec) + : TCompiler(type, spec) { +} + +void TranslatorGLSL::translate(TIntermNode* root) { + TInfoSinkBase& sink = getInfoSink().obj; + + // Write GLSL version. + writeVersion(getShaderType(), root, sink); + + // Write emulated built-in functions if needed. + getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( + sink, false); + + // Write translated shader. + TOutputGLSL outputGLSL(sink); + root->traverse(&outputGLSL); +} diff --git a/src/3rdparty/angle/src/compiler/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/TranslatorGLSL.h new file mode 100644 index 0000000000..c2ce06d192 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/TranslatorGLSL.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TRANSLATORGLSL_H_ +#define COMPILER_TRANSLATORGLSL_H_ + +#include "compiler/ShHandle.h" + +class TranslatorGLSL : public TCompiler { +public: + TranslatorGLSL(ShShaderType type, ShShaderSpec spec); + +protected: + virtual void translate(TIntermNode* root); +}; + +#endif // COMPILER_TRANSLATORGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp b/src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp new file mode 100644 index 0000000000..f41decd48c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp @@ -0,0 +1,23 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/TranslatorHLSL.h" + +#include "compiler/InitializeParseContext.h" +#include "compiler/OutputHLSL.h" + +TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec) + : TCompiler(type, spec) +{ +} + +void TranslatorHLSL::translate(TIntermNode *root) +{ + TParseContext& parseContext = *GetGlobalParseContext(); + sh::OutputHLSL outputHLSL(parseContext); + + outputHLSL.output(); +} diff --git a/src/3rdparty/angle/src/compiler/TranslatorHLSL.h b/src/3rdparty/angle/src/compiler/TranslatorHLSL.h new file mode 100644 index 0000000000..c3f672ba91 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/TranslatorHLSL.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TRANSLATORHLSL_H_ +#define COMPILER_TRANSLATORHLSL_H_ + +#include "compiler/ShHandle.h" + +class TranslatorHLSL : public TCompiler { +public: + TranslatorHLSL(ShShaderType type, ShShaderSpec spec); + +protected: + virtual void translate(TIntermNode* root); +}; + +#endif // COMPILER_TRANSLATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/Types.h b/src/3rdparty/angle/src/compiler/Types.h new file mode 100644 index 0000000000..d4576673b1 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/Types.h @@ -0,0 +1,318 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _TYPES_INCLUDED +#define _TYPES_INCLUDED + +#include "compiler/BaseTypes.h" +#include "compiler/Common.h" +#include "compiler/debug.h" + +class TType; +struct TPublicType; + +// +// Need to have association of line numbers to types in a list for building structs. +// +struct TTypeLine { + TType* type; + int line; +}; +typedef TVector TTypeList; + +inline TTypeList* NewPoolTTypeList() +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TTypeList)); + return new(memory) TTypeList; +} + +typedef TMap TStructureMap; +typedef TMap::iterator TStructureMapIterator; + +// +// Base class for things that have a type. +// +class TType +{ +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TType() {} + TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) : + type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0), + maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0) + { + } + explicit TType(const TPublicType &p); + TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) : + type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0), + maxArraySize(0), arrayInformationType(0), structure(userDef), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0) + { + typeName = NewPoolTString(n.c_str()); + } + + void copyType(const TType& copyOf, TStructureMap& remapper) + { + type = copyOf.type; + precision = copyOf.precision; + qualifier = copyOf.qualifier; + size = copyOf.size; + matrix = copyOf.matrix; + array = copyOf.array; + arraySize = copyOf.arraySize; + + TStructureMapIterator iter; + if (copyOf.structure) { + if ((iter = remapper.find(structure)) == remapper.end()) { + // create the new structure here + structure = NewPoolTTypeList(); + for (unsigned int i = 0; i < copyOf.structure->size(); ++i) { + TTypeLine typeLine; + typeLine.line = (*copyOf.structure)[i].line; + typeLine.type = (*copyOf.structure)[i].type->clone(remapper); + structure->push_back(typeLine); + } + } else { + structure = iter->second; + } + } else + structure = 0; + + fieldName = 0; + if (copyOf.fieldName) + fieldName = NewPoolTString(copyOf.fieldName->c_str()); + typeName = 0; + if (copyOf.typeName) + typeName = NewPoolTString(copyOf.typeName->c_str()); + + mangled = 0; + if (copyOf.mangled) + mangled = NewPoolTString(copyOf.mangled->c_str()); + + structureSize = copyOf.structureSize; + maxArraySize = copyOf.maxArraySize; + deepestStructNesting = copyOf.deepestStructNesting; + assert(copyOf.arrayInformationType == 0); + arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level + } + + TType* clone(TStructureMap& remapper) + { + TType *newType = new TType(); + newType->copyType(*this, remapper); + + return newType; + } + + TBasicType getBasicType() const { return type; } + void setBasicType(TBasicType t) { type = t; } + + TPrecision getPrecision() const { return precision; } + void setPrecision(TPrecision p) { precision = p; } + + TQualifier getQualifier() const { return qualifier; } + void setQualifier(TQualifier q) { qualifier = q; } + + // One-dimensional size of single instance type + int getNominalSize() const { return size; } + void setNominalSize(int s) { size = s; } + // Full size of single instance of type + int getObjectSize() const + { + int totalSize; + + if (getBasicType() == EbtStruct) + totalSize = getStructSize(); + else if (matrix) + totalSize = size * size; + else + totalSize = size; + + if (isArray()) + totalSize *= std::max(getArraySize(), getMaxArraySize()); + + return totalSize; + } + + bool isMatrix() const { return matrix ? true : false; } + void setMatrix(bool m) { matrix = m; } + + bool isArray() const { return array ? true : false; } + int getArraySize() const { return arraySize; } + void setArraySize(int s) { array = true; arraySize = s; } + int getMaxArraySize () const { return maxArraySize; } + void setMaxArraySize (int s) { maxArraySize = s; } + void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; } + void setArrayInformationType(TType* t) { arrayInformationType = t; } + TType* getArrayInformationType() const { return arrayInformationType; } + + bool isVector() const { return size > 1 && !matrix; } + bool isScalar() const { return size == 1 && !matrix && !structure; } + + TTypeList* getStruct() const { return structure; } + void setStruct(TTypeList* s) { structure = s; computeDeepestStructNesting(); } + + const TString& getTypeName() const + { + assert(typeName); + return *typeName; + } + void setTypeName(const TString& n) + { + typeName = NewPoolTString(n.c_str()); + } + + bool isField() const { return fieldName != 0; } + const TString& getFieldName() const + { + assert(fieldName); + return *fieldName; + } + void setFieldName(const TString& n) + { + fieldName = NewPoolTString(n.c_str()); + } + + TString& getMangledName() { + if (!mangled) { + mangled = NewPoolTString(""); + buildMangledName(*mangled); + *mangled += ';' ; + } + + return *mangled; + } + + bool sameElementType(const TType& right) const { + return type == right.type && + size == right.size && + matrix == right.matrix && + structure == right.structure; + } + bool operator==(const TType& right) const { + return type == right.type && + size == right.size && + matrix == right.matrix && + array == right.array && (!array || arraySize == right.arraySize) && + structure == right.structure; + // don't check the qualifier, it's not ever what's being sought after + } + bool operator!=(const TType& right) const { + return !operator==(right); + } + bool operator<(const TType& right) const { + if (type != right.type) return type < right.type; + if (size != right.size) return size < right.size; + if (matrix != right.matrix) return matrix < right.matrix; + if (array != right.array) return array < right.array; + if (arraySize != right.arraySize) return arraySize < right.arraySize; + if (structure != right.structure) return structure < right.structure; + + return false; + } + + const char* getBasicString() const { return ::getBasicString(type); } + const char* getPrecisionString() const { return ::getPrecisionString(precision); } + const char* getQualifierString() const { return ::getQualifierString(qualifier); } + TString getCompleteString() const; + + // If this type is a struct, returns the deepest struct nesting of + // any field in the struct. For example: + // struct nesting1 { + // vec4 position; + // }; + // struct nesting2 { + // nesting1 field1; + // vec4 field2; + // }; + // For type "nesting2", this method would return 2 -- the number + // of structures through which indirection must occur to reach the + // deepest field (nesting2.field1.position). + int getDeepestStructNesting() const { return deepestStructNesting; } + + bool isStructureContainingArrays() const; + +protected: + void buildMangledName(TString&); + int getStructSize() const; + void computeDeepestStructNesting(); + + TBasicType type : 6; + TPrecision precision; + TQualifier qualifier : 7; + int size : 8; // size of vector or matrix, not size of array + unsigned int matrix : 1; + unsigned int array : 1; + int arraySize; + int maxArraySize; + TType* arrayInformationType; + + TTypeList* structure; // 0 unless this is a struct + mutable int structureSize; + int deepestStructNesting; + + TString *fieldName; // for structure field names + TString *mangled; + TString *typeName; // for structure field type name +}; + +// +// This is a workaround for a problem with the yacc stack, It can't have +// types that it thinks have non-trivial constructors. It should +// just be used while recognizing the grammar, not anything else. Pointers +// could be used, but also trying to avoid lots of memory management overhead. +// +// Not as bad as it looks, there is no actual assumption that the fields +// match up or are name the same or anything like that. +// +struct TPublicType +{ + TBasicType type; + TQualifier qualifier; + TPrecision precision; + int size; // size of vector or matrix, not size of array + bool matrix; + bool array; + int arraySize; + TType* userDef; + int line; + + void setBasic(TBasicType bt, TQualifier q, int ln = 0) + { + type = bt; + qualifier = q; + precision = EbpUndefined; + size = 1; + matrix = false; + array = false; + arraySize = 0; + userDef = 0; + line = ln; + } + + void setAggregate(int s, bool m = false) + { + size = s; + matrix = m; + } + + void setArray(bool a, int s = 0) + { + array = a; + arraySize = s; + } + + bool isStructureContainingArrays() const + { + if (!userDef) + { + return false; + } + + return userDef->isStructureContainingArrays(); + } +}; + +#endif // _TYPES_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp new file mode 100644 index 0000000000..1782ebc90c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp @@ -0,0 +1,172 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements. +// The results are assigned to s# temporaries, which are used by the main translator instead of +// the original expression. +// + +#include "compiler/UnfoldShortCircuit.h" + +#include "compiler/InfoSink.h" +#include "compiler/OutputHLSL.h" + +namespace sh +{ +UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL) +{ + mTemporaryIndex = 0; +} + +void UnfoldShortCircuit::traverse(TIntermNode *node) +{ + int rewindIndex = mTemporaryIndex; + node->traverse(this); + mTemporaryIndex = rewindIndex; +} + +bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + + switch (node->getOp()) + { + case EOpLogicalOr: + // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;", + // and then further simplifies down to "bool s = x; if(!s) s = y;". + { + int i = mTemporaryIndex; + + out << "bool s" << i << ";\n"; + + out << "{\n"; + + mTemporaryIndex = i + 1; + node->getLeft()->traverse(this); + out << "s" << i << " = "; + mTemporaryIndex = i + 1; + node->getLeft()->traverse(mOutputHLSL); + out << ";\n"; + out << "if(!s" << i << ")\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getRight()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getRight()->traverse(mOutputHLSL); + out << ";\n" + "}\n"; + + out << "}\n"; + + mTemporaryIndex = i + 1; + } + return false; + case EOpLogicalAnd: + // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;", + // and then further simplifies down to "bool s = x; if(s) s = y;". + { + int i = mTemporaryIndex; + + out << "bool s" << i << ";\n"; + + out << "{\n"; + + mTemporaryIndex = i + 1; + node->getLeft()->traverse(this); + out << "s" << i << " = "; + mTemporaryIndex = i + 1; + node->getLeft()->traverse(mOutputHLSL); + out << ";\n"; + out << "if(s" << i << ")\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getRight()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getRight()->traverse(mOutputHLSL); + out << ";\n" + "}\n"; + + out << "}\n"; + + mTemporaryIndex = i + 1; + } + return false; + } + + return true; +} + +bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) +{ + TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + + // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" + if (node->usesTernaryOperator()) + { + int i = mTemporaryIndex; + + out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n"; + + mTemporaryIndex = i + 1; + node->getCondition()->traverse(this); + out << "if("; + mTemporaryIndex = i + 1; + node->getCondition()->traverse(mOutputHLSL); + out << ")\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getTrueBlock()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getTrueBlock()->traverse(mOutputHLSL); + out << ";\n" + "}\n" + "else\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getFalseBlock()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getFalseBlock()->traverse(mOutputHLSL); + out << ";\n" + "}\n"; + + mTemporaryIndex = i + 1; + } + + return false; +} + +bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node) +{ + int rewindIndex = mTemporaryIndex; + + if (node->getInit()) + { + node->getInit()->traverse(this); + } + + if (node->getCondition()) + { + node->getCondition()->traverse(this); + } + + if (node->getExpression()) + { + node->getExpression()->traverse(this); + } + + mTemporaryIndex = rewindIndex; + + return false; +} + +int UnfoldShortCircuit::getNextTemporaryIndex() +{ + return mTemporaryIndex++; +} +} diff --git a/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h new file mode 100644 index 0000000000..cb176a5f1c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements +// + +#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_ +#define COMPILER_UNFOLDSHORTCIRCUIT_H_ + +#include "compiler/intermediate.h" +#include "compiler/ParseHelper.h" + +namespace sh +{ +class OutputHLSL; + +class UnfoldShortCircuit : public TIntermTraverser +{ + public: + UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL); + + void traverse(TIntermNode *node); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitSelection(Visit visit, TIntermSelection *node); + bool visitLoop(Visit visit, TIntermLoop *node); + + int getNextTemporaryIndex(); + + protected: + TParseContext &mContext; + OutputHLSL *const mOutputHLSL; + + int mTemporaryIndex; +}; +} + +#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_ diff --git a/src/3rdparty/angle/src/compiler/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/ValidateLimitations.cpp new file mode 100644 index 0000000000..d69ec6bbaa --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ValidateLimitations.cpp @@ -0,0 +1,512 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/ValidateLimitations.h" +#include "compiler/InfoSink.h" +#include "compiler/InitializeParseContext.h" +#include "compiler/ParseHelper.h" + +namespace { +bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) { + for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) { + if (i->index.id == symbol->getId()) + return true; + } + return false; +} + +void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) { + for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) { + if (i->index.id == symbol->getId()) { + ASSERT(i->loop != NULL); + i->loop->setUnrollFlag(true); + return; + } + } + UNREACHABLE(); +} + +// Traverses a node to check if it represents a constant index expression. +// Definition: +// constant-index-expressions are a superset of constant-expressions. +// Constant-index-expressions can include loop indices as defined in +// GLSL ES 1.0 spec, Appendix A, section 4. +// The following are constant-index-expressions: +// - Constant expressions +// - Loop indices as defined in section 4 +// - Expressions composed of both of the above +class ValidateConstIndexExpr : public TIntermTraverser { +public: + ValidateConstIndexExpr(const TLoopStack& stack) + : mValid(true), mLoopStack(stack) {} + + // Returns true if the parsed node represents a constant index expression. + bool isValid() const { return mValid; } + + virtual void visitSymbol(TIntermSymbol* symbol) { + // Only constants and loop indices are allowed in a + // constant index expression. + if (mValid) { + mValid = (symbol->getQualifier() == EvqConst) || + IsLoopIndex(symbol, mLoopStack); + } + } + +private: + bool mValid; + const TLoopStack& mLoopStack; +}; + +// Traverses a node to check if it uses a loop index. +// If an int loop index is used in its body as a sampler array index, +// mark the loop for unroll. +class ValidateLoopIndexExpr : public TIntermTraverser { +public: + ValidateLoopIndexExpr(TLoopStack& stack) + : mUsesFloatLoopIndex(false), + mUsesIntLoopIndex(false), + mLoopStack(stack) {} + + bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; } + bool usesIntLoopIndex() const { return mUsesIntLoopIndex; } + + virtual void visitSymbol(TIntermSymbol* symbol) { + if (IsLoopIndex(symbol, mLoopStack)) { + switch (symbol->getBasicType()) { + case EbtFloat: + mUsesFloatLoopIndex = true; + break; + case EbtInt: + mUsesIntLoopIndex = true; + MarkLoopForUnroll(symbol, mLoopStack); + break; + default: + UNREACHABLE(); + } + } + } + +private: + bool mUsesFloatLoopIndex; + bool mUsesIntLoopIndex; + TLoopStack& mLoopStack; +}; +} // namespace + +ValidateLimitations::ValidateLimitations(ShShaderType shaderType, + TInfoSinkBase& sink) + : mShaderType(shaderType), + mSink(sink), + mNumErrors(0) +{ +} + +bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node) +{ + // Check if loop index is modified in the loop body. + validateOperation(node, node->getLeft()); + + // Check indexing. + switch (node->getOp()) { + case EOpIndexDirect: + validateIndexing(node); + break; + case EOpIndexIndirect: +#if defined(__APPLE__) + // Loop unrolling is a work-around for a Mac Cg compiler bug where it + // crashes when a sampler array's index is also the loop index. + // Once Apple fixes this bug, we should remove the code in this CL. + // See http://codereview.appspot.com/4331048/. + if ((node->getLeft() != NULL) && (node->getRight() != NULL) && + (node->getLeft()->getAsSymbolNode())) { + TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode(); + if (IsSampler(symbol->getBasicType()) && symbol->isArray()) { + ValidateLoopIndexExpr validate(mLoopStack); + node->getRight()->traverse(&validate); + if (validate.usesFloatLoopIndex()) { + error(node->getLine(), + "sampler array index is float loop index", + "for"); + } + } + } +#endif + validateIndexing(node); + break; + default: break; + } + return true; +} + +bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node) +{ + // Check if loop index is modified in the loop body. + validateOperation(node, node->getOperand()); + + return true; +} + +bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node) +{ + switch (node->getOp()) { + case EOpFunctionCall: + validateFunctionCall(node); + break; + default: + break; + } + return true; +} + +bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node) +{ + if (!validateLoopType(node)) + return false; + + TLoopInfo info; + memset(&info, 0, sizeof(TLoopInfo)); + info.loop = node; + if (!validateForLoopHeader(node, &info)) + return false; + + TIntermNode* body = node->getBody(); + if (body != NULL) { + mLoopStack.push_back(info); + body->traverse(this); + mLoopStack.pop_back(); + } + + // The loop is fully processed - no need to visit children. + return false; +} + +void ValidateLimitations::error(TSourceLoc loc, + const char *reason, const char* token) +{ + mSink.prefix(EPrefixError); + mSink.location(loc); + mSink << "'" << token << "' : " << reason << "\n"; + ++mNumErrors; +} + +bool ValidateLimitations::withinLoopBody() const +{ + return !mLoopStack.empty(); +} + +bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const +{ + return IsLoopIndex(symbol, mLoopStack); +} + +bool ValidateLimitations::validateLoopType(TIntermLoop* node) { + TLoopType type = node->getType(); + if (type == ELoopFor) + return true; + + // Reject while and do-while loops. + error(node->getLine(), + "This type of loop is not allowed", + type == ELoopWhile ? "while" : "do"); + return false; +} + +bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node, + TLoopInfo* info) +{ + ASSERT(node->getType() == ELoopFor); + + // + // The for statement has the form: + // for ( init-declaration ; condition ; expression ) statement + // + if (!validateForLoopInit(node, info)) + return false; + if (!validateForLoopCond(node, info)) + return false; + if (!validateForLoopExpr(node, info)) + return false; + + return true; +} + +bool ValidateLimitations::validateForLoopInit(TIntermLoop* node, + TLoopInfo* info) +{ + TIntermNode* init = node->getInit(); + if (init == NULL) { + error(node->getLine(), "Missing init declaration", "for"); + return false; + } + + // + // init-declaration has the form: + // type-specifier identifier = constant-expression + // + TIntermAggregate* decl = init->getAsAggregate(); + if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) { + error(init->getLine(), "Invalid init declaration", "for"); + return false; + } + // To keep things simple do not allow declaration list. + TIntermSequence& declSeq = decl->getSequence(); + if (declSeq.size() != 1) { + error(decl->getLine(), "Invalid init declaration", "for"); + return false; + } + TIntermBinary* declInit = declSeq[0]->getAsBinaryNode(); + if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) { + error(decl->getLine(), "Invalid init declaration", "for"); + return false; + } + TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode(); + if (symbol == NULL) { + error(declInit->getLine(), "Invalid init declaration", "for"); + return false; + } + // The loop index has type int or float. + TBasicType type = symbol->getBasicType(); + if ((type != EbtInt) && (type != EbtFloat)) { + error(symbol->getLine(), + "Invalid type for loop index", getBasicString(type)); + return false; + } + // The loop index is initialized with constant expression. + if (!isConstExpr(declInit->getRight())) { + error(declInit->getLine(), + "Loop index cannot be initialized with non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + + info->index.id = symbol->getId(); + return true; +} + +bool ValidateLimitations::validateForLoopCond(TIntermLoop* node, + TLoopInfo* info) +{ + TIntermNode* cond = node->getCondition(); + if (cond == NULL) { + error(node->getLine(), "Missing condition", "for"); + return false; + } + // + // condition has the form: + // loop_index relational_operator constant_expression + // + TIntermBinary* binOp = cond->getAsBinaryNode(); + if (binOp == NULL) { + error(node->getLine(), "Invalid condition", "for"); + return false; + } + // Loop index should be to the left of relational operator. + TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode(); + if (symbol == NULL) { + error(binOp->getLine(), "Invalid condition", "for"); + return false; + } + if (symbol->getId() != info->index.id) { + error(symbol->getLine(), + "Expected loop index", symbol->getSymbol().c_str()); + return false; + } + // Relational operator is one of: > >= < <= == or !=. + switch (binOp->getOp()) { + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + break; + default: + error(binOp->getLine(), + "Invalid relational operator", + getOperatorString(binOp->getOp())); + break; + } + // Loop index must be compared with a constant. + if (!isConstExpr(binOp->getRight())) { + error(binOp->getLine(), + "Loop index cannot be compared with non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + + return true; +} + +bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node, + TLoopInfo* info) +{ + TIntermNode* expr = node->getExpression(); + if (expr == NULL) { + error(node->getLine(), "Missing expression", "for"); + return false; + } + + // for expression has one of the following forms: + // loop_index++ + // loop_index-- + // loop_index += constant_expression + // loop_index -= constant_expression + // ++loop_index + // --loop_index + // The last two forms are not specified in the spec, but I am assuming + // its an oversight. + TIntermUnary* unOp = expr->getAsUnaryNode(); + TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode(); + + TOperator op = EOpNull; + TIntermSymbol* symbol = NULL; + if (unOp != NULL) { + op = unOp->getOp(); + symbol = unOp->getOperand()->getAsSymbolNode(); + } else if (binOp != NULL) { + op = binOp->getOp(); + symbol = binOp->getLeft()->getAsSymbolNode(); + } + + // The operand must be loop index. + if (symbol == NULL) { + error(expr->getLine(), "Invalid expression", "for"); + return false; + } + if (symbol->getId() != info->index.id) { + error(symbol->getLine(), + "Expected loop index", symbol->getSymbol().c_str()); + return false; + } + + // The operator is one of: ++ -- += -=. + switch (op) { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + ASSERT((unOp != NULL) && (binOp == NULL)); + break; + case EOpAddAssign: + case EOpSubAssign: + ASSERT((unOp == NULL) && (binOp != NULL)); + break; + default: + error(expr->getLine(), "Invalid operator", getOperatorString(op)); + return false; + } + + // Loop index must be incremented/decremented with a constant. + if (binOp != NULL) { + if (!isConstExpr(binOp->getRight())) { + error(binOp->getLine(), + "Loop index cannot be modified by non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + } + + return true; +} + +bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node) +{ + ASSERT(node->getOp() == EOpFunctionCall); + + // If not within loop body, there is nothing to check. + if (!withinLoopBody()) + return true; + + // List of param indices for which loop indices are used as argument. + typedef std::vector ParamIndex; + ParamIndex pIndex; + TIntermSequence& params = node->getSequence(); + for (TIntermSequence::size_type i = 0; i < params.size(); ++i) { + TIntermSymbol* symbol = params[i]->getAsSymbolNode(); + if (symbol && isLoopIndex(symbol)) + pIndex.push_back(i); + } + // If none of the loop indices are used as arguments, + // there is nothing to check. + if (pIndex.empty()) + return true; + + bool valid = true; + TSymbolTable& symbolTable = GlobalParseContext->symbolTable; + TSymbol* symbol = symbolTable.find(node->getName()); + ASSERT(symbol && symbol->isFunction()); + TFunction* function = static_cast(symbol); + for (ParamIndex::const_iterator i = pIndex.begin(); + i != pIndex.end(); ++i) { + const TParameter& param = function->getParam(*i); + TQualifier qual = param.type->getQualifier(); + if ((qual == EvqOut) || (qual == EvqInOut)) { + error(params[*i]->getLine(), + "Loop index cannot be used as argument to a function out or inout parameter", + params[*i]->getAsSymbolNode()->getSymbol().c_str()); + valid = false; + } + } + + return valid; +} + +bool ValidateLimitations::validateOperation(TIntermOperator* node, + TIntermNode* operand) { + // Check if loop index is modified in the loop body. + if (!withinLoopBody() || !node->modifiesState()) + return true; + + const TIntermSymbol* symbol = operand->getAsSymbolNode(); + if (symbol && isLoopIndex(symbol)) { + error(node->getLine(), + "Loop index cannot be statically assigned to within the body of the loop", + symbol->getSymbol().c_str()); + } + return true; +} + +bool ValidateLimitations::isConstExpr(TIntermNode* node) +{ + ASSERT(node != NULL); + return node->getAsConstantUnion() != NULL; +} + +bool ValidateLimitations::isConstIndexExpr(TIntermNode* node) +{ + ASSERT(node != NULL); + + ValidateConstIndexExpr validate(mLoopStack); + node->traverse(&validate); + return validate.isValid(); +} + +bool ValidateLimitations::validateIndexing(TIntermBinary* node) +{ + ASSERT((node->getOp() == EOpIndexDirect) || + (node->getOp() == EOpIndexIndirect)); + + bool valid = true; + TIntermTyped* index = node->getRight(); + // The index expression must have integral type. + if (!index->isScalar() || (index->getBasicType() != EbtInt)) { + error(index->getLine(), + "Index expression must have integral type", + index->getCompleteString().c_str()); + valid = false; + } + // The index expession must be a constant-index-expression unless + // the operand is a uniform in a vertex shader. + TIntermTyped* operand = node->getLeft(); + bool skip = (mShaderType == SH_VERTEX_SHADER) && + (operand->getQualifier() == EvqUniform); + if (!skip && !isConstIndexExpr(index)) { + error(index->getLine(), "Index expression must be constant", "[]"); + valid = false; + } + return valid; +} + diff --git a/src/3rdparty/angle/src/compiler/ValidateLimitations.h b/src/3rdparty/angle/src/compiler/ValidateLimitations.h new file mode 100644 index 0000000000..a835cb3c22 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ValidateLimitations.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "GLSLANG/ShaderLang.h" +#include "compiler/intermediate.h" + +class TInfoSinkBase; + +struct TLoopInfo { + struct TIndex { + int id; // symbol id. + } index; + TIntermLoop* loop; +}; +typedef TVector TLoopStack; + +// Traverses intermediate tree to ensure that the shader does not exceed the +// minimum functionality mandated in GLSL 1.0 spec, Appendix A. +class ValidateLimitations : public TIntermTraverser { +public: + ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink); + + int numErrors() const { return mNumErrors; } + + virtual bool visitBinary(Visit, TIntermBinary*); + virtual bool visitUnary(Visit, TIntermUnary*); + virtual bool visitAggregate(Visit, TIntermAggregate*); + virtual bool visitLoop(Visit, TIntermLoop*); + +private: + void error(TSourceLoc loc, const char *reason, const char* token); + + bool withinLoopBody() const; + bool isLoopIndex(const TIntermSymbol* symbol) const; + bool validateLoopType(TIntermLoop* node); + bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info); + bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info); + bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info); + bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info); + // Returns true if none of the loop indices is used as the argument to + // the given function out or inout parameter. + bool validateFunctionCall(TIntermAggregate* node); + bool validateOperation(TIntermOperator* node, TIntermNode* operand); + + // Returns true if indexing does not exceed the minimum functionality + // mandated in GLSL 1.0 spec, Appendix A, Section 5. + bool isConstExpr(TIntermNode* node); + bool isConstIndexExpr(TIntermNode* node); + bool validateIndexing(TIntermBinary* node); + + ShShaderType mShaderType; + TInfoSinkBase& mSink; + int mNumErrors; + TLoopStack mLoopStack; +}; + diff --git a/src/3rdparty/angle/src/compiler/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/VariableInfo.cpp new file mode 100644 index 0000000000..3ff283627b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/VariableInfo.cpp @@ -0,0 +1,232 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/VariableInfo.h" + +static TString arrayBrackets(int index) +{ + TStringStream stream; + stream << "[" << index << "]"; + return stream.str(); +} + +// Returns the data type for an attribute or uniform. +static ShDataType getVariableDataType(const TType& type) +{ + switch (type.getBasicType()) { + case EbtFloat: + if (type.isMatrix()) { + switch (type.getNominalSize()) { + case 2: return SH_FLOAT_MAT2; + case 3: return SH_FLOAT_MAT3; + case 4: return SH_FLOAT_MAT4; + default: UNREACHABLE(); + } + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_FLOAT_VEC2; + case 3: return SH_FLOAT_VEC3; + case 4: return SH_FLOAT_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_FLOAT; + } + case EbtInt: + if (type.isMatrix()) { + UNREACHABLE(); + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_INT_VEC2; + case 3: return SH_INT_VEC3; + case 4: return SH_INT_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_INT; + } + case EbtBool: + if (type.isMatrix()) { + UNREACHABLE(); + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_BOOL_VEC2; + case 3: return SH_BOOL_VEC3; + case 4: return SH_BOOL_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_BOOL; + } + case EbtSampler2D: return SH_SAMPLER_2D; + case EbtSamplerCube: return SH_SAMPLER_CUBE; + case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES; + case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB; + default: UNREACHABLE(); + } + return SH_NONE; +} + +static void getBuiltInVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList); +static void getUserDefinedVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList); + +// Returns info for an attribute or uniform. +static void getVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList) +{ + if (type.getBasicType() == EbtStruct) { + if (type.isArray()) { + for (int i = 0; i < type.getArraySize(); ++i) { + TString lname = name + arrayBrackets(i); + TString lmappedName = mappedName + arrayBrackets(i); + getUserDefinedVariableInfo(type, lname, lmappedName, infoList); + } + } else { + getUserDefinedVariableInfo(type, name, mappedName, infoList); + } + } else { + getBuiltInVariableInfo(type, name, mappedName, infoList); + } +} + +void getBuiltInVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList) +{ + ASSERT(type.getBasicType() != EbtStruct); + + TVariableInfo varInfo; + if (type.isArray()) { + varInfo.name = (name + "[0]").c_str(); + varInfo.mappedName = (mappedName + "[0]").c_str(); + varInfo.size = type.getArraySize(); + } else { + varInfo.name = name.c_str(); + varInfo.mappedName = mappedName.c_str(); + varInfo.size = 1; + } + varInfo.type = getVariableDataType(type); + infoList.push_back(varInfo); +} + +void getUserDefinedVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList) +{ + ASSERT(type.getBasicType() == EbtStruct); + + const TTypeList* structure = type.getStruct(); + for (size_t i = 0; i < structure->size(); ++i) { + const TType* fieldType = (*structure)[i].type; + getVariableInfo(*fieldType, + name + "." + fieldType->getFieldName(), + mappedName + "." + fieldType->getFieldName(), + infoList); + } +} + +TVariableInfo::TVariableInfo() +{ +} + +TVariableInfo::TVariableInfo(ShDataType type, int size) + : type(type), + size(size) +{ +} + +CollectAttribsUniforms::CollectAttribsUniforms(TVariableInfoList& attribs, + TVariableInfoList& uniforms) + : mAttribs(attribs), + mUniforms(uniforms) +{ +} + +// We are only interested in attribute and uniform variable declaration. +void CollectAttribsUniforms::visitSymbol(TIntermSymbol*) +{ +} + +void CollectAttribsUniforms::visitConstantUnion(TIntermConstantUnion*) +{ +} + +bool CollectAttribsUniforms::visitBinary(Visit, TIntermBinary*) +{ + return false; +} + +bool CollectAttribsUniforms::visitUnary(Visit, TIntermUnary*) +{ + return false; +} + +bool CollectAttribsUniforms::visitSelection(Visit, TIntermSelection*) +{ + return false; +} + +bool CollectAttribsUniforms::visitAggregate(Visit, TIntermAggregate* node) +{ + bool visitChildren = false; + + switch (node->getOp()) + { + case EOpSequence: + // We need to visit sequence children to get to variable declarations. + visitChildren = true; + break; + case EOpDeclaration: { + const TIntermSequence& sequence = node->getSequence(); + TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); + if (qualifier == EvqAttribute || qualifier == EvqUniform) + { + TVariableInfoList& infoList = qualifier == EvqAttribute ? + mAttribs : mUniforms; + for (TIntermSequence::const_iterator i = sequence.begin(); + i != sequence.end(); ++i) + { + const TIntermSymbol* variable = (*i)->getAsSymbolNode(); + // The only case in which the sequence will not contain a + // TIntermSymbol node is initialization. It will contain a + // TInterBinary node in that case. Since attributes and unifroms + // cannot be initialized in a shader, we must have only + // TIntermSymbol nodes in the sequence. + ASSERT(variable != NULL); + getVariableInfo(variable->getType(), + variable->getOriginalSymbol(), + variable->getSymbol(), + infoList); + } + } + break; + } + default: break; + } + + return visitChildren; +} + +bool CollectAttribsUniforms::visitLoop(Visit, TIntermLoop*) +{ + return false; +} + +bool CollectAttribsUniforms::visitBranch(Visit, TIntermBranch*) +{ + return false; +} + diff --git a/src/3rdparty/angle/src/compiler/VariableInfo.h b/src/3rdparty/angle/src/compiler/VariableInfo.h new file mode 100644 index 0000000000..fdcc08f5b5 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/VariableInfo.h @@ -0,0 +1,46 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_VARIABLE_INFO_H_ +#define COMPILER_VARIABLE_INFO_H_ + +#include "GLSLANG/ShaderLang.h" +#include "compiler/intermediate.h" + +// Provides information about a variable. +// It is currently being used to store info about active attribs and uniforms. +struct TVariableInfo { + TVariableInfo(ShDataType type, int size); + TVariableInfo(); + + TPersistString name; + TPersistString mappedName; + ShDataType type; + int size; +}; +typedef std::vector TVariableInfoList; + +// Traverses intermediate tree to collect all attributes and uniforms. +class CollectAttribsUniforms : public TIntermTraverser { +public: + CollectAttribsUniforms(TVariableInfoList& attribs, + TVariableInfoList& uniforms); + + virtual void visitSymbol(TIntermSymbol*); + virtual void visitConstantUnion(TIntermConstantUnion*); + virtual bool visitBinary(Visit, TIntermBinary*); + virtual bool visitUnary(Visit, TIntermUnary*); + virtual bool visitSelection(Visit, TIntermSelection*); + virtual bool visitAggregate(Visit, TIntermAggregate*); + virtual bool visitLoop(Visit, TIntermLoop*); + virtual bool visitBranch(Visit, TIntermBranch*); + +private: + TVariableInfoList& mAttribs; + TVariableInfoList& mUniforms; +}; + +#endif // COMPILER_VARIABLE_INFO_H_ diff --git a/src/3rdparty/angle/src/compiler/VariablePacker.cpp b/src/3rdparty/angle/src/compiler/VariablePacker.cpp new file mode 100644 index 0000000000..2f0c4bc2a2 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/VariablePacker.cpp @@ -0,0 +1,297 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#include "compiler/VariablePacker.h" + +#include +#include "compiler/ShHandle.h" + +namespace { +int GetSortOrder(ShDataType type) +{ + switch (type) { + case SH_FLOAT_MAT4: + return 0; + case SH_FLOAT_MAT2: + return 1; + case SH_FLOAT_VEC4: + case SH_INT_VEC4: + case SH_BOOL_VEC4: + return 2; + case SH_FLOAT_MAT3: + return 3; + case SH_FLOAT_VEC3: + case SH_INT_VEC3: + case SH_BOOL_VEC3: + return 4; + case SH_FLOAT_VEC2: + case SH_INT_VEC2: + case SH_BOOL_VEC2: + return 5; + case SH_FLOAT: + case SH_INT: + case SH_BOOL: + case SH_SAMPLER_2D: + case SH_SAMPLER_CUBE: + case SH_SAMPLER_EXTERNAL_OES: + case SH_SAMPLER_2D_RECT_ARB: + return 6; + default: + ASSERT(false); + return 7; + } +} +} // namespace + +int VariablePacker::GetNumComponentsPerRow(ShDataType type) +{ + switch (type) { + case SH_FLOAT_MAT4: + case SH_FLOAT_MAT2: + case SH_FLOAT_VEC4: + case SH_INT_VEC4: + case SH_BOOL_VEC4: + return 4; + case SH_FLOAT_MAT3: + case SH_FLOAT_VEC3: + case SH_INT_VEC3: + case SH_BOOL_VEC3: + return 3; + case SH_FLOAT_VEC2: + case SH_INT_VEC2: + case SH_BOOL_VEC2: + return 2; + case SH_FLOAT: + case SH_INT: + case SH_BOOL: + case SH_SAMPLER_2D: + case SH_SAMPLER_CUBE: + case SH_SAMPLER_EXTERNAL_OES: + case SH_SAMPLER_2D_RECT_ARB: + return 1; + default: + ASSERT(false); + return 5; + } +} + +int VariablePacker::GetNumRows(ShDataType type) +{ + switch (type) { + case SH_FLOAT_MAT4: + return 4; + case SH_FLOAT_MAT3: + return 3; + case SH_FLOAT_MAT2: + return 1; + case SH_FLOAT_VEC4: + case SH_INT_VEC4: + case SH_BOOL_VEC4: + case SH_FLOAT_VEC3: + case SH_INT_VEC3: + case SH_BOOL_VEC3: + case SH_FLOAT_VEC2: + case SH_INT_VEC2: + case SH_BOOL_VEC2: + case SH_FLOAT: + case SH_INT: + case SH_BOOL: + case SH_SAMPLER_2D: + case SH_SAMPLER_CUBE: + case SH_SAMPLER_EXTERNAL_OES: + case SH_SAMPLER_2D_RECT_ARB: + return 1; + default: + ASSERT(false); + return 100000; + } +} + +struct TVariableInfoComparer { + bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const + { + int lhsSortOrder = GetSortOrder(lhs.type); + int rhsSortOrder = GetSortOrder(rhs.type); + if (lhsSortOrder != rhsSortOrder) { + return lhsSortOrder < rhsSortOrder; + } + // Sort by largest first. + return lhs.size > rhs.size; + } +}; + +unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow) +{ + return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & + kColumnMask) >> column; +} + +void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow) +{ + unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow); + for (int r = 0; r < numRows; ++r) { + int row = topRow + r; + ASSERT((rows_[row] & columnFlags) == 0); + rows_[row] |= columnFlags; + } +} + +bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize) +{ + ASSERT(destRow); + + for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; + ++topNonFullRow_) { + } + + for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; + --bottomNonFullRow_) { + } + + if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) { + return false; + } + + unsigned columnFlags = makeColumnFlags(column, 1); + int topGoodRow = 0; + int smallestGoodTop = -1; + int smallestGoodSize = maxRows_ + 1; + int bottomRow = bottomNonFullRow_ + 1; + bool found = false; + for (int row = topNonFullRow_; row <= bottomRow; ++row) { + bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false; + if (rowEmpty) { + if (!found) { + topGoodRow = row; + found = true; + } + } else { + if (found) { + int size = row - topGoodRow; + if (size >= numRows && size < smallestGoodSize) { + smallestGoodSize = size; + smallestGoodTop = topGoodRow; + } + } + found = false; + } + } + if (smallestGoodTop < 0) { + return false; + } + + *destRow = smallestGoodTop; + if (destSize) { + *destSize = smallestGoodSize; + } + return true; +} + +bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables) +{ + ASSERT(maxVectors > 0); + maxRows_ = maxVectors; + topNonFullRow_ = 0; + bottomNonFullRow_ = maxRows_ - 1; + TVariableInfoList variables(in_variables); + + // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific + // order by type, then by size of array, largest first. + std::sort(variables.begin(), variables.end(), TVariableInfoComparer()); + rows_.clear(); + rows_.resize(maxVectors, 0); + + // Packs the 4 column variables. + size_t ii = 0; + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + if (GetNumComponentsPerRow(variable.type) != 4) { + break; + } + topNonFullRow_ += GetNumRows(variable.type) * variable.size; + } + + if (topNonFullRow_ > maxRows_) { + return false; + } + + // Packs the 3 column variables. + int num3ColumnRows = 0; + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + if (GetNumComponentsPerRow(variable.type) != 3) { + break; + } + num3ColumnRows += GetNumRows(variable.type) * variable.size; + } + + if (topNonFullRow_ + num3ColumnRows > maxRows_) { + return false; + } + + fillColumns(topNonFullRow_, num3ColumnRows, 0, 3); + + // Packs the 2 column variables. + int top2ColumnRow = topNonFullRow_ + num3ColumnRows; + int twoColumnRowsAvailable = maxRows_ - top2ColumnRow; + int rowsAvailableInColumns01 = twoColumnRowsAvailable; + int rowsAvailableInColumns23 = twoColumnRowsAvailable; + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + if (GetNumComponentsPerRow(variable.type) != 2) { + break; + } + int numRows = GetNumRows(variable.type) * variable.size; + if (numRows <= rowsAvailableInColumns01) { + rowsAvailableInColumns01 -= numRows; + } else if (numRows <= rowsAvailableInColumns23) { + rowsAvailableInColumns23 -= numRows; + } else { + return false; + } + } + + int numRowsUsedInColumns01 = + twoColumnRowsAvailable - rowsAvailableInColumns01; + int numRowsUsedInColumns23 = + twoColumnRowsAvailable - rowsAvailableInColumns23; + fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2); + fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, + 2, 2); + + // Packs the 1 column variables. + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + ASSERT(1 == GetNumComponentsPerRow(variable.type)); + int numRows = GetNumRows(variable.type) * variable.size; + int smallestColumn = -1; + int smallestSize = maxRows_ + 1; + int topRow = -1; + for (int column = 0; column < kNumColumns; ++column) { + int row = 0; + int size = 0; + if (searchColumn(column, numRows, &row, &size)) { + if (size < smallestSize) { + smallestSize = size; + smallestColumn = column; + topRow = row; + } + } + } + + if (smallestColumn < 0) { + return false; + } + + fillColumns(topRow, numRows, smallestColumn, 1); + } + + ASSERT(variables.size() == ii); + + return true; +} + + + diff --git a/src/3rdparty/angle/src/compiler/VariablePacker.h b/src/3rdparty/angle/src/compiler/VariablePacker.h new file mode 100644 index 0000000000..8987066cc3 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/VariablePacker.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _VARIABLEPACKER_INCLUDED_ +#define _VARIABLEPACKER_INCLUDED_ + +#include +#include "compiler/ShHandle.h" + +class VariablePacker { + public: + // Returns true if the passed in variables pack in maxVectors following + // the packing rules from the GLSL 1.017 spec, Appendix A, section 7. + bool CheckVariablesWithinPackingLimits( + int maxVectors, + const TVariableInfoList& in_variables); + + // Gets how many components in a row a data type takes. + static int GetNumComponentsPerRow(ShDataType type); + + // Gets how many rows a data type takes. + static int GetNumRows(ShDataType type); + + private: + static const int kNumColumns = 4; + static const unsigned kColumnMask = (1 << kNumColumns) - 1; + + unsigned makeColumnFlags(int column, int numComponentsPerRow); + void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); + bool searchColumn(int column, int numRows, int* destRow, int* destSize); + + int topNonFullRow_; + int bottomNonFullRow_; + int maxRows_; + std::vector rows_; +}; + +#endif // _VARIABLEPACKER_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/VersionGLSL.cpp new file mode 100644 index 0000000000..7a82bb4dc1 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/VersionGLSL.cpp @@ -0,0 +1,140 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/VersionGLSL.h" + +static const int GLSL_VERSION_110 = 110; +static const int GLSL_VERSION_120 = 120; + +// We need to scan for the following: +// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders +// but only at the global scope. +// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader +// but inside any scope. +// 3. Call to a matrix constructor with another matrix as argument. +// (These constructors were reserved in GLSL version 1.10.) +// 4. Arrays as "out" function parameters. +// GLSL spec section 6.1.1: "When calling a function, expressions that do +// not evaluate to l-values cannot be passed to parameters declared as +// out or inout." +// GLSL 1.1 section 5.8: "Other binary or unary expressions, +// non-dereferenced arrays, function names, swizzles with repeated fields, +// and constants cannot be l-values." +// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that +// are built-in types, entire structures or arrays... are all l-values." +// +// TODO(alokp): The following two cases of invariant decalaration get lost +// during parsing - they do not get carried over to the intermediate tree. +// Handle these cases: +// 1. When a pragma is used to force all output variables to be invariant: +// - #pragma STDGL invariant(all) +// 2. When a previously decalared or built-in variable is marked invariant: +// - invariant gl_Position; +// - varying vec3 color; invariant color; +// +TVersionGLSL::TVersionGLSL(ShShaderType type) + : mShaderType(type), + mVersion(GLSL_VERSION_110) +{ +} + +void TVersionGLSL::visitSymbol(TIntermSymbol* node) +{ + if (node->getSymbol() == "gl_PointCoord") + updateVersion(GLSL_VERSION_120); +} + +void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*) +{ +} + +bool TVersionGLSL::visitBinary(Visit, TIntermBinary*) +{ + return true; +} + +bool TVersionGLSL::visitUnary(Visit, TIntermUnary*) +{ + return true; +} + +bool TVersionGLSL::visitSelection(Visit, TIntermSelection*) +{ + return true; +} + +bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node) +{ + bool visitChildren = true; + + switch (node->getOp()) { + case EOpSequence: + // We need to visit sequence children to get to global or inner scope. + visitChildren = true; + break; + case EOpDeclaration: { + const TIntermSequence& sequence = node->getSequence(); + TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); + if ((qualifier == EvqInvariantVaryingIn) || + (qualifier == EvqInvariantVaryingOut)) { + updateVersion(GLSL_VERSION_120); + } + break; + } + case EOpParameters: { + const TIntermSequence& params = node->getSequence(); + for (TIntermSequence::const_iterator iter = params.begin(); + iter != params.end(); ++iter) + { + const TIntermTyped* param = (*iter)->getAsTyped(); + if (param->isArray()) + { + TQualifier qualifier = param->getQualifier(); + if ((qualifier == EvqOut) || (qualifier == EvqInOut)) + { + updateVersion(GLSL_VERSION_120); + break; + } + } + } + // Fully processed. No need to visit children. + visitChildren = false; + break; + } + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: { + const TIntermSequence& sequence = node->getSequence(); + if (sequence.size() == 1) { + TIntermTyped* typed = sequence.front()->getAsTyped(); + if (typed && typed->isMatrix()) { + updateVersion(GLSL_VERSION_120); + } + } + break; + } + + default: break; + } + + return visitChildren; +} + +bool TVersionGLSL::visitLoop(Visit, TIntermLoop*) +{ + return true; +} + +bool TVersionGLSL::visitBranch(Visit, TIntermBranch*) +{ + return true; +} + +void TVersionGLSL::updateVersion(int version) +{ + mVersion = std::max(version, mVersion); +} + diff --git a/src/3rdparty/angle/src/compiler/VersionGLSL.h b/src/3rdparty/angle/src/compiler/VersionGLSL.h new file mode 100644 index 0000000000..1c1cb1ab97 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/VersionGLSL.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_VERSIONGLSL_H_ +#define COMPILER_VERSIONGLSL_H_ + +#include "GLSLANG/ShaderLang.h" +#include "compiler/intermediate.h" + +// Traverses the intermediate tree to return the minimum GLSL version +// required to legally access all built-in features used in the shader. +// GLSL 1.1 which is mandated by OpenGL 2.0 provides: +// - #version and #extension to declare version and extensions. +// - built-in functions refract, exp, and log. +// - updated step() to compare x < edge instead of x <= edge. +// GLSL 1.2 which is mandated by OpenGL 2.1 provides: +// - many changes to reduce differences when compared to the ES specification. +// - invariant keyword and its support. +// - c++ style name hiding rules. +// - built-in variable gl_PointCoord for fragment shaders. +// - matrix constructors taking matrix as argument. +// - array as "out" function parameters +// +class TVersionGLSL : public TIntermTraverser { +public: + TVersionGLSL(ShShaderType type); + + // Returns 120 if the following is used the shader: + // - "invariant", + // - "gl_PointCoord", + // - matrix/matrix constructors + // - array "out" parameters + // Else 110 is returned. + int getVersion() { return mVersion; } + + virtual void visitSymbol(TIntermSymbol*); + virtual void visitConstantUnion(TIntermConstantUnion*); + virtual bool visitBinary(Visit, TIntermBinary*); + virtual bool visitUnary(Visit, TIntermUnary*); + virtual bool visitSelection(Visit, TIntermSelection*); + virtual bool visitAggregate(Visit, TIntermAggregate*); + virtual bool visitLoop(Visit, TIntermLoop*); + virtual bool visitBranch(Visit, TIntermBranch*); + +protected: + void updateVersion(int version); + +private: + ShShaderType mShaderType; + int mVersion; +}; + +#endif // COMPILER_VERSIONGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/debug.cpp b/src/3rdparty/angle/src/compiler/debug.cpp new file mode 100644 index 0000000000..53778bd3eb --- /dev/null +++ b/src/3rdparty/angle/src/compiler/debug.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// debug.cpp: Debugging utilities. + +#include "compiler/debug.h" + +#include +#include + +#include "compiler/InitializeParseContext.h" +#include "compiler/ParseHelper.h" + +static const int kTraceBufferLen = 1024; + +#ifdef TRACE_ENABLED +extern "C" { +void Trace(const char *format, ...) { + if (!format) return; + + TParseContext* parseContext = GetGlobalParseContext(); + if (parseContext) { + char buf[kTraceBufferLen]; + va_list args; + va_start(args, format); + vsnprintf(buf, kTraceBufferLen, format, args); + va_end(args); + + parseContext->trace(buf); + } +} +} // extern "C" +#endif // TRACE_ENABLED + diff --git a/src/3rdparty/angle/src/compiler/debug.h b/src/3rdparty/angle/src/compiler/debug.h new file mode 100644 index 0000000000..7a371516af --- /dev/null +++ b/src/3rdparty/angle/src/compiler/debug.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// debug.h: Debugging utilities. + +#ifndef COMPILER_DEBUG_H_ +#define COMPILER_DEBUG_H_ + +#include + +#ifdef _DEBUG +#define TRACE_ENABLED // define to enable debug message tracing +#endif // _DEBUG + +// Outputs text to the debug log +#ifdef TRACE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +void Trace(const char* format, ...); +#ifdef __cplusplus +} +#endif // __cplusplus + +#else // TRACE_ENABLED + +#define Trace(...) ((void)0) + +#endif // TRACE_ENABLED + +// A macro asserting a condition and outputting failures to the debug log +#define ASSERT(expression) do { \ + if(!(expression)) \ + Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \ + assert(expression); \ +} while(0) + +#define UNIMPLEMENTED() do { \ + Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ +} while(0) + +#define UNREACHABLE() do { \ + Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ +} while(0) + +#endif // COMPILER_DEBUG_H_ + diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp new file mode 100644 index 0000000000..ca661d6767 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp @@ -0,0 +1,97 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#pragma warning(disable: 4718) + +#include "compiler/depgraph/DependencyGraph.h" +#include "compiler/depgraph/DependencyGraphBuilder.h" + +TDependencyGraph::TDependencyGraph(TIntermNode* intermNode) +{ + TDependencyGraphBuilder::build(intermNode, this); +} + +TDependencyGraph::~TDependencyGraph() +{ + for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter) + { + TGraphNode* node = *iter; + delete node; + } +} + +TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall, + int argumentNumber) +{ + TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber); + mAllNodes.push_back(argument); + return argument; +} + +TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall) +{ + TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall); + mAllNodes.push_back(functionCall); + if (functionCall->getIntermFunctionCall()->isUserDefined()) + mUserDefinedFunctionCalls.push_back(functionCall); + return functionCall; +} + +TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol) +{ + TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId()); + + TGraphSymbol* symbol = NULL; + + if (iter != mSymbolIdMap.end()) { + TSymbolIdPair pair = *iter; + symbol = pair.second; + } else { + symbol = new TGraphSymbol(intermSymbol); + mAllNodes.push_back(symbol); + + TSymbolIdPair pair(intermSymbol->getId(), symbol); + mSymbolIdMap.insert(pair); + + // We save all sampler symbols in a collection, so we can start graph traversals from them quickly. + if (IsSampler(intermSymbol->getBasicType())) + mSamplerSymbols.push_back(symbol); + } + + return symbol; +} + +TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection) +{ + TGraphSelection* selection = new TGraphSelection(intermSelection); + mAllNodes.push_back(selection); + return selection; +} + +TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop) +{ + TGraphLoop* loop = new TGraphLoop(intermLoop); + mAllNodes.push_back(loop); + return loop; +} + +TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp) +{ + TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp); + mAllNodes.push_back(logicalOp); + return logicalOp; +} + +const char* TGraphLogicalOp::getOpString() const +{ + const char* opString = NULL; + switch (getIntermLogicalOp()->getOp()) { + case EOpLogicalAnd: opString = "and"; break; + case EOpLogicalOr: opString = "or"; break; + default: opString = "unknown"; break; + } + return opString; +} diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h new file mode 100644 index 0000000000..5a9c35d00b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h @@ -0,0 +1,212 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H +#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H + +#include "compiler/intermediate.h" + +#include +#include + +class TGraphNode; +class TGraphParentNode; +class TGraphArgument; +class TGraphFunctionCall; +class TGraphSymbol; +class TGraphSelection; +class TGraphLoop; +class TGraphLogicalOp; +class TDependencyGraphTraverser; +class TDependencyGraphOutput; + +typedef std::set TGraphNodeSet; +typedef std::vector TGraphNodeVector; +typedef std::vector TGraphSymbolVector; +typedef std::vector TFunctionCallVector; + +// +// Base class for all dependency graph nodes. +// +class TGraphNode { +public: + TGraphNode(TIntermNode* node) : intermNode(node) {} + virtual ~TGraphNode() {} + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +protected: + TIntermNode* intermNode; +}; + +// +// Base class for dependency graph nodes that may have children. +// +class TGraphParentNode : public TGraphNode { +public: + TGraphParentNode(TIntermNode* node) : TGraphNode(node) {} + virtual ~TGraphParentNode() {} + void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +private: + TGraphNodeSet mDependentNodes; +}; + +// +// Handle function call arguments. +// +class TGraphArgument : public TGraphParentNode { +public: + TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber) + : TGraphParentNode(intermFunctionCall) + , mArgumentNumber(argumentNumber) {} + virtual ~TGraphArgument() {} + const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } + int getArgumentNumber() const { return mArgumentNumber; } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +private: + int mArgumentNumber; +}; + +// +// Handle function calls. +// +class TGraphFunctionCall : public TGraphParentNode { +public: + TGraphFunctionCall(TIntermAggregate* intermFunctionCall) + : TGraphParentNode(intermFunctionCall) {} + virtual ~TGraphFunctionCall() {} + const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle symbols. +// +class TGraphSymbol : public TGraphParentNode { +public: + TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {} + virtual ~TGraphSymbol() {} + const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle if statements and ternary operators. +// +class TGraphSelection : public TGraphNode { +public: + TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {} + virtual ~TGraphSelection() {} + const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle for, do-while, and while loops. +// +class TGraphLoop : public TGraphNode { +public: + TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {} + virtual ~TGraphLoop() {} + const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle logical and, or. +// +class TGraphLogicalOp : public TGraphNode { +public: + TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {} + virtual ~TGraphLogicalOp() {} + const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); } + const char* getOpString() const; + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// A dependency graph of symbols, function calls, conditions etc. +// +// This class provides an interface to the entry points of the dependency graph. +// +// Dependency graph nodes should be created by using one of the provided "create..." methods. +// This class (and nobody else) manages the memory of the created nodes. +// Nodes may not be removed after being added, so all created nodes will exist while the +// TDependencyGraph instance exists. +// +class TDependencyGraph { +public: + TDependencyGraph(TIntermNode* intermNode); + ~TDependencyGraph(); + TGraphNodeVector::const_iterator begin() const { return mAllNodes.begin(); } + TGraphNodeVector::const_iterator end() const { return mAllNodes.end(); } + + TGraphSymbolVector::const_iterator beginSamplerSymbols() const + { + return mSamplerSymbols.begin(); + } + + TGraphSymbolVector::const_iterator endSamplerSymbols() const + { + return mSamplerSymbols.end(); + } + + TFunctionCallVector::const_iterator beginUserDefinedFunctionCalls() const + { + return mUserDefinedFunctionCalls.begin(); + } + + TFunctionCallVector::const_iterator endUserDefinedFunctionCalls() const + { + return mUserDefinedFunctionCalls.end(); + } + + TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber); + TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall); + TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol); + TGraphSelection* createSelection(TIntermSelection* intermSelection); + TGraphLoop* createLoop(TIntermLoop* intermLoop); + TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp); +private: + typedef TMap TSymbolIdMap; + typedef std::pair TSymbolIdPair; + + TGraphNodeVector mAllNodes; + TGraphSymbolVector mSamplerSymbols; + TFunctionCallVector mUserDefinedFunctionCalls; + TSymbolIdMap mSymbolIdMap; +}; + +// +// For traversing the dependency graph. Users should derive from this, +// put their traversal specific data in it, and then pass it to a +// traverse method. +// +// When using this, just fill in the methods for nodes you want visited. +// +class TDependencyGraphTraverser { +public: + TDependencyGraphTraverser() : mDepth(0) {} + + virtual void visitSymbol(TGraphSymbol* symbol) {}; + virtual void visitArgument(TGraphArgument* selection) {}; + virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {}; + virtual void visitSelection(TGraphSelection* selection) {}; + virtual void visitLoop(TGraphLoop* loop) {}; + virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {}; + + int getDepth() const { return mDepth; } + void incrementDepth() { ++mDepth; } + void decrementDepth() { --mDepth; } + + void clearVisited() { mVisited.clear(); } + void markVisited(TGraphNode* node) { mVisited.insert(node); } + bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); } +private: + int mDepth; + TGraphNodeSet mVisited; +}; + +#endif diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp new file mode 100644 index 0000000000..d586cfd03c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp @@ -0,0 +1,227 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/depgraph/DependencyGraphBuilder.h" + +void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph) +{ + TDependencyGraphBuilder builder(graph); + builder.build(node); +} + +bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate) +{ + switch (intermAggregate->getOp()) { + case EOpFunction: visitFunctionDefinition(intermAggregate); break; + case EOpFunctionCall: visitFunctionCall(intermAggregate); break; + default: visitAggregateChildren(intermAggregate); break; + } + + return false; +} + +void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate) +{ + // Currently, we do not support user defined functions. + if (intermAggregate->getName() != "main(") + return; + + visitAggregateChildren(intermAggregate); +} + +// Takes an expression like "f(x)" and creates a dependency graph like +// "x -> argument 0 -> function call". +void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall) +{ + TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall); + + // Run through the function call arguments. + int argumentNumber = 0; + TIntermSequence& intermArguments = intermFunctionCall->getSequence(); + for (TIntermSequence::const_iterator iter = intermArguments.begin(); + iter != intermArguments.end(); + ++iter, ++argumentNumber) + { + TNodeSetMaintainer nodeSetMaintainer(this); + + TIntermNode* intermArgument = *iter; + intermArgument->traverse(this); + + if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) { + TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber); + connectMultipleNodesToSingleNode(argumentNodes, argument); + argument->addDependentNode(functionCall); + } + } + + // Push the leftmost symbol of this function call into the current set of dependent symbols to + // represent the result of this function call. + // Thus, an expression like "y = f(x)" will yield a dependency graph like + // "x -> argument 0 -> function call -> y". + // This line essentially passes the function call node back up to an earlier visitAssignment + // call, which will create the connection "function call -> y". + mNodeSets.insertIntoTopSet(functionCall); +} + +void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate) +{ + TIntermSequence& sequence = intermAggregate->getSequence(); + for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter) + { + TIntermNode* intermChild = *iter; + intermChild->traverse(this); + } +} + +void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol) +{ + // Push this symbol into the set of dependent symbols for the current assignment or condition + // that we are traversing. + TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol); + mNodeSets.insertIntoTopSet(symbol); + + // If this symbol is the current leftmost symbol under an assignment, replace the previous + // leftmost symbol with this symbol. + if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) { + mLeftmostSymbols.pop(); + mLeftmostSymbols.push(symbol); + } +} + +bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary) +{ + TOperator op = intermBinary->getOp(); + if (op == EOpInitialize || intermBinary->modifiesState()) + visitAssignment(intermBinary); + else if (op == EOpLogicalAnd || op == EOpLogicalOr) + visitLogicalOp(intermBinary); + else + visitBinaryChildren(intermBinary); + + return false; +} + +void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment) +{ + TIntermTyped* intermLeft = intermAssignment->getLeft(); + if (!intermLeft) + return; + + TGraphSymbol* leftmostSymbol = NULL; + + { + TNodeSetMaintainer nodeSetMaintainer(this); + + { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree); + intermLeft->traverse(this); + leftmostSymbol = mLeftmostSymbols.top(); + + // After traversing the left subtree of this assignment, we should have found a real + // leftmost symbol, and the leftmost symbol should not be a placeholder. + ASSERT(leftmostSymbol != &mLeftSubtree); + ASSERT(leftmostSymbol != &mRightSubtree); + } + + if (TIntermTyped* intermRight = intermAssignment->getRight()) { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); + intermRight->traverse(this); + } + + if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet()) + connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol); + } + + // Push the leftmost symbol of this assignment into the current set of dependent symbols to + // represent the result of this assignment. + // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a". + // This line essentially passes the leftmost symbol of the nested assignment ("b" in this + // example) back up to the earlier visitAssignment call for the outer assignment, which will + // create the connection "b -> a". + mNodeSets.insertIntoTopSet(leftmostSymbol); +} + +void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp) +{ + if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) { + TNodeSetPropagatingMaintainer nodeSetMaintainer(this); + + intermLeft->traverse(this); + if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) { + TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp); + connectMultipleNodesToSingleNode(leftNodes, logicalOp); + } + } + + if (TIntermTyped* intermRight = intermLogicalOp->getRight()) { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); + intermRight->traverse(this); + } +} + +void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary) +{ + if (TIntermTyped* intermLeft = intermBinary->getLeft()) + intermLeft->traverse(this); + + if (TIntermTyped* intermRight = intermBinary->getRight()) { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); + intermRight->traverse(this); + } +} + +bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection) +{ + if (TIntermNode* intermCondition = intermSelection->getCondition()) { + TNodeSetMaintainer nodeSetMaintainer(this); + + intermCondition->traverse(this); + if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) { + TGraphSelection* selection = mGraph->createSelection(intermSelection); + connectMultipleNodesToSingleNode(conditionNodes, selection); + } + } + + if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock()) + intermTrueBlock->traverse(this); + + if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock()) + intermFalseBlock->traverse(this); + + return false; +} + +bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop) +{ + if (TIntermTyped* intermCondition = intermLoop->getCondition()) { + TNodeSetMaintainer nodeSetMaintainer(this); + + intermCondition->traverse(this); + if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) { + TGraphLoop* loop = mGraph->createLoop(intermLoop); + connectMultipleNodesToSingleNode(conditionNodes, loop); + } + } + + if (TIntermNode* intermBody = intermLoop->getBody()) + intermBody->traverse(this); + + if (TIntermTyped* intermExpression = intermLoop->getExpression()) + intermExpression->traverse(this); + + return false; +} + + +void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes, + TGraphNode* node) const +{ + for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter) + { + TGraphParentNode* currentNode = *iter; + currentNode->addDependentNode(node); + } +} diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h new file mode 100644 index 0000000000..c5f232cb21 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h @@ -0,0 +1,181 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H + +#include "compiler/depgraph/DependencyGraph.h" + +// +// Creates a dependency graph of symbols, function calls, conditions etc. by traversing a +// intermediate tree. +// +class TDependencyGraphBuilder : public TIntermTraverser { +public: + static void build(TIntermNode* node, TDependencyGraph* graph); + + virtual void visitSymbol(TIntermSymbol*); + virtual bool visitBinary(Visit visit, TIntermBinary*); + virtual bool visitSelection(Visit visit, TIntermSelection*); + virtual bool visitAggregate(Visit visit, TIntermAggregate*); + virtual bool visitLoop(Visit visit, TIntermLoop*); + +private: + typedef std::stack TSymbolStack; + typedef std::set TParentNodeSet; + + // + // For collecting the dependent nodes of assignments, conditions, etc. + // while traversing the intermediate tree. + // + // This data structure is stack of sets. Each set contains dependency graph parent nodes. + // + class TNodeSetStack { + public: + TNodeSetStack() {}; + ~TNodeSetStack() { clear(); } + + // This should only be called after a pushSet. + // Returns NULL if the top set is empty. + TParentNodeSet* getTopSet() const + { + ASSERT(!nodeSets.empty()); + TParentNodeSet* topSet = nodeSets.top(); + return !topSet->empty() ? topSet : NULL; + } + + void pushSet() { nodeSets.push(new TParentNodeSet()); } + void popSet() + { + ASSERT(!nodeSets.empty()); + delete nodeSets.top(); + nodeSets.pop(); + } + + // Pops the top set and adds its contents to the new top set. + // This should only be called after a pushSet. + // If there is no set below the top set, the top set is just deleted. + void popSetIntoNext() + { + ASSERT(!nodeSets.empty()); + TParentNodeSet* oldTopSet = nodeSets.top(); + nodeSets.pop(); + + if (!nodeSets.empty()) { + TParentNodeSet* newTopSet = nodeSets.top(); + newTopSet->insert(oldTopSet->begin(), oldTopSet->end()); + } + + delete oldTopSet; + } + + // Does nothing if there is no top set. + // This can be called when there is no top set if we are visiting + // symbols that are not under an assignment or condition. + // We don't need to track those symbols. + void insertIntoTopSet(TGraphParentNode* node) + { + if (nodeSets.empty()) + return; + + nodeSets.top()->insert(node); + } + + void clear() + { + while (!nodeSets.empty()) + popSet(); + } + + private: + typedef std::stack TParentNodeSetStack; + + TParentNodeSetStack nodeSets; + }; + + // + // An instance of this class pushes a new node set when instantiated. + // When the instance goes out of scope, it and pops the node set. + // + class TNodeSetMaintainer { + public: + TNodeSetMaintainer(TDependencyGraphBuilder* factory) + : sets(factory->mNodeSets) { sets.pushSet(); } + ~TNodeSetMaintainer() { sets.popSet(); } + protected: + TNodeSetStack& sets; + }; + + // + // An instance of this class pushes a new node set when instantiated. + // When the instance goes out of scope, it and pops the top node set and adds its contents to + // the new top node set. + // + class TNodeSetPropagatingMaintainer { + public: + TNodeSetPropagatingMaintainer(TDependencyGraphBuilder* factory) + : sets(factory->mNodeSets) { sets.pushSet(); } + ~TNodeSetPropagatingMaintainer() { sets.popSetIntoNext(); } + protected: + TNodeSetStack& sets; + }; + + // + // An instance of this class keeps track of the leftmost symbol while we're exploring an + // assignment. + // It will push the placeholder symbol kLeftSubtree when instantiated under a left subtree, + // and kRightSubtree under a right subtree. + // When it goes out of scope, it will pop the leftmost symbol at the top of the scope. + // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with a real symbol. + // kRightSubtree will never be replaced by a real symbol because we are tracking the leftmost + // symbol. + // + class TLeftmostSymbolMaintainer { + public: + TLeftmostSymbolMaintainer(TDependencyGraphBuilder* factory, TGraphSymbol& subtree) + : leftmostSymbols(factory->mLeftmostSymbols) + { + needsPlaceholderSymbol = leftmostSymbols.empty() || leftmostSymbols.top() != &subtree; + if (needsPlaceholderSymbol) + leftmostSymbols.push(&subtree); + } + + ~TLeftmostSymbolMaintainer() + { + if (needsPlaceholderSymbol) + leftmostSymbols.pop(); + } + + protected: + TSymbolStack& leftmostSymbols; + bool needsPlaceholderSymbol; + }; + + TDependencyGraphBuilder(TDependencyGraph* graph) + : TIntermTraverser(true, false, false) + , mLeftSubtree(NULL) + , mRightSubtree(NULL) + , mGraph(graph) {} + void build(TIntermNode* intermNode) { intermNode->traverse(this); } + + void connectMultipleNodesToSingleNode(TParentNodeSet* nodes, TGraphNode* node) const; + + void visitAssignment(TIntermBinary*); + void visitLogicalOp(TIntermBinary*); + void visitBinaryChildren(TIntermBinary*); + void visitFunctionDefinition(TIntermAggregate*); + void visitFunctionCall(TIntermAggregate* intermFunctionCall); + void visitAggregateChildren(TIntermAggregate*); + + TGraphSymbol mLeftSubtree; + TGraphSymbol mRightSubtree; + + TDependencyGraph* mGraph; + TNodeSetStack mNodeSets; + TSymbolStack mLeftmostSymbols; +}; + +#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp new file mode 100644 index 0000000000..6fc489e7b6 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp @@ -0,0 +1,65 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/depgraph/DependencyGraphOutput.h" + +void TDependencyGraphOutput::outputIndentation() +{ + for (int i = 0; i < getDepth(); ++i) + mSink << " "; +} + +void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter) +{ + outputIndentation(); + mSink << "argument " << parameter->getArgumentNumber() << " of call to " + << parameter->getIntermFunctionCall()->getName() << "\n"; +} + +void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall) +{ + outputIndentation(); + mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n"; +} + +void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol) +{ + outputIndentation(); + mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: " + << symbol->getIntermSymbol()->getId() << ")\n"; +} + +void TDependencyGraphOutput::visitSelection(TGraphSelection* selection) +{ + outputIndentation(); + mSink << "selection\n"; +} + +void TDependencyGraphOutput::visitLoop(TGraphLoop* loop) +{ + outputIndentation(); + mSink << "loop condition\n"; +} + +void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp) +{ + outputIndentation(); + mSink << "logical " << logicalOp->getOpString() << "\n"; +} + +void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph) +{ + mSink << "\n"; + + for (TGraphNodeVector::const_iterator iter = graph.begin(); iter != graph.end(); ++iter) + { + TGraphNode* symbol = *iter; + mSink << "--- Dependency graph spanning tree ---\n"; + clearVisited(); + symbol->traverse(this); + mSink << "\n"; + } +} diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h new file mode 100644 index 0000000000..01447da987 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h @@ -0,0 +1,30 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H +#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H + +#include "compiler/depgraph/DependencyGraph.h" +#include "compiler/InfoSink.h" + +class TDependencyGraphOutput : public TDependencyGraphTraverser { +public: + TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {} + virtual void visitSymbol(TGraphSymbol* symbol); + virtual void visitArgument(TGraphArgument* parameter); + virtual void visitFunctionCall(TGraphFunctionCall* functionCall); + virtual void visitSelection(TGraphSelection* selection); + virtual void visitLoop(TGraphLoop* loop); + virtual void visitLogicalOp(TGraphLogicalOp* logicalOp); + + void outputAllSpanningTrees(TDependencyGraph& graph); +private: + void outputIndentation(); + + TInfoSinkBase& mSink; +}; + +#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp new file mode 100644 index 0000000000..b158575cec --- /dev/null +++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/depgraph/DependencyGraph.h" + +// These methods do a breadth-first traversal through the graph and mark visited nodes. + +void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->markVisited(this); +} + +void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser) +{ + TGraphNode::traverse(graphTraverser); + + graphTraverser->incrementDepth(); + + // Visit the parent node's children. + for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin(); + iter != mDependentNodes.end(); + ++iter) + { + TGraphNode* node = *iter; + if (!graphTraverser->isVisited(node)) + node->traverse(graphTraverser); + } + + graphTraverser->decrementDepth(); +} + +void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitArgument(this); + TGraphParentNode::traverse(graphTraverser); +} + +void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitFunctionCall(this); + TGraphParentNode::traverse(graphTraverser); +} + +void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitSymbol(this); + TGraphParentNode::traverse(graphTraverser); +} + +void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitSelection(this); + TGraphNode::traverse(graphTraverser); +} + +void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitLoop(this); + TGraphNode::traverse(graphTraverser); +} + +void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitLogicalOp(this); + TGraphNode::traverse(graphTraverser); +} diff --git a/src/3rdparty/angle/src/compiler/glslang.h b/src/3rdparty/angle/src/compiler/glslang.h new file mode 100644 index 0000000000..3a45daf3a4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/glslang.h @@ -0,0 +1,16 @@ +// +// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +struct TParseContext; +extern int glslang_initialize(TParseContext* context); +extern int glslang_finalize(TParseContext* context); + +extern int glslang_scan(int count, + const char* const string[], + const int length[], + TParseContext* context); +extern int glslang_parse(TParseContext* context); + diff --git a/src/3rdparty/angle/src/compiler/glslang.l b/src/3rdparty/angle/src/compiler/glslang.l new file mode 100644 index 0000000000..e0483e2ea9 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/glslang.l @@ -0,0 +1,511 @@ +/* +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +This file contains the Lex specification for GLSL ES. +Based on ANSI C grammar, Lex specification: +http://www.lysator.liu.se/c/ANSI-C-grammar-l.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). +*/ + +%top{ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif +} + +%{ +#include "compiler/glslang.h" +#include "compiler/ParseHelper.h" +#include "compiler/preprocessor/new/Token.h" +#include "compiler/util.h" +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +#define YY_USER_ACTION yylval->lex.line = yylineno; +#define YY_INPUT(buf, result, max_size) \ + result = string_input(buf, max_size, yyscanner); + +static int string_input(char* buf, int max_size, yyscan_t yyscanner); +static int check_type(yyscan_t yyscanner); +static int reserved_word(yyscan_t yyscanner); +%} + +%option noyywrap nounput never-interactive +%option yylineno reentrant bison-bridge +%option stack +%option extra-type="TParseContext*" +%x COMMENT FIELDS + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +O [0-7] + +%% + +%{ + TParseContext* context = yyextra; +%} + + /* Single-line comments */ +"//"[^\n]* ; + + /* Multi-line comments */ +"/*" { yy_push_state(COMMENT, yyscanner); } +. | +\n ; +"*/" { yy_pop_state(yyscanner); } + +"invariant" { return(INVARIANT); } +"highp" { return(HIGH_PRECISION); } +"mediump" { return(MEDIUM_PRECISION); } +"lowp" { return(LOW_PRECISION); } +"precision" { return(PRECISION); } + +"attribute" { return(ATTRIBUTE); } +"const" { return(CONST_QUAL); } +"uniform" { return(UNIFORM); } +"varying" { return(VARYING); } + +"break" { return(BREAK); } +"continue" { return(CONTINUE); } +"do" { return(DO); } +"for" { return(FOR); } +"while" { return(WHILE); } + +"if" { return(IF); } +"else" { return(ELSE); } + +"in" { return(IN_QUAL); } +"out" { return(OUT_QUAL); } +"inout" { return(INOUT_QUAL); } + +"float" { context->lexAfterType = true; return(FLOAT_TYPE); } +"int" { context->lexAfterType = true; return(INT_TYPE); } +"void" { context->lexAfterType = true; return(VOID_TYPE); } +"bool" { context->lexAfterType = true; return(BOOL_TYPE); } +"true" { yylval->lex.b = true; return(BOOLCONSTANT); } +"false" { yylval->lex.b = false; return(BOOLCONSTANT); } + +"discard" { return(DISCARD); } +"return" { return(RETURN); } + +"mat2" { context->lexAfterType = true; return(MATRIX2); } +"mat3" { context->lexAfterType = true; return(MATRIX3); } +"mat4" { context->lexAfterType = true; return(MATRIX4); } + +"vec2" { context->lexAfterType = true; return (VEC2); } +"vec3" { context->lexAfterType = true; return (VEC3); } +"vec4" { context->lexAfterType = true; return (VEC4); } +"ivec2" { context->lexAfterType = true; return (IVEC2); } +"ivec3" { context->lexAfterType = true; return (IVEC3); } +"ivec4" { context->lexAfterType = true; return (IVEC4); } +"bvec2" { context->lexAfterType = true; return (BVEC2); } +"bvec3" { context->lexAfterType = true; return (BVEC3); } +"bvec4" { context->lexAfterType = true; return (BVEC4); } + +"sampler2D" { context->lexAfterType = true; return SAMPLER2D; } +"samplerCube" { context->lexAfterType = true; return SAMPLERCUBE; } +"samplerExternalOES" { context->lexAfterType = true; return SAMPLER_EXTERNAL_OES; } +"sampler2DRect" { context->lexAfterType = true; return SAMPLER2DRECT; } + +"struct" { context->lexAfterType = true; return(STRUCT); } + +"asm" { return reserved_word(yyscanner); } + +"class" { return reserved_word(yyscanner); } +"union" { return reserved_word(yyscanner); } +"enum" { return reserved_word(yyscanner); } +"typedef" { return reserved_word(yyscanner); } +"template" { return reserved_word(yyscanner); } +"this" { return reserved_word(yyscanner); } +"packed" { return reserved_word(yyscanner); } + +"goto" { return reserved_word(yyscanner); } +"switch" { return reserved_word(yyscanner); } +"default" { return reserved_word(yyscanner); } + +"inline" { return reserved_word(yyscanner); } +"noinline" { return reserved_word(yyscanner); } +"volatile" { return reserved_word(yyscanner); } +"public" { return reserved_word(yyscanner); } +"static" { return reserved_word(yyscanner); } +"extern" { return reserved_word(yyscanner); } +"external" { return reserved_word(yyscanner); } +"interface" { return reserved_word(yyscanner); } +"flat" { return reserved_word(yyscanner); } + +"long" { return reserved_word(yyscanner); } +"short" { return reserved_word(yyscanner); } +"double" { return reserved_word(yyscanner); } +"half" { return reserved_word(yyscanner); } +"fixed" { return reserved_word(yyscanner); } +"unsigned" { return reserved_word(yyscanner); } +"superp" { return reserved_word(yyscanner); } + +"input" { return reserved_word(yyscanner); } +"output" { return reserved_word(yyscanner); } + +"hvec2" { return reserved_word(yyscanner); } +"hvec3" { return reserved_word(yyscanner); } +"hvec4" { return reserved_word(yyscanner); } +"dvec2" { return reserved_word(yyscanner); } +"dvec3" { return reserved_word(yyscanner); } +"dvec4" { return reserved_word(yyscanner); } +"fvec2" { return reserved_word(yyscanner); } +"fvec3" { return reserved_word(yyscanner); } +"fvec4" { return reserved_word(yyscanner); } + +"sampler1D" { return reserved_word(yyscanner); } +"sampler3D" { return reserved_word(yyscanner); } + +"sampler1DShadow" { return reserved_word(yyscanner); } +"sampler2DShadow" { return reserved_word(yyscanner); } + +"sampler3DRect" { return reserved_word(yyscanner); } +"sampler2DRectShadow" { return reserved_word(yyscanner); } + +"sizeof" { return reserved_word(yyscanner); } +"cast" { return reserved_word(yyscanner); } + +"namespace" { return reserved_word(yyscanner); } +"using" { return reserved_word(yyscanner); } + +{L}({L}|{D})* { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); +} + +0[xX]{H}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{O}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{D}+ { context->error(yylineno, "Invalid Octal number.", yytext); context->recover(); return 0;} +{D}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } + +{D}+{E} { yylval->lex.f = static_cast(atof_dot(yytext)); return(FLOATCONSTANT); } +{D}+"."{D}*({E})? { yylval->lex.f = static_cast(atof_dot(yytext)); return(FLOATCONSTANT); } +"."{D}+({E})? { yylval->lex.f = static_cast(atof_dot(yytext)); return(FLOATCONSTANT); } + +"+=" { return(ADD_ASSIGN); } +"-=" { return(SUB_ASSIGN); } +"*=" { return(MUL_ASSIGN); } +"/=" { return(DIV_ASSIGN); } +"%=" { return(MOD_ASSIGN); } +"<<=" { return(LEFT_ASSIGN); } +">>=" { return(RIGHT_ASSIGN); } +"&=" { return(AND_ASSIGN); } +"^=" { return(XOR_ASSIGN); } +"|=" { return(OR_ASSIGN); } + +"++" { return(INC_OP); } +"--" { return(DEC_OP); } +"&&" { return(AND_OP); } +"||" { return(OR_OP); } +"^^" { return(XOR_OP); } +"<=" { return(LE_OP); } +">=" { return(GE_OP); } +"==" { return(EQ_OP); } +"!=" { return(NE_OP); } +"<<" { return(LEFT_OP); } +">>" { return(RIGHT_OP); } +";" { context->lexAfterType = false; return(SEMICOLON); } +("{"|"<%") { context->lexAfterType = false; return(LEFT_BRACE); } +("}"|"%>") { return(RIGHT_BRACE); } +"," { if (context->inTypeParen) context->lexAfterType = false; return(COMMA); } +":" { return(COLON); } +"=" { context->lexAfterType = false; return(EQUAL); } +"(" { context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); } +")" { context->inTypeParen = false; return(RIGHT_PAREN); } +("["|"<:") { return(LEFT_BRACKET); } +("]"|":>") { return(RIGHT_BRACKET); } +"." { BEGIN(FIELDS); return(DOT); } +"!" { return(BANG); } +"-" { return(DASH); } +"~" { return(TILDE); } +"+" { return(PLUS); } +"*" { return(STAR); } +"/" { return(SLASH); } +"%" { return(PERCENT); } +"<" { return(LEFT_ANGLE); } +">" { return(RIGHT_ANGLE); } +"|" { return(VERTICAL_BAR); } +"^" { return(CARET); } +"&" { return(AMPERSAND); } +"?" { return(QUESTION); } + +{L}({L}|{D})* { + BEGIN(INITIAL); + yylval->lex.string = NewPoolTString(yytext); + return FIELD_SELECTION; +} +[ \t\v\f\r] {} + +[ \t\v\n\f\r] { } +<*><> { context->AfterEOF = true; yyterminate(); } +<*>. { context->warning(yylineno, "Unknown char", yytext, ""); return 0; } + +%% + +// Old preprocessor interface. +extern "C" { +#include "compiler/preprocessor/preprocess.h" + +extern int InitPreprocessor(); +extern int FinalizePreprocessor(); +extern void PredefineIntMacro(const char *name, int value); + +#define SETUP_CONTEXT(pp) \ + TParseContext* context = (TParseContext*) pp->pC; \ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + +// Preprocessor callbacks. +void CPPDebugLogMsg(const char *msg) +{ + SETUP_CONTEXT(cpp); + context->trace(msg); +} + +void CPPWarningToInfoLog(const char *msg) +{ + SETUP_CONTEXT(cpp); + context->warning(yylineno, msg, ""); +} + +void CPPShInfoLogMsg(const char *msg) +{ + SETUP_CONTEXT(cpp); + context->error(yylineno, msg, ""); + context->recover(); +} + +void CPPErrorToInfoLog(const char *msg) +{ + SETUP_CONTEXT(cpp); + context->error(yylineno, msg, ""); + context->recover(); +} + +void SetLineNumber(int line) +{ + SETUP_CONTEXT(cpp); + int string = 0; + DecodeSourceLoc(yylineno, &string, NULL); + yylineno = EncodeSourceLoc(string, line); +} + +void SetStringNumber(int string) +{ + SETUP_CONTEXT(cpp); + int line = 0; + DecodeSourceLoc(yylineno, NULL, &line); + yylineno = EncodeSourceLoc(string, line); +} + +int GetStringNumber() +{ + SETUP_CONTEXT(cpp); + int string = 0; + DecodeSourceLoc(yylineno, &string, NULL); + return string; +} + +int GetLineNumber() +{ + SETUP_CONTEXT(cpp); + int line = 0; + DecodeSourceLoc(yylineno, NULL, &line); + return line; +} + +void IncLineNumber() +{ + SETUP_CONTEXT(cpp); + int string = 0, line = 0; + DecodeSourceLoc(yylineno, &string, &line); + yylineno = EncodeSourceLoc(string, ++line); +} + +void DecLineNumber() +{ + SETUP_CONTEXT(cpp); + int string = 0, line = 0; + DecodeSourceLoc(yylineno, &string, &line); + yylineno = EncodeSourceLoc(string, --line); +} + +void HandlePragma(const char **tokens, int numTokens) +{ + SETUP_CONTEXT(cpp); + + if (numTokens != 4) return; + if (strcmp(tokens[1], "(") != 0) return; + if (strcmp(tokens[3], ")") != 0) return; + + context->handlePragmaDirective(yylineno, tokens[0], tokens[2]); +} + +void StoreStr(const char *string) +{ + SETUP_CONTEXT(cpp); + TString strSrc; + strSrc = TString(string); + + context->HashErrMsg = context->HashErrMsg + " " + strSrc; +} + +const char* GetStrfromTStr(void) +{ + SETUP_CONTEXT(cpp); + cpp->ErrMsg = context->HashErrMsg.c_str(); + return cpp->ErrMsg; +} + +void ResetTString(void) +{ + SETUP_CONTEXT(cpp); + context->HashErrMsg = ""; +} + +void updateExtensionBehavior(const char* extName, const char* behavior) +{ + SETUP_CONTEXT(cpp); + context->handleExtensionDirective(yylineno, extName, behavior); +} +} // extern "C" + +int string_input(char* buf, int max_size, yyscan_t yyscanner) { + int len = 0; + +#if ANGLE_USE_NEW_PREPROCESSOR + pp::Token token; + yyget_extra(yyscanner)->preprocessor.lex(&token); + len = token.type == pp::Token::LAST ? 0 : token.text.size(); + if ((len > 0) && (len < max_size)) + memcpy(buf, token.text.c_str(), len); + yyset_lineno(EncodeSourceLoc(token.location.file, token.location.line), yyscanner); +#else + len = yylex_CPP(buf, max_size); +#endif // ANGLE_USE_NEW_PREPROCESSOR + + if (len >= max_size) + YY_FATAL_ERROR("Input buffer overflow"); + else if (len > 0) + buf[len++] = ' '; + return len; +} + +int check_type(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + int token = IDENTIFIER; + TSymbol* symbol = yyextra->symbolTable.find(yytext); + if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) { + TVariable* variable = static_cast(symbol); + if (variable->isUserType()) { + yyextra->lexAfterType = true; + token = TYPE_NAME; + } + } + yylval->lex.symbol = symbol; + return token; +} + +int reserved_word(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + yyextra->error(yylineno, "Illegal use of reserved word", yytext, ""); + yyextra->recover(); + return 0; +} + +void yyerror(TParseContext* context, const char* reason) { + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + + if (context->AfterEOF) { + context->error(yylineno, reason, "unexpected EOF"); + } else { + context->error(yylineno, reason, yytext); + } + context->recover(); +} + +int glslang_initialize(TParseContext* context) { + yyscan_t scanner = NULL; + if (yylex_init_extra(context, &scanner)) + return 1; + + context->scanner = scanner; + return 0; +} + +int glslang_finalize(TParseContext* context) { + yyscan_t scanner = context->scanner; + if (scanner == NULL) return 0; + + context->scanner = NULL; + yylex_destroy(scanner); + +#if !ANGLE_USE_NEW_PREPROCESSOR + FinalizePreprocessor(); +#endif + return 0; +} + +int glslang_scan(int count, const char* const string[], const int length[], + TParseContext* context) { + yyrestart(NULL, context->scanner); + yyset_lineno(EncodeSourceLoc(0, 1), context->scanner); + context->AfterEOF = false; + + // Initialize preprocessor. +#if ANGLE_USE_NEW_PREPROCESSOR + if (!context->preprocessor.init(count, string, length)) + return 1; +#else + if (InitPreprocessor()) + return 1; + cpp->pC = context; + cpp->pastFirstStatement = 0; + if (InitScannerInput(cpp, count, string, length)) + return 1; +#endif // ANGLE_USE_NEW_PREPROCESSOR + + // Define extension macros. + const TExtensionBehavior& extBehavior = context->extensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { +#if ANGLE_USE_NEW_PREPROCESSOR + context->preprocessor.predefineMacro(iter->first.c_str(), 1); +#else + PredefineIntMacro(iter->first.c_str(), 1); +#endif + } + return 0; +} + diff --git a/src/3rdparty/angle/src/compiler/glslang.y b/src/3rdparty/angle/src/compiler/glslang.y new file mode 100644 index 0000000000..39c9cee26e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/glslang.y @@ -0,0 +1,2142 @@ +/* +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +This file contains the Yacc grammar for GLSL ES. +Based on ANSI C Yacc grammar: +http://www.lysator.liu.se/c/ANSI-C-grammar-y.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). +*/ + +%{ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif + +#include "compiler/SymbolTable.h" +#include "compiler/ParseHelper.h" +#include "GLSLANG/ShaderLang.h" + +#define YYLEX_PARAM context->scanner +%} + +%expect 1 /* One shift reduce conflict because of if | else */ +%pure-parser +%parse-param {TParseContext* context} + +%union { + struct { + TSourceLoc line; + union { + TString *string; + float f; + int i; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TSourceLoc line; + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TQualifier qualifier; + TFunction* function; + TParameter param; + TTypeLine typeLine; + TTypeList* typeList; + }; + } interm; +} + +%{ +extern int yylex(YYSTYPE* yylval_param, void* yyscanner); +extern void yyerror(TParseContext* context, const char* reason); + +#define FRAG_VERT_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER && \ + context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex/fragment shaders only ", S); \ + context->recover(); \ + } \ +} + +#define VERTEX_ONLY(S, L) { \ + if (context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex shaders only ", S); \ + context->recover(); \ + } \ +} + +#define FRAG_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER) { \ + context->error(L, " supported in fragment shaders only ", S); \ + context->recover(); \ + } \ +} +%} + +%token INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION +%token ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE +%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN +%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 +%token MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING +%token STRUCT VOID_TYPE WHILE +%token SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT + +%token IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT +%token FIELD_SELECTION +%token LEFT_OP RIGHT_OP +%token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN +%token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN +%token SUB_ASSIGN + +%token LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT +%token COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT +%token LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION + +%type assignment_operator unary_operator +%type variable_identifier primary_expression postfix_expression +%type expression integer_expression assignment_expression +%type unary_expression multiplicative_expression additive_expression +%type relational_expression equality_expression +%type conditional_expression constant_expression +%type logical_or_expression logical_xor_expression logical_and_expression +%type shift_expression and_expression exclusive_or_expression inclusive_or_expression +%type function_call initializer condition conditionopt + +%type translation_unit function_definition +%type statement simple_statement +%type statement_list compound_statement +%type declaration_statement selection_statement expression_statement +%type declaration external_declaration +%type for_init_statement compound_statement_no_new_scope +%type selection_rest_statement for_rest_statement +%type iteration_statement jump_statement statement_no_new_scope statement_with_scope +%type single_declaration init_declarator_list + +%type parameter_declaration parameter_declarator parameter_type_specifier +%type parameter_qualifier + +%type precision_qualifier +%type type_qualifier fully_specified_type type_specifier +%type type_specifier_no_prec type_specifier_nonarray +%type struct_specifier +%type struct_declarator +%type struct_declarator_list struct_declaration struct_declaration_list +%type function_header function_declarator function_identifier +%type function_header_with_parameters function_call_header +%type function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype +%type function_call_or_method + +%start translation_unit +%% + +variable_identifier + : IDENTIFIER { + // The symbol table search was done in the lexical phase + const TSymbol* symbol = $1.symbol; + const TVariable* variable; + if (symbol == 0) { + context->error($1.line, "undeclared identifier", $1.string->c_str()); + context->recover(); + TType type(EbtFloat, EbpUndefined); + TVariable* fakeVariable = new TVariable($1.string, type); + context->symbolTable.insert(*fakeVariable); + variable = fakeVariable; + } else { + // This identifier can only be a variable type symbol + if (! symbol->isVariable()) { + context->error($1.line, "variable expected", $1.string->c_str()); + context->recover(); + } + variable = static_cast(symbol); + } + + // don't delete $1.string, it's used by error recovery, and the pool + // pop will reclaim the memory + + if (variable->getType().getQualifier() == EvqConst ) { + ConstantUnion* constArray = variable->getConstPointer(); + TType t(variable->getType()); + $$ = context->intermediate.addConstantUnion(constArray, t, $1.line); + } else + $$ = context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), $1.line); + } + ; + +primary_expression + : variable_identifier { + $$ = $1; + } + | INTCONSTANT { + // + // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders, + // check for overflow for constants + // + if (abs($1.i) >= (1 << 16)) { + context->error($1.line, " integer constant overflow", ""); + context->recover(); + } + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst($1.i); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $1.line); + } + | FLOATCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst($1.f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line); + } + | BOOLCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst($1.b); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $1.line); + } + | LEFT_PAREN expression RIGHT_PAREN { + $$ = $2; + } + ; + +postfix_expression + : primary_expression { + $$ = $1; + } + | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET { + if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) { + if ($1->getAsSymbolNode()) + context->error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str()); + else + context->error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression"); + context->recover(); + } + if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) { + if ($1->isArray()) { // constant folding for arrays + $$ = context->addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line); + } else if ($1->isVector()) { // constant folding for vectors + TVectorFields fields; + fields.num = 1; + fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array + $$ = context->addConstVectorNode(fields, $1, $2.line); + } else if ($1->isMatrix()) { // constant folding for matrices + $$ = context->addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line); + } + } else { + if ($3->getQualifier() == EvqConst) { + if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !$1->isArray() ) { + std::stringstream extraInfoStream; + extraInfoStream << "field selection out of range '" << $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'"; + std::string extraInfo = extraInfoStream.str(); + context->error($2.line, "", "[", extraInfo.c_str()); + context->recover(); + } else { + if ($1->isArray()) { + if ($1->getType().getArraySize() == 0) { + if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) { + if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line)) + context->recover(); + } else { + if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line)) + context->recover(); + } + } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) { + std::stringstream extraInfoStream; + extraInfoStream << "array index out of range '" << $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'"; + std::string extraInfo = extraInfoStream.str(); + context->error($2.line, "", "[", extraInfo.c_str()); + context->recover(); + } + } + $$ = context->intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line); + } + } else { + if ($1->isArray() && $1->getType().getArraySize() == 0) { + context->error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable"); + context->recover(); + } + + $$ = context->intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line); + } + } + if ($$ == 0) { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), $2.line); + } else if ($1->isArray()) { + if ($1->getType().getStruct()) + $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName())); + else + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize(), $1->isMatrix())); + + if ($1->getType().getQualifier() == EvqConst) + $$->getTypePointer()->setQualifier(EvqConst); + } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, $1->getNominalSize())); + else if ($1->isMatrix()) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize())); + else if ($1->isVector() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst)); + else if ($1->isVector()) + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary)); + else + $$->setType($1->getType()); + } + | function_call { + $$ = $1; + } + | postfix_expression DOT FIELD_SELECTION { + if ($1->isArray()) { + context->error($3.line, "cannot apply dot operator to an array", "."); + context->recover(); + } + + if ($1->isVector()) { + TVectorFields fields; + if (! context->parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.num = 1; + fields.offsets[0] = 0; + context->recover(); + } + + if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields + $$ = context->addConstVectorNode(fields, $1, $3.line); + if ($$ == 0) { + context->recover(); + $$ = $1; + } + else + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, (int) (*$3.string).size())); + } else { + TString vectorString = *$3.string; + TIntermTyped* index = context->intermediate.addSwizzle(fields, $3.line); + $$ = context->intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, (int) vectorString.size())); + } + } else if ($1->isMatrix()) { + TMatrixFields fields; + if (! context->parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = 0; + fields.col = 0; + context->recover(); + } + + if (fields.wholeRow || fields.wholeCol) { + context->error($2.line, " non-scalar fields not implemented yet", "."); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(0); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line); + $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), $1->getPrecision(),EvqTemporary, $1->getNominalSize())); + } else { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line); + $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), $1->getPrecision())); + } + } else if ($1->getBasicType() == EbtStruct) { + bool fieldFound = false; + const TTypeList* fields = $1->getType().getStruct(); + if (fields == 0) { + context->error($2.line, "structure has no fields", "Internal Error"); + context->recover(); + $$ = $1; + } else { + unsigned int i; + for (i = 0; i < fields->size(); ++i) { + if ((*fields)[i].type->getFieldName() == *$3.string) { + fieldFound = true; + break; + } + } + if (fieldFound) { + if ($1->getType().getQualifier() == EvqConst) { + $$ = context->addConstStruct(*$3.string, $1, $2.line); + if ($$ == 0) { + context->recover(); + $$ = $1; + } + else { + $$->setType(*(*fields)[i].type); + // change the qualifier of the return type, not of the structure field + // as the structure definition is shared between various structures. + $$->getTypePointer()->setQualifier(EvqConst); + } + } else { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *(*fields)[i].type, $3.line); + $$ = context->intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line); + $$->setType(*(*fields)[i].type); + } + } else { + context->error($2.line, " no such field in structure", $3.string->c_str()); + context->recover(); + $$ = $1; + } + } + } else { + context->error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str()); + context->recover(); + $$ = $1; + } + // don't delete $3.string, it's from the pool + } + | postfix_expression INC_OP { + if (context->lValueErrorCheck($2.line, "++", $1)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($2.line, "++", $1->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | postfix_expression DEC_OP { + if (context->lValueErrorCheck($2.line, "--", $1)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($2.line, "--", $1->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +integer_expression + : expression { + if (context->integerErrorCheck($1, "[]")) + context->recover(); + $$ = $1; + } + ; + +function_call + : function_call_or_method { + TFunction* fnCall = $1.function; + TOperator op = fnCall->getBuiltInOp(); + + if (op != EOpNull) + { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid, EbpUndefined); // use this to get the type back + if (context->constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) { + $$ = 0; + } else { + // + // It's a constructor, of type 'type'. + // + $$ = context->addConstructor($1.intermNode, &type, op, fnCall, $1.line); + } + + if ($$ == 0) { + context->recover(); + $$ = context->intermediate.setAggregateOperator(0, op, $1.line); + } + $$->setType(type); + } else { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = context->findFunction($1.line, fnCall, &builtIn); + if (fnCandidate) { + // + // A declared function. + // + if (builtIn && !fnCandidate->getExtension().empty() && + context->extensionErrorCheck($1.line, fnCandidate->getExtension())) { + context->recover(); + } + op = fnCandidate->getBuiltInOp(); + if (builtIn && op != EOpNull) { + // + // A function call mapped to a built-in operation. + // + if (fnCandidate->getParamCount() == 1) { + // + // Treat it like a built-in unary operator. + // + $$ = context->intermediate.addUnaryMath(op, $1.intermNode, 0, context->symbolTable); + if ($$ == 0) { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " << static_cast($1.intermNode)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + YYERROR; + } + } else { + $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, $1.line); + } + } else { + // This is a real function call + + $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, $1.line); + $$->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if (!builtIn) + $$->getAsAggregate()->setUserDefined(); + $$->getAsAggregate()->setName(fnCandidate->getMangledName()); + + TQualifier qual; + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + qual = fnCandidate->getParam(i).type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) { + if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) { + context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); + context->recover(); + } + } + } + } + $$->setType(fnCandidate->getReturnType()); + } else { + // error message was put out by PaFindFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line); + context->recover(); + } + } + delete fnCall; + } + ; + +function_call_or_method + : function_call_generic { + $$ = $1; + } + | postfix_expression DOT function_call_generic { + context->error($3.line, "methods are not supported", ""); + context->recover(); + $$ = $3; + } + ; + +function_call_generic + : function_call_header_with_parameters RIGHT_PAREN { + $$ = $1; + $$.line = $2.line; + } + | function_call_header_no_parameters RIGHT_PAREN { + $$ = $1; + $$.line = $2.line; + } + ; + +function_call_header_no_parameters + : function_call_header VOID_TYPE { + $$.function = $1; + $$.intermNode = 0; + } + | function_call_header { + $$.function = $1; + $$.intermNode = 0; + } + ; + +function_call_header_with_parameters + : function_call_header assignment_expression { + TParameter param = { 0, new TType($2->getType()) }; + $1->addParameter(param); + $$.function = $1; + $$.intermNode = $2; + } + | function_call_header_with_parameters COMMA assignment_expression { + TParameter param = { 0, new TType($3->getType()) }; + $1.function->addParameter(param); + $$.function = $1.function; + $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, $2.line); + } + ; + +function_call_header + : function_identifier LEFT_PAREN { + $$ = $1; + } + ; + +// Grammar Note: Constructors look like functions, but are recognized as types. + +function_identifier + : type_specifier_nonarray { + // + // Constructor + // + TOperator op = EOpNull; + if ($1.userDef) { + op = EOpConstructStruct; + } else { + switch ($1.type) { + case EbtFloat: + if ($1.matrix) { + switch($1.size) { + case 2: op = EOpConstructMat2; break; + case 3: op = EOpConstructMat3; break; + case 4: op = EOpConstructMat4; break; + } + } else { + switch($1.size) { + case 1: op = EOpConstructFloat; break; + case 2: op = EOpConstructVec2; break; + case 3: op = EOpConstructVec3; break; + case 4: op = EOpConstructVec4; break; + } + } + break; + case EbtInt: + switch($1.size) { + case 1: op = EOpConstructInt; break; + case 2: FRAG_VERT_ONLY("ivec2", $1.line); op = EOpConstructIVec2; break; + case 3: FRAG_VERT_ONLY("ivec3", $1.line); op = EOpConstructIVec3; break; + case 4: FRAG_VERT_ONLY("ivec4", $1.line); op = EOpConstructIVec4; break; + } + break; + case EbtBool: + switch($1.size) { + case 1: op = EOpConstructBool; break; + case 2: FRAG_VERT_ONLY("bvec2", $1.line); op = EOpConstructBVec2; break; + case 3: FRAG_VERT_ONLY("bvec3", $1.line); op = EOpConstructBVec3; break; + case 4: FRAG_VERT_ONLY("bvec4", $1.line); op = EOpConstructBVec4; break; + } + break; + default: break; + } + if (op == EOpNull) { + context->error($1.line, "cannot construct this type", getBasicString($1.type)); + context->recover(); + $1.type = EbtFloat; + op = EOpConstructFloat; + } + } + TString tempString; + TType type($1); + TFunction *function = new TFunction(&tempString, type, op); + $$ = function; + } + | IDENTIFIER { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + | FIELD_SELECTION { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + ; + +unary_expression + : postfix_expression { + $$ = $1; + } + | INC_OP unary_expression { + if (context->lValueErrorCheck($1.line, "++", $2)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($1.line, "++", $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } + | DEC_OP unary_expression { + if (context->lValueErrorCheck($1.line, "--", $2)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, context->symbolTable); + if ($$ == 0) { + context->unaryOpError($1.line, "--", $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } + | unary_operator unary_expression { + if ($1.op != EOpNull) { + $$ = context->intermediate.addUnaryMath($1.op, $2, $1.line, context->symbolTable); + if ($$ == 0) { + const char* errorOp = ""; + switch($1.op) { + case EOpNegative: errorOp = "-"; break; + case EOpLogicalNot: errorOp = "!"; break; + default: break; + } + context->unaryOpError($1.line, errorOp, $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } else + $$ = $2; + } + ; +// Grammar Note: No traditional style type casts. + +unary_operator + : PLUS { $$.line = $1.line; $$.op = EOpNull; } + | DASH { $$.line = $1.line; $$.op = EOpNegative; } + | BANG { $$.line = $1.line; $$.op = EOpLogicalNot; } + ; +// Grammar Note: No '*' or '&' unary ops. Pointers are not supported. + +multiplicative_expression + : unary_expression { $$ = $1; } + | multiplicative_expression STAR unary_expression { + FRAG_VERT_ONLY("*", $2.line); + $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | multiplicative_expression SLASH unary_expression { + FRAG_VERT_ONLY("/", $2.line); + $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +additive_expression + : multiplicative_expression { $$ = $1; } + | additive_expression PLUS multiplicative_expression { + $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | additive_expression DASH multiplicative_expression { + $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +shift_expression + : additive_expression { $$ = $1; } + ; + +relational_expression + : shift_expression { $$ = $1; } + | relational_expression LEFT_ANGLE shift_expression { + $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | relational_expression RIGHT_ANGLE shift_expression { + $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | relational_expression LE_OP shift_expression { + $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | relational_expression GE_OP shift_expression { + $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +equality_expression + : relational_expression { $$ = $1; } + | equality_expression EQ_OP relational_expression { + $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + | equality_expression NE_OP relational_expression { + $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +and_expression + : equality_expression { $$ = $1; } + ; + +exclusive_or_expression + : and_expression { $$ = $1; } + ; + +inclusive_or_expression + : exclusive_or_expression { $$ = $1; } + ; + +logical_and_expression + : inclusive_or_expression { $$ = $1; } + | logical_and_expression AND_OP inclusive_or_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +logical_xor_expression + : logical_and_expression { $$ = $1; } + | logical_xor_expression XOR_OP logical_and_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +logical_or_expression + : logical_xor_expression { $$ = $1; } + | logical_or_expression OR_OP logical_xor_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, context->symbolTable); + if ($$ == 0) { + context->binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line); + } + } + ; + +conditional_expression + : logical_or_expression { $$ = $1; } + | logical_or_expression QUESTION expression COLON assignment_expression { + if (context->boolErrorCheck($2.line, $1)) + context->recover(); + + $$ = context->intermediate.addSelection($1, $3, $5, $2.line); + if ($3->getType() != $5->getType()) + $$ = 0; + + if ($$ == 0) { + context->binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString()); + context->recover(); + $$ = $5; + } + } + ; + +assignment_expression + : conditional_expression { $$ = $1; } + | unary_expression assignment_operator assignment_expression { + if (context->lValueErrorCheck($2.line, "assign", $1)) + context->recover(); + $$ = context->intermediate.addAssign($2.op, $1, $3, $2.line); + if ($$ == 0) { + context->assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +assignment_operator + : EQUAL { $$.line = $1.line; $$.op = EOpAssign; } + | MUL_ASSIGN { FRAG_VERT_ONLY("*=", $1.line); $$.line = $1.line; $$.op = EOpMulAssign; } + | DIV_ASSIGN { FRAG_VERT_ONLY("/=", $1.line); $$.line = $1.line; $$.op = EOpDivAssign; } + | ADD_ASSIGN { $$.line = $1.line; $$.op = EOpAddAssign; } + | SUB_ASSIGN { $$.line = $1.line; $$.op = EOpSubAssign; } + ; + +expression + : assignment_expression { + $$ = $1; + } + | expression COMMA assignment_expression { + $$ = context->intermediate.addComma($1, $3, $2.line); + if ($$ == 0) { + context->binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $3; + } + } + ; + +constant_expression + : conditional_expression { + if (context->constErrorCheck($1)) + context->recover(); + $$ = $1; + } + ; + +declaration + : function_prototype SEMICOLON { + TFunction &function = *($1.function); + + TIntermAggregate *prototype = new TIntermAggregate; + prototype->setType(function.getReturnType()); + prototype->setName(function.getName()); + + for (int i = 0; i < function.getParamCount(); i++) + { + const TParameter ¶m = function.getParam(i); + if (param.name != 0) + { + TVariable *variable = new TVariable(param.name, *param.type); + + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), $1.line), $1.line); + } + else + { + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line); + } + } + + prototype->setOp(EOpPrototype); + $$ = prototype; + + context->symbolTable.pop(); + } + | init_declarator_list SEMICOLON { + if ($1.intermAggregate) + $1.intermAggregate->setOp(EOpDeclaration); + $$ = $1.intermAggregate; + } + | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { + context->symbolTable.setDefaultPrecision( $3.type, $2 ); + $$ = 0; + } + ; + +function_prototype + : function_declarator RIGHT_PAREN { + // + // Multiple declarations of the same function are allowed. + // + // If this is a definition, the definition production code will check for redefinitions + // (we don't know at this point if it's a definition or not). + // + // Redeclarations are allowed. But, return types and parameter qualifiers must match. + // + TFunction* prevDec = static_cast(context->symbolTable.find($1->getMangledName())); + if (prevDec) { + if (prevDec->getReturnType() != $1->getReturnType()) { + context->error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString()); + context->recover(); + } + for (int i = 0; i < prevDec->getParamCount(); ++i) { + if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) { + context->error($2.line, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString()); + context->recover(); + } + } + } + + // + // If this is a redeclaration, it could also be a definition, + // in which case, we want to use the variable names from this one, and not the one that's + // being redeclared. So, pass back up this declaration, not the one in the symbol table. + // + $$.function = $1; + $$.line = $2.line; + + // We're at the inner scope level of the function's arguments and body statement. + // Add the function prototype to the surrounding scope instead. + context->symbolTable.getOuterLevel()->insert(*$$.function); + } + ; + +function_declarator + : function_header { + $$ = $1; + } + | function_header_with_parameters { + $$ = $1; + } + ; + + +function_header_with_parameters + : function_header parameter_declaration { + // Add the parameter + $$ = $1; + if ($2.param.type->getBasicType() != EbtVoid) + $1->addParameter($2.param); + else + delete $2.param.type; + } + | function_header_with_parameters COMMA parameter_declaration { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ($3.param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + context->error($2.line, "cannot be an argument type except for '(void)'", "void"); + context->recover(); + delete $3.param.type; + } else { + // Add the parameter + $$ = $1; + $1->addParameter($3.param); + } + } + ; + +function_header + : fully_specified_type IDENTIFIER LEFT_PAREN { + if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) { + context->error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier)); + context->recover(); + } + // make sure a sampler is not involved as well... + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type($1); + function = new TFunction($2.string, type); + $$ = function; + + context->symbolTable.push(); + } + ; + +parameter_declarator + // Type + name + : type_specifier IDENTIFIER { + if ($1.type == EbtVoid) { + context->error($2.line, "illegal use of type 'void'", $2.string->c_str()); + context->recover(); + } + if (context->reservedErrorCheck($2.line, *$2.string)) + context->recover(); + TParameter param = {$2.string, new TType($1)}; + $$.line = $2.line; + $$.param = param; + } + | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + // Check that we can make an array out of this type + if (context->arrayTypeErrorCheck($3.line, $1)) + context->recover(); + + if (context->reservedErrorCheck($2.line, *$2.string)) + context->recover(); + + int size; + if (context->arraySizeErrorCheck($3.line, $4, size)) + context->recover(); + $1.setArray(true, size); + + TType* type = new TType($1); + TParameter param = { $2.string, type }; + $$.line = $2.line; + $$.param = param; + } + ; + +parameter_declaration + // + // The only parameter qualifier a parameter can have are + // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST. + // + + // + // Type + name + // + : type_qualifier parameter_qualifier parameter_declarator { + $$ = $3; + if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + context->recover(); + } + | parameter_qualifier parameter_declarator { + $$ = $2; + if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + context->recover(); + if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + context->recover(); + } + // + // Only type + // + | type_qualifier parameter_qualifier parameter_type_specifier { + $$ = $3; + if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + context->recover(); + } + | parameter_qualifier parameter_type_specifier { + $$ = $2; + if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + context->recover(); + if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + context->recover(); + } + ; + +parameter_qualifier + : /* empty */ { + $$ = EvqIn; + } + | IN_QUAL { + $$ = EvqIn; + } + | OUT_QUAL { + $$ = EvqOut; + } + | INOUT_QUAL { + $$ = EvqInOut; + } + ; + +parameter_type_specifier + : type_specifier { + TParameter param = { 0, new TType($1) }; + $$.param = param; + } + ; + +init_declarator_list + : single_declaration { + $$ = $1; + } + | init_declarator_list COMMA IDENTIFIER { + if ($1.type.type == EbtInvariant && !$3.symbol) + { + context->error($3.line, "undeclared identifier declared as invariant", $3.string->c_str()); + context->recover(); + } + + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), $3.line); + $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, $3.line); + + if (context->structQualifierErrorCheck($3.line, $$.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($3.line, *$3.string, $$.type, false)) + context->recover(); + + TVariable* variable = 0; + if (context->nonInitErrorCheck($3.line, *$3.string, $$.type, variable)) + context->recover(); + if (symbol && variable) + symbol->setId(variable->getUniqueId()); + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + if (context->structQualifierErrorCheck($3.line, $1.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true)) + context->recover(); + + $$ = $1; + + if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type)) + context->recover(); + else { + $1.type.setArray(true); + TVariable* variable; + if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + context->recover(); + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + if (context->structQualifierErrorCheck($3.line, $1.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true)) + context->recover(); + + $$ = $1; + + if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck($4.line, $5, size)) + context->recover(); + $1.type.setArray(true, size); + TVariable* variable = 0; + if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + context->recover(); + TType type = TType($1.type); + type.setArraySize(size); + $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, $3.line), $3.line); + } + } + | init_declarator_list COMMA IDENTIFIER EQUAL initializer { + if (context->structQualifierErrorCheck($3.line, $1.type)) + context->recover(); + + $$ = $1; + + TIntermNode* intermNode; + if (!context->executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, $4.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + context->recover(); + $$.intermAggregate = 0; + } + } + ; + +single_declaration + : fully_specified_type { + $$.type = $1; + $$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), $1.line), $1.line); + } + | fully_specified_type IDENTIFIER { + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + + if (context->structQualifierErrorCheck($2.line, $$.type)) + context->recover(); + + if (context->nonInitConstErrorCheck($2.line, *$2.string, $$.type, false)) + context->recover(); + + $$.type = $1; + + TVariable* variable = 0; + if (context->nonInitErrorCheck($2.line, *$2.string, $$.type, variable)) + context->recover(); + if (variable && symbol) + symbol->setId(variable->getUniqueId()); + } + | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + context->error($2.line, "unsized array declarations not supported", $2.string->c_str()); + context->recover(); + + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + $$.type = $1; + } + | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + TType type = TType($1); + int size; + if (context->arraySizeErrorCheck($2.line, $4, size)) + context->recover(); + type.setArraySize(size); + TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + + if (context->nonInitConstErrorCheck($2.line, *$2.string, $1, true)) + context->recover(); + + $$.type = $1; + + if (context->arrayTypeErrorCheck($3.line, $1) || context->arrayQualifierErrorCheck($3.line, $1)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck($3.line, $4, size)) + context->recover(); + + $1.setArray(true, size); + TVariable* variable = 0; + if (context->arrayErrorCheck($3.line, *$2.string, $1, variable)) + context->recover(); + if (variable && symbol) + symbol->setId(variable->getUniqueId()); + } + } + | fully_specified_type IDENTIFIER EQUAL initializer { + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + + $$.type = $1; + + TIntermNode* intermNode; + if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode)) { + // + // Build intermediate representation + // + if(intermNode) + $$.intermAggregate = context->intermediate.makeAggregate(intermNode, $3.line); + else + $$.intermAggregate = 0; + } else { + context->recover(); + $$.intermAggregate = 0; + } + } + | INVARIANT IDENTIFIER { + VERTEX_ONLY("invariant declaration", $1.line); + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, $2.line); + if (!$2.symbol) + { + context->error($2.line, "undeclared identifier declared as invariant", $2.string->c_str()); + context->recover(); + + $$.intermAggregate = 0; + } + else + { + TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), $2.line); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line); + } + } + +// +// Place holder for the pack/unpack languages. +// +// | buffer_specifier { +// $$.intermAggregate = 0; +// } + ; + +// Grammar Note: No 'enum', or 'typedef'. + +// +// Place holder for the pack/unpack languages. +// +//%type buffer_declaration +//%type buffer_specifier input_or_output buffer_declaration_list +//buffer_specifier +// : input_or_output LEFT_BRACE buffer_declaration_list RIGHT_BRACE { +// } +// ; +// +//input_or_output +// : INPUT { +// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "input")) +// context->recover(); +// UNPACK_ONLY("input", $1.line); +// $$.qualifier = EvqInput; +// } +// | OUTPUT { +// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "output")) +// context->recover(); +// PACK_ONLY("output", $1.line); +// $$.qualifier = EvqOutput; +// } +// ; + +// +// Place holder for the pack/unpack languages. +// +//buffer_declaration_list +// : buffer_declaration { +// } +// | buffer_declaration_list buffer_declaration { +// } +// ; + +// +// Input/output semantics: +// float must be 16 or 32 bits +// float alignment restrictions? +// check for only one input and only one output +// sum of bitfields has to be multiple of 32 +// + +// +// Place holder for the pack/unpack languages. +// +//buffer_declaration +// : type_specifier IDENTIFIER COLON constant_expression SEMICOLON { +// if (context->reservedErrorCheck($2.line, *$2.string, context)) +// context->recover(); +// $$.variable = new TVariable($2.string, $1); +// if (! context->symbolTable.insert(*$$.variable)) { +// context->error($2.line, "redefinition", $$.variable->getName().c_str()); +// context->recover(); +// // don't have to delete $$.variable, the pool pop will take care of it +// } +// } +// ; + +fully_specified_type + : type_specifier { + $$ = $1; + + if ($1.array) { + context->error($1.line, "not supported", "first-class array"); + context->recover(); + $1.setArray(false); + } + } + | type_qualifier type_specifier { + if ($2.array) { + context->error($2.line, "not supported", "first-class array"); + context->recover(); + $2.setArray(false); + } + + if ($1.qualifier == EvqAttribute && + ($2.type == EbtBool || $2.type == EbtInt)) { + context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier)); + context->recover(); + } + if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) && + ($2.type == EbtBool || $2.type == EbtInt)) { + context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier)); + context->recover(); + } + $$ = $2; + $$.qualifier = $1.qualifier; + } + ; + +type_qualifier + : CONST_QUAL { + $$.setBasic(EbtVoid, EvqConst, $1.line); + } + | ATTRIBUTE { + VERTEX_ONLY("attribute", $1.line); + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "attribute")) + context->recover(); + $$.setBasic(EbtVoid, EvqAttribute, $1.line); + } + | VARYING { + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + $$.setBasic(EbtVoid, EvqVaryingOut, $1.line); + else + $$.setBasic(EbtVoid, EvqVaryingIn, $1.line); + } + | INVARIANT VARYING { + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + $$.setBasic(EbtVoid, EvqInvariantVaryingOut, $1.line); + else + $$.setBasic(EbtVoid, EvqInvariantVaryingIn, $1.line); + } + | UNIFORM { + if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "uniform")) + context->recover(); + $$.setBasic(EbtVoid, EvqUniform, $1.line); + } + ; + +type_specifier + : type_specifier_no_prec { + $$ = $1; + + if ($$.precision == EbpUndefined) { + $$.precision = context->symbolTable.getDefaultPrecision($1.type); + if (context->precisionErrorCheck($1.line, $$.precision, $1.type)) { + context->recover(); + } + } + } + | precision_qualifier type_specifier_no_prec { + $$ = $2; + $$.precision = $1; + } + ; + +precision_qualifier + : HIGH_PRECISION { + $$ = EbpHigh; + } + | MEDIUM_PRECISION { + $$ = EbpMedium; + } + | LOW_PRECISION { + $$ = EbpLow; + } + ; + +type_specifier_no_prec + : type_specifier_nonarray { + $$ = $1; + } + | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$ = $1; + + if (context->arrayTypeErrorCheck($2.line, $1)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck($2.line, $3, size)) + context->recover(); + $$.setArray(true, size); + } + } + ; + +type_specifier_nonarray + : VOID_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtVoid, qual, $1.line); + } + | FLOAT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + } + | INT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + } + | BOOL_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + } +// | UNSIGNED INT_TYPE { +// PACK_UNPACK_ONLY("unsigned", $1.line); +// TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; +// $$.setBasic(EbtInt, qual, $1.line); +// } + | VEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2); + } + | VEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3); + } + | VEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4); + } + | BVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(2); + } + | BVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(3); + } + | BVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(4); + } + | IVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(2); + } + | IVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(3); + } + | IVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(4); + } + | MATRIX2 { + FRAG_VERT_ONLY("mat2", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2, true); + } + | MATRIX3 { + FRAG_VERT_ONLY("mat3", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3, true); + } + | MATRIX4 { + FRAG_VERT_ONLY("mat4", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4, true); + } + | SAMPLER2D { + FRAG_VERT_ONLY("sampler2D", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2D, qual, $1.line); + } + | SAMPLERCUBE { + FRAG_VERT_ONLY("samplerCube", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerCube, qual, $1.line); + } + | SAMPLER_EXTERNAL_OES { + if (!context->supportsExtension("GL_OES_EGL_image_external")) { + context->error($1.line, "unsupported type", "samplerExternalOES"); + context->recover(); + } + FRAG_VERT_ONLY("samplerExternalOES", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerExternalOES, qual, $1.line); + } + | SAMPLER2DRECT { + if (!context->supportsExtension("GL_ARB_texture_rectangle")) { + context->error($1.line, "unsupported type", "sampler2DRect"); + context->recover(); + } + FRAG_VERT_ONLY("sampler2DRect", $1.line); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DRect, qual, $1.line); + } + | struct_specifier { + FRAG_VERT_ONLY("struct", $1.line); + $$ = $1; + $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + | TYPE_NAME { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + TType& structure = static_cast($1.symbol)->getType(); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtStruct, qual, $1.line); + $$.userDef = &structure; + } + ; + +struct_specifier + : STRUCT IDENTIFIER LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + if (context->reservedErrorCheck($2.line, *$2.string)) + context->recover(); + + TType* structure = new TType($5, *$2.string); + TVariable* userTypeDef = new TVariable($2.string, *structure, true); + if (! context->symbolTable.insert(*userTypeDef)) { + context->error($2.line, "redefinition", $2.string->c_str(), "struct"); + context->recover(); + } + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + context->exitStructDeclaration(); + } + | STRUCT LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($4, TString("")); + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + context->exitStructDeclaration(); + } + ; + +struct_declaration_list + : struct_declaration { + $$ = $1; + } + | struct_declaration_list struct_declaration { + $$ = $1; + for (unsigned int i = 0; i < $2->size(); ++i) { + for (unsigned int j = 0; j < $$->size(); ++j) { + if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) { + context->error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str()); + context->recover(); + } + } + $$->push_back((*$2)[i]); + } + } + ; + +struct_declaration + : type_specifier struct_declarator_list SEMICOLON { + $$ = $2; + + if (context->voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) { + context->recover(); + } + for (unsigned int i = 0; i < $$->size(); ++i) { + // + // Careful not to replace already known aspects of type, like array-ness + // + TType* type = (*$$)[i].type; + type->setBasicType($1.type); + type->setNominalSize($1.size); + type->setMatrix($1.matrix); + type->setPrecision($1.precision); + + // don't allow arrays of arrays + if (type->isArray()) { + if (context->arrayTypeErrorCheck($1.line, $1)) + context->recover(); + } + if ($1.array) + type->setArraySize($1.arraySize); + if ($1.userDef) { + type->setStruct($1.userDef->getStruct()); + type->setTypeName($1.userDef->getTypeName()); + } + + if (context->structNestingErrorCheck($1.line, *type)) { + context->recover(); + } + } + } + ; + +struct_declarator_list + : struct_declarator { + $$ = NewPoolTTypeList(); + $$->push_back($1); + } + | struct_declarator_list COMMA struct_declarator { + $$->push_back($3); + } + ; + +struct_declarator + : IDENTIFIER { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + + $$.type = new TType(EbtVoid, EbpUndefined); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + } + | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + if (context->reservedErrorCheck($1.line, *$1.string)) + context->recover(); + + $$.type = new TType(EbtVoid, EbpUndefined); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + + int size; + if (context->arraySizeErrorCheck($2.line, $3, size)) + context->recover(); + $$.type->setArraySize(size); + } + ; + +initializer + : assignment_expression { $$ = $1; } + ; + +declaration_statement + : declaration { $$ = $1; } + ; + +statement + : compound_statement { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +// Grammar Note: No labeled statements; 'goto' is not supported. + +simple_statement + : declaration_statement { $$ = $1; } + | expression_statement { $$ = $1; } + | selection_statement { $$ = $1; } + | iteration_statement { $$ = $1; } + | jump_statement { $$ = $1; } + ; + +compound_statement + : LEFT_BRACE RIGHT_BRACE { $$ = 0; } + | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE { + if ($3 != 0) { + $3->setOp(EOpSequence); + $3->setEndLine($5.line); + } + $$ = $3; + } + ; + +statement_no_new_scope + : compound_statement_no_new_scope { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +statement_with_scope + : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; } + | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; } + ; + +compound_statement_no_new_scope + // Statement that doesn't create a new scope, for selection_statement, iteration_statement + : LEFT_BRACE RIGHT_BRACE { + $$ = 0; + } + | LEFT_BRACE statement_list RIGHT_BRACE { + if ($2) { + $2->setOp(EOpSequence); + $2->setEndLine($3.line); + } + $$ = $2; + } + ; + +statement_list + : statement { + $$ = context->intermediate.makeAggregate($1, 0); + } + | statement_list statement { + $$ = context->intermediate.growAggregate($1, $2, 0); + } + ; + +expression_statement + : SEMICOLON { $$ = 0; } + | expression SEMICOLON { $$ = static_cast($1); } + ; + +selection_statement + : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { + if (context->boolErrorCheck($1.line, $3)) + context->recover(); + $$ = context->intermediate.addSelection($3, $5, $1.line); + } + ; + +selection_rest_statement + : statement_with_scope ELSE statement_with_scope { + $$.node1 = $1; + $$.node2 = $3; + } + | statement_with_scope { + $$.node1 = $1; + $$.node2 = 0; + } + ; + +// Grammar Note: No 'switch'. Switch statements not supported. + +condition + // In 1996 c++ draft, conditions can include single declarations + : expression { + $$ = $1; + if (context->boolErrorCheck($1->getLine(), $1)) + context->recover(); + } + | fully_specified_type IDENTIFIER EQUAL initializer { + TIntermNode* intermNode; + if (context->structQualifierErrorCheck($2.line, $1)) + context->recover(); + if (context->boolErrorCheck($2.line, $1)) + context->recover(); + + if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode)) + $$ = $4; + else { + context->recover(); + $$ = 0; + } + } + ; + +iteration_statement + : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { + context->symbolTable.pop(); + $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, $1.line); + --context->loopNestingLevel; + } + | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + if (context->boolErrorCheck($8.line, $6)) + context->recover(); + + $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, $4.line); + --context->loopNestingLevel; + } + | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { + context->symbolTable.pop(); + $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast($5.node1), reinterpret_cast($5.node2), $7, $1.line); + --context->loopNestingLevel; + } + ; + +for_init_statement + : expression_statement { + $$ = $1; + } + | declaration_statement { + $$ = $1; + } + ; + +conditionopt + : condition { + $$ = $1; + } + | /* May be null */ { + $$ = 0; + } + ; + +for_rest_statement + : conditionopt SEMICOLON { + $$.node1 = $1; + $$.node2 = 0; + } + | conditionopt SEMICOLON expression { + $$.node1 = $1; + $$.node2 = $3; + } + ; + +jump_statement + : CONTINUE SEMICOLON { + if (context->loopNestingLevel <= 0) { + context->error($1.line, "continue statement only allowed in loops", ""); + context->recover(); + } + $$ = context->intermediate.addBranch(EOpContinue, $1.line); + } + | BREAK SEMICOLON { + if (context->loopNestingLevel <= 0) { + context->error($1.line, "break statement only allowed in loops", ""); + context->recover(); + } + $$ = context->intermediate.addBranch(EOpBreak, $1.line); + } + | RETURN SEMICOLON { + $$ = context->intermediate.addBranch(EOpReturn, $1.line); + if (context->currentFunctionType->getBasicType() != EbtVoid) { + context->error($1.line, "non-void function must return a value", "return"); + context->recover(); + } + } + | RETURN expression SEMICOLON { + $$ = context->intermediate.addBranch(EOpReturn, $2, $1.line); + context->functionReturnsValue = true; + if (context->currentFunctionType->getBasicType() == EbtVoid) { + context->error($1.line, "void function cannot return a value", "return"); + context->recover(); + } else if (*(context->currentFunctionType) != $2->getType()) { + context->error($1.line, "function return is not matching type:", "return"); + context->recover(); + } + } + | DISCARD SEMICOLON { + FRAG_ONLY("discard", $1.line); + $$ = context->intermediate.addBranch(EOpKill, $1.line); + } + ; + +// Grammar Note: No 'goto'. Gotos are not supported. + +translation_unit + : external_declaration { + $$ = $1; + context->treeRoot = $$; + } + | translation_unit external_declaration { + $$ = context->intermediate.growAggregate($1, $2, 0); + context->treeRoot = $$; + } + ; + +external_declaration + : function_definition { + $$ = $1; + } + | declaration { + $$ = $1; + } + ; + +function_definition + : function_prototype { + TFunction* function = $1.function; + + const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName()); + + if (builtIn) + { + context->error($1.line, "built-in functions cannot be redefined", function->getName().c_str()); + context->recover(); + } + + TFunction* prevDec = static_cast(context->symbolTable.find(function->getMangledName())); + // + // Note: 'prevDec' could be 'function' if this is the first time we've seen function + // as it would have just been put in the symbol table. Otherwise, we're looking up + // an earlier occurance. + // + if (prevDec->isDefined()) { + // + // Then this function already has a body. + // + context->error($1.line, "function already has a body", function->getName().c_str()); + context->recover(); + } + prevDec->setDefined(); + + // + // Raise error message if main function takes any parameters or return anything other than void + // + if (function->getName() == "main") { + if (function->getParamCount() > 0) { + context->error($1.line, "function cannot take any parameter(s)", function->getName().c_str()); + context->recover(); + } + if (function->getReturnType().getBasicType() != EbtVoid) { + context->error($1.line, "", function->getReturnType().getBasicString(), "main function cannot return a value"); + context->recover(); + } + } + + // + // Remember the return type for later checking for RETURN statements. + // + context->currentFunctionType = &(prevDec->getReturnType()); + context->functionReturnsValue = false; + + // + // Insert parameters into the symbol table. + // If the parameter has no name, it's not an error, just don't insert it + // (could be used for unused args). + // + // Also, accumulate the list of parameters into the HIL, so lower level code + // knows where to find parameters. + // + TIntermAggregate* paramNodes = new TIntermAggregate; + for (int i = 0; i < function->getParamCount(); i++) { + const TParameter& param = function->getParam(i); + if (param.name != 0) { + TVariable *variable = new TVariable(param.name, *param.type); + // + // Insert the parameters with name in the symbol table. + // + if (! context->symbolTable.insert(*variable)) { + context->error($1.line, "redefinition", variable->getName().c_str()); + context->recover(); + delete variable; + } + + // + // Add the parameter to the HIL + // + paramNodes = context->intermediate.growAggregate( + paramNodes, + context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), $1.line), + $1.line); + } else { + paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line); + } + } + context->intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line); + $1.intermAggregate = paramNodes; + context->loopNestingLevel = 0; + } + compound_statement_no_new_scope { + //?? Check that all paths return a value if return type != void ? + // May be best done as post process phase on intermediate code + if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) { + context->error($1.line, "function does not return a value:", "", $1.function->getName().c_str()); + context->recover(); + } + + $$ = context->intermediate.growAggregate($1.intermAggregate, $3, 0); + context->intermediate.setAggregateOperator($$, EOpFunction, $1.line); + $$->getAsAggregate()->setName($1.function->getMangledName().c_str()); + $$->getAsAggregate()->setType($1.function->getReturnType()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + $$->getAsAggregate()->setOptimize(context->pragma().optimize); + $$->getAsAggregate()->setDebug(context->pragma().debug); + + if ($3 && $3->getAsAggregate()) + $$->getAsAggregate()->setEndLine($3->getAsAggregate()->getEndLine()); + + context->symbolTable.pop(); + } + ; + +%% + +int glslang_parse(TParseContext* context) { + return yyparse(context); +} + diff --git a/src/3rdparty/angle/src/compiler/intermOut.cpp b/src/3rdparty/angle/src/compiler/intermOut.cpp new file mode 100644 index 0000000000..e83c7b72f2 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/intermOut.cpp @@ -0,0 +1,419 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/localintermediate.h" + +// +// Two purposes: +// 1. Show an example of how to iterate tree. Functions can +// also directly call Traverse() on children themselves to +// have finer grained control over the process than shown here. +// See the last function for how to get started. +// 2. Print out a text based description of the tree. +// + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TOutputTraverser : public TIntermTraverser { +public: + TOutputTraverser(TInfoSinkBase& i) : sink(i) { } + TInfoSinkBase& sink; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); +}; + +TString TType::getCompleteString() const +{ + TStringStream stream; + + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + stream << getQualifierString() << " " << getPrecisionString() << " "; + if (array) + stream << "array of "; + if (matrix) + stream << size << "X" << size << " matrix of "; + else if (size > 1) + stream << size << "-component vector of "; + + stream << getBasicString(); + return stream.str(); +} + +// +// Helper functions for printing, not part of traversing. +// + +void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth) +{ + int i; + + sink.location(node->getLine()); + + for (i = 0; i < depth; ++i) + sink << " "; +} + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TOutputTraverser::visitSymbol(TIntermSymbol* node) +{ + OutputTreeText(sink, node, depth); + + sink << "'" << node->getSymbol() << "' "; + sink << "(" << node->getCompleteString() << ")\n"; +} + +bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpAssign: out << "move second child to first child"; break; + case EOpInitialize: out << "initialize first child with second child"; break; + case EOpAddAssign: out << "add second child into first child"; break; + case EOpSubAssign: out << "subtract second child into first child"; break; + case EOpMulAssign: out << "multiply second child into first child"; break; + case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break; + case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break; + case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break; + case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break; + case EOpDivAssign: out << "divide second child into first child"; break; + case EOpIndexDirect: out << "direct index"; break; + case EOpIndexIndirect: out << "indirect index"; break; + case EOpIndexDirectStruct: out << "direct index for structure"; break; + case EOpVectorSwizzle: out << "vector swizzle"; break; + + case EOpAdd: out << "add"; break; + case EOpSub: out << "subtract"; break; + case EOpMul: out << "component-wise multiply"; break; + case EOpDiv: out << "divide"; break; + case EOpEqual: out << "Compare Equal"; break; + case EOpNotEqual: out << "Compare Not Equal"; break; + case EOpLessThan: out << "Compare Less Than"; break; + case EOpGreaterThan: out << "Compare Greater Than"; break; + case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; + + case EOpVectorTimesScalar: out << "vector-scale"; break; + case EOpVectorTimesMatrix: out << "vector-times-matrix"; break; + case EOpMatrixTimesVector: out << "matrix-times-vector"; break; + case EOpMatrixTimesScalar: out << "matrix-scale"; break; + case EOpMatrixTimesMatrix: out << "matrix-multiply"; break; + + case EOpLogicalOr: out << "logical-or"; break; + case EOpLogicalXor: out << "logical-xor"; break; + case EOpLogicalAnd: out << "logical-and"; break; + default: out << ""; + } + + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpNegative: out << "Negate value"; break; + case EOpVectorLogicalNot: + case EOpLogicalNot: out << "Negate conditional"; break; + + case EOpPostIncrement: out << "Post-Increment"; break; + case EOpPostDecrement: out << "Post-Decrement"; break; + case EOpPreIncrement: out << "Pre-Increment"; break; + case EOpPreDecrement: out << "Pre-Decrement"; break; + + case EOpConvIntToBool: out << "Convert int to bool"; break; + case EOpConvFloatToBool:out << "Convert float to bool";break; + case EOpConvBoolToFloat:out << "Convert bool to float";break; + case EOpConvIntToFloat: out << "Convert int to float"; break; + case EOpConvFloatToInt: out << "Convert float to int"; break; + case EOpConvBoolToInt: out << "Convert bool to int"; break; + + case EOpRadians: out << "radians"; break; + case EOpDegrees: out << "degrees"; break; + case EOpSin: out << "sine"; break; + case EOpCos: out << "cosine"; break; + case EOpTan: out << "tangent"; break; + case EOpAsin: out << "arc sine"; break; + case EOpAcos: out << "arc cosine"; break; + case EOpAtan: out << "arc tangent"; break; + + case EOpExp: out << "exp"; break; + case EOpLog: out << "log"; break; + case EOpExp2: out << "exp2"; break; + case EOpLog2: out << "log2"; break; + case EOpSqrt: out << "sqrt"; break; + case EOpInverseSqrt: out << "inverse sqrt"; break; + + case EOpAbs: out << "Absolute value"; break; + case EOpSign: out << "Sign"; break; + case EOpFloor: out << "Floor"; break; + case EOpCeil: out << "Ceiling"; break; + case EOpFract: out << "Fraction"; break; + + case EOpLength: out << "length"; break; + case EOpNormalize: out << "normalize"; break; + // case EOpDPdx: out << "dPdx"; break; + // case EOpDPdy: out << "dPdy"; break; + // case EOpFwidth: out << "fwidth"; break; + + case EOpAny: out << "any"; break; + case EOpAll: out << "all"; break; + + default: out.message(EPrefixError, "Bad unary op"); + } + + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + TInfoSinkBase& out = sink; + + if (node->getOp() == EOpNull) { + out.message(EPrefixError, "node is still EOpNull!"); + return true; + } + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpSequence: out << "Sequence\n"; return true; + case EOpComma: out << "Comma\n"; return true; + case EOpFunction: out << "Function Definition: " << node->getName(); break; + case EOpFunctionCall: out << "Function Call: " << node->getName(); break; + case EOpParameters: out << "Function Parameters: "; break; + + case EOpConstructFloat: out << "Construct float"; break; + case EOpConstructVec2: out << "Construct vec2"; break; + case EOpConstructVec3: out << "Construct vec3"; break; + case EOpConstructVec4: out << "Construct vec4"; break; + case EOpConstructBool: out << "Construct bool"; break; + case EOpConstructBVec2: out << "Construct bvec2"; break; + case EOpConstructBVec3: out << "Construct bvec3"; break; + case EOpConstructBVec4: out << "Construct bvec4"; break; + case EOpConstructInt: out << "Construct int"; break; + case EOpConstructIVec2: out << "Construct ivec2"; break; + case EOpConstructIVec3: out << "Construct ivec3"; break; + case EOpConstructIVec4: out << "Construct ivec4"; break; + case EOpConstructMat2: out << "Construct mat2"; break; + case EOpConstructMat3: out << "Construct mat3"; break; + case EOpConstructMat4: out << "Construct mat4"; break; + case EOpConstructStruct: out << "Construct structure"; break; + + case EOpLessThan: out << "Compare Less Than"; break; + case EOpGreaterThan: out << "Compare Greater Than"; break; + case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; + case EOpVectorEqual: out << "Equal"; break; + case EOpVectorNotEqual: out << "NotEqual"; break; + + case EOpMod: out << "mod"; break; + case EOpPow: out << "pow"; break; + + case EOpAtan: out << "arc tangent"; break; + + case EOpMin: out << "min"; break; + case EOpMax: out << "max"; break; + case EOpClamp: out << "clamp"; break; + case EOpMix: out << "mix"; break; + case EOpStep: out << "step"; break; + case EOpSmoothStep: out << "smoothstep"; break; + + case EOpDistance: out << "distance"; break; + case EOpDot: out << "dot-product"; break; + case EOpCross: out << "cross-product"; break; + case EOpFaceForward: out << "face-forward"; break; + case EOpReflect: out << "reflect"; break; + case EOpRefract: out << "refract"; break; + case EOpMul: out << "component-wise multiply"; break; + + case EOpDeclaration: out << "Declaration: "; break; + + default: out.message(EPrefixError, "Bad aggregation op"); + } + + if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + out << "Test condition and select"; + out << " (" << node->getCompleteString() << ")\n"; + + ++depth; + + OutputTreeText(sink, node, depth); + out << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(sink, node, depth); + if (node->getTrueBlock()) { + out << "true case\n"; + node->getTrueBlock()->traverse(this); + } else + out << "true case is null\n"; + + if (node->getFalseBlock()) { + OutputTreeText(sink, node, depth); + out << "false case\n"; + node->getFalseBlock()->traverse(this); + } + + --depth; + + return false; +} + +void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + TInfoSinkBase& out = sink; + + int size = node->getType().getObjectSize(); + + for (int i = 0; i < size; i++) { + OutputTreeText(out, node, depth); + switch (node->getUnionArrayPointer()[i].getType()) { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + out << "true"; + else + out << "false"; + + out << " (" << "const bool" << ")"; + out << "\n"; + break; + case EbtFloat: + out << node->getUnionArrayPointer()[i].getFConst(); + out << " (const float)\n"; + break; + case EbtInt: + out << node->getUnionArrayPointer()[i].getIConst(); + out << " (const int)\n"; + break; + default: + out.message(EPrefixInternalError, "Unknown constant", node->getLine()); + break; + } + } +} + +bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + out << "Loop with condition "; + if (node->getType() == ELoopDoWhile) + out << "not "; + out << "tested first\n"; + + ++depth; + + OutputTreeText(sink, node, depth); + if (node->getCondition()) { + out << "Loop Condition\n"; + node->getCondition()->traverse(this); + } else + out << "No loop condition\n"; + + OutputTreeText(sink, node, depth); + if (node->getBody()) { + out << "Loop Body\n"; + node->getBody()->traverse(this); + } else + out << "No loop body\n"; + + if (node->getExpression()) { + OutputTreeText(sink, node, depth); + out << "Loop Terminal Expression\n"; + node->getExpression()->traverse(this); + } + + --depth; + + return false; +} + +bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getFlowOp()) { + case EOpKill: out << "Branch: Kill"; break; + case EOpBreak: out << "Branch: Break"; break; + case EOpContinue: out << "Branch: Continue"; break; + case EOpReturn: out << "Branch: Return"; break; + default: out << "Branch: Unknown Branch"; break; + } + + if (node->getExpression()) { + out << " with expression\n"; + ++depth; + node->getExpression()->traverse(this); + --depth; + } else + out << "\n"; + + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +void TIntermediate::outputTree(TIntermNode* root) +{ + if (root == 0) + return; + + TOutputTraverser it(infoSink.info); + + root->traverse(&it); +} diff --git a/src/3rdparty/angle/src/compiler/intermediate.h b/src/3rdparty/angle/src/compiler/intermediate.h new file mode 100644 index 0000000000..af78fa00ef --- /dev/null +++ b/src/3rdparty/angle/src/compiler/intermediate.h @@ -0,0 +1,557 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Definition of the in-memory high-level intermediate representation +// of shaders. This is a tree that parser creates. +// +// Nodes in the tree are defined as a hierarchy of classes derived from +// TIntermNode. Each is a node in a tree. There is no preset branching factor; +// each node can have it's own type of list of children. +// + +#ifndef __INTERMEDIATE_H +#define __INTERMEDIATE_H + +#include "compiler/Common.h" +#include "compiler/Types.h" +#include "compiler/ConstantUnion.h" + +// +// Operators used by the high-level (parse tree) representation. +// +enum TOperator { + EOpNull, // if in a node, should only mean a node is still being built + EOpSequence, // denotes a list of statements, or parameters, etc. + EOpFunctionCall, + EOpFunction, // For function definition + EOpParameters, // an aggregate listing the parameters to a function + + EOpDeclaration, + EOpPrototype, + + // + // Unary operators + // + + EOpNegative, + EOpLogicalNot, + EOpVectorLogicalNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + EOpConvIntToBool, + EOpConvFloatToBool, + EOpConvBoolToFloat, + EOpConvIntToFloat, + EOpConvFloatToInt, + EOpConvBoolToInt, + + // + // binary operations + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpEqual, + EOpNotEqual, + EOpVectorEqual, + EOpVectorNotEqual, + EOpLessThan, + EOpGreaterThan, + EOpLessThanEqual, + EOpGreaterThanEqual, + EOpComma, + + EOpVectorTimesScalar, + EOpVectorTimesMatrix, + EOpMatrixTimesVector, + EOpMatrixTimesScalar, + + EOpLogicalOr, + EOpLogicalXor, + EOpLogicalAnd, + + EOpIndexDirect, + EOpIndexIndirect, + EOpIndexDirectStruct, + + EOpVectorSwizzle, + + // + // Built-in functions potentially mapped to operators + // + + EOpRadians, + EOpDegrees, + EOpSin, + EOpCos, + EOpTan, + EOpAsin, + EOpAcos, + EOpAtan, + + EOpPow, + EOpExp, + EOpLog, + EOpExp2, + EOpLog2, + EOpSqrt, + EOpInverseSqrt, + + EOpAbs, + EOpSign, + EOpFloor, + EOpCeil, + EOpFract, + EOpMod, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothStep, + + EOpLength, + EOpDistance, + EOpDot, + EOpCross, + EOpNormalize, + EOpFaceForward, + EOpReflect, + EOpRefract, + + EOpDFdx, // Fragment only, OES_standard_derivatives extension + EOpDFdy, // Fragment only, OES_standard_derivatives extension + EOpFwidth, // Fragment only, OES_standard_derivatives extension + + EOpMatrixTimesMatrix, + + EOpAny, + EOpAll, + + // + // Branch + // + + EOpKill, // Fragment only + EOpReturn, + EOpBreak, + EOpContinue, + + // + // Constructors + // + + EOpConstructInt, + EOpConstructBool, + EOpConstructFloat, + EOpConstructVec2, + EOpConstructVec3, + EOpConstructVec4, + EOpConstructBVec2, + EOpConstructBVec3, + EOpConstructBVec4, + EOpConstructIVec2, + EOpConstructIVec3, + EOpConstructIVec4, + EOpConstructMat2, + EOpConstructMat3, + EOpConstructMat4, + EOpConstructStruct, + + // + // moves + // + + EOpAssign, + EOpInitialize, + EOpAddAssign, + EOpSubAssign, + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + EOpDivAssign, +}; + +extern const char* getOperatorString(TOperator op); + +class TIntermTraverser; +class TIntermAggregate; +class TIntermBinary; +class TIntermUnary; +class TIntermConstantUnion; +class TIntermSelection; +class TIntermTyped; +class TIntermSymbol; +class TIntermLoop; +class TInfoSink; + +// +// Base class for the tree nodes +// +class TIntermNode { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermNode() : line(0) {} + + TSourceLoc getLine() const { return line; } + void setLine(TSourceLoc l) { line = l; } + + virtual void traverse(TIntermTraverser*) = 0; + virtual TIntermTyped* getAsTyped() { return 0; } + virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } + virtual TIntermAggregate* getAsAggregate() { return 0; } + virtual TIntermBinary* getAsBinaryNode() { return 0; } + virtual TIntermUnary* getAsUnaryNode() { return 0; } + virtual TIntermSelection* getAsSelectionNode() { return 0; } + virtual TIntermSymbol* getAsSymbolNode() { return 0; } + virtual TIntermLoop* getAsLoopNode() { return 0; } + virtual ~TIntermNode() { } + +protected: + TSourceLoc line; +}; + +// +// This is just to help yacc. +// +struct TIntermNodePair { + TIntermNode* node1; + TIntermNode* node2; +}; + +// +// Intermediate class for nodes that have a type. +// +class TIntermTyped : public TIntermNode { +public: + TIntermTyped(const TType& t) : type(t) { } + virtual TIntermTyped* getAsTyped() { return this; } + + void setType(const TType& t) { type = t; } + const TType& getType() const { return type; } + TType* getTypePointer() { return &type; } + + TBasicType getBasicType() const { return type.getBasicType(); } + TQualifier getQualifier() const { return type.getQualifier(); } + TPrecision getPrecision() const { return type.getPrecision(); } + int getNominalSize() const { return type.getNominalSize(); } + + bool isMatrix() const { return type.isMatrix(); } + bool isArray() const { return type.isArray(); } + bool isVector() const { return type.isVector(); } + bool isScalar() const { return type.isScalar(); } + const char* getBasicString() const { return type.getBasicString(); } + const char* getQualifierString() const { return type.getQualifierString(); } + TString getCompleteString() const { return type.getCompleteString(); } + +protected: + TType type; +}; + +// +// Handle for, do-while, and while loops. +// +enum TLoopType { + ELoopFor, + ELoopWhile, + ELoopDoWhile, +}; + +class TIntermLoop : public TIntermNode { +public: + TIntermLoop(TLoopType aType, + TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, + TIntermNode* aBody) : + type(aType), + init(aInit), + cond(aCond), + expr(aExpr), + body(aBody), + unrollFlag(false) { } + + virtual TIntermLoop* getAsLoopNode() { return this; } + virtual void traverse(TIntermTraverser*); + + TLoopType getType() const { return type; } + TIntermNode* getInit() { return init; } + TIntermTyped* getCondition() { return cond; } + TIntermTyped* getExpression() { return expr; } + TIntermNode* getBody() { return body; } + + void setUnrollFlag(bool flag) { unrollFlag = flag; } + bool getUnrollFlag() { return unrollFlag; } + +protected: + TLoopType type; + TIntermNode* init; // for-loop initialization + TIntermTyped* cond; // loop exit condition + TIntermTyped* expr; // for-loop expression + TIntermNode* body; // loop body + + bool unrollFlag; // Whether the loop should be unrolled or not. +}; + +// +// Handle break, continue, return, and kill. +// +class TIntermBranch : public TIntermNode { +public: + TIntermBranch(TOperator op, TIntermTyped* e) : + flowOp(op), + expression(e) { } + + virtual void traverse(TIntermTraverser*); + + TOperator getFlowOp() { return flowOp; } + TIntermTyped* getExpression() { return expression; } + +protected: + TOperator flowOp; + TIntermTyped* expression; // non-zero except for "return exp;" statements +}; + +// +// Nodes that correspond to symbols or constants in the source code. +// +class TIntermSymbol : public TIntermTyped { +public: + // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from + // per process globalpoolallocator, then it causes increased memory usage per compile + // it is essential to use "symbol = sym" to assign to symbol + TIntermSymbol(int i, const TString& sym, const TType& t) : + TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; } + + int getId() const { return id; } + const TString& getSymbol() const { return symbol; } + + void setId(int newId) { id = newId; } + void setSymbol(const TString& sym) { symbol = sym; } + + const TString& getOriginalSymbol() const { return originalSymbol; } + + virtual void traverse(TIntermTraverser*); + virtual TIntermSymbol* getAsSymbolNode() { return this; } + +protected: + int id; + TString symbol; + TString originalSymbol; +}; + +class TIntermConstantUnion : public TIntermTyped { +public: + TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } + + ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } + void setUnionArrayPointer(ConstantUnion *c) { unionArrayPointer = c; } + + virtual TIntermConstantUnion* getAsConstantUnion() { return this; } + virtual void traverse(TIntermTraverser*); + + TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); + +protected: + ConstantUnion *unionArrayPointer; +}; + +// +// Intermediate class for node types that hold operators. +// +class TIntermOperator : public TIntermTyped { +public: + TOperator getOp() const { return op; } + void setOp(TOperator o) { op = o; } + + bool modifiesState() const; + bool isConstructor() const; + +protected: + TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} + TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} + TOperator op; +}; + +// +// Nodes for all the basic binary math operators. +// +class TIntermBinary : public TIntermOperator { +public: + TIntermBinary(TOperator o) : TIntermOperator(o) {} + + virtual TIntermBinary* getAsBinaryNode() { return this; } + virtual void traverse(TIntermTraverser*); + + void setLeft(TIntermTyped* n) { left = n; } + void setRight(TIntermTyped* n) { right = n; } + TIntermTyped* getLeft() const { return left; } + TIntermTyped* getRight() const { return right; } + bool promote(TInfoSink&); + +protected: + TIntermTyped* left; + TIntermTyped* right; +}; + +// +// Nodes for unary math operators. +// +class TIntermUnary : public TIntermOperator { +public: + TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {} + TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {} + + virtual void traverse(TIntermTraverser*); + virtual TIntermUnary* getAsUnaryNode() { return this; } + + void setOperand(TIntermTyped* o) { operand = o; } + TIntermTyped* getOperand() { return operand; } + bool promote(TInfoSink&); + + void setUseEmulatedFunction() { useEmulatedFunction = true; } + bool getUseEmulatedFunction() { return useEmulatedFunction; } + +protected: + TIntermTyped* operand; + + // If set to true, replace the built-in function call with an emulated one + // to work around driver bugs. + bool useEmulatedFunction; +}; + +typedef TVector TIntermSequence; +typedef TVector TQualifierList; + +// +// Nodes that operate on an arbitrary sized set of children. +// +class TIntermAggregate : public TIntermOperator { +public: + TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), endLine(0), useEmulatedFunction(false) { } + TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { } + ~TIntermAggregate() { } + + virtual TIntermAggregate* getAsAggregate() { return this; } + virtual void traverse(TIntermTraverser*); + + TIntermSequence& getSequence() { return sequence; } + + void setName(const TString& n) { name = n; } + const TString& getName() const { return name; } + + void setUserDefined() { userDefined = true; } + bool isUserDefined() const { return userDefined; } + + void setOptimize(bool o) { optimize = o; } + bool getOptimize() { return optimize; } + void setDebug(bool d) { debug = d; } + bool getDebug() { return debug; } + + void setEndLine(TSourceLoc line) { endLine = line; } + TSourceLoc getEndLine() const { return endLine; } + + void setUseEmulatedFunction() { useEmulatedFunction = true; } + bool getUseEmulatedFunction() { return useEmulatedFunction; } + +protected: + TIntermAggregate(const TIntermAggregate&); // disallow copy constructor + TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator + TIntermSequence sequence; + TString name; + bool userDefined; // used for user defined function names + + bool optimize; + bool debug; + TSourceLoc endLine; + + // If set to true, replace the built-in function call with an emulated one + // to work around driver bugs. + bool useEmulatedFunction; +}; + +// +// For if tests. Simplified since there is no switch statement. +// +class TIntermSelection : public TIntermTyped { +public: + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : + TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : + TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + + virtual void traverse(TIntermTraverser*); + + bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } + TIntermNode* getCondition() const { return condition; } + TIntermNode* getTrueBlock() const { return trueBlock; } + TIntermNode* getFalseBlock() const { return falseBlock; } + TIntermSelection* getAsSelectionNode() { return this; } + +protected: + TIntermTyped* condition; + TIntermNode* trueBlock; + TIntermNode* falseBlock; +}; + +enum Visit +{ + PreVisit, + InVisit, + PostVisit +}; + +// +// For traversing the tree. User should derive from this, +// put their traversal specific data in it, and then pass +// it to a Traverse method. +// +// When using this, just fill in the methods for nodes you want visited. +// Return false from a pre-visit to skip visiting that node's subtree. +// +class TIntermTraverser +{ +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : + preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + rightToLeft(rightToLeft), + depth(0) {} + virtual ~TIntermTraverser() {}; + + virtual void visitSymbol(TIntermSymbol*) {} + virtual void visitConstantUnion(TIntermConstantUnion*) {} + virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} + virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} + virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} + virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} + virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} + virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} + + void incrementDepth() {depth++;} + void decrementDepth() {depth--;} + + const bool preVisit; + const bool inVisit; + const bool postVisit; + const bool rightToLeft; + +protected: + int depth; +}; + +#endif // __INTERMEDIATE_H diff --git a/src/3rdparty/angle/src/compiler/localintermediate.h b/src/3rdparty/angle/src/compiler/localintermediate.h new file mode 100644 index 0000000000..56890bd569 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/localintermediate.h @@ -0,0 +1,58 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _LOCAL_INTERMEDIATE_INCLUDED_ +#define _LOCAL_INTERMEDIATE_INCLUDED_ + +#include "GLSLANG/ShaderLang.h" +#include "compiler/intermediate.h" +#include "compiler/SymbolTable.h" + +struct TVectorFields { + int offsets[4]; + int num; +}; + +// +// Set of helper functions to help parse and build the tree. +// +class TInfoSink; +class TIntermediate { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermediate(TInfoSink& i) : infoSink(i) { } + TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc); + TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*); + TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, TSymbolTable&); + TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); + TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); + TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, TSourceLoc, TSymbolTable&); + TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc); + TIntermAggregate* makeAggregate(TIntermNode* node, TSourceLoc); + TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc); + TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc); + TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc); + TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc); + TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, TSourceLoc); + TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ; + bool parseConstTree(TSourceLoc, TIntermNode*, ConstantUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false); + TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, TSourceLoc); + TIntermBranch* addBranch(TOperator, TSourceLoc); + TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc); + TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc); + bool postProcess(TIntermNode*); + void remove(TIntermNode*); + void outputTree(TIntermNode*); + +protected: + TInfoSink& infoSink; + +private: + void operator=(TIntermediate&); // prevent assignments +}; + +#endif // _LOCAL_INTERMEDIATE_INCLUDED_ diff --git a/src/3rdparty/angle/src/compiler/osinclude.h b/src/3rdparty/angle/src/compiler/osinclude.h new file mode 100644 index 0000000000..1d95907b79 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/osinclude.h @@ -0,0 +1,72 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef __OSINCLUDE_H +#define __OSINCLUDE_H + +// +// This file contains contains os-specific datatypes and +// declares any os-specific functions. +// + +#if defined(_WIN32) || defined(_WIN64) +#define ANGLE_OS_WIN +#elif defined(__APPLE__) || defined(__linux__) || \ + defined(__FreeBSD__) || defined(__OpenBSD__) || \ + defined(__sun) || defined(ANDROID) || \ + defined(__GLIBC__) || defined(__GNU__) || \ + defined(__QNX__) +#define ANGLE_OS_POSIX +#else +#error Unsupported platform. +#endif + +#if defined(ANGLE_USE_NSPR) +#include "prthread.h" +#elif defined(ANGLE_OS_WIN) +#define STRICT +#define VC_EXTRALEAN 1 +#include +#elif defined(ANGLE_OS_POSIX) +#include +#include +#include +#endif // ANGLE_USE_NSPR + + +#include "compiler/debug.h" + +// +// Thread Local Storage Operations +// +#if defined(ANGLE_USE_NSPR) +typedef PRUintn OS_TLSIndex; +#define OS_INVALID_TLS_INDEX 0xFFFFFFFF +#elif defined(ANGLE_OS_WIN) +typedef DWORD OS_TLSIndex; +#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES) +#elif defined(ANGLE_OS_POSIX) +typedef unsigned int OS_TLSIndex; +#define OS_INVALID_TLS_INDEX 0xFFFFFFFF +#endif // ANGLE_USE_NSPR + +OS_TLSIndex OS_AllocTLSIndex(); +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue); +bool OS_FreeTLSIndex(OS_TLSIndex nIndex); + +inline void* OS_GetTLSValue(OS_TLSIndex nIndex) +{ + ASSERT(nIndex != OS_INVALID_TLS_INDEX); +#if defined(ANGLE_USE_NSPR) + return PR_GetThreadPrivate(nIndex); +#elif defined(ANGLE_OS_WIN) + return TlsGetValue(nIndex); +#elif defined(ANGLE_OS_POSIX) + return pthread_getspecific(nIndex); +#endif // ANGLE_OS_WIN +} + +#endif // __OSINCLUDE_H diff --git a/src/3rdparty/angle/src/compiler/ossource_nspr.cpp b/src/3rdparty/angle/src/compiler/ossource_nspr.cpp new file mode 100644 index 0000000000..f63d81e5d5 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ossource_nspr.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// This file contains the nspr specific functions +// +#include "compiler/osinclude.h" + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + PRUintn index; + PRStatus status = PR_NewThreadPrivateIndex(&index, NULL); + + if (status) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return OS_INVALID_TLS_INDEX; + } + + return index; +} + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + return PR_SetThreadPrivate(nIndex, lpvValue) == 0; +} + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + // Can't delete TLS keys with nspr + return true; +} + diff --git a/src/3rdparty/angle/src/compiler/ossource_posix.cpp b/src/3rdparty/angle/src/compiler/ossource_posix.cpp new file mode 100644 index 0000000000..1e1e699aeb --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ossource_posix.cpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// This file contains the posix specific functions +// +#include "compiler/osinclude.h" + +#if !defined(ANGLE_OS_POSIX) +#error Trying to build a posix specific file in a non-posix build. +#endif + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + pthread_key_t pPoolIndex; + + // + // Create global pool key. + // + if ((pthread_key_create(&pPoolIndex, NULL)) != 0) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return false; + } + else { + return pPoolIndex; + } +} + + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (pthread_setspecific(nIndex, lpvValue) == 0) + return true; + else + return false; +} + + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + // + // Delete the global pool key. + // + if (pthread_key_delete(nIndex) == 0) + return true; + else + return false; +} diff --git a/src/3rdparty/angle/src/compiler/ossource_win.cpp b/src/3rdparty/angle/src/compiler/ossource_win.cpp new file mode 100644 index 0000000000..89922fef3f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/ossource_win.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/osinclude.h" +// +// This file contains contains the window's specific functions +// + +#if !defined(ANGLE_OS_WIN) +#error Trying to build a windows specific file in a non windows build. +#endif + + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + DWORD dwIndex = TlsAlloc(); + if (dwIndex == TLS_OUT_OF_INDEXES) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return OS_INVALID_TLS_INDEX; + } + + return dwIndex; +} + + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsSetValue(nIndex, lpvValue)) + return true; + else + return false; +} + + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsFree(nIndex)) + return true; + else + return false; +} diff --git a/src/3rdparty/angle/src/compiler/parseConst.cpp b/src/3rdparty/angle/src/compiler/parseConst.cpp new file mode 100644 index 0000000000..9a8a50c31c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/parseConst.cpp @@ -0,0 +1,238 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/ParseHelper.h" + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TConstTraverser : public TIntermTraverser { +public: + TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t) + : error(false), + index(0), + unionArray(cUnion), + type(t), + constructorType(constructType), + singleConstantParam(singleConstParam), + infoSink(sink), + symbolTable(symTable), + size(0), + isMatrix(false), + matrixSize(0) { + } + + bool error; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); + + int index; + ConstantUnion *unionArray; + TType type; + TOperator constructorType; + bool singleConstantParam; + TInfoSink& infoSink; + TSymbolTable& symbolTable; + int size; // size of the constructor ( 4 for vec4) + bool isMatrix; + int matrixSize; // dimension of the matrix (nominal size and not the instance size) +}; + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TConstTraverser::visitSymbol(TIntermSymbol* node) +{ + infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine()); + return; + +} + +bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TQualifier qualifier = node->getType().getQualifier(); + + if (qualifier != EvqConst) { + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); + error = true; + return false; + } + + infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine()); + + return false; +} + +bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); + error = true; + return false; +} + +bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + if (!node->isConstructor() && node->getOp() != EOpComma) { + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, buf.c_str(), node->getLine()); + error = true; + return false; + } + + if (node->getSequence().size() == 0) { + error = true; + return false; + } + + bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); + if (flag) + { + singleConstantParam = true; + constructorType = node->getOp(); + size = node->getType().getObjectSize(); + + if (node->getType().isMatrix()) { + isMatrix = true; + matrixSize = node->getType().getNominalSize(); + } + } + + for (TIntermSequence::iterator p = node->getSequence().begin(); + p != node->getSequence().end(); p++) { + + if (node->getOp() == EOpComma) + index = 0; + + (*p)->traverse(this); + } + if (flag) + { + singleConstantParam = false; + constructorType = EOpNull; + size = 0; + isMatrix = false; + matrixSize = 0; + } + return false; +} + +bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + ConstantUnion* leftUnionArray = unionArray; + int instanceSize = type.getObjectSize(); + + if (index >= instanceSize) + return; + + if (!singleConstantParam) { + int size = node->getType().getObjectSize(); + + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + for (int i=0; i < size; i++) { + if (index >= instanceSize) + return; + leftUnionArray[index] = rightUnionArray[i]; + + (index)++; + } + } else { + int totalSize = index + size; + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + if (!isMatrix) { + int count = 0; + for (int i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + + leftUnionArray[i] = rightUnionArray[count]; + + (index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } else { // for matrix constructors + int count = 0; + int element = index; + for (int i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 ) + leftUnionArray[i] = rightUnionArray[count]; + else + leftUnionArray[i].setFConst(0.0f); + + (index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } + } +} + +bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam) +{ + if (root == 0) + return false; + + TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t); + + root->traverse(&it); + if (it.error) + return true; + else + return false; +} diff --git a/src/3rdparty/angle/src/compiler/preprocessor/atom.c b/src/3rdparty/angle/src/compiler/preprocessor/atom.c new file mode 100644 index 0000000000..39158d2fa1 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/atom.c @@ -0,0 +1,737 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +// +// atom.c +// + +#include +#include +#include + +#include "common/angleutils.h" +#include "compiler/debug.h" +#include "compiler/preprocessor/slglobals.h" + +#undef malloc +#undef realloc +#undef free + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////// String table: ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +static const struct { + int val; + const char *str; +} tokens[] = { + { CPP_AND_OP, "&&" }, + { CPP_AND_ASSIGN, "&=" }, + { CPP_SUB_ASSIGN, "-=" }, + { CPP_MOD_ASSIGN, "%=" }, + { CPP_ADD_ASSIGN, "+=" }, + { CPP_DIV_ASSIGN, "/=" }, + { CPP_MUL_ASSIGN, "*=" }, + { CPP_RIGHT_BRACKET, ":>" }, + { CPP_EQ_OP, "==" }, + { CPP_XOR_OP, "^^" }, + { CPP_XOR_ASSIGN, "^=" }, + { CPP_FLOATCONSTANT, "" }, + { CPP_GE_OP, ">=" }, + { CPP_RIGHT_OP, ">>" }, + { CPP_RIGHT_ASSIGN, ">>=" }, + { CPP_IDENTIFIER, "" }, + { CPP_INTCONSTANT, "" }, + { CPP_LE_OP, "<=" }, + { CPP_LEFT_OP, "<<" }, + { CPP_LEFT_ASSIGN, "<<=" }, + { CPP_LEFT_BRACKET, "<:" }, + { CPP_LEFT_BRACE, "<%" }, + { CPP_DEC_OP, "--" }, + { CPP_RIGHT_BRACE, "%>" }, + { CPP_NE_OP, "!=" }, + { CPP_OR_OP, "||" }, + { CPP_OR_ASSIGN, "|=" }, + { CPP_INC_OP, "++" }, + { CPP_STRCONSTANT, "" }, + { CPP_TYPEIDENTIFIER, "" }, +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////// String table: ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_STRING_TABLE_SIZE 16384 + +typedef struct StringTable_Rec { + char *strings; + int nextFree; + int size; +} StringTable; + +/* + * InitStringTable() - Initialize the string table. + * + */ + +static int InitStringTable(StringTable *stable) +{ + stable->strings = (char *) malloc(INIT_STRING_TABLE_SIZE); + if (!stable->strings) + return 0; + // Zero-th offset means "empty" so don't use it. + stable->nextFree = 1; + stable->size = INIT_STRING_TABLE_SIZE; + return 1; +} // InitStringTable + +/* + * FreeStringTable() - Free the string table. + * + */ + +static void FreeStringTable(StringTable *stable) +{ + if (stable->strings) + free(stable->strings); + stable->strings = NULL; + stable->nextFree = 0; + stable->size = 0; +} // FreeStringTable + +/* + * HashString() - Hash a string with the base hash function. + * + */ + +static int HashString(const char *s) +{ + int hval = 0; + + while (*s) { + hval = (hval*13507 + *s*197) ^ (hval >> 2); + s++; + } + return hval & 0x7fffffff; +} // HashString + +/* + * HashString2() - Hash a string with the incrimenting hash function. + * + */ + +static int HashString2(const char *s) +{ + int hval = 0; + + while (*s) { + hval = (hval*729 + *s*37) ^ (hval >> 1); + s++; + } + return hval; +} // HashString2 + +/* + * AddString() - Add a string to a string table. Return it's offset. + * + */ + +static int AddString(StringTable *stable, const char *s) +{ + int len, loc; + char *str; + + len = (int) strlen(s); + while (stable->nextFree + len + 1 >= stable->size) { + assert(stable->size < 1000000); + str = (char *) malloc(stable->size*2); + memcpy(str, stable->strings, stable->size); + free(stable->strings); + stable->strings = str; + stable->size = stable->size*2; + } + loc = stable->nextFree; + strcpy(&stable->strings[loc], s); + stable->nextFree += len + 1; + return loc; +} // AddString + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////// Hash table: /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_HASH_TABLE_SIZE 2047 +#define HASH_TABLE_MAX_COLLISIONS 3 + +typedef struct HashEntry_Rec { + int index; // String table offset of string representation + int value; // Atom (symbol) value +} HashEntry; + +typedef struct HashTable_Rec { + HashEntry *entry; + int size; + int entries; + int counts[HASH_TABLE_MAX_COLLISIONS + 1]; +} HashTable; + +/* + * InitHashTable() - Initialize the hash table. + * + */ + +static int InitHashTable(HashTable *htable, int fsize) +{ + int ii; + + htable->entry = (HashEntry *) malloc(sizeof(HashEntry)*fsize); + if (!htable->entry) + return 0; + htable->size = fsize; + for (ii = 0; ii < fsize; ii++) { + htable->entry[ii].index = 0; + htable->entry[ii].value = 0; + } + htable->entries = 0; + for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) + htable->counts[ii] = 0; + return 1; +} // InitHashTable + +/* + * FreeHashTable() - Free the hash table. + * + */ + +static void FreeHashTable(HashTable *htable) +{ + if (htable->entry) + free(htable->entry); + htable->entry = NULL; + htable->size = 0; + htable->entries = 0; +} // FreeHashTable + +/* + * Empty() - See if a hash table entry is empty. + * + */ + +static int Empty(HashTable *htable, int hashloc) +{ + assert(hashloc >= 0 && hashloc < htable->size); + if (htable->entry[hashloc].index == 0) { + return 1; + } else { + return 0; + } +} // Empty + +/* + * Match() - See if a hash table entry is matches a string. + * + */ + +static int Match(HashTable *htable, StringTable *stable, const char *s, int hashloc) +{ + int strloc; + + strloc = htable->entry[hashloc].index; + if (!strcmp(s, &stable->strings[strloc])) { + return 1; + } else { + return 0; + } +} // Match + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////// Atom table: /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_ATOM_TABLE_SIZE 1024 + + +struct AtomTable_Rec { + StringTable stable; // String table. + HashTable htable; // Hashes string to atom number and token value. Multiple strings can + // have the same token value but each unique string is a unique atom. + int *amap; // Maps atom value to offset in string table. Atoms all map to unique + // strings except for some undefined values in the lower, fixed part + // of the atom table that map to "". The lowest 256 atoms + // correspond to single character ASCII values except for alphanumeric + // characters and '_', which can be other tokens. Next come the + // language tokens with their atom values equal to the token value. + // Then come predefined atoms, followed by user specified identifiers. + int *arev; // Reversed atom for symbol table use. + int nextFree; + int size; +}; + +static AtomTable latable = { { NULL, 0, 0 }, { NULL, 0, 0, {0} }, NULL, NULL, 0, 0 }; +AtomTable *atable = &latable; + +static int AddAtomFixed(AtomTable *atable, const char *s, int atom); + +/* + * GrowAtomTable() - Grow the atom table to at least "size" if it's smaller. + * + */ + +static int GrowAtomTable(AtomTable *atable, int size) +{ + int *newmap, *newrev; + + if (atable->size < size) { + if (atable->amap) { + newmap = realloc(atable->amap, sizeof(int)*size); + newrev = realloc(atable->arev, sizeof(int)*size); + } else { + newmap = malloc(sizeof(int)*size); + newrev = malloc(sizeof(int)*size); + atable->size = 0; + } + if (!newmap || !newrev) { + /* failed to grow -- error */ + if (newmap) + atable->amap = newmap; + if (newrev) + atable->arev = newrev; + return -1; + } + memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int)); + memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int)); + atable->amap = newmap; + atable->arev = newrev; + atable->size = size; + } + return 0; +} // GrowAtomTable + +/* + * lReverse() - Reverse the bottom 20 bits of a 32 bit int. + * + */ + +static int lReverse(int fval) +{ + unsigned int in = fval; + int result = 0, cnt = 0; + + while(in) { + result <<= 1; + result |= in&1; + in >>= 1; + cnt++; + } + + // Don't use all 31 bits. One million atoms is plenty and sometimes the + // upper bits are used for other things. + + if (cnt < 20) + result <<= 20 - cnt; + return result; +} // lReverse + +/* + * AllocateAtom() - Allocate a new atom. Associated with the "undefined" value of -1. + * + */ + +static int AllocateAtom(AtomTable *atable) +{ + if (atable->nextFree >= atable->size) + GrowAtomTable(atable, atable->nextFree*2); + atable->amap[atable->nextFree] = -1; + atable->arev[atable->nextFree] = lReverse(atable->nextFree); + atable->nextFree++; + return atable->nextFree - 1; +} // AllocateAtom + +/* + * SetAtomValue() - Allocate a new atom associated with "hashindex". + * + */ + +static void SetAtomValue(AtomTable *atable, int atomnumber, int hashindex) +{ + atable->amap[atomnumber] = atable->htable.entry[hashindex].index; + atable->htable.entry[hashindex].value = atomnumber; +} // SetAtomValue + +/* + * FindHashLoc() - Find the hash location for this string. Return -1 it hash table is full. + * + */ + +static int FindHashLoc(AtomTable *atable, const char *s) +{ + int hashloc, hashdelta, count; + int FoundEmptySlot = 0; + int collision[HASH_TABLE_MAX_COLLISIONS + 1]; + + hashloc = HashString(s) % atable->htable.size; + if (!Empty(&atable->htable, hashloc)) { + if (Match(&atable->htable, &atable->stable, s, hashloc)) + return hashloc; + collision[0] = hashloc; + hashdelta = HashString2(s); + count = 0; + while (count < HASH_TABLE_MAX_COLLISIONS) { + hashloc = ((hashloc + hashdelta) & 0x7fffffff) % atable->htable.size; + if (!Empty(&atable->htable, hashloc)) { + if (Match(&atable->htable, &atable->stable, s, hashloc)) { + return hashloc; + } + } else { + FoundEmptySlot = 1; + break; + } + count++; + collision[count] = hashloc; + } + + if (!FoundEmptySlot) { + if (cpp->options.DumpAtomTable) { + int ii; + char str[200]; + snprintf(str, sizeof(str), "*** Hash failed with more than %d collisions. Must increase hash table size. ***", + HASH_TABLE_MAX_COLLISIONS); + CPPShInfoLogMsg(str); + + snprintf(str, sizeof(str), "*** New string \"%s\", hash=%04x, delta=%04x", s, collision[0], hashdelta); + CPPShInfoLogMsg(str); + for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) { + snprintf(str, sizeof(str), "*** Collides on try %d at hash entry %04x with \"%s\"", + ii + 1, collision[ii], GetAtomString(atable, atable->htable.entry[collision[ii]].value)); + CPPShInfoLogMsg(str); + } + } + return -1; + } else { + atable->htable.counts[count]++; + } + } + return hashloc; +} // FindHashLoc + +/* + * IncreaseHashTableSize() + * + */ + +static int IncreaseHashTableSize(AtomTable *atable) +{ + int ii, strloc, oldhashloc, value, size; + AtomTable oldtable; + char *s; + + // Save the old atom table and create a new one: + + oldtable = *atable; + size = oldtable.htable.size*2 + 1; + if (!InitAtomTable(atable, size)) + return 0; + + // Add all the existing values to the new atom table preserving their atom values: + + for (ii = atable->nextFree; ii < oldtable.nextFree; ii++) { + strloc = oldtable.amap[ii]; + s = &oldtable.stable.strings[strloc]; + oldhashloc = FindHashLoc(&oldtable, s); + assert(oldhashloc >= 0); + value = oldtable.htable.entry[oldhashloc].value; + AddAtomFixed(atable, s, value); + } + FreeAtomTable(&oldtable); + return 1; +} // IncreaseHashTableSize + +/* + * LookUpAddStringHash() - Lookup a string in the hash table. If it's not there, add it and + * initialize the atom value in the hash table to 0. Return the hash table index. + */ + +static int LookUpAddStringHash(AtomTable *atable, const char *s) +{ + int hashloc, strloc; + + while(1) { + hashloc = FindHashLoc(atable, s); + if (hashloc >= 0) + break; + IncreaseHashTableSize(atable); + } + + if (Empty(&atable->htable, hashloc)) { + atable->htable.entries++; + strloc = AddString(&atable->stable, s); + atable->htable.entry[hashloc].index = strloc; + atable->htable.entry[hashloc].value = 0; + } + return hashloc; +} // LookUpAddStringHash + +/* + * LookUpAddString() - Lookup a string in the hash table. If it's not there, add it and + * initialize the atom value in the hash table to the next atom number. + * Return the atom value of string. + */ + +int LookUpAddString(AtomTable *atable, const char *s) +{ + int hashindex, atom; + + hashindex = LookUpAddStringHash(atable, s); + atom = atable->htable.entry[hashindex].value; + if (atom == 0) { + atom = AllocateAtom(atable); + SetAtomValue(atable, atom, hashindex); + } + return atom; +} // LookUpAddString + +/* + * GetAtomString() + * + */ + +const char *GetAtomString(AtomTable *atable, int atom) +{ + int soffset; + + if (atom > 0 && atom < atable->nextFree) { + soffset = atable->amap[atom]; + if (soffset > 0 && soffset < atable->stable.nextFree) { + return &atable->stable.strings[soffset]; + } else { + return ""; + } + } else { + if (atom == 0) { + return ""; + } else { + if (atom == EOF) { + return ""; + } else { + return ""; + } + } + } +} // GetAtomString + +/* + * GetReversedAtom() + * + */ + +int GetReversedAtom(AtomTable *atable, int atom) +{ + if (atom > 0 && atom < atable->nextFree) { + return atable->arev[atom]; + } else { + return 0; + } +} // GetReversedAtom + +/* + * AddAtom() - Add a string to the atom, hash and string tables if it isn't already there. + * Return it's atom index. + */ + +int AddAtom(AtomTable *atable, const char *s) +{ + int atom; + + atom = LookUpAddString(atable, s); + return atom; +} // AddAtom + +/* + * AddAtomFixed() - Add an atom to the hash and string tables if it isn't already there. + * Assign it the atom value of "atom". + */ + +static int AddAtomFixed(AtomTable *atable, const char *s, int atom) +{ + int hashindex, lsize; + + hashindex = LookUpAddStringHash(atable, s); + if (atable->nextFree >= atable->size || atom >= atable->size) { + lsize = atable->size*2; + if (lsize <= atom) + lsize = atom + 1; + GrowAtomTable(atable, lsize); + } + atable->amap[atom] = atable->htable.entry[hashindex].index; + atable->htable.entry[hashindex].value = atom; + //if (atom >= atable->nextFree) + // atable->nextFree = atom + 1; + while (atom >= atable->nextFree) { + atable->arev[atable->nextFree] = lReverse(atable->nextFree); + atable->nextFree++; + } + return atom; +} // AddAtomFixed + +/* + * InitAtomTable() - Initialize the atom table. + * + */ + +int InitAtomTable(AtomTable *atable, int htsize) +{ + unsigned int ii; + + htsize = htsize <= 0 ? INIT_HASH_TABLE_SIZE : htsize; + if (!InitStringTable(&atable->stable)) + return 0; + if (!InitHashTable(&atable->htable, htsize)) + return 0; + + atable->nextFree = 0; + atable->amap = NULL; + atable->size = 0; + GrowAtomTable(atable, INIT_ATOM_TABLE_SIZE); + if (!atable->amap) + return 0; + + // Initialize lower part of atom table to "" atom: + + AddAtomFixed(atable, "", 0); + for (ii = 0; ii < FIRST_USER_TOKEN_SY; ii++) + atable->amap[ii] = atable->amap[0]; + + // Add single character tokens to the atom table: + + { + const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#"; + char t[2]; + + t[1] = '\0'; + while (*s) { + t[0] = *s; + AddAtomFixed(atable, t, s[0]); + s++; + } + } + + // Add multiple character scanner tokens : + + for (ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++) + AddAtomFixed(atable, tokens[ii].str, tokens[ii].val); + + // Add error symbol if running in error mode: + + if (cpp->options.ErrorMode) + AddAtomFixed(atable, "error", ERROR_SY); + + AddAtom(atable, "<*** end fixed atoms ***>"); + + return 1; +} // InitAtomTable + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// Debug Printing Functions: ////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +/* + * PrintAtomTable() + * + */ + +void PrintAtomTable(AtomTable *atable) +{ + int ii; + char str[200]; + + for (ii = 0; ii < atable->nextFree; ii++) { + snprintf(str, sizeof(str), "%d: \"%s\"", ii, &atable->stable.strings[atable->amap[ii]]); + CPPDebugLogMsg(str); + } + snprintf(str, sizeof(str), "Hash table: size=%d, entries=%d, collisions=", + atable->htable.size, atable->htable.entries); + CPPDebugLogMsg(str); + for (ii = 0; ii < HASH_TABLE_MAX_COLLISIONS; ii++) { + snprintf(str, sizeof(str), " %d", atable->htable.counts[ii]); + CPPDebugLogMsg(str); + } + +} // PrintAtomTable + + +/* + * GetStringOfAtom() + * + */ + +char* GetStringOfAtom(AtomTable *atable, int atom) +{ + char* chr_str; + chr_str=&atable->stable.strings[atable->amap[atom]]; + return chr_str; +} // GetStringOfAtom + +/* + * FreeAtomTable() - Free the atom table and associated memory + * + */ + +void FreeAtomTable(AtomTable *atable) +{ + FreeStringTable(&atable->stable); + FreeHashTable(&atable->htable); + if (atable->amap) + free(atable->amap); + if (atable->arev) + free(atable->arev); + atable->amap = NULL; + atable->arev = NULL; + atable->nextFree = 0; + atable->size = 0; +} // FreeAtomTable + +/////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// End of atom.c /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/atom.h b/src/3rdparty/angle/src/compiler/preprocessor/atom.h new file mode 100644 index 0000000000..1d84c32515 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/atom.h @@ -0,0 +1,63 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// atom.h +// + +#if !defined(__ATOM_H) +#define __ATOM_H 1 + +typedef struct AtomTable_Rec AtomTable; + +extern AtomTable *atable; + +int InitAtomTable(AtomTable *atable, int htsize); +void FreeAtomTable(AtomTable *atable); +int AddAtom(AtomTable *atable, const char *s); +void PrintAtomTable(AtomTable *atable); +int LookUpAddString(AtomTable *atable, const char *s); +const char *GetAtomString(AtomTable *atable, int atom); +int GetReversedAtom(AtomTable *atable, int atom); +char* GetStringOfAtom(AtomTable *atable, int atom); +#endif // !defined(__ATOM_H) diff --git a/src/3rdparty/angle/src/compiler/preprocessor/compile.h b/src/3rdparty/angle/src/compiler/preprocessor/compile.h new file mode 100644 index 0000000000..11808531cc --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/compile.h @@ -0,0 +1,100 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// compile.h +// + +#if !defined(__COMPILE_H) +#define __COMPILE_H 1 + +int InitCPPStruct(void); + +typedef struct Options_Rec{ + const char *profileString; + int ErrorMode; + int Quiet; + + // Debug The Compiler options: + int DumpAtomTable; +} Options; + +#define MAX_IF_NESTING 64 +struct CPPStruct_Rec { + // Public members + SourceLoc *pLastSourceLoc; // Set at the start of each statement by the tree walkers + Options options; // Compile options and parameters + + // Private members + SourceLoc lastSourceLoc; + + // Scanner data: + + SourceLoc *tokenLoc; // Source location of most recent token seen by the scanner + int mostRecentToken; // Most recent token seen by the scanner + InputSrc *currentInput; + int previous_token; + int pastFirstStatement; // used to make sure that #version is the first statement seen in the file, if present + + void *pC; // storing the parseContext of the compile object in cpp. + + // Private members: + SourceLoc ltokenLoc; + int ifdepth; //current #if-#else-#endif nesting in the cpp.c file (pre-processor) + int elsedepth[MAX_IF_NESTING];//Keep a track of #if depth..Max allowed is 64. + int elsetracker; //#if-#else and #endif constructs...Counter. + const char *ErrMsg; + int CompileError; //Indicate compile error when #error, #else,#elif mismatch. + + // + // Globals used to communicate between PaParseStrings() and yy_input()and + // also across the files.(gen_glslang.cpp and scanner.c) + // + int PaWhichStr; // which string we're parsing + const int* PaStrLen; // array of lengths of the PaArgv strings + int PaArgc; // count of strings in the array + const char* const* PaArgv; // our array of strings to parse + unsigned int tokensBeforeEOF : 1; +}; + +#endif // !defined(__COMPILE_H) diff --git a/src/3rdparty/angle/src/compiler/preprocessor/cpp.c b/src/3rdparty/angle/src/compiler/preprocessor/cpp.c new file mode 100644 index 0000000000..8a1076b9df --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/cpp.c @@ -0,0 +1,1118 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cpp.c +// + +#include +#include +#include +#include +#include + +#include "common/angleutils.h" +#include "compiler/preprocessor/slglobals.h" + +#if defined(_MSC_VER) +#pragma warning(disable: 4054) +#pragma warning(disable: 4152) +#pragma warning(disable: 4706) +#endif + +static int CPPif(yystypepp * yylvalpp); + +/* Don't use memory.c's replacements, as we clean up properly here */ +#undef malloc +#undef free + +static int bindAtom = 0; +static int constAtom = 0; +static int defaultAtom = 0; +static int defineAtom = 0; +static int definedAtom = 0; +static int elseAtom = 0; +static int elifAtom = 0; +static int endifAtom = 0; +static int ifAtom = 0; +static int ifdefAtom = 0; +static int ifndefAtom = 0; +static int includeAtom = 0; +static int lineAtom = 0; +static int pragmaAtom = 0; +static int texunitAtom = 0; +static int undefAtom = 0; +static int errorAtom = 0; +static int __LINE__Atom = 0; +static int __FILE__Atom = 0; +static int __VERSION__Atom = 0; +static int versionAtom = 0; +static int extensionAtom = 0; + +static Scope *macros = 0; +#define MAX_MACRO_ARGS 64 + +static SourceLoc ifloc; /* outermost #if */ + +int InitCPP(void) +{ + char buffer[64], *t; + const char *f; + + // Add various atoms needed by the CPP line scanner: + bindAtom = LookUpAddString(atable, "bind"); + constAtom = LookUpAddString(atable, "const"); + defaultAtom = LookUpAddString(atable, "default"); + defineAtom = LookUpAddString(atable, "define"); + definedAtom = LookUpAddString(atable, "defined"); + elifAtom = LookUpAddString(atable, "elif"); + elseAtom = LookUpAddString(atable, "else"); + endifAtom = LookUpAddString(atable, "endif"); + ifAtom = LookUpAddString(atable, "if"); + ifdefAtom = LookUpAddString(atable, "ifdef"); + ifndefAtom = LookUpAddString(atable, "ifndef"); + includeAtom = LookUpAddString(atable, "include"); + lineAtom = LookUpAddString(atable, "line"); + pragmaAtom = LookUpAddString(atable, "pragma"); + texunitAtom = LookUpAddString(atable, "texunit"); + undefAtom = LookUpAddString(atable, "undef"); + errorAtom = LookUpAddString(atable, "error"); + __LINE__Atom = LookUpAddString(atable, "__LINE__"); + __FILE__Atom = LookUpAddString(atable, "__FILE__"); + __VERSION__Atom = LookUpAddString(atable, "__VERSION__"); + versionAtom = LookUpAddString(atable, "version"); + extensionAtom = LookUpAddString(atable, "extension"); + macros = NewScopeInPool(mem_CreatePool(0, 0)); + strcpy(buffer, "PROFILE_"); + t = buffer + strlen(buffer); + f = cpp->options.profileString; + while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1) + *t++ = toupper(*f++); + *t = 0; + + PredefineIntMacro("GL_ES", 1); + PredefineIntMacro("GL_FRAGMENT_PRECISION_HIGH", 1); + + return 1; +} // InitCPP + +int FreeCPP(void) +{ + if (macros) + { + mem_FreePool(macros->pool); + macros = 0; + } + + return 1; +} + +int FinalCPP(void) +{ + if (cpp->ifdepth) + CPPErrorToInfoLog("#if mismatch"); + return 1; +} + +static int CPPdefine(yystypepp * yylvalpp) +{ + int token, name, args[MAX_MACRO_ARGS], argc; + const char *message; + MacroSymbol mac; + Symbol *symb; + SourceLoc dummyLoc; + memset(&mac, 0, sizeof(mac)); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != CPP_IDENTIFIER) { + CPPErrorToInfoLog("#define"); + return token; + } + name = yylvalpp->sc_ident; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(' && !yylvalpp->sc_int) { + // gather arguments + argc = 0; + do { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (argc == 0 && token == ')') break; + if (token != CPP_IDENTIFIER) { + CPPErrorToInfoLog("#define"); + return token; + } + if (argc < MAX_MACRO_ARGS) + args[argc++] = yylvalpp->sc_ident; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } while (token == ','); + if (token != ')') { + CPPErrorToInfoLog("#define"); + return token; + } + mac.argc = argc; + mac.args = mem_Alloc(macros->pool, argc * sizeof(int)); + memcpy(mac.args, args, argc * sizeof(int)); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool); + while (token != '\n') { + if (token == '\\') { + CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language"); + return token; + } else if (token <= 0) { // EOF or error + CPPErrorToInfoLog("unexpected end of input in #define preprocessor directive - expected a newline"); + return 0; + } + RecordToken(mac.body, token, yylvalpp); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + }; + + symb = LookUpSymbol(macros, name); + if (symb) { + if (!symb->details.mac.undef) { + // already defined -- need to make sure they are identical + if (symb->details.mac.argc != mac.argc) goto error; + for (argc=0; argc < mac.argc; argc++) + if (symb->details.mac.args[argc] != mac.args[argc]) + goto error; + RewindTokenStream(symb->details.mac.body); + RewindTokenStream(mac.body); + do { + int old_lval, old_token; + old_token = ReadToken(symb->details.mac.body, yylvalpp); + old_lval = yylvalpp->sc_int; + token = ReadToken(mac.body, yylvalpp); + if (token != old_token || yylvalpp->sc_int != old_lval) { + error: + StoreStr("Macro Redefined"); + StoreStr(GetStringOfAtom(atable,name)); + message=GetStrfromTStr(); + DecLineNumber(); + CPPShInfoLogMsg(message); + IncLineNumber(); + ResetTString(); + break; } + } while (token > 0); + } + //FreeMacro(&symb->details.mac); + } else { + dummyLoc.file = 0; + dummyLoc.line = 0; + symb = AddSymbol(&dummyLoc, macros, name, MACRO_S); + } + symb->details.mac = mac; + return '\n'; +} // CPPdefine + +static int CPPundef(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + Symbol *symb; + if(token == '\n'){ + CPPErrorToInfoLog("#undef"); + return token; + } + if (token != CPP_IDENTIFIER) + goto error; + symb = LookUpSymbol(macros, yylvalpp->sc_ident); + if (symb) { + symb->details.mac.undef = 1; + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + error: + CPPErrorToInfoLog("#undef"); + } + return token; +} // CPPundef + +/* CPPelse -- skip forward to appropriate spot. This is actually used +** to skip to and #endif after seeing an #else, AND to skip to a #else, +** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false +*/ + +static int CPPelse(int matchelse, yystypepp * yylvalpp) +{ + int atom,depth=0; + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + while (token > 0) { + if (token != '#') { + while (token != '\n') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { // EOF or error + CPPErrorToInfoLog("unexpected end of input in #else preprocessor directive - expected a newline"); + return 0; + } + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + continue; + } + if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER) + continue; + atom = yylvalpp->sc_ident; + if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){ + depth++; cpp->ifdepth++; cpp->elsetracker++; + if (cpp->ifdepth > MAX_IF_NESTING) { + CPPErrorToInfoLog("max #if nesting depth exceeded"); + cpp->CompileError = 1; + return 0; + } + // sanity check elsetracker + if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) { + CPPErrorToInfoLog("mismatched #if/#endif statements"); + cpp->CompileError = 1; + return 0; + } + cpp->elsedepth[cpp->elsetracker] = 0; + } + else if (atom == endifAtom) { + if(--depth<0){ + if (cpp->elsetracker) + --cpp->elsetracker; + if (cpp->ifdepth) + --cpp->ifdepth; + break; + } + --cpp->elsetracker; + --cpp->ifdepth; + } + else if (((int)(matchelse) != 0)&& depth==0) { + if (atom == elseAtom ) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); + while (token != '\n') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { // EOF or error + CPPErrorToInfoLog("unexpected end of input following #else preprocessor directive - expected a newline"); + return 0; + } + } + } + break; + } + else if (atom == elifAtom) { + /* we decrement cpp->ifdepth here, because CPPif will increment + * it and we really want to leave it alone */ + if (cpp->ifdepth){ + --cpp->ifdepth; + --cpp->elsetracker; + } + return CPPif(yylvalpp); + } + } + else if((atom==elseAtom) && (!ChkCorrectElseNesting())){ + CPPErrorToInfoLog("#else after a #else"); + cpp->CompileError=1; + return 0; + } + }; + return token; +} + +enum eval_prec { + MIN_PREC, + COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY, + MAX_PREC +}; + +static int op_logor(int a, int b) { return a || b; } +static int op_logand(int a, int b) { return a && b; } +static int op_or(int a, int b) { return a | b; } +static int op_xor(int a, int b) { return a ^ b; } +static int op_and(int a, int b) { return a & b; } +static int op_eq(int a, int b) { return a == b; } +static int op_ne(int a, int b) { return a != b; } +static int op_ge(int a, int b) { return a >= b; } +static int op_le(int a, int b) { return a <= b; } +static int op_gt(int a, int b) { return a > b; } +static int op_lt(int a, int b) { return a < b; } +static int op_shl(int a, int b) { return a << b; } +static int op_shr(int a, int b) { return a >> b; } +static int op_add(int a, int b) { return a + b; } +static int op_sub(int a, int b) { return a - b; } +static int op_mul(int a, int b) { return a * b; } +static int op_div(int a, int b) { return a / b; } +static int op_mod(int a, int b) { return a % b; } +static int op_pos(int a) { return a; } +static int op_neg(int a) { return -a; } +static int op_cmpl(int a) { return ~a; } +static int op_not(int a) { return !a; } + +struct { + int token, prec, (*op)(int, int); +} binop[] = { + { CPP_OR_OP, LOGOR, op_logor }, + { CPP_AND_OP, LOGAND, op_logand }, + { '|', OR, op_or }, + { '^', XOR, op_xor }, + { '&', AND, op_and }, + { CPP_EQ_OP, EQUAL, op_eq }, + { CPP_NE_OP, EQUAL, op_ne }, + { '>', RELATION, op_gt }, + { CPP_GE_OP, RELATION, op_ge }, + { '<', RELATION, op_lt }, + { CPP_LE_OP, RELATION, op_le }, + { CPP_LEFT_OP, SHIFT, op_shl }, + { CPP_RIGHT_OP, SHIFT, op_shr }, + { '+', ADD, op_add }, + { '-', ADD, op_sub }, + { '*', MUL, op_mul }, + { '/', MUL, op_div }, + { '%', MUL, op_mod }, +}; + +struct { + int token, (*op)(int); +} unop[] = { + { '+', op_pos }, + { '-', op_neg }, + { '~', op_cmpl }, + { '!', op_not }, +}; + +#define ALEN(A) (sizeof(A)/sizeof(A[0])) + +static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp) +{ + int i, val; + Symbol *s; + if (token == CPP_IDENTIFIER) { + if (yylvalpp->sc_ident == definedAtom) { + int needclose = 0; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(') { + needclose = 1; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + if (token != CPP_IDENTIFIER) + goto error; + *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident)) + ? !s->details.mac.undef : 0; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (needclose) { + if (token != ')') + goto error; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + return eval(token, prec, res, err, yylvalpp); + } else { + goto error; + } + } else if (token == CPP_INTCONSTANT) { + *res = yylvalpp->sc_int; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } else if (token == '(') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, MIN_PREC, res, err, yylvalpp); + if (!*err) { + if (token != ')') + goto error; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } else { + for (i = ALEN(unop) - 1; i >= 0; i--) { + if (unop[i].token == token) + break; + } + if (i >= 0) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, UNARY, res, err, yylvalpp); + *res = unop[i].op(*res); + } else { + goto error; + } + } + while (!*err) { + if (token == ')' || token == '\n') break; + for (i = ALEN(binop) - 1; i >= 0; i--) { + if (binop[i].token == token) + break; + } + if (i < 0 || binop[i].prec <= prec) + break; + val = *res; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, binop[i].prec, res, err, yylvalpp); + + if (binop[i].op == op_div || binop[i].op == op_mod) + { + if (*res == 0) + { + CPPErrorToInfoLog("preprocessor divide or modulo by zero"); + *err = 1; + return token; + } + } + + *res = binop[i].op(val, *res); + } + return token; +error: + CPPErrorToInfoLog("incorrect preprocessor directive"); + *err = 1; + *res = 0; + return token; +} // eval + +static int CPPif(yystypepp * yylvalpp) { + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + int res = 0, err = 0; + + if (!cpp->ifdepth++) + ifloc = *cpp->tokenLoc; + if(cpp->ifdepth > MAX_IF_NESTING){ + CPPErrorToInfoLog("max #if nesting depth exceeded"); + cpp->CompileError = 1; + return 0; + } + cpp->elsetracker++; + // sanity check elsetracker + if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) { + CPPErrorToInfoLog("mismatched #if/#endif statements"); + cpp->CompileError = 1; + return 0; + } + cpp->elsedepth[cpp->elsetracker] = 0; + + token = eval(token, MIN_PREC, &res, &err, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #if preprocessor directive - expected a newline"); + while (token != '\n') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { // EOF or error + CPPErrorToInfoLog("unexpected end of input in #if preprocessor directive - expected a newline"); + return 0; + } + } + } + if (!res && !err) { + token = CPPelse(1, yylvalpp); + } + + return token; +} // CPPif + +static int CPPifdef(int defined, yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + int name = yylvalpp->sc_ident; + if(++cpp->ifdepth > MAX_IF_NESTING){ + CPPErrorToInfoLog("max #if nesting depth exceeded"); + cpp->CompileError = 1; + return 0; + } + cpp->elsetracker++; + // sanity check elsetracker + if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) { + CPPErrorToInfoLog("mismatched #if/#endif statements"); + cpp->CompileError = 1; + return 0; + } + cpp->elsedepth[cpp->elsetracker] = 0; + + if (token != CPP_IDENTIFIER) { + defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef"); + } else { + Symbol *s = LookUpSymbol(macros, name); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline"); + while (token != '\n') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { // EOF or error + CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline"); + return 0; + } + } + } + if (((s && !s->details.mac.undef) ? 1 : 0) != defined) + token = CPPelse(1, yylvalpp); + } + return token; +} // CPPifdef + +static int CPPline(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if(token=='\n'){ + DecLineNumber(); + CPPErrorToInfoLog("#line"); + IncLineNumber(); + return token; + } + else if (token == CPP_INTCONSTANT) { + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + SetLineNumber(yylvalpp->sc_int); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token == CPP_INTCONSTANT) { + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + SetStringNumber(yylvalpp->sc_int); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if(token!='\n') + CPPErrorToInfoLog("#line"); + } + else if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#line"); + } + } + else{ + CPPErrorToInfoLog("#line"); + } + return token; +} + +static int CPPerror(yystypepp * yylvalpp) { + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + const char *message; + + while (token != '\n') { + if (token <= 0){ + CPPErrorToInfoLog("unexpected end of input in #error preprocessor directive - expected a newline"); + return 0; + }else if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){ + StoreStr(yylvalpp->symbol_name); + }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){ + StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); + }else { + StoreStr(GetStringOfAtom(atable,token)); + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + DecLineNumber(); + //store this msg into the shader's information log..set the Compile Error flag!!!! + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + cpp->CompileError=1; + IncLineNumber(); + return '\n'; +}//CPPerror + +static int CPPpragma(yystypepp * yylvalpp) +{ + char SrcStrName[2]; + char** allTokens; + int tokenCount = 0; + int maxTokenCount = 10; + const char* SrcStr; + int i; + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token=='\n') { + DecLineNumber(); + CPPErrorToInfoLog("#pragma"); + IncLineNumber(); + return token; + } + + allTokens = (char**)malloc(sizeof(char*) * maxTokenCount); + + while (token != '\n') { + if (tokenCount >= maxTokenCount) { + maxTokenCount *= 2; + allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount); + } + switch (token) { + case CPP_IDENTIFIER: + SrcStr = GetAtomString(atable, yylvalpp->sc_ident); + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case CPP_INTCONSTANT: + SrcStr = yylvalpp->symbol_name; + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case CPP_FLOATCONSTANT: + SrcStr = yylvalpp->symbol_name; + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case -1: + // EOF + CPPShInfoLogMsg("#pragma directive must end with a newline"); + goto freeMemoryAndReturnToken; + default: + SrcStrName[0] = token; + SrcStrName[1] = '\0'; + allTokens[tokenCount] = (char*)malloc(2); + strcpy(allTokens[tokenCount++], SrcStrName); + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + + HandlePragma((const char**)allTokens, tokenCount); + +freeMemoryAndReturnToken: + for (i = 0; i < tokenCount; ++i) { + free (allTokens[i]); + } + free (allTokens); + + return token; +} // CPPpragma + +#define ESSL_VERSION_NUMBER 100 +#define ESSL_VERSION_STRING "100" + +static int CPPversion(yystypepp * yylvalpp) +{ + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (cpp->pastFirstStatement == 1) + CPPShInfoLogMsg("#version must occur before any other statement in the program"); + + if(token=='\n'){ + DecLineNumber(); + CPPErrorToInfoLog("#version"); + IncLineNumber(); + return token; + } + if (token != CPP_INTCONSTANT) + CPPErrorToInfoLog("#version"); + + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + //SetVersionNumber(yylvalpp->sc_int); + + if (yylvalpp->sc_int != ESSL_VERSION_NUMBER) + CPPShInfoLogMsg("Version number not supported by ESSL"); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#version"); + } + return token; +} // CPPversion + +static int CPPextension(yystypepp * yylvalpp) +{ + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + char extensionName[MAX_SYMBOL_NAME_LEN + 1]; + + if(token=='\n'){ + DecLineNumber(); + CPPShInfoLogMsg("extension name not specified"); + IncLineNumber(); + return token; + } + + if (token != CPP_IDENTIFIER) + CPPErrorToInfoLog("#extension"); + + strncpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident), MAX_SYMBOL_NAME_LEN); + extensionName[MAX_SYMBOL_NAME_LEN] = '\0'; + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != ':') { + CPPShInfoLogMsg("':' missing after extension name"); + return token; + } + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != CPP_IDENTIFIER) { + CPPShInfoLogMsg("behavior for extension not specified"); + return token; + } + + updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident)); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#extension"); + } + return token; +} // CPPextension + +int readCPPline(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + const char *message; + + if (token == CPP_IDENTIFIER) { + if (yylvalpp->sc_ident == defineAtom) { + token = CPPdefine(yylvalpp); + } else if (yylvalpp->sc_ident == elseAtom) { + if(ChkCorrectElseNesting()){ + if (!cpp->ifdepth ){ + CPPErrorToInfoLog("#else mismatch"); + cpp->CompileError=1; + return 0; + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); + while (token != '\n') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { // EOF or error + CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline"); + return 0; + } + } + } + token = CPPelse(0, yylvalpp); + }else{ + CPPErrorToInfoLog("#else after a #else"); + cpp->ifdepth = 0; + cpp->elsetracker = 0; + cpp->pastFirstStatement = 1; + cpp->CompileError = 1; + return 0; + } + } else if (yylvalpp->sc_ident == elifAtom) { + if (!cpp->ifdepth){ + CPPErrorToInfoLog("#elif mismatch"); + cpp->CompileError=1; + return 0; + } + // this token is really a dont care, but we still need to eat the tokens + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + while (token != '\n') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { // EOF or error + CPPErrorToInfoLog("unexpect tokens following #elif preprocessor directive - expected a newline"); + cpp->CompileError = 1; + return 0; + } + } + token = CPPelse(0, yylvalpp); + } else if (yylvalpp->sc_ident == endifAtom) { + if (!cpp->ifdepth){ + CPPErrorToInfoLog("#endif mismatch"); + cpp->CompileError=1; + return 0; + } + else + --cpp->ifdepth; + + if (cpp->elsetracker) + --cpp->elsetracker; + + } else if (yylvalpp->sc_ident == ifAtom) { + token = CPPif(yylvalpp); + } else if (yylvalpp->sc_ident == ifdefAtom) { + token = CPPifdef(1, yylvalpp); + } else if (yylvalpp->sc_ident == ifndefAtom) { + token = CPPifdef(0, yylvalpp); + } else if (yylvalpp->sc_ident == lineAtom) { + token = CPPline(yylvalpp); + } else if (yylvalpp->sc_ident == pragmaAtom) { + token = CPPpragma(yylvalpp); + } else if (yylvalpp->sc_ident == undefAtom) { + token = CPPundef(yylvalpp); + } else if (yylvalpp->sc_ident == errorAtom) { + token = CPPerror(yylvalpp); + } else if (yylvalpp->sc_ident == versionAtom) { + token = CPPversion(yylvalpp); + } else if (yylvalpp->sc_ident == extensionAtom) { + token = CPPextension(yylvalpp); + } else { + StoreStr("Invalid Directive"); + StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } + } + while (token != '\n' && token != 0 && token != EOF) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + + cpp->pastFirstStatement = 1; + + return token; +} // readCPPline + +void FreeMacro(MacroSymbol *s) { + DeleteTokenStream(s->body); +} + +void PredefineIntMacro(const char *name, int value) { + SourceLoc location = {0, 0}; + Symbol *symbol = NULL; + MacroSymbol macro = {0, NULL, NULL, 0, 0}; + yystypepp val = {0, 0.0, 0, {0}}; + int atom = 0; + + macro.body = NewTokenStream(name, macros->pool); + val.sc_int = value; + snprintf(val.symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", value); + RecordToken(macro.body, CPP_INTCONSTANT, &val); + atom = LookUpAddString(atable, name); + symbol = AddSymbol(&location, macros, atom, MACRO_S); + symbol->details.mac = macro; +} + +static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; } +static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { } + +static void PushEofSrc() { + InputSrc *in = malloc(sizeof(InputSrc)); + memset(in, 0, sizeof(InputSrc)); + in->scan = eof_scan; + in->getch = eof_scan; + in->ungetch = noop; + in->prev = cpp->currentInput; + cpp->currentInput = in; +} + +static void PopEofSrc() { + if (cpp->currentInput->scan == eof_scan) { + InputSrc *in = cpp->currentInput; + cpp->currentInput = in->prev; + free(in); + } +} + +static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) { + int token; + TokenStream *n; + RewindTokenStream(a); + do { + token = ReadToken(a, yylvalpp); + if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident)) + break; + } while (token > 0); + if (token <= 0) return a; + n = NewTokenStream("macro arg", 0); + PushEofSrc(); + ReadFromTokenStream(a, 0, 0); + while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) { + if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp)) + continue; + RecordToken(n, token, yylvalpp); + } + PopEofSrc(); + DeleteTokenStream(a); + return n; +} // PrescanMacroArg + +typedef struct MacroInputSrc { + InputSrc base; + MacroSymbol *mac; + TokenStream **args; +} MacroInputSrc; + +/* macro_scan --- +** return the next token for a macro expanion, handling macro args +*/ +static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) { + int i; + int token = ReadToken(in->mac->body, yylvalpp); + if (token == CPP_IDENTIFIER) { + for (i = in->mac->argc-1; i>=0; i--) + if (in->mac->args[i] == yylvalpp->sc_ident) break; + if (i >= 0) { + ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0); + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } + if (token > 0) return token; + in->mac->busy = 0; + cpp->currentInput = in->base.prev; + if (in->args) { + for (i=in->mac->argc-1; i>=0; i--) + DeleteTokenStream(in->args[i]); + free(in->args); + } + free(in); + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); +} // macro_scan + +/* MacroExpand +** check an identifier (atom) to see if it a macro that should be expanded. +** If it is, push an InputSrc that will produce the appropriate expansion +** and return TRUE. If not, return FALSE. +*/ + +int MacroExpand(int atom, yystypepp * yylvalpp) +{ + Symbol *sym = LookUpSymbol(macros, atom); + MacroInputSrc *in; + int i,j, token, depth=0; + const char *message; + if (atom == __LINE__Atom) { + yylvalpp->sc_int = GetLineNumber(); + snprintf(yylvalpp->symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", yylvalpp->sc_int); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (atom == __FILE__Atom) { + yylvalpp->sc_int = GetStringNumber(); + snprintf(yylvalpp->symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", yylvalpp->sc_int); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (atom == __VERSION__Atom) { + strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING); + yylvalpp->sc_int = atoi(yylvalpp->symbol_name); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (!sym || sym->details.mac.undef) return 0; + if (sym->details.mac.busy) return 0; // no recursive expansions + in = malloc(sizeof(*in)); + memset(in, 0, sizeof(*in)); + in->base.scan = (void *)macro_scan; + in->base.line = cpp->currentInput->line; + in->base.name = cpp->currentInput->name; + in->mac = &sym->details.mac; + if (sym->details.mac.args) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '(') { + UngetToken(token, yylvalpp); + yylvalpp->sc_ident = atom; + return 0; + } + in->args = malloc(in->mac->argc * sizeof(TokenStream *)); + for (i=0; imac->argc; i++) + in->args[i] = NewTokenStream("macro arg", 0); + i=0;j=0; + do{ + depth = 0; + while(1) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { + StoreStr("EOF in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + return 1; + } + if((in->mac->argc==0) && (token!=')')) break; + if (depth == 0 && (token == ',' || token == ')')) break; + if (token == '(') depth++; + if (token == ')') depth--; + RecordToken(in->args[i], token, yylvalpp); + j=1; + } + if (token == ')') { + if((in->mac->argc==1) &&j==0) + break; + i++; + break; + } + i++; + }while(i < in->mac->argc); + + if (i < in->mac->argc) { + StoreStr("Too few args in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } else if (token != ')') { + depth=0; + while (token >= 0 && (depth > 0 || token != ')')) { + if (token == ')') depth--; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(') depth++; + } + + if (token <= 0) { + StoreStr("EOF in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + return 1; + } + StoreStr("Too many args in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } + for (i=0; imac->argc; i++) { + in->args[i] = PrescanMacroArg(in->args[i], yylvalpp); + } + } +#if 0 + printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file), + loc.line, GetAtomString(atable, atom)); + for (i=0; imac->argc; i++) { + printf("\targ %s = '", GetAtomString(atable, in->mac->args[i])); + DumpTokenStream(stdout, in->args[i]); + printf("'\n"); + } +#endif + /*retain the input source*/ + in->base.prev = cpp->currentInput; + sym->details.mac.busy = 1; + RewindTokenStream(sym->details.mac.body); + cpp->currentInput = &in->base; + return 1; +} // MacroExpand + +int ChkCorrectElseNesting(void) +{ + // sanity check to make sure elsetracker is in a valid range + if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) { + return 0; + } + + if (cpp->elsedepth[cpp->elsetracker] == 0) { + cpp->elsedepth[cpp->elsetracker] = 1; + return 1; + } + return 0; +} + + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/cpp.h b/src/3rdparty/angle/src/compiler/preprocessor/cpp.h new file mode 100644 index 0000000000..802e23ef07 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/cpp.h @@ -0,0 +1,86 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cpp.h +// + +#if !defined(__CPP_H) +#define __CPP_H 1 + +#include "compiler/preprocessor/parser.h" +#include "compiler/preprocessor/tokens.h" + +int InitCPP(void); +int FinalCPP(void); +int readCPPline(yystypepp * yylvalpp); +int MacroExpand(int atom, yystypepp * yylvalpp); +int ChkCorrectElseNesting(void); + +typedef struct MacroSymbol { + int argc; + int *args; + TokenStream *body; + unsigned busy:1; + unsigned undef:1; +} MacroSymbol; + +void FreeMacro(MacroSymbol *); +void PredefineIntMacro(const char *name, int value); + +void CPPDebugLogMsg(const char *msg); // Prints information into debug log +void CPPShInfoLogMsg(const char*); // Store cpp Err Msg into Sh.Info.Log +void CPPWarningToInfoLog(const char *msg); // Prints warning messages into info log +void HandlePragma(const char**, int numTokens); // #pragma directive container. +void ResetTString(void); // #error Message as TString. +void CPPErrorToInfoLog(const char*); // Stick all cpp errors into Sh.Info.log. +void StoreStr(const char*); // Store the TString in Parse Context. +void SetLineNumber(int); // Set line number. +void SetStringNumber(int); // Set string number. +int GetLineNumber(void); // Get the current String Number. +int GetStringNumber(void); // Get the current String Number. +const char* GetStrfromTStr(void); // Convert TString to String. +void updateExtensionBehavior(const char* extName, const char* behavior); +int FreeCPP(void); + +#endif // !(defined(__CPP_H) diff --git a/src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c b/src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c new file mode 100644 index 0000000000..58cff31091 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c @@ -0,0 +1,152 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cppstruct.c +// + +#include +#include + +#include "compiler/preprocessor/slglobals.h" + +CPPStruct *cpp = NULL; +static int refCount = 0; + +int InitPreprocessor(void); +int ResetPreprocessor(void); +int FreeCPPStruct(void); +int FinalizePreprocessor(void); + +/* + * InitCPPStruct() - Initilaize the CPP structure. + * + */ + +int InitCPPStruct(void) +{ + int len; + char *p; + + cpp = (CPPStruct *) malloc(sizeof(CPPStruct)); + if (cpp == NULL) + return 0; + + refCount++; + + // Initialize public members: + cpp->pLastSourceLoc = &cpp->lastSourceLoc; + + p = (char *) &cpp->options; + len = sizeof(cpp->options); + while (--len >= 0) + p[len] = 0; + + ResetPreprocessor(); + return 1; +} // InitCPPStruct + +int ResetPreprocessor(void) +{ + // Initialize private members: + + cpp->lastSourceLoc.file = 0; + cpp->lastSourceLoc.line = 0; + cpp->pC = 0; + cpp->CompileError = 0; + cpp->ifdepth = 0; + for(cpp->elsetracker = 0; cpp->elsetracker < MAX_IF_NESTING; cpp->elsetracker++) + cpp->elsedepth[cpp->elsetracker] = 0; + cpp->elsetracker = 0; + cpp->tokensBeforeEOF = 0; + return 1; +} + +//Intializing the Preprocessor. + +int InitPreprocessor(void) +{ + # define CPP_STUFF true + # ifdef CPP_STUFF + FreeCPPStruct(); + InitCPPStruct(); + cpp->options.Quiet = 1; + cpp->options.profileString = "generic"; + if (!InitAtomTable(atable, 0)) + return 1; + if (!InitScanner(cpp)) + return 1; + # endif + return 0; +} + +//FreeCPPStruct() - Free the CPP structure. + +int FreeCPPStruct(void) +{ + if (refCount) + { + free(cpp); + refCount--; + } + + return 1; +} + +//Finalizing the Preprocessor. + +int FinalizePreprocessor(void) +{ + # define CPP_STUFF true + # ifdef CPP_STUFF + FreeAtomTable(atable); + FreeCPPStruct(); + FreeScanner(); + # endif + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// End of cppstruct.c ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h b/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h new file mode 100644 index 0000000000..4f1f71319f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// length_limits.h +// + +#if !defined(__LENGTH_LIMITS_H) +#define __LENGTH_LIMITS_H 1 + +// These constants are factored out from the rest of the headers to +// make it easier to reference them from the compiler sources. + +// These lengths do not include the NULL terminator. +#define MAX_SYMBOL_NAME_LEN 256 +#define MAX_STRING_LEN 511 + +#endif // !(defined(__LENGTH_LIMITS_H) diff --git a/src/3rdparty/angle/src/compiler/preprocessor/memory.c b/src/3rdparty/angle/src/compiler/preprocessor/memory.c new file mode 100644 index 0000000000..029521a559 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/memory.c @@ -0,0 +1,158 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +#include +#include +#include + +#ifndef _MSC_VER +#include +#endif + +#include "compiler/preprocessor/memory.h" + +#if defined(_MSC_VER) +#pragma warning(disable: 4706) +#endif + +// default alignment and chunksize, if called with 0 arguments +#define CHUNKSIZE (64*1024) +#define ALIGN 8 + +// we need to call the `real' malloc and free, not our replacements +#undef malloc +#undef free + +struct chunk { + struct chunk *next; +}; + +struct cleanup { + struct cleanup *next; + void (*fn)(void *); + void *arg; +}; + +struct MemoryPool_rec { + struct chunk *next; + uintptr_t free, end; + size_t chunksize; + uintptr_t alignmask; + struct cleanup *cleanup; +}; + +MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align) +{ + MemoryPool *pool; + + if (align == 0) align = ALIGN; + if (chunksize == 0) chunksize = CHUNKSIZE; + if (align & (align-1)) return 0; + if (chunksize < sizeof(MemoryPool)) return 0; + if (chunksize & (align-1)) return 0; + if (!(pool = malloc(chunksize))) return 0; + pool->next = 0; + pool->chunksize = chunksize; + pool->alignmask = (uintptr_t)(align)-1; + pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask; + pool->end = (uintptr_t)pool + chunksize; + pool->cleanup = 0; + return pool; +} + +void mem_FreePool(MemoryPool *pool) +{ + struct cleanup *cleanup; + struct chunk *p, *next; + + for (cleanup = pool->cleanup; cleanup; cleanup = cleanup->next) { + cleanup->fn(cleanup->arg); + } + for (p = (struct chunk *)pool; p; p = next) { + next = p->next; + free(p); + } +} + +void *mem_Alloc(MemoryPool *pool, size_t size) +{ + struct chunk *ch; + void *rv = (void *)pool->free; + size = (size + pool->alignmask) & ~pool->alignmask; + if (size <= 0) size = pool->alignmask; + pool->free += size; + if (pool->free > pool->end || pool->free < (uintptr_t)rv) { + size_t minreq = (size + sizeof(struct chunk) + pool->alignmask) + & ~pool->alignmask; + pool->free = (uintptr_t)rv; + if (minreq >= pool->chunksize) { + // request size is too big for the chunksize, so allocate it as + // a single chunk of the right size + ch = malloc(minreq); + if (!ch) return 0; + } else { + ch = malloc(pool->chunksize); + if (!ch) return 0; + pool->free = (uintptr_t)ch + minreq; + pool->end = (uintptr_t)ch + pool->chunksize; + } + ch->next = pool->next; + pool->next = ch; + rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask); + } + return rv; +} + +int mem_AddCleanup(MemoryPool *pool, void (*fn)(void *), void *arg) { + struct cleanup *cleanup; + + pool->free = (pool->free + sizeof(void *) - 1) & ~(sizeof(void *)-1); + cleanup = mem_Alloc(pool, sizeof(struct cleanup)); + if (!cleanup) return -1; + cleanup->next = pool->cleanup; + cleanup->fn = fn; + cleanup->arg = arg; + pool->cleanup = cleanup; + return 0; +} diff --git a/src/3rdparty/angle/src/compiler/preprocessor/memory.h b/src/3rdparty/angle/src/compiler/preprocessor/memory.h new file mode 100644 index 0000000000..5fcadb32f6 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/memory.h @@ -0,0 +1,58 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +#ifndef __MEMORY_H +#define __MEMORY_H + +#include + +typedef struct MemoryPool_rec MemoryPool; + +extern MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align); +extern void mem_FreePool(MemoryPool *); +extern void *mem_Alloc(MemoryPool *p, size_t size); +extern void *mem_Realloc(MemoryPool *p, void *old, size_t oldsize, size_t newsize); +extern int mem_AddCleanup(MemoryPool *p, void (*fn)(void *), void *arg); + +#endif /* __MEMORY_H */ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp new file mode 100644 index 0000000000..3f50dfc98a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp @@ -0,0 +1,127 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "Diagnostics.h" + +#include + +namespace pp +{ + +Diagnostics::~Diagnostics() +{ +} + +void Diagnostics::report(ID id, + const SourceLocation& loc, + const std::string& text) +{ + // TODO(alokp): Keep a count of errors and warnings. + print(id, loc, text); +} + +Diagnostics::Severity Diagnostics::severity(ID id) +{ + if ((id > ERROR_BEGIN) && (id < ERROR_END)) + return ERROR; + + if ((id > WARNING_BEGIN) && (id < WARNING_END)) + return WARNING; + + assert(false); + return ERROR; +} + +std::string Diagnostics::message(ID id) +{ + switch (id) + { + // Errors begin. + case INTERNAL_ERROR: + return "internal error"; + case OUT_OF_MEMORY: + return "out of memory"; + case INVALID_CHARACTER: + return "invalid character"; + case INVALID_NUMBER: + return "invalid number"; + case INTEGER_OVERFLOW: + return "integer overflow"; + case FLOAT_OVERFLOW: + return "float overflow"; + case TOKEN_TOO_LONG: + return "token too long"; + case INVALID_EXPRESSION: + return "invalid expression"; + case DIVISION_BY_ZERO: + return "division by zero"; + case EOF_IN_COMMENT: + return "unexpected end of file found in comment"; + case UNEXPECTED_TOKEN: + return "unexpected token"; + case DIRECTIVE_INVALID_NAME: + return "invalid directive name"; + case MACRO_NAME_RESERVED: + return "macro name is reserved"; + case MACRO_REDEFINED: + return "macro redefined"; + case MACRO_PREDEFINED_REDEFINED: + return "predefined macro redefined"; + case MACRO_PREDEFINED_UNDEFINED: + return "predefined macro undefined"; + case MACRO_UNTERMINATED_INVOCATION: + return "unterminated macro invocation"; + case MACRO_TOO_FEW_ARGS: + return "Not enough arguments for macro"; + case MACRO_TOO_MANY_ARGS: + return "Too many arguments for macro"; + case CONDITIONAL_ENDIF_WITHOUT_IF: + return "unexpected #endif found without a matching #if"; + case CONDITIONAL_ELSE_WITHOUT_IF: + return "unexpected #else found without a matching #if"; + case CONDITIONAL_ELSE_AFTER_ELSE: + return "unexpected #else found after another #else"; + case CONDITIONAL_ELIF_WITHOUT_IF: + return "unexpected #elif found without a matching #if"; + case CONDITIONAL_ELIF_AFTER_ELSE: + return "unexpected #elif found after #else"; + case CONDITIONAL_UNTERMINATED: + return "unexpected end of file found in conditional block"; + case INVALID_EXTENSION_NAME: + return "invalid extension name"; + case INVALID_EXTENSION_BEHAVIOR: + return "invalid extension behavior"; + case INVALID_EXTENSION_DIRECTIVE: + return "invalid extension directive"; + case INVALID_VERSION_NUMBER: + return "invalid version number"; + case INVALID_VERSION_DIRECTIVE: + return "invalid version directive"; + case VERSION_NOT_FIRST_STATEMENT: + return "#version directive must occur before anything else, " + "except for comments and white space"; + case INVALID_LINE_NUMBER: + return "invalid line number"; + case INVALID_FILE_NUMBER: + return "invalid file number"; + case INVALID_LINE_DIRECTIVE: + return "invalid line directive"; + // Errors end. + // Warnings begin. + case EOF_IN_DIRECTIVE: + return "unexpected end of file found in directive"; + case CONDITIONAL_UNEXPECTED_TOKEN: + return "unexpected token after conditional expression"; + case UNRECOGNIZED_PRAGMA: + return "unrecognized pragma"; + // Warnings end. + default: + assert(false); + return ""; + } +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h new file mode 100644 index 0000000000..07bc411846 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h @@ -0,0 +1,87 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ +#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ + +#include + +namespace pp +{ + +struct SourceLocation; + +// Base class for reporting diagnostic messages. +// Derived classes are responsible for formatting and printing the messages. +class Diagnostics +{ + public: + enum Severity + { + ERROR, + WARNING + }; + enum ID + { + ERROR_BEGIN, + INTERNAL_ERROR, + OUT_OF_MEMORY, + INVALID_CHARACTER, + INVALID_NUMBER, + INTEGER_OVERFLOW, + FLOAT_OVERFLOW, + TOKEN_TOO_LONG, + INVALID_EXPRESSION, + DIVISION_BY_ZERO, + EOF_IN_COMMENT, + UNEXPECTED_TOKEN, + DIRECTIVE_INVALID_NAME, + MACRO_NAME_RESERVED, + MACRO_REDEFINED, + MACRO_PREDEFINED_REDEFINED, + MACRO_PREDEFINED_UNDEFINED, + MACRO_UNTERMINATED_INVOCATION, + MACRO_TOO_FEW_ARGS, + MACRO_TOO_MANY_ARGS, + CONDITIONAL_ENDIF_WITHOUT_IF, + CONDITIONAL_ELSE_WITHOUT_IF, + CONDITIONAL_ELSE_AFTER_ELSE, + CONDITIONAL_ELIF_WITHOUT_IF, + CONDITIONAL_ELIF_AFTER_ELSE, + CONDITIONAL_UNTERMINATED, + INVALID_EXTENSION_NAME, + INVALID_EXTENSION_BEHAVIOR, + INVALID_EXTENSION_DIRECTIVE, + INVALID_VERSION_NUMBER, + INVALID_VERSION_DIRECTIVE, + VERSION_NOT_FIRST_STATEMENT, + INVALID_LINE_NUMBER, + INVALID_FILE_NUMBER, + INVALID_LINE_DIRECTIVE, + ERROR_END, + + WARNING_BEGIN, + EOF_IN_DIRECTIVE, + CONDITIONAL_UNEXPECTED_TOKEN, + UNRECOGNIZED_PRAGMA, + WARNING_END + }; + + virtual ~Diagnostics(); + + void report(ID id, const SourceLocation& loc, const std::string& text); + + protected: + Severity severity(ID id); + std::string message(ID id); + + virtual void print(ID id, + const SourceLocation& loc, + const std::string& text) = 0; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp new file mode 100644 index 0000000000..ca91e1c71b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp @@ -0,0 +1,16 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "DirectiveHandler.h" + +namespace pp +{ + +DirectiveHandler::~DirectiveHandler() +{ +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h new file mode 100644 index 0000000000..2aaeec2818 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ + +#include + +namespace pp +{ + +struct SourceLocation; + +// Base class for handling directives. +// Preprocessor uses this class to notify the clients about certain +// preprocessor directives. Derived classes are responsible for +// handling them in an appropriate manner. +class DirectiveHandler +{ + public: + virtual ~DirectiveHandler(); + + virtual void handleError(const SourceLocation& loc, + const std::string& msg) = 0; + + // Handle pragma of form: #pragma name[(value)] + virtual void handlePragma(const SourceLocation& loc, + const std::string& name, + const std::string& value) = 0; + + virtual void handleExtension(const SourceLocation& loc, + const std::string& name, + const std::string& behavior) = 0; + + virtual void handleVersion(const SourceLocation& loc, + int version) = 0; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp new file mode 100644 index 0000000000..f2e42d06bf --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp @@ -0,0 +1,932 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "DirectiveParser.h" + +#include +#include +#include + +#include "Diagnostics.h" +#include "DirectiveHandler.h" +#include "ExpressionParser.h" +#include "MacroExpander.h" +#include "Token.h" +#include "Tokenizer.h" + +namespace { +enum DirectiveType +{ + DIRECTIVE_NONE, + DIRECTIVE_DEFINE, + DIRECTIVE_UNDEF, + DIRECTIVE_IF, + DIRECTIVE_IFDEF, + DIRECTIVE_IFNDEF, + DIRECTIVE_ELSE, + DIRECTIVE_ELIF, + DIRECTIVE_ENDIF, + DIRECTIVE_ERROR, + DIRECTIVE_PRAGMA, + DIRECTIVE_EXTENSION, + DIRECTIVE_VERSION, + DIRECTIVE_LINE +}; +} // namespace + +static DirectiveType getDirective(const pp::Token* token) +{ + static const std::string kDirectiveDefine("define"); + static const std::string kDirectiveUndef("undef"); + static const std::string kDirectiveIf("if"); + static const std::string kDirectiveIfdef("ifdef"); + static const std::string kDirectiveIfndef("ifndef"); + static const std::string kDirectiveElse("else"); + static const std::string kDirectiveElif("elif"); + static const std::string kDirectiveEndif("endif"); + static const std::string kDirectiveError("error"); + static const std::string kDirectivePragma("pragma"); + static const std::string kDirectiveExtension("extension"); + static const std::string kDirectiveVersion("version"); + static const std::string kDirectiveLine("line"); + + if (token->type != pp::Token::IDENTIFIER) + return DIRECTIVE_NONE; + + if (token->text == kDirectiveDefine) + return DIRECTIVE_DEFINE; + else if (token->text == kDirectiveUndef) + return DIRECTIVE_UNDEF; + else if (token->text == kDirectiveIf) + return DIRECTIVE_IF; + else if (token->text == kDirectiveIfdef) + return DIRECTIVE_IFDEF; + else if (token->text == kDirectiveIfndef) + return DIRECTIVE_IFNDEF; + else if (token->text == kDirectiveElse) + return DIRECTIVE_ELSE; + else if (token->text == kDirectiveElif) + return DIRECTIVE_ELIF; + else if (token->text == kDirectiveEndif) + return DIRECTIVE_ENDIF; + else if (token->text == kDirectiveError) + return DIRECTIVE_ERROR; + else if (token->text == kDirectivePragma) + return DIRECTIVE_PRAGMA; + else if (token->text == kDirectiveExtension) + return DIRECTIVE_EXTENSION; + else if (token->text == kDirectiveVersion) + return DIRECTIVE_VERSION; + else if (token->text == kDirectiveLine) + return DIRECTIVE_LINE; + + return DIRECTIVE_NONE; +} + +static bool isConditionalDirective(DirectiveType directive) +{ + switch (directive) + { + case DIRECTIVE_IF: + case DIRECTIVE_IFDEF: + case DIRECTIVE_IFNDEF: + case DIRECTIVE_ELSE: + case DIRECTIVE_ELIF: + case DIRECTIVE_ENDIF: + return true; + default: + return false; + } +} + +// Returns true if the token represents End Of Directive. +static bool isEOD(const pp::Token* token) +{ + return (token->type == '\n') || (token->type == pp::Token::LAST); +} + +static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token) +{ + while(!isEOD(token)) + { + lexer->lex(token); + } +} + +static bool isMacroNameReserved(const std::string& name) +{ + // Names prefixed with "GL_" are reserved. + if (name.substr(0, 3) == "GL_") + return true; + + // Names containing two consecutive underscores are reserved. + if (name.find("__") != std::string::npos) + return true; + + return false; +} + +static bool isMacroPredefined(const std::string& name, + const pp::MacroSet& macroSet) +{ + pp::MacroSet::const_iterator iter = macroSet.find(name); + return iter != macroSet.end() ? iter->second.predefined : false; +} + +namespace pp +{ + +class DefinedParser : public Lexer +{ + public: + DefinedParser(Lexer* lexer, + const MacroSet* macroSet, + Diagnostics* diagnostics) : + mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics) + { + } + + protected: + virtual void lex(Token* token) + { + static const std::string kDefined("defined"); + + mLexer->lex(token); + if (token->type != Token::IDENTIFIER) + return; + if (token->text != kDefined) + return; + + bool paren = false; + mLexer->lex(token); + if (token->type == '(') + { + paren = true; + mLexer->lex(token); + } + + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mLexer, token); + return; + } + MacroSet::const_iterator iter = mMacroSet->find(token->text); + std::string expression = iter != mMacroSet->end() ? "1" : "0"; + + if (paren) + { + mLexer->lex(token); + if (token->type != ')') + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mLexer, token); + return; + } + } + + // We have a valid defined operator. + // Convert the current token into a CONST_INT token. + token->type = Token::CONST_INT; + token->text = expression; + } + + private: + Lexer* mLexer; + const MacroSet* mMacroSet; + Diagnostics* mDiagnostics; +}; + +DirectiveParser::DirectiveParser(Tokenizer* tokenizer, + MacroSet* macroSet, + Diagnostics* diagnostics, + DirectiveHandler* directiveHandler) : + mPastFirstStatement(false), + mTokenizer(tokenizer), + mMacroSet(macroSet), + mDiagnostics(diagnostics), + mDirectiveHandler(directiveHandler) +{ +} + +void DirectiveParser::lex(Token* token) +{ + do + { + mTokenizer->lex(token); + + if (token->type == Token::PP_HASH) + { + parseDirective(token); + mPastFirstStatement = true; + } + + if (token->type == Token::LAST) + { + if (!mConditionalStack.empty()) + { + const ConditionalBlock& block = mConditionalStack.back(); + mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED, + block.location, block.type); + } + break; + } + + } while (skipping() || (token->type == '\n')); + + mPastFirstStatement = true; +} + +void DirectiveParser::parseDirective(Token* token) +{ + assert(token->type == Token::PP_HASH); + + mTokenizer->lex(token); + if (isEOD(token)) + { + // Empty Directive. + return; + } + + DirectiveType directive = getDirective(token); + + // While in an excluded conditional block/group, + // we only parse conditional directives. + if (skipping() && !isConditionalDirective(directive)) + { + skipUntilEOD(mTokenizer, token); + return; + } + + switch(directive) + { + case DIRECTIVE_NONE: + mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + break; + case DIRECTIVE_DEFINE: + parseDefine(token); + break; + case DIRECTIVE_UNDEF: + parseUndef(token); + break; + case DIRECTIVE_IF: + parseIf(token); + break; + case DIRECTIVE_IFDEF: + parseIfdef(token); + break; + case DIRECTIVE_IFNDEF: + parseIfndef(token); + break; + case DIRECTIVE_ELSE: + parseElse(token); + break; + case DIRECTIVE_ELIF: + parseElif(token); + break; + case DIRECTIVE_ENDIF: + parseEndif(token); + break; + case DIRECTIVE_ERROR: + parseError(token); + break; + case DIRECTIVE_PRAGMA: + parsePragma(token); + break; + case DIRECTIVE_EXTENSION: + parseExtension(token); + break; + case DIRECTIVE_VERSION: + parseVersion(token); + break; + case DIRECTIVE_LINE: + parseLine(token); + break; + default: + assert(false); + break; + } + + skipUntilEOD(mTokenizer, token); + if (token->type == Token::LAST) + { + mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE, + token->location, token->text); + } +} + +void DirectiveParser::parseDefine(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_DEFINE); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + return; + } + if (isMacroPredefined(token->text, *mMacroSet)) + { + mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED, + token->location, token->text); + return; + } + if (isMacroNameReserved(token->text)) + { + mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED, + token->location, token->text); + return; + } + + Macro macro; + macro.type = Macro::kTypeObj; + macro.name = token->text; + + mTokenizer->lex(token); + if (token->type == '(' && !token->hasLeadingSpace()) + { + // Function-like macro. Collect arguments. + macro.type = Macro::kTypeFunc; + do { + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + break; + macro.parameters.push_back(token->text); + + mTokenizer->lex(token); // Get ','. + } while (token->type == ','); + + if (token->type != ')') + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, + token->text); + return; + } + mTokenizer->lex(token); // Get ')'. + } + + while ((token->type != '\n') && (token->type != Token::LAST)) + { + // Reset the token location because it is unnecessary in replacement + // list. Resetting it also allows us to reuse Token::equals() to + // compare macros. + token->location = SourceLocation(); + macro.replacements.push_back(*token); + mTokenizer->lex(token); + } + if (!macro.replacements.empty()) + { + // Whitespace preceding the replacement list is not considered part of + // the replacement list for either form of macro. + macro.replacements.front().setHasLeadingSpace(false); + } + + // Check for macro redefinition. + MacroSet::const_iterator iter = mMacroSet->find(macro.name); + if (iter != mMacroSet->end() && !macro.equals(iter->second)) + { + mDiagnostics->report(Diagnostics::MACRO_REDEFINED, + token->location, + macro.name); + return; + } + mMacroSet->insert(std::make_pair(macro.name, macro)); +} + +void DirectiveParser::parseUndef(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_UNDEF); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + return; + } + + MacroSet::iterator iter = mMacroSet->find(token->text); + if (iter != mMacroSet->end()) + { + if (iter->second.predefined) + { + mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED, + token->location, token->text); + } + else + { + mMacroSet->erase(iter); + } + } + + mTokenizer->lex(token); +} + +void DirectiveParser::parseIf(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_IF); + parseConditionalIf(token); +} + +void DirectiveParser::parseIfdef(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_IFDEF); + parseConditionalIf(token); +} + +void DirectiveParser::parseIfndef(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_IFNDEF); + parseConditionalIf(token); +} + +void DirectiveParser::parseElse(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ELSE); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + ConditionalBlock& block = mConditionalStack.back(); + if (block.skipBlock) + { + // No diagnostics. Just skip the whole line. + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundElseGroup) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + block.foundElseGroup = true; + block.skipGroup = block.foundValidGroup; + block.foundValidGroup = true; + + // Warn if there are extra tokens after #else. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } +} + +void DirectiveParser::parseElif(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ELIF); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + ConditionalBlock& block = mConditionalStack.back(); + if (block.skipBlock) + { + // No diagnostics. Just skip the whole line. + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundElseGroup) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + if (block.foundValidGroup) + { + // Do not parse the expression. + // Also be careful not to emit a diagnostic. + block.skipGroup = true; + skipUntilEOD(mTokenizer, token); + return; + } + + int expression = parseExpressionIf(token); + block.skipGroup = expression == 0; + block.foundValidGroup = expression != 0; +} + +void DirectiveParser::parseEndif(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ENDIF); + + if (mConditionalStack.empty()) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + mConditionalStack.pop_back(); + + // Warn if there are tokens after #endif. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } +} + +void DirectiveParser::parseError(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_ERROR); + + std::ostringstream stream; + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + stream << *token; + mTokenizer->lex(token); + } + mDirectiveHandler->handleError(token->location, stream.str()); +} + +// Parses pragma of form: #pragma name[(value)]. +void DirectiveParser::parsePragma(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_PRAGMA); + + enum State + { + PRAGMA_NAME, + LEFT_PAREN, + PRAGMA_VALUE, + RIGHT_PAREN + }; + + bool valid = true; + std::string name, value; + int state = PRAGMA_NAME; + + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch(state++) + { + case PRAGMA_NAME: + name = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case LEFT_PAREN: + valid = valid && (token->type == '('); + break; + case PRAGMA_VALUE: + value = token->text; + valid = valid && (token->type == Token::IDENTIFIER); + break; + case RIGHT_PAREN: + valid = valid && (token->type == ')'); + break; + default: + valid = false; + break; + } + mTokenizer->lex(token); + } + + valid = valid && ((state == PRAGMA_NAME) || // Empty pragma. + (state == LEFT_PAREN) || // Without value. + (state == RIGHT_PAREN + 1)); // With value. + if (!valid) + { + mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA, + token->location, name); + } + else if (state > PRAGMA_NAME) // Do not notify for empty pragma. + { + mDirectiveHandler->handlePragma(token->location, name, value); + } +} + +void DirectiveParser::parseExtension(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_EXTENSION); + + enum State + { + EXT_NAME, + COLON, + EXT_BEHAVIOR + }; + + bool valid = true; + std::string name, behavior; + int state = EXT_NAME; + + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch (state++) + { + case EXT_NAME: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME, + token->location, token->text); + valid = false; + } + if (valid) name = token->text; + break; + case COLON: + if (valid && (token->type != ':')) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + case EXT_BEHAVIOR: + if (valid && (token->type != Token::IDENTIFIER)) + { + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR, + token->location, token->text); + valid = false; + } + if (valid) behavior = token->text; + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + } + mTokenizer->lex(token); + } + if (valid && (state != EXT_BEHAVIOR + 1)) + { + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE, + token->location, token->text); + valid = false; + } + if (valid) + mDirectiveHandler->handleExtension(token->location, name, behavior); +} + +void DirectiveParser::parseVersion(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_VERSION); + + if (mPastFirstStatement) + { + mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return; + } + + enum State + { + VERSION_NUMBER + }; + + bool valid = true; + int version = 0; + int state = VERSION_NUMBER; + + mTokenizer->lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch (state++) + { + case VERSION_NUMBER: + if (valid && (token->type != Token::CONST_INT)) + { + mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER, + token->location, token->text); + valid = false; + } + if (valid && !token->iValue(&version)) + { + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + valid = false; + } + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + } + mTokenizer->lex(token); + } + if (valid && (state != VERSION_NUMBER + 1)) + { + mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE, + token->location, token->text); + valid = false; + } + if (valid) + mDirectiveHandler->handleVersion(token->location, version); +} + +void DirectiveParser::parseLine(Token* token) +{ + assert(getDirective(token) == DIRECTIVE_LINE); + + enum State + { + LINE_NUMBER, + FILE_NUMBER + }; + + bool valid = true; + int line = 0, file = 0; + int state = LINE_NUMBER; + + MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics); + macroExpander.lex(token); + while ((token->type != '\n') && (token->type != Token::LAST)) + { + switch (state++) + { + case LINE_NUMBER: + if (valid && (token->type != Token::CONST_INT)) + { + mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER, + token->location, token->text); + valid = false; + } + if (valid && !token->iValue(&line)) + { + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + valid = false; + } + break; + case FILE_NUMBER: + if (valid && (token->type != Token::CONST_INT)) + { + mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER, + token->location, token->text); + valid = false; + } + if (valid && !token->iValue(&file)) + { + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + valid = false; + } + break; + default: + if (valid) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + valid = false; + } + break; + } + macroExpander.lex(token); + } + + if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1)) + { + mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE, + token->location, token->text); + valid = false; + } + if (valid) + { + mTokenizer->setLineNumber(line); + if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file); + } +} + +bool DirectiveParser::skipping() const +{ + if (mConditionalStack.empty()) return false; + + const ConditionalBlock& block = mConditionalStack.back(); + return block.skipBlock || block.skipGroup; +} + +void DirectiveParser::parseConditionalIf(Token* token) +{ + ConditionalBlock block; + block.type = token->text; + block.location = token->location; + + if (skipping()) + { + // This conditional block is inside another conditional group + // which is skipped. As a consequence this whole block is skipped. + // Be careful not to parse the conditional expression that might + // emit a diagnostic. + skipUntilEOD(mTokenizer, token); + block.skipBlock = true; + } + else + { + DirectiveType directive = getDirective(token); + + int expression = 0; + switch (directive) + { + case DIRECTIVE_IF: + expression = parseExpressionIf(token); + break; + case DIRECTIVE_IFDEF: + expression = parseExpressionIfdef(token); + break; + case DIRECTIVE_IFNDEF: + expression = parseExpressionIfdef(token) == 0 ? 1 : 0; + break; + default: + assert(false); + break; + } + block.skipGroup = expression == 0; + block.foundValidGroup = expression != 0; + } + mConditionalStack.push_back(block); +} + +int DirectiveParser::parseExpressionIf(Token* token) +{ + assert((getDirective(token) == DIRECTIVE_IF) || + (getDirective(token) == DIRECTIVE_ELIF)); + + DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics); + MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics); + ExpressionParser expressionParser(¯oExpander, mDiagnostics); + + int expression = 0; + macroExpander.lex(token); + expressionParser.parse(token, &expression); + + // Warn if there are tokens after #if expression. + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } + + return expression; +} + +int DirectiveParser::parseExpressionIfdef(Token* token) +{ + assert((getDirective(token) == DIRECTIVE_IFDEF) || + (getDirective(token) == DIRECTIVE_IFNDEF)); + + mTokenizer->lex(token); + if (token->type != Token::IDENTIFIER) + { + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + return 0; + } + + MacroSet::const_iterator iter = mMacroSet->find(token->text); + int expression = iter != mMacroSet->end() ? 1 : 0; + + // Warn if there are tokens after #ifdef expression. + mTokenizer->lex(token); + if (!isEOD(token)) + { + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, + token->location, token->text); + skipUntilEOD(mTokenizer, token); + } + return expression; +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h new file mode 100644 index 0000000000..8a7f0072ba --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h @@ -0,0 +1,82 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ + +#include "Lexer.h" +#include "Macro.h" +#include "pp_utils.h" +#include "SourceLocation.h" + +namespace pp +{ + +class Diagnostics; +class DirectiveHandler; +class Tokenizer; + +class DirectiveParser : public Lexer +{ + public: + DirectiveParser(Tokenizer* tokenizer, + MacroSet* macroSet, + Diagnostics* diagnostics, + DirectiveHandler* directiveHandler); + + virtual void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser); + + void parseDirective(Token* token); + void parseDefine(Token* token); + void parseUndef(Token* token); + void parseIf(Token* token); + void parseIfdef(Token* token); + void parseIfndef(Token* token); + void parseElse(Token* token); + void parseElif(Token* token); + void parseEndif(Token* token); + void parseError(Token* token); + void parsePragma(Token* token); + void parseExtension(Token* token); + void parseVersion(Token* token); + void parseLine(Token* token); + + bool skipping() const; + void parseConditionalIf(Token* token); + int parseExpressionIf(Token* token); + int parseExpressionIfdef(Token* token); + + struct ConditionalBlock + { + std::string type; + SourceLocation location; + bool skipBlock; + bool skipGroup; + bool foundValidGroup; + bool foundElseGroup; + + ConditionalBlock() : + skipBlock(false), + skipGroup(false), + foundValidGroup(false), + foundElseGroup(false) + { + } + }; + bool mPastFirstStatement; + std::vector mConditionalStack; + Tokenizer* mTokenizer; + MacroSet* mMacroSet; + Diagnostics* mDiagnostics; + DirectiveHandler* mDirectiveHandler; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h new file mode 100644 index 0000000000..092d059413 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ +#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ + +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; +class Lexer; +struct Token; + +class ExpressionParser +{ + public: + ExpressionParser(Lexer* lexer, Diagnostics* diagnostics); + + bool parse(Token* token, int* result); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser); + + Lexer* mLexer; + Diagnostics* mDiagnostics; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y new file mode 100644 index 0000000000..832ad4001e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y @@ -0,0 +1,279 @@ +/* +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +This file contains the Yacc grammar for GLSL ES preprocessor expression. + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES preprocessor expression parser. +*/ + +%{ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +#if defined(__GNUC__) +// Triggered by the auto-generated pplval variable. +#pragma GCC diagnostic ignored "-Wuninitialized" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065 4701) +#endif + +#include "ExpressionParser.h" + +#include +#include + +#include "Diagnostics.h" +#include "Lexer.h" +#include "Token.h" + +#if defined(_MSC_VER) +typedef __int64 YYSTYPE; +#else +#include +typedef intmax_t YYSTYPE; +#endif // _MSC_VER +#define YYSTYPE_IS_TRIVIAL 1 +#define YYSTYPE_IS_DECLARED 1 + +namespace { +struct Context +{ + pp::Diagnostics* diagnostics; + pp::Lexer* lexer; + pp::Token* token; + int* result; +}; +} // namespace +%} + +%pure-parser +%name-prefix="pp" +%parse-param {Context *context} +%lex-param {Context *context} + +%{ +static int yylex(YYSTYPE* lvalp, Context* context); +static void yyerror(Context* context, const char* reason); +%} + +%token TOK_CONST_INT +%left TOK_OP_OR +%left TOK_OP_AND +%left '|' +%left '^' +%left '&' +%left TOK_OP_EQ TOK_OP_NE +%left '<' '>' TOK_OP_LE TOK_OP_GE +%left TOK_OP_LEFT TOK_OP_RIGHT +%left '+' '-' +%left '*' '/' '%' +%right TOK_UNARY + +%% + +input + : expression { + *(context->result) = static_cast($1); + YYACCEPT; + } +; + +expression + : TOK_CONST_INT + | expression TOK_OP_OR expression { + $$ = $1 || $3; + } + | expression TOK_OP_AND expression { + $$ = $1 && $3; + } + | expression '|' expression { + $$ = $1 | $3; + } + | expression '^' expression { + $$ = $1 ^ $3; + } + | expression '&' expression { + $$ = $1 & $3; + } + | expression TOK_OP_NE expression { + $$ = $1 != $3; + } + | expression TOK_OP_EQ expression { + $$ = $1 == $3; + } + | expression TOK_OP_GE expression { + $$ = $1 >= $3; + } + | expression TOK_OP_LE expression { + $$ = $1 <= $3; + } + | expression '>' expression { + $$ = $1 > $3; + } + | expression '<' expression { + $$ = $1 < $3; + } + | expression TOK_OP_RIGHT expression { + $$ = $1 >> $3; + } + | expression TOK_OP_LEFT expression { + $$ = $1 << $3; + } + | expression '-' expression { + $$ = $1 - $3; + } + | expression '+' expression { + $$ = $1 + $3; + } + | expression '%' expression { + if ($3 == 0) { + std::ostringstream stream; + stream << $1 << " % " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, + context->token->location, + text.c_str()); + YYABORT; + } else { + $$ = $1 % $3; + } + } + | expression '/' expression { + if ($3 == 0) { + std::ostringstream stream; + stream << $1 << " / " << $3; + std::string text = stream.str(); + context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO, + context->token->location, + text.c_str()); + YYABORT; + } else { + $$ = $1 / $3; + } + } + | expression '*' expression { + $$ = $1 * $3; + } + | '!' expression %prec TOK_UNARY { + $$ = ! $2; + } + | '~' expression %prec TOK_UNARY { + $$ = ~ $2; + } + | '-' expression %prec TOK_UNARY { + $$ = - $2; + } + | '+' expression %prec TOK_UNARY { + $$ = + $2; + } + | '(' expression ')' { + $$ = $2; + } +; + +%% + +int yylex(YYSTYPE* lvalp, Context* context) +{ + int type = 0; + + pp::Token* token = context->token; + switch (token->type) + { + case pp::Token::CONST_INT: + { + unsigned int val = 0; + if (!token->uValue(&val)) + { + context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + } + *lvalp = static_cast(val); + type = TOK_CONST_INT; + break; + } + case pp::Token::OP_OR: type = TOK_OP_OR; break; + case pp::Token::OP_AND: type = TOK_OP_AND; break; + case pp::Token::OP_NE: type = TOK_OP_NE; break; + case pp::Token::OP_EQ: type = TOK_OP_EQ; break; + case pp::Token::OP_GE: type = TOK_OP_GE; break; + case pp::Token::OP_LE: type = TOK_OP_LE; break; + case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break; + case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break; + case '|': type = '|'; break; + case '^': type = '^'; break; + case '&': type = '&'; break; + case '>': type = '>'; break; + case '<': type = '<'; break; + case '-': type = '-'; break; + case '+': type = '+'; break; + case '%': type = '%'; break; + case '/': type = '/'; break; + case '*': type = '*'; break; + case '!': type = '!'; break; + case '~': type = '~'; break; + case '(': type = '('; break; + case ')': type = ')'; break; + + default: break; + } + + // Advance to the next token if the current one is valid. + if (type != 0) context->lexer->lex(token); + + return type; +} + +void yyerror(Context* context, const char* reason) +{ + context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION, + context->token->location, + reason); +} + +namespace pp { + +ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) : + mLexer(lexer), + mDiagnostics(diagnostics) +{ +} + +bool ExpressionParser::parse(Token* token, int* result) +{ + Context context; + context.diagnostics = mDiagnostics; + context.lexer = mLexer; + context.token = token; + context.result = result; + int ret = yyparse(&context); + switch (ret) + { + case 0: + case 1: + break; + + case 2: + mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, ""); + break; + + default: + assert(false); + mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, ""); + break; + } + + return ret == 0; +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp new file mode 100644 index 0000000000..c3de95f313 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp @@ -0,0 +1,55 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "Input.h" + +#include +#include +#include + +namespace pp +{ + +Input::Input() : mCount(0), mString(0) +{ +} + +Input::Input(int count, const char* const string[], const int length[]) : + mCount(count), + mString(string) +{ + assert(mCount >= 0); + mLength.reserve(mCount); + for (int i = 0; i < mCount; ++i) + { + int len = length ? length[i] : -1; + mLength.push_back(len < 0 ? strlen(mString[i]) : len); + } +} + +int Input::read(char* buf, int maxSize) +{ + int nRead = 0; + while ((nRead < maxSize) && (mReadLoc.sIndex < mCount)) + { + int size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex; + size = std::min(size, maxSize); + memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size); + nRead += size; + mReadLoc.cIndex += size; + + // Advance string if we reached the end of current string. + if (mReadLoc.cIndex == mLength[mReadLoc.sIndex]) + { + ++mReadLoc.sIndex; + mReadLoc.cIndex = 0; + } + } + return nRead; +} + +} // namespace pp + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.h new file mode 100644 index 0000000000..dac734b68d --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_INPUT_H_ +#define COMPILER_PREPROCESSOR_INPUT_H_ + +#include + +namespace pp +{ + +// Holds and reads input for Lexer. +class Input +{ + public: + Input(); + Input(int count, const char* const string[], const int length[]); + + int count() const { return mCount; } + const char* string(int index) const { return mString[index]; } + int length(int index) const { return mLength[index]; } + + int read(char* buf, int maxSize); + + struct Location + { + int sIndex; // String index; + int cIndex; // Char index. + + Location() : sIndex(0), cIndex(0) { } + }; + const Location& readLoc() const { return mReadLoc; } + + private: + // Input. + int mCount; + const char* const* mString; + std::vector mLength; + + Location mReadLoc; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_INPUT_H_ + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp new file mode 100644 index 0000000000..7c663ee761 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp @@ -0,0 +1,16 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "Lexer.h" + +namespace pp +{ + +Lexer::~Lexer() +{ +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h new file mode 100644 index 0000000000..eb85cea873 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_LEXER_H_ +#define COMPILER_PREPROCESSOR_LEXER_H_ + +namespace pp +{ + +struct Token; + +class Lexer +{ + public: + virtual ~Lexer(); + + virtual void lex(Token* token) = 0; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_LEXER_H_ + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp new file mode 100644 index 0000000000..b2e3088e32 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp @@ -0,0 +1,23 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "Macro.h" + +#include "Token.h" + +namespace pp +{ + +bool Macro::equals(const Macro& other) const +{ + return (type == other.type) && + (name == other.name) && + (parameters == other.parameters) && + (replacements == other.replacements); +} + +} // namespace pp + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h new file mode 100644 index 0000000000..7ec0149116 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_MACRO_H_ +#define COMPILER_PREPROCESSOR_MACRO_H_ + +#include +#include +#include + +namespace pp +{ + +struct Token; + +struct Macro +{ + enum Type + { + kTypeObj, + kTypeFunc + }; + typedef std::vector Parameters; + typedef std::vector Replacements; + + Macro() : predefined(false), disabled(false), type(kTypeObj) { } + bool equals(const Macro& other) const; + + bool predefined; + mutable bool disabled; + + Type type; + std::string name; + Parameters parameters; + Replacements replacements; +}; + +typedef std::map MacroSet; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_MACRO_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp new file mode 100644 index 0000000000..701cec9a4b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp @@ -0,0 +1,370 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "MacroExpander.h" + +#include +#include + +#include "Diagnostics.h" +#include "Token.h" + +namespace pp +{ + +class TokenLexer : public Lexer +{ + public: + typedef std::vector TokenVector; + + TokenLexer(TokenVector* tokens) + { + tokens->swap(mTokens); + mIter = mTokens.begin(); + } + + virtual void lex(Token* token) + { + if (mIter == mTokens.end()) + { + token->reset(); + token->type = Token::LAST; + } + else + { + *token = *mIter++; + } + } + + private: + PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer); + + TokenVector mTokens; + TokenVector::const_iterator mIter; +}; + +MacroExpander::MacroExpander(Lexer* lexer, + MacroSet* macroSet, + Diagnostics* diagnostics) : + mLexer(lexer), + mMacroSet(macroSet), + mDiagnostics(diagnostics) +{ +} + +MacroExpander::~MacroExpander() +{ + for (size_t i = 0; i < mContextStack.size(); ++i) + { + delete mContextStack[i]; + } +} + +void MacroExpander::lex(Token* token) +{ + while (true) + { + getToken(token); + + if (token->type != Token::IDENTIFIER) + break; + + if (token->expansionDisabled()) + break; + + MacroSet::const_iterator iter = mMacroSet->find(token->text); + if (iter == mMacroSet->end()) + break; + + const Macro& macro = iter->second; + if (macro.disabled) + { + // If a particular token is not expanded, it is never expanded. + token->setExpansionDisabled(true); + break; + } + if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen()) + { + // If the token immediately after the macro name is not a '(', + // this macro should not be expanded. + break; + } + + pushMacro(macro, *token); + } +} + +void MacroExpander::getToken(Token* token) +{ + if (mReserveToken.get()) + { + *token = *mReserveToken; + mReserveToken.reset(); + return; + } + + // First pop all empty macro contexts. + while (!mContextStack.empty() && mContextStack.back()->empty()) + { + popMacro(); + } + + if (!mContextStack.empty()) + { + *token = mContextStack.back()->get(); + } + else + { + mLexer->lex(token); + } +} + +void MacroExpander::ungetToken(const Token& token) +{ + if (!mContextStack.empty()) + { + MacroContext* context = mContextStack.back(); + context->unget(); + assert(context->replacements[context->index] == token); + } + else + { + assert(!mReserveToken.get()); + mReserveToken.reset(new Token(token)); + } +} + +bool MacroExpander::isNextTokenLeftParen() +{ + Token token; + getToken(&token); + + bool lparen = token.type == '('; + ungetToken(token); + + return lparen; +} + +bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier) +{ + assert(!macro.disabled); + assert(!identifier.expansionDisabled()); + assert(identifier.type == Token::IDENTIFIER); + assert(identifier.text == macro.name); + + std::vector replacements; + if (!expandMacro(macro, identifier, &replacements)) + return false; + + // Macro is disabled for expansion until it is popped off the stack. + macro.disabled = true; + + MacroContext* context = new MacroContext; + context->macro = ¯o; + context->replacements.swap(replacements); + mContextStack.push_back(context); + return true; +} + +void MacroExpander::popMacro() +{ + assert(!mContextStack.empty()); + + MacroContext* context = mContextStack.back(); + mContextStack.pop_back(); + + assert(context->empty()); + assert(context->macro->disabled); + context->macro->disabled = false; + delete context; +} + +bool MacroExpander::expandMacro(const Macro& macro, + const Token& identifier, + std::vector* replacements) +{ + replacements->clear(); + if (macro.type == Macro::kTypeObj) + { + replacements->assign(macro.replacements.begin(), + macro.replacements.end()); + + if (macro.predefined) + { + static const std::string kLine = "__LINE__"; + static const std::string kFile = "__FILE__"; + + assert(replacements->size() == 1); + Token& repl = replacements->front(); + if (macro.name == kLine) + { + std::ostringstream stream; + stream << identifier.location.line; + repl.text = stream.str(); + } + else if (macro.name == kFile) + { + std::ostringstream stream; + stream << identifier.location.file; + repl.text = stream.str(); + } + } + } + else + { + assert(macro.type == Macro::kTypeFunc); + std::vector args; + args.reserve(macro.parameters.size()); + if (!collectMacroArgs(macro, identifier, &args)) + return false; + + replaceMacroParams(macro, args, replacements); + } + + for (size_t i = 0; i < replacements->size(); ++i) + { + Token& repl = replacements->at(i); + if (i == 0) + { + // The first token in the replacement list inherits the padding + // properties of the identifier token. + repl.setAtStartOfLine(identifier.atStartOfLine()); + repl.setHasLeadingSpace(identifier.hasLeadingSpace()); + } + repl.location = identifier.location; + } + return true; +} + +bool MacroExpander::collectMacroArgs(const Macro& macro, + const Token& identifier, + std::vector* args) +{ + Token token; + getToken(&token); + assert(token.type == '('); + + args->push_back(MacroArg()); + for (int openParens = 1; openParens != 0; ) + { + getToken(&token); + + if (token.type == Token::LAST) + { + mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION, + identifier.location, identifier.text); + // Do not lose EOF token. + ungetToken(token); + return false; + } + + bool isArg = false; // True if token is part of the current argument. + switch (token.type) + { + case '(': + ++openParens; + isArg = true; + break; + case ')': + --openParens; + isArg = openParens != 0; + break; + case ',': + // The individual arguments are separated by comma tokens, but + // the comma tokens between matching inner parentheses do not + // seperate arguments. + if (openParens == 1) args->push_back(MacroArg()); + isArg = openParens != 1; + break; + default: + isArg = true; + break; + } + if (isArg) + { + MacroArg& arg = args->back(); + // Initial whitespace is not part of the argument. + if (arg.empty()) token.setHasLeadingSpace(false); + arg.push_back(token); + } + } + + const Macro::Parameters& params = macro.parameters; + // If there is only one empty argument, it is equivalent to no argument. + if (params.empty() && (args->size() == 1) && args->front().empty()) + { + args->clear(); + } + // Validate the number of arguments. + if (args->size() != params.size()) + { + Diagnostics::ID id = args->size() < macro.parameters.size() ? + Diagnostics::MACRO_TOO_FEW_ARGS : + Diagnostics::MACRO_TOO_MANY_ARGS; + mDiagnostics->report(id, identifier.location, identifier.text); + return false; + } + + // Pre-expand each argument before substitution. + // This step expands each argument individually before they are + // inserted into the macro body. + for (size_t i = 0; i < args->size(); ++i) + { + MacroArg& arg = args->at(i); + TokenLexer lexer(&arg); + MacroExpander expander(&lexer, mMacroSet, mDiagnostics); + + arg.clear(); + expander.lex(&token); + while (token.type != Token::LAST) + { + arg.push_back(token); + expander.lex(&token); + } + } + return true; +} + +void MacroExpander::replaceMacroParams(const Macro& macro, + const std::vector& args, + std::vector* replacements) +{ + for (size_t i = 0; i < macro.replacements.size(); ++i) + { + const Token& repl = macro.replacements[i]; + if (repl.type != Token::IDENTIFIER) + { + replacements->push_back(repl); + continue; + } + + // TODO(alokp): Optimize this. + // There is no need to search for macro params every time. + // The param index can be cached with the replacement token. + Macro::Parameters::const_iterator iter = std::find( + macro.parameters.begin(), macro.parameters.end(), repl.text); + if (iter == macro.parameters.end()) + { + replacements->push_back(repl); + continue; + } + + size_t iArg = std::distance(macro.parameters.begin(), iter); + const MacroArg& arg = args[iArg]; + if (arg.empty()) + { + continue; + } + size_t iRepl = replacements->size(); + replacements->insert(replacements->end(), arg.begin(), arg.end()); + // The replacement token inherits padding properties from + // macro replacement token. + replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace()); + } +} + +} // namespace pp + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h new file mode 100644 index 0000000000..7c5c543871 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h @@ -0,0 +1,75 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ +#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ + +#include +#include +#include + +#include "Lexer.h" +#include "Macro.h" +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; + +class MacroExpander : public Lexer +{ + public: + MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics); + virtual ~MacroExpander(); + + virtual void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander); + + void getToken(Token* token); + void ungetToken(const Token& token); + bool isNextTokenLeftParen(); + + bool pushMacro(const Macro& macro, const Token& identifier); + void popMacro(); + + bool expandMacro(const Macro& macro, + const Token& identifier, + std::vector* replacements); + + typedef std::vector MacroArg; + bool collectMacroArgs(const Macro& macro, + const Token& identifier, + std::vector* args); + void replaceMacroParams(const Macro& macro, + const std::vector& args, + std::vector* replacements); + + struct MacroContext + { + const Macro* macro; + size_t index; + std::vector replacements; + + MacroContext() : macro(0), index(0) { } + bool empty() const { return index == replacements.size(); } + const Token& get() { return replacements[index++]; } + void unget() { assert(index > 0); --index; } + }; + + Lexer* mLexer; + MacroSet* mMacroSet; + Diagnostics* mDiagnostics; + + std::auto_ptr mReserveToken; + std::vector mContextStack; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp new file mode 100644 index 0000000000..ffa7225a8f --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp @@ -0,0 +1,142 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "Preprocessor.h" + +#include +#include + +#include "Diagnostics.h" +#include "DirectiveParser.h" +#include "Macro.h" +#include "MacroExpander.h" +#include "Token.h" +#include "Tokenizer.h" + +namespace pp +{ + +struct PreprocessorImpl +{ + Diagnostics* diagnostics; + MacroSet macroSet; + Tokenizer tokenizer; + DirectiveParser directiveParser; + MacroExpander macroExpander; + + PreprocessorImpl(Diagnostics* diag, + DirectiveHandler* directiveHandler) : + diagnostics(diag), + tokenizer(diag), + directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), + macroExpander(&directiveParser, ¯oSet, diag) + { + } +}; + +Preprocessor::Preprocessor(Diagnostics* diagnostics, + DirectiveHandler* directiveHandler) +{ + mImpl = new PreprocessorImpl(diagnostics, directiveHandler); +} + +Preprocessor::~Preprocessor() +{ + delete mImpl; +} + +bool Preprocessor::init(int count, + const char* const string[], + const int length[]) +{ + static const int kGLSLVersion = 100; + + // Add standard pre-defined macros. + predefineMacro("__LINE__", 0); + predefineMacro("__FILE__", 0); + predefineMacro("__VERSION__", kGLSLVersion); + predefineMacro("GL_ES", 1); + + return mImpl->tokenizer.init(count, string, length); +} + +void Preprocessor::predefineMacro(const char* name, int value) +{ + std::ostringstream stream; + stream << value; + + Token token; + token.type = Token::CONST_INT; + token.text = stream.str(); + + Macro macro; + macro.predefined = true; + macro.type = Macro::kTypeObj; + macro.name = name; + macro.replacements.push_back(token); + + mImpl->macroSet[name] = macro; +} + +void Preprocessor::lex(Token* token) +{ + bool validToken = false; + while (!validToken) + { + mImpl->macroExpander.lex(token); + switch (token->type) + { + // We should not be returning internal preprocessing tokens. + // Convert preprocessing tokens to compiler tokens or report + // diagnostics. + case Token::PP_HASH: + assert(false); + break; + case Token::CONST_INT: + { + int val = 0; + if (!token->iValue(&val)) + { + // Do not mark the token as invalid. + // Just emit the diagnostic and reset value to 0. + mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW, + token->location, token->text); + token->text.assign("0"); + } + validToken = true; + break; + } + case Token::CONST_FLOAT: + { + float val = 0; + if (!token->fValue(&val)) + { + // Do not mark the token as invalid. + // Just emit the diagnostic and reset value to 0.0. + mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW, + token->location, token->text); + token->text.assign("0.0"); + } + validToken = true; + break; + } + case Token::PP_NUMBER: + mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER, + token->location, token->text); + break; + case Token::PP_OTHER: + mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER, + token->location, token->text); + break; + default: + validToken = true; + break; + } + } +} + +} // namespace pp + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h new file mode 100644 index 0000000000..5fe35b27bd --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_ +#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_ + +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; +class DirectiveHandler; +struct PreprocessorImpl; +struct Token; + +class Preprocessor +{ + public: + Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler); + ~Preprocessor(); + + // count: specifies the number of elements in the string and length arrays. + // string: specifies an array of pointers to strings. + // length: specifies an array of string lengths. + // If length is NULL, each string is assumed to be null terminated. + // If length is a value other than NULL, it points to an array containing + // a string length for each of the corresponding elements of string. + // Each element in the length array may contain the length of the + // corresponding string or a value less than 0 to indicate that the string + // is null terminated. + bool init(int count, const char* const string[], const int length[]); + // Adds a pre-defined macro. + void predefineMacro(const char* name, int value); + + void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor); + + PreprocessorImpl* mImpl; +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_ + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h b/src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h new file mode 100644 index 0000000000..6982613ac7 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ +#define COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ + +namespace pp +{ + +struct SourceLocation +{ + SourceLocation() : file(0), line(0) { } + SourceLocation(int f, int l) : file(f), line(l) { } + + bool equals(const SourceLocation& other) const + { + return (file == other.file) && (line == other.line); + } + + int file; + int line; +}; + +inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs) +{ + return lhs.equals(rhs); +} + +inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs) +{ + return !lhs.equals(rhs); +} + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp new file mode 100644 index 0000000000..67f50aa32c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp @@ -0,0 +1,83 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "Token.h" + +#include + +#include "numeric_lex.h" + +namespace pp +{ + +void Token::reset() +{ + type = 0; + flags = 0; + location = SourceLocation(); + text.clear(); +} + +bool Token::equals(const Token& other) const +{ + return (type == other.type) && + (flags == other.flags) && + (location == other.location) && + (text == other.text); +} + +void Token::setAtStartOfLine(bool start) +{ + if (start) + flags |= AT_START_OF_LINE; + else + flags &= ~AT_START_OF_LINE; +} + +void Token::setHasLeadingSpace(bool space) +{ + if (space) + flags |= HAS_LEADING_SPACE; + else + flags &= ~HAS_LEADING_SPACE; +} + +void Token::setExpansionDisabled(bool disable) +{ + if (disable) + flags |= EXPANSION_DISABLED; + else + flags &= ~EXPANSION_DISABLED; +} + +bool Token::iValue(int* value) const +{ + assert(type == CONST_INT); + return numeric_lex_int(text, value); +} + +bool Token::uValue(unsigned int* value) const +{ + assert(type == CONST_INT); + return numeric_lex_int(text, value); +} + +bool Token::fValue(float* value) const +{ + assert(type == CONST_FLOAT); + return numeric_lex_float(text, value); +} + +std::ostream& operator<<(std::ostream& out, const Token& token) +{ + if (token.hasLeadingSpace()) + out << " "; + + out << token.text; + return out; +} + +} // namespace pp diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Token.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.h new file mode 100644 index 0000000000..8b553aecb6 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.h @@ -0,0 +1,106 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_TOKEN_H_ +#define COMPILER_PREPROCESSOR_TOKEN_H_ + +#include +#include + +#include "SourceLocation.h" + +namespace pp +{ + +struct Token +{ + enum Type + { + LAST = 0, // EOF. + + IDENTIFIER = 258, + + CONST_INT, + CONST_FLOAT, + + OP_INC, + OP_DEC, + OP_LEFT, + OP_RIGHT, + OP_LE, + OP_GE, + OP_EQ, + OP_NE, + OP_AND, + OP_XOR, + OP_OR, + OP_ADD_ASSIGN, + OP_SUB_ASSIGN, + OP_MUL_ASSIGN, + OP_DIV_ASSIGN, + OP_MOD_ASSIGN, + OP_LEFT_ASSIGN, + OP_RIGHT_ASSIGN, + OP_AND_ASSIGN, + OP_XOR_ASSIGN, + OP_OR_ASSIGN, + + // Preprocessing token types. + // These types are used by the preprocessor internally. + // Preprocessor clients must not depend or check for them. + PP_HASH, + PP_NUMBER, + PP_OTHER + }; + enum Flags + { + AT_START_OF_LINE = 1 << 0, + HAS_LEADING_SPACE = 1 << 1, + EXPANSION_DISABLED = 1 << 2 + }; + + Token() : type(0), flags(0) { } + + void reset(); + bool equals(const Token& other) const; + + // Returns true if this is the first token on line. + // It disregards any leading whitespace. + bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; } + void setAtStartOfLine(bool start); + + bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; } + void setHasLeadingSpace(bool space); + + bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; } + void setExpansionDisabled(bool disable); + + // Converts text into numeric value for CONST_INT and CONST_FLOAT token. + // Returns false if the parsed value cannot fit into an int or float. + bool iValue(int* value) const; + bool uValue(unsigned int* value) const; + bool fValue(float* value) const; + + int type; + unsigned int flags; + SourceLocation location; + std::string text; +}; + +inline bool operator==(const Token& lhs, const Token& rhs) +{ + return lhs.equals(rhs); +} + +inline bool operator!=(const Token& lhs, const Token& rhs) +{ + return !lhs.equals(rhs); +} + +extern std::ostream& operator<<(std::ostream& out, const Token& token); + +} // namepsace pp +#endif // COMPILER_PREPROCESSOR_TOKEN_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h new file mode 100644 index 0000000000..a594d2d865 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h @@ -0,0 +1,58 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_ +#define COMPILER_PREPROCESSOR_TOKENIZER_H_ + +#include "Input.h" +#include "Lexer.h" +#include "pp_utils.h" + +namespace pp +{ + +class Diagnostics; + +class Tokenizer : public Lexer +{ + public: + struct Context + { + Diagnostics* diagnostics; + + Input input; + // The location where yytext points to. Token location should track + // scanLoc instead of Input::mReadLoc because they may not be the same + // if text is buffered up in the scanner input buffer. + Input::Location scanLoc; + + bool leadingSpace; + bool lineStart; + }; + static const size_t kMaxTokenLength; + + Tokenizer(Diagnostics* diagnostics); + ~Tokenizer(); + + bool init(int count, const char* const string[], const int length[]); + + void setFileNumber(int file); + void setLineNumber(int line); + + virtual void lex(Token* token); + + private: + PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer); + bool initScanner(); + void destroyScanner(); + + void* mHandle; // Scanner handle. + Context mContext; // Scanner extra. +}; + +} // namespace pp +#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_ + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l new file mode 100644 index 0000000000..9762988350 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l @@ -0,0 +1,340 @@ +/* +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +This file contains the Lex specification for GLSL ES preprocessor. +Based on Microsoft Visual Studio 2010 Preprocessor Grammar: +http://msdn.microsoft.com/en-us/library/2scxys89.aspx + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. +*/ + +%top{ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! +} + +%{ +#include "Tokenizer.h" + +#include "Diagnostics.h" +#include "Token.h" + +#if defined(__GNUC__) +// Triggered by the auto-generated yy_fatal_error function. +#pragma GCC diagnostic ignored "-Wmissing-noreturn" +#endif + +typedef std::string YYSTYPE; +typedef pp::SourceLocation YYLTYPE; + +// Use the unused yycolumn variable to track file (string) number. +#define yyfileno yycolumn + +#define YY_USER_INIT \ + do { \ + yyfileno = 0; \ + yylineno = 1; \ + yyextra->leadingSpace = false; \ + yyextra->lineStart = true; \ + } while(0); + +#define YY_USER_ACTION \ + do \ + { \ + pp::Input* input = &yyextra->input; \ + pp::Input::Location* scanLoc = &yyextra->scanLoc; \ + while ((scanLoc->sIndex < input->count()) && \ + (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \ + { \ + scanLoc->cIndex -= input->length(scanLoc->sIndex++); \ + ++yyfileno; yylineno = 1; \ + } \ + yylloc->file = yyfileno; \ + yylloc->line = yylineno; \ + scanLoc->cIndex += yyleng; \ + } while(0); + +#define YY_INPUT(buf, result, maxSize) \ + result = yyextra->input.read(buf, maxSize); + +%} + +%option noyywrap nounput never-interactive +%option reentrant bison-bridge bison-locations +%option prefix="pp" +%option extra-type="pp::Tokenizer::Context*" +%x COMMENT + +NEWLINE \n|\r|\r\n +IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* +PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?] + +DECIMAL_CONSTANT [1-9][0-9]* +OCTAL_CONSTANT 0[0-7]* +HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+ + +DIGIT [0-9] +EXPONENT_PART [eE][+-]?{DIGIT}+ +FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") + +%% + + /* Line comment */ +"//"[^\r\n]* + + /* Block comment */ + /* Line breaks are just counted - not returned. */ + /* The comment is replaced by a single space. */ +"/*" { BEGIN(COMMENT); } +[^*\r\n]+ +"*" +{NEWLINE} { ++yylineno; } +"*/" { + yyextra->leadingSpace = true; + BEGIN(INITIAL); +} + +# { + // # is only valid at start of line for preprocessor directives. + yylval->assign(1, yytext[0]); + return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER; +} + +{IDENTIFIER} { + yylval->assign(yytext, yyleng); + return pp::Token::IDENTIFIER; +} + +{DECIMAL_CONSTANT}|{OCTAL_CONSTANT}|{HEXADECIMAL_CONSTANT} { + yylval->assign(yytext, yyleng); + return pp::Token::CONST_INT; +} + +({DIGIT}+{EXPONENT_PART})|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?) { + yylval->assign(yytext, yyleng); + return pp::Token::CONST_FLOAT; +} + + /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */ + /* Rule to catch all invalid integers and floats. */ +({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) { + yylval->assign(yytext, yyleng); + return pp::Token::PP_NUMBER; +} + +"++" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_INC; +} +"--" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_DEC; +} +"<<" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_LEFT; +} +">>" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_RIGHT; +} +"<=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_LE; +} +">=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_GE; +} +"==" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_EQ; +} +"!=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_NE; +} +"&&" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_AND; +} +"^^" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_XOR; +} +"||" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_OR; +} +"+=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_ADD_ASSIGN; +} +"-=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_SUB_ASSIGN; +} +"*=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_MUL_ASSIGN; +} +"/=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_DIV_ASSIGN; +} +"%=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_MOD_ASSIGN; +} +"<<=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_LEFT_ASSIGN; +} +">>=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_RIGHT_ASSIGN; +} +"&=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_AND_ASSIGN; +} +"^=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_XOR_ASSIGN; +} +"|=" { + yylval->assign(yytext, yyleng); + return pp::Token::OP_OR_ASSIGN; +} + +{PUNCTUATOR} { + yylval->assign(1, yytext[0]); + return yytext[0]; +} + +[ \t\v\f]+ { yyextra->leadingSpace = true; } + +{NEWLINE} { + ++yylineno; + yylval->assign(1, '\n'); + return '\n'; +} + +. { + yylval->assign(1, yytext[0]); + return pp::Token::PP_OTHER; +} + +<*><> { + // YY_USER_ACTION is not invoked for handling EOF. + // Set the location for EOF token manually. + pp::Input* input = &yyextra->input; + pp::Input::Location* scanLoc = &yyextra->scanLoc; + int sIndexMax = std::max(0, input->count() - 1); + if (scanLoc->sIndex != sIndexMax) + { + // We can only reach here if there are empty strings at the + // end of the input. + scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0; + yyfileno = sIndexMax; yylineno = 1; + } + yylloc->file = yyfileno; + yylloc->line = yylineno; + yylval->clear(); + + if (YY_START == COMMENT) + { + yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT, + pp::SourceLocation(yyfileno, yylineno), + ""); + } + yyterminate(); +} + +%% + +namespace pp { + +// TODO(alokp): Maximum token length should ideally be specified by +// the preprocessor client, i.e., the compiler. +const size_t Tokenizer::kMaxTokenLength = 256; + +Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0) +{ + mContext.diagnostics = diagnostics; +} + +Tokenizer::~Tokenizer() +{ + destroyScanner(); +} + +bool Tokenizer::init(int count, const char* const string[], const int length[]) +{ + if (count < 0) return false; + if ((count > 0) && (string == 0)) return false; + + mContext.input = Input(count, string, length); + return initScanner(); +} + +void Tokenizer::setFileNumber(int file) +{ + // We use column number as file number. + // See macro yyfileno. + yyset_column(file, mHandle); +} + +void Tokenizer::setLineNumber(int line) +{ + yyset_lineno(line, mHandle); +} + +void Tokenizer::lex(Token* token) +{ + token->type = yylex(&token->text, &token->location, mHandle); + if (token->text.size() > kMaxTokenLength) + { + mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG, + token->location, token->text); + token->text.erase(kMaxTokenLength); + } + + token->flags = 0; + + token->setAtStartOfLine(mContext.lineStart); + mContext.lineStart = token->type == '\n'; + + token->setHasLeadingSpace(mContext.leadingSpace); + mContext.leadingSpace = false; +} + +bool Tokenizer::initScanner() +{ + if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle)) + return false; + + yyrestart(0, mHandle); + return true; +} + +void Tokenizer::destroyScanner() +{ + if (mHandle == NULL) + return; + + yylex_destroy(mHandle); + mHandle = NULL; +} + +} // namespace pp + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h new file mode 100644 index 0000000000..b04125d230 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// numeric_lex.h: Functions to extract numeric values from string. + +#ifndef COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ +#define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ + +#include + +namespace pp { + +inline std::ios::fmtflags numeric_base_int(const std::string& str) +{ + if ((str.size() >= 2) && + (str[0] == '0') && + (str[1] == 'x' || str[1] == 'X')) + { + return std::ios::hex; + } + else if ((str.size() >= 1) && (str[0] == '0')) + { + return std::ios::oct; + } + return std::ios::dec; +} + +// The following functions parse the given string to extract a numerical +// value of the given type. These functions assume that the string is +// of the correct form. They can only fail if the parsed value is too big, +// in which case false is returned. + +template +bool numeric_lex_int(const std::string& str, IntType* value) +{ + std::istringstream stream(str); + // This should not be necessary, but MSVS has a buggy implementation. + // It returns incorrect results if the base is not specified. + stream.setf(numeric_base_int(str), std::ios::basefield); + + stream >> (*value); + return !stream.fail(); +} + +template +bool numeric_lex_float(const std::string& str, FloatType* value) +{ + std::istringstream stream(str); + // Force "C" locale so that decimal character is always '.', and + // not dependent on the current locale. + stream.imbue(std::locale::classic()); + + stream >> (*value); + return !stream.fail(); +} + +} // namespace pp. +#endif // COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h b/src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h new file mode 100644 index 0000000000..17164ea8b0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// pp_utils.h: Common preprocessor utilities + +#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_ +#define COMPILER_PREPROCESSOR_PPUTILS_H_ + +// A macro to disallow the copy constructor and operator= functions +// This must be used in the private: declarations for a class. +#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#endif // COMPILER_PREPROCESSOR_PPUTILS_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/parser.h b/src/3rdparty/angle/src/compiler/preprocessor/parser.h new file mode 100644 index 0000000000..f67342b670 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/parser.h @@ -0,0 +1,93 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +#ifndef BISON_PARSER_H +# define BISON_PARSER_H + +#ifndef yystypepp +typedef struct { + int sc_int; + float sc_fval; + int sc_ident; + char symbol_name[MAX_SYMBOL_NAME_LEN+1]; +} yystypepp; + +# define YYSTYPE_IS_TRIVIAL 1 +#endif +# define CPP_AND_OP 257 +# define CPP_SUB_ASSIGN 259 +# define CPP_MOD_ASSIGN 260 +# define CPP_ADD_ASSIGN 261 +# define CPP_DIV_ASSIGN 262 +# define CPP_MUL_ASSIGN 263 +# define CPP_EQ_OP 264 +# define CPP_XOR_OP 265 +# define ERROR_SY 266 +# define CPP_FLOATCONSTANT 267 +# define CPP_GE_OP 268 +# define CPP_RIGHT_OP 269 +# define CPP_IDENTIFIER 270 +# define CPP_INTCONSTANT 271 +# define CPP_LE_OP 272 +# define CPP_LEFT_OP 273 +# define CPP_DEC_OP 274 +# define CPP_NE_OP 275 +# define CPP_OR_OP 276 +# define CPP_INC_OP 277 +# define CPP_STRCONSTANT 278 +# define CPP_TYPEIDENTIFIER 279 + +# define FIRST_USER_TOKEN_SY 289 + +# define CPP_RIGHT_ASSIGN 280 +# define CPP_LEFT_ASSIGN 281 +# define CPP_AND_ASSIGN 282 +# define CPP_OR_ASSIGN 283 +# define CPP_XOR_ASSIGN 284 +# define CPP_LEFT_BRACKET 285 +# define CPP_RIGHT_BRACKET 286 +# define CPP_LEFT_BRACE 287 +# define CPP_RIGHT_BRACE 288 + +#endif /* not BISON_PARSER_H */ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/preprocess.h b/src/3rdparty/angle/src/compiler/preprocessor/preprocess.h new file mode 100644 index 0000000000..15056da2c9 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/preprocess.h @@ -0,0 +1,50 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +#include "compiler/preprocessor/slglobals.h" +extern CPPStruct *cpp; +int InitCPPStruct(void); +int InitScanner(CPPStruct *cpp); +int InitAtomTable(AtomTable *atable, int htsize); +char* GetStringOfAtom(AtomTable *atable, int atom); diff --git a/src/3rdparty/angle/src/compiler/preprocessor/scanner.c b/src/3rdparty/angle/src/compiler/preprocessor/scanner.c new file mode 100644 index 0000000000..fde853c1e0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/scanner.c @@ -0,0 +1,698 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// scanner.c +// + +#include +#include +#include +#include +#include + +#if 0 + #include +#else + #define isinff(x) (((*(int *)&(x) & 0x7f800000L)==0x7f800000L) && \ + ((*(int *)&(x) & 0x007fffffL)==0000000000L)) +#endif + +#include "compiler/preprocessor/slglobals.h" +#include "compiler/util.h" + +typedef struct StringInputSrc { + InputSrc base; + char *p; +} StringInputSrc; + +static int ScanFromString(const char *s); + +static int eof_scan(InputSrc *is, yystypepp * yylvalpp) +{ + return EOF; +} // eof_scan + +static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) {} + +static InputSrc eof_inputsrc = { 0, &eof_scan, &eof_scan, &noop, 0, 0 }; + +static int byte_scan(InputSrc *, yystypepp * yylvalpp); + +#define EOL_SY '\n' + +#if defined(_MSC_VER) + #define DBG_BREAKPOINT() __asm int 3 +#elif defined(_M_AMD64) + #define DBG_BREAKPOINT() assert(!"Dbg_Breakpoint"); +#else + #define DBG_BREAKPOINT() +#endif + +#if defined(_MSC_VER) && !defined(_M_AMD64) + __int64 RDTSC ( void ) { + + __int64 v; + + __asm __emit 0x0f + __asm __emit 0x31 + __asm mov dword ptr v, eax + __asm mov dword ptr v+4, edx + + return v; + } +#endif + + +int InitScanner(CPPStruct *cpp) +{ + // Add various atoms needed by the CPP line scanner: + if (!InitCPP()) + return 0; + + cpp->mostRecentToken = 0; + cpp->tokenLoc = &cpp->ltokenLoc; + + cpp->ltokenLoc.file = 0; + cpp->ltokenLoc.line = 0; + + cpp->currentInput = &eof_inputsrc; + cpp->previous_token = '\n'; + cpp->pastFirstStatement = 0; + + return 1; +} // InitScanner + +int FreeScanner(void) +{ + return (FreeCPP()); +} + +int InitScannerInput(CPPStruct *cpp, int count, const char* const string[], const int length[]) +{ + cpp->PaWhichStr = 0; + cpp->PaArgv = string; + cpp->PaArgc = count; + cpp->PaStrLen = length; + ScanFromString(string[0]); + return 0; +} + +/* + * str_getch() + * takes care of reading from multiple strings. + * returns the next-char from the input stream. + * returns EOF when the complete shader is parsed. + */ +static int str_getch(StringInputSrc *in) +{ + for(;;){ + if (*in->p){ + if (*in->p == '\n') { + in->base.line++; + IncLineNumber(); + } + return *in->p++; + } + if(++(cpp->PaWhichStr) < cpp->PaArgc){ + free(in); + SetStringNumber(cpp->PaWhichStr); + SetLineNumber(1); + ScanFromString(cpp->PaArgv[cpp->PaWhichStr]); + in=(StringInputSrc*)cpp->currentInput; + continue; + } + else{ + cpp->currentInput = in->base.prev; + cpp->PaWhichStr=0; + free(in); + return EOF; + } + } +} // str_getch + +static void str_ungetch(StringInputSrc *in, int ch, yystypepp *type) { + if (in->p[-1] == ch)in->p--; + else { + *(in->p)='\0'; //this would take care of shifting to the previous string. + cpp->PaWhichStr--; + } + if (ch == '\n') { + in->base.line--; + DecLineNumber(); + } +} // str_ungetch + +int ScanFromString(const char *s) +{ + + StringInputSrc *in = malloc(sizeof(StringInputSrc)); + memset(in, 0, sizeof(StringInputSrc)); + in->p = (char*) s; + in->base.line = 1; + in->base.scan = byte_scan; + in->base.getch = (int (*)(InputSrc *, yystypepp *))str_getch; + in->base.ungetch = (void (*)(InputSrc *, int, yystypepp *))str_ungetch; + in->base.prev = cpp->currentInput; + cpp->currentInput = &in->base; + + return 1; +} // ScanFromString; + + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Floating point constants: ///////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define APPEND_CHAR_S(ch, str, len, max_len) \ + if (len < max_len) { \ + str[len++] = ch; \ + } else if (!alreadyComplained) { \ + CPPErrorToInfoLog("BUFFER OVERFLOW"); \ + alreadyComplained = 1; \ + } + +/* + * lFloatConst() - Scan a floating point constant. Assumes that the scanner + * has seen at least one digit, followed by either a decimal '.' or the + * letter 'e'. + * ch - '.' or 'e' + * len - length of string already copied into yylvalpp->symbol_name. + */ + +static int lFloatConst(int ch, int len, yystypepp * yylvalpp) +{ + int alreadyComplained = 0; + assert((ch == '.') || (ch == 'e') || (ch == 'E')); + + if (ch == '.') { + do { + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch >= '0' && ch <= '9'); + } + + // Exponent: + if (ch == 'e' || ch == 'E') { + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '+') { + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } else if (ch == '-') { + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + if (ch >= '0' && ch <= '9') { + while (ch >= '0' && ch <= '9') { + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + } else { + CPPErrorToInfoLog("EXPONENT INVALID"); + } + } + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + + assert(len <= MAX_SYMBOL_NAME_LEN); + yylvalpp->symbol_name[len] = '\0'; + yylvalpp->sc_fval = (float) atof_dot(yylvalpp->symbol_name); + if (isinff(yylvalpp->sc_fval)) { + CPPErrorToInfoLog("FLOAT CONSTANT OVERFLOW"); + } + return CPP_FLOATCONSTANT; +} // lFloatConst + +/////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// Normal Scanner ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +static int byte_scan(InputSrc *in, yystypepp * yylvalpp) +{ + char string_val[MAX_STRING_LEN + 1]; + int alreadyComplained = 0; + int len, ch, ii, ival = 0; + + for (;;) { + yylvalpp->sc_int = 0; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + + while (ch == ' ' || ch == '\t' || ch == '\r') { + yylvalpp->sc_int = 1; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + + cpp->ltokenLoc.file = cpp->currentInput->name; + cpp->ltokenLoc.line = cpp->currentInput->line; + alreadyComplained = 0; + len = 0; + switch (ch) { + default: + return ch; // Single character token + case EOF: + return -1; + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + do { + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '_'); + assert(len <= MAX_SYMBOL_NAME_LEN); + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_ident = LookUpAddString(atable, yylvalpp->symbol_name); + return CPP_IDENTIFIER; + break; + case '0': + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == 'x' || ch == 'X') { // hexadecimal integer constants + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f')) + { + ival = 0; + do { + if ((ival <= 0x0fffffff) && (len < MAX_SYMBOL_NAME_LEN)) { + yylvalpp->symbol_name[len++] = ch; + if (ch >= '0' && ch <= '9') { + ii = ch - '0'; + } else if (ch >= 'A' && ch <= 'F') { + ii = ch - 'A' + 10; + } else { + ii = ch - 'a' + 10; + } + ival = (ival << 4) | ii; + } else if (!alreadyComplained) { + CPPErrorToInfoLog("HEX CONSTANT OVERFLOW"); + alreadyComplained = 1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f')); + } else { + CPPErrorToInfoLog("HEX CONSTANT INVALID"); + } + assert(len <= MAX_SYMBOL_NAME_LEN); + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_int = ival; + return CPP_INTCONSTANT; + } else if (ch >= '0' && ch <= '7') { // octal integer constants + ival = 0; + do { + if ((ival <= 0x1fffffff) && (len < MAX_SYMBOL_NAME_LEN)) { + yylvalpp->symbol_name[len++] = ch; + ii = ch - '0'; + ival = (ival << 3) | ii; + } else if (!alreadyComplained) { + CPPErrorToInfoLog("OCT CONSTANT OVERFLOW"); + alreadyComplained = 1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch >= '0' && ch <= '7'); + if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'h' || ch == 'x'|| ch == 'E') + return lFloatConst(ch, len, yylvalpp); + assert(len <= MAX_SYMBOL_NAME_LEN); + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_int = ival; + return CPP_INTCONSTANT; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + ch = '0'; + } + // Fall through... + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + do { + APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch >= '0' && ch <= '9'); + if (ch == '.' || ch == 'e' || ch == 'E') { + return lFloatConst(ch, len, yylvalpp); + } else { + assert(len <= MAX_SYMBOL_NAME_LEN); + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + ival = 0; + for (ii = 0; ii < len; ii++) { + ch = yylvalpp->symbol_name[ii] - '0'; + ival = ival*10 + ch; + if ((ival > 214748364) || (ival == 214748364 && ch >= 8)) { + CPPErrorToInfoLog("INTEGER CONSTANT OVERFLOW"); + break; + } + } + yylvalpp->sc_int = ival; + if(ival==0) + strcpy(yylvalpp->symbol_name,"0"); + return CPP_INTCONSTANT; + } + break; + case '-': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '-') { + return CPP_DEC_OP; + } else if (ch == '=') { + return CPP_SUB_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '-'; + } + case '+': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '+') { + return CPP_INC_OP; + } else if (ch == '=') { + return CPP_ADD_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '+'; + } + case '*': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_MUL_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '*'; + } + case '%': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_MOD_ASSIGN; + } else if (ch == '>'){ + return CPP_RIGHT_BRACE; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '%'; + } + case ':': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '>') { + return CPP_RIGHT_BRACKET; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return ':'; + } + case '^': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '^') { + return CPP_XOR_OP; + } else { + if (ch == '=') + return CPP_XOR_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '^'; + } + } + + case '=': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_EQ_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '='; + } + case '!': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_NE_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '!'; + } + case '|': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '|') { + return CPP_OR_OP; + } else { + if (ch == '=') + return CPP_OR_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '|'; + } + } + case '&': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '&') { + return CPP_AND_OP; + } else { + if (ch == '=') + return CPP_AND_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '&'; + } + } + case '<': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '<') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if(ch == '=') + return CPP_LEFT_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_LEFT_OP; + } + } else { + if (ch == '=') { + return CPP_LE_OP; + } else { + if (ch == '%') + return CPP_LEFT_BRACE; + else if (ch == ':') + return CPP_LEFT_BRACKET; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '<'; + } + } + } + case '>': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '>') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if(ch == '=') + return CPP_RIGHT_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_RIGHT_OP; + } + } else { + if (ch == '=') { + return CPP_GE_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '>'; + } + } + case '.': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch >= '0' && ch <= '9') { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return lFloatConst('.', 0, yylvalpp); + } else { + if (ch == '.') { + return -1; // Special EOF hack + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '.'; + } + } + case '/': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '/') { + do { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch != '\n' && ch != EOF); + if (ch == EOF) + return -1; + return '\n'; + } else if (ch == '*') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + do { + while (ch != '*') { + if (ch == EOF) { + CPPErrorToInfoLog("EOF IN COMMENT"); + return -1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == EOF) { + CPPErrorToInfoLog("EOF IN COMMENT"); + return -1; + } + } while (ch != '/'); + // Go try it again... + } else if (ch == '=') { + return CPP_DIV_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '/'; + } + break; + case '"': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + while (ch != '"' && ch != '\n' && ch != EOF) { + if (ch == '\\') { + CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language"); + return -1; + } + APPEND_CHAR_S(ch, string_val, len, MAX_STRING_LEN); + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + }; + assert(len <= MAX_STRING_LEN); + string_val[len] = '\0'; + if (ch == '"') { + yylvalpp->sc_ident = LookUpAddString(atable, string_val); + return CPP_STRCONSTANT; + } else { + CPPErrorToInfoLog("EOL IN STRING"); + return ERROR_SY; + } + break; + } + } +} // byte_scan + +int yylex_CPP(char* buf, int maxSize) +{ + yystypepp yylvalpp; + int token = '\n'; + + for(;;) { + + char* tokenString = 0; + token = cpp->currentInput->scan(cpp->currentInput, &yylvalpp); + if(check_EOF(token)) + return 0; + if (token < 0) { + // This check may need to be improved to support UTF-8 + // characters in comments. + CPPErrorToInfoLog("preprocessor encountered non-ASCII character in shader source"); + return 0; + } + if (token == '#') { + if (cpp->previous_token == '\n'|| cpp->previous_token == 0) { + token = readCPPline(&yylvalpp); + if(check_EOF(token)) + return 0; + continue; + } else { + CPPErrorToInfoLog("preprocessor command must not be preceded by any other statement in that line"); + return 0; + } + } + cpp->previous_token = token; + // expand macros + if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp.sc_ident, &yylvalpp)) { + cpp->pastFirstStatement = 1; + continue; + } + + if (token == '\n') + continue; + cpp->pastFirstStatement = 1; + + if (token == CPP_IDENTIFIER) { + tokenString = GetStringOfAtom(atable,yylvalpp.sc_ident); + } else if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){ + tokenString = yylvalpp.symbol_name; + } else { + tokenString = GetStringOfAtom(atable,token); + } + + if (tokenString) { + int len = strlen(tokenString); + cpp->tokensBeforeEOF = 1; + if (len >= maxSize) { + return maxSize; + } else if (len > 0) { + strcpy(buf, tokenString); + return len; + } + + return 0; + } + } +} // yylex + +//Checks if the token just read is EOF or not. +int check_EOF(int token) +{ + if(token==-1){ + if(cpp->ifdepth >0){ + CPPErrorToInfoLog("#endif missing!! Compilation stopped"); + cpp->CompileError=1; + } + return 1; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////// End of scanner.c ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/scanner.h b/src/3rdparty/angle/src/compiler/preprocessor/scanner.h new file mode 100644 index 0000000000..b67c1d644e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/scanner.h @@ -0,0 +1,81 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// scanner.h +// + +#if !defined(__SCANNER_H) +#define __SCANNER_H 1 + +#include "compiler/preprocessor/length_limits.h" +#include "compiler/preprocessor/parser.h" + +// Not really atom table stuff but needed first... + +typedef struct SourceLoc_Rec { + unsigned short file, line; +} SourceLoc; + +int yylex_CPP(char* buf, int maxSize); + +typedef struct InputSrc { + struct InputSrc *prev; + int (*scan)(struct InputSrc *, yystypepp *); + int (*getch)(struct InputSrc *, yystypepp *); + void (*ungetch)(struct InputSrc *, int, yystypepp *); + int name; /* atom */ + int line; +} InputSrc; + +int InitScanner(CPPStruct *cpp); // Intialise the cpp scanner. +int InitScannerInput(CPPStruct *cpp, int count, const char* const string[], const int length[]); +int check_EOF(int); // check if we hit a EOF abruptly +void CPPErrorToInfoLog(const char *); // sticking the msg,line into the Shader's.Info.log +void SetLineNumber(int); +void SetStringNumber(int); +void IncLineNumber(void); +void DecLineNumber(void); +int FreeScanner(void); // Free the cpp scanner +#endif // !(defined(__SCANNER_H) + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/slglobals.h b/src/3rdparty/angle/src/compiler/preprocessor/slglobals.h new file mode 100644 index 0000000000..4634626643 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/slglobals.h @@ -0,0 +1,82 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// slglobals.h +// + +#if !defined(__SLGLOBALS_H) +#define __SLGLOBALS_H 1 + +typedef struct CPPStruct_Rec CPPStruct; + +extern CPPStruct *cpp; + +#undef CPPC_DEBUG_THE_COMPILER +#if defined(_DEBUG) +#define CPPC_DEBUG_THE_COMPILER 1 +#endif + +#undef CPPC_ENABLE_TOOLS +#define CPPC_ENABLE_TOOLS 1 + +#include "compiler/preprocessor/memory.h" +#include "compiler/preprocessor/atom.h" +#include "compiler/preprocessor/scanner.h" +#include "compiler/preprocessor/cpp.h" +#include "compiler/preprocessor/tokens.h" +#include "compiler/preprocessor/symbols.h" +#include "compiler/preprocessor/compile.h" +#if !defined(NO_PARSER) +#include "compiler/preprocessor/parser.h" +#endif + +#if !defined(NULL) +#define NULL 0 +#endif + +#endif // !(defined(__SLGLOBALS_H) + + + + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/symbols.c b/src/3rdparty/angle/src/compiler/preprocessor/symbols.c new file mode 100644 index 0000000000..f18b2569b3 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/symbols.c @@ -0,0 +1,288 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// symbols.c +// + +#include +#include +#include + +#include "compiler/preprocessor/slglobals.h" + +#if defined(_MSC_VER) +#pragma warning(disable: 4706) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Symbol Table Variables: /////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +Scope *ScopeList = NULL; +Scope *CurrentScope = NULL; +Scope *GlobalScope = NULL; + +static void unlinkScope(void *_scope) { + Scope *scope = _scope; + + if (scope->next) + scope->next->prev = scope->prev; + if (scope->prev) + scope->prev->next = scope->next; + else + ScopeList = scope->next; +} + +/* + * NewScope() + * + */ +Scope *NewScopeInPool(MemoryPool *pool) +{ + Scope *lScope; + + lScope = mem_Alloc(pool, sizeof(Scope)); + lScope->pool = pool; + lScope->parent = NULL; + lScope->funScope = NULL; + lScope->symbols = NULL; + + lScope->level = 0; + + lScope->programs = NULL; + if ((lScope->next = ScopeList)) + ScopeList->prev = lScope; + lScope->prev = 0; + ScopeList = lScope; + mem_AddCleanup(pool, unlinkScope, lScope); + return lScope; +} // NewScope + +/* + * PushScope() + * + */ + +void PushScope(Scope *fScope) +{ + Scope *lScope; + + if (CurrentScope) { + fScope->level = CurrentScope->level + 1; + if (fScope->level == 1) { + if (!GlobalScope) { + /* HACK - CTD -- if GlobalScope==NULL and level==1, we're + * defining a function in the superglobal scope. Things + * will break if we leave the level as 1, so we arbitrarily + * set it to 2 */ + fScope->level = 2; + } + } + if (fScope->level >= 2) { + lScope = fScope; + while (lScope->level > 2) + lScope = lScope->next; + fScope->funScope = lScope; + } + } else { + fScope->level = 0; + } + fScope->parent = CurrentScope; + CurrentScope = fScope; +} // PushScope + +/* + * PopScope() + * + */ + +Scope *PopScope(void) +{ + Scope *lScope; + + lScope = CurrentScope; + if (CurrentScope) + CurrentScope = CurrentScope->parent; + return lScope; +} // PopScope + +/* + * NewSymbol() - Allocate a new symbol node; + * + */ + +Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind) +{ + Symbol *lSymb; + char *pch; + unsigned int ii; + + lSymb = (Symbol *) mem_Alloc(fScope->pool, sizeof(Symbol)); + lSymb->left = NULL; + lSymb->right = NULL; + lSymb->next = NULL; + lSymb->name = name; + lSymb->loc = *loc; + lSymb->kind = kind; + + // Clear union area: + + pch = (char *) &lSymb->details; + for (ii = 0; ii < sizeof(lSymb->details); ii++) + *pch++ = 0; + return lSymb; +} // NewSymbol + +/* + * lAddToTree() - Using a binary tree is not a good idea for basic atom values because they + * are generated in order. We'll fix this later (by reversing the bit pattern). + */ + +static void lAddToTree(Symbol **fSymbols, Symbol *fSymb) +{ + Symbol *lSymb; + int lrev, frev; + + lSymb = *fSymbols; + if (lSymb) { + frev = GetReversedAtom(atable, fSymb->name); + while (lSymb) { + lrev = GetReversedAtom(atable, lSymb->name); + if (lrev == frev) { + CPPErrorToInfoLog("GetAtomString(atable, fSymb->name)"); + break; + } else { + if (lrev > frev) { + if (lSymb->left) { + lSymb = lSymb->left; + } else { + lSymb->left = fSymb; + break; + } + } else { + if (lSymb->right) { + lSymb = lSymb->right; + } else { + lSymb->right = fSymb; + break; + } + } + } + } + } else { + *fSymbols = fSymb; + } +} // lAddToTree + + +/* + * AddSymbol() - Add a variable, type, or function name to a scope. + * + */ + +Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind) +{ + Symbol *lSymb; + + if (!fScope) + fScope = CurrentScope; + lSymb = NewSymbol(loc, fScope, atom, kind); + lAddToTree(&fScope->symbols, lSymb); + return lSymb; +} // AddSymbol + + +/*********************************************************************************************/ +/************************************ Symbol Semantic Functions ******************************/ +/*********************************************************************************************/ + +/* + * LookUpLocalSymbol() + * + */ + +Symbol *LookUpLocalSymbol(Scope *fScope, int atom) +{ + Symbol *lSymb; + int rname, ratom; + + ratom = GetReversedAtom(atable, atom); + if (!fScope) + fScope = CurrentScope; + lSymb = fScope->symbols; + while (lSymb) { + rname = GetReversedAtom(atable, lSymb->name); + if (rname == ratom) { + return lSymb; + } else { + if (rname > ratom) { + lSymb = lSymb->left; + } else { + lSymb = lSymb->right; + } + } + } + return NULL; +} // LookUpLocalSymbol + +/* + * LookUpSymbol() + * + */ + +Symbol *LookUpSymbol(Scope *fScope, int atom) +{ + Symbol *lSymb; + + if (!fScope) + fScope = CurrentScope; + while (fScope) { + lSymb = LookUpLocalSymbol(fScope, atom); + if (lSymb) + return lSymb; + fScope = fScope->parent; + } + return NULL; +} // LookUpSymbol + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/symbols.h b/src/3rdparty/angle/src/compiler/preprocessor/symbols.h new file mode 100644 index 0000000000..e7d0b075fa --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/symbols.h @@ -0,0 +1,111 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// symbols.h +// + +#if !defined(__SYMBOLS_H) +#define __SYMBOLS_H 1 + +#include "compiler/preprocessor/memory.h" + +typedef enum symbolkind { + MACRO_S +} symbolkind; + +// Typedefs for things defined here in "symbols.h": + +typedef struct Scope_Rec Scope; +typedef struct Symbol_Rec Symbol; + +typedef struct SymbolList_Rec { + struct SymbolList_Rec *next; + Symbol *symb; +} SymbolList; + +struct Scope_Rec { + Scope *next, *prev; // doubly-linked list of all scopes + Scope *parent; + Scope *funScope; // Points to base scope of enclosing function + MemoryPool *pool; // pool used for allocation in this scope + Symbol *symbols; + + int level; // 0 = super globals, 1 = globals, etc. + + // Only used at global scope (level 1): + SymbolList *programs; // List of programs for this compilation. +}; + + +// Symbol table is a simple binary tree. + +#include "compiler/preprocessor/cpp.h" // to get MacroSymbol def + +struct Symbol_Rec { + Symbol *left, *right; + Symbol *next; + int name; // Name atom + SourceLoc loc; + symbolkind kind; + union { + MacroSymbol mac; + } details; +}; + +extern Scope *CurrentScope; +extern Scope *GlobalScope; +extern Scope *ScopeList; + +Scope *NewScopeInPool(MemoryPool *); +#define NewScope() NewScopeInPool(CurrentScope->pool) +void PushScope(Scope *fScope); +Scope *PopScope(void); +Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind); +Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind); +Symbol *LookUpLocalSymbol(Scope *fScope, int atom); +Symbol *LookUpSymbol(Scope *fScope, int atom); + + +#endif // !defined(__SYMBOLS_H) + diff --git a/src/3rdparty/angle/src/compiler/preprocessor/tokens.c b/src/3rdparty/angle/src/compiler/preprocessor/tokens.c new file mode 100644 index 0000000000..b94c05ebd4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/tokens.c @@ -0,0 +1,467 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// tokens.c +// + +#include +#include +#include +#include + +#include "common/angleutils.h" +#include "compiler/debug.h" +#include "compiler/preprocessor/slglobals.h" +#include "compiler/util.h" + +#if defined(_MSC_VER) +#pragma warning(disable: 4054) +#pragma warning(disable: 4152) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////// Preprocessor and Token Recorder and Playback: //////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +/* + * idstr() + * Copy a string to a malloc'ed block and convert it into something suitable + * for an ID + * + */ + +static char *idstr(const char *fstr, MemoryPool *pool) +{ + size_t len; + char *str, *t; + const char *f; + + len = strlen(fstr); + if (!pool) + str = (char *) malloc(len + 1); + else + str = (char *) mem_Alloc(pool, len + 1); + + for (f=fstr, t=str; *f; f++) { + if (isalnum(*f)) *t++ = *f; + else if (*f == '.' || *f == '/') *t++ = '_'; + } + *t = 0; + return str; +} // idstr + + +/* + * lNewBlock() + * + */ + +static TokenBlock *lNewBlock(TokenStream *fTok, MemoryPool *pool) +{ + TokenBlock *lBlock; + + if (!pool) + lBlock = (TokenBlock *) malloc(sizeof(TokenBlock) + 256); + else + lBlock = (TokenBlock *) mem_Alloc(pool, sizeof(TokenBlock) + 256); + lBlock->count = 0; + lBlock->current = 0; + lBlock->data = (unsigned char *) lBlock + sizeof(TokenBlock); + lBlock->max = 256; + lBlock->next = NULL; + if (fTok->head) { + fTok->current->next = lBlock; + } else { + fTok->head = lBlock; + } + fTok->current = lBlock; + return lBlock; +} // lNewBlock + +/* + * lAddByte() + * + */ + +static void lAddByte(TokenStream *fTok, unsigned char fVal) +{ + TokenBlock *lBlock; + lBlock = fTok->current; + if (lBlock->count >= lBlock->max) + lBlock = lNewBlock(fTok, 0); + lBlock->data[lBlock->count++] = fVal; +} // lAddByte + + + +/* + * lReadByte() - Get the next byte from a stream. + * + */ + +static int lReadByte(TokenStream *pTok) +{ + TokenBlock *lBlock; + int lval = -1; + + lBlock = pTok->current; + if (lBlock) { + if (lBlock->current >= lBlock->count) { + lBlock = lBlock->next; + if (lBlock) + lBlock->current = 0; + pTok->current = lBlock; + } + if (lBlock) + lval = lBlock->data[lBlock->current++]; + } + return lval; +} // lReadByte + +/////////////////////////////////////// Global Functions:////////////////////////////////////// + +/* + * NewTokenStream() + * + */ + +TokenStream *NewTokenStream(const char *name, MemoryPool *pool) +{ + TokenStream *pTok; + + if (!pool) + pTok = (TokenStream *) malloc(sizeof(TokenStream)); + else + pTok = (TokenStream*)mem_Alloc(pool, sizeof(TokenStream)); + pTok->next = NULL; + pTok->name = idstr(name, pool); + pTok->head = NULL; + pTok->current = NULL; + lNewBlock(pTok, pool); + return pTok; +} // NewTokenStream + +/* + * DeleteTokenStream() + * + */ + +void DeleteTokenStream(TokenStream *pTok) +{ + TokenBlock *pBlock, *nBlock; + + if (pTok) { + pBlock = pTok->head; + while (pBlock) { + nBlock = pBlock->next; + free(pBlock); + pBlock = nBlock; + } + if (pTok->name) + free(pTok->name); + free(pTok); + } +} // DeleteTokenStream + +/* + * RecordToken() - Add a token to the end of a list for later playback or printout. + * + */ + +void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp) +{ + const char *s; + char *str=NULL; + + if (token > 256) + lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80)); + else + lAddByte(pTok, (unsigned char)(token & 0x7f)); + switch (token) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + case CPP_STRCONSTANT: + s = GetAtomString(atable, yylvalpp->sc_ident); + while (*s) + lAddByte(pTok, (unsigned char) *s++); + lAddByte(pTok, 0); + break; + case CPP_FLOATCONSTANT: + case CPP_INTCONSTANT: + str=yylvalpp->symbol_name; + while (*str){ + lAddByte(pTok, (unsigned char) *str++); + } + lAddByte(pTok, 0); + break; + case '(': + lAddByte(pTok, (unsigned char)(yylvalpp->sc_int ? 1 : 0)); + default: + break; + } +} // RecordToken + +/* + * RewindTokenStream() - Reset a token stream in preperation for reading. + * + */ + +void RewindTokenStream(TokenStream *pTok) +{ + if (pTok->head) { + pTok->current = pTok->head; + pTok->current->current = 0; + } +} // RewindTokenStream + +/* + * ReadToken() - Read the next token from a stream. + * + */ + +int ReadToken(TokenStream *pTok, yystypepp * yylvalpp) +{ + char symbol_name[MAX_SYMBOL_NAME_LEN + 1]; + char string_val[MAX_STRING_LEN + 1]; + int ltoken, len; + char ch; + int base, accum; + char ch_val; + + ltoken = lReadByte(pTok); + if (ltoken >= 0) { + if (ltoken > 127) + ltoken += 128; + switch (ltoken) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + len = 0; + ch = lReadByte(pTok); + while ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '_') + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len++] = ch; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + yylvalpp->sc_ident = LookUpAddString(atable, symbol_name); + return CPP_IDENTIFIER; + break; + case CPP_STRCONSTANT: + len = 0; + while ((ch = lReadByte(pTok)) != 0) + if (len < MAX_STRING_LEN) + string_val[len++] = ch; + string_val[len] = '\0'; + yylvalpp->sc_ident = LookUpAddString(atable, string_val); + break; + case CPP_FLOATCONSTANT: + len = 0; + ch = lReadByte(pTok); + while ((ch >= '0' && ch <= '9')||(ch=='e'||ch=='E'||ch=='.')||(ch=='+'||ch=='-')) + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len++] = ch; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + strcpy(yylvalpp->symbol_name,symbol_name); + yylvalpp->sc_fval=(float)atof_dot(yylvalpp->symbol_name); + break; + case CPP_INTCONSTANT: + len = 0; + accum = 0; + ch = lReadByte(pTok); + if (ch == '0') { + symbol_name[len++] = ch; + ch = lReadByte(pTok); + if (ch == 'x' || ch == 'X') { + symbol_name[len++] = ch; + base = 16; + ch = lReadByte(pTok); + } else { + base = 8; + } + } else { + base = 10; + } + + while (len < MAX_SYMBOL_NAME_LEN) + { + ch_val = -1; + if (isdigit(ch)) + ch_val = ch - '0'; + else if (isxdigit(ch)) + ch_val = tolower(ch) - 'a' + 10; + + if (ch_val < 0 || ch_val >= base) + break; + + symbol_name[len++] = ch; + accum = accum * base + ch_val; + ch = lReadByte(pTok); + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + strcpy(yylvalpp->symbol_name, symbol_name); + yylvalpp->sc_int = accum; + break; + case '(': + yylvalpp->sc_int = lReadByte(pTok); + break; + } + return ltoken; + } + return EOF_SY; +} // ReadToken + +typedef struct TokenInputSrc { + InputSrc base; + TokenStream *tokens; + int (*final)(CPPStruct *); +} TokenInputSrc; + +static int scan_token(TokenInputSrc *in, yystypepp * yylvalpp) +{ + int token = ReadToken(in->tokens, yylvalpp); + int (*final)(CPPStruct *); + cpp->tokenLoc->file = cpp->currentInput->name; + cpp->tokenLoc->line = cpp->currentInput->line; + if (token == '\n') { + in->base.line++; + return token; + } + if (token > 0) return token; + cpp->currentInput = in->base.prev; + final = in->final; + free(in); + if (final && !final(cpp)) return -1; + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); +} + +int ReadFromTokenStream(TokenStream *ts, int name, int (*final)(CPPStruct *)) +{ + TokenInputSrc *in = malloc(sizeof(TokenInputSrc)); + memset(in, 0, sizeof(TokenInputSrc)); + in->base.name = name; + in->base.prev = cpp->currentInput; + in->base.scan = (int (*)(InputSrc *, yystypepp *))scan_token; + in->base.line = 1; + in->tokens = ts; + in->final = final; + RewindTokenStream(ts); + cpp->currentInput = &in->base; + return 1; +} + +typedef struct UngotToken { + InputSrc base; + int token; + yystypepp lval; +} UngotToken; + +static int reget_token(UngotToken *t, yystypepp * yylvalpp) +{ + int token = t->token; + *yylvalpp = t->lval; + cpp->currentInput = t->base.prev; + free(t); + return token; +} + +void UngetToken(int token, yystypepp * yylvalpp) { + UngotToken *t = malloc(sizeof(UngotToken)); + memset(t, 0, sizeof(UngotToken)); + t->token = token; + t->lval = *yylvalpp; + t->base.scan = (void *)reget_token; + t->base.prev = cpp->currentInput; + t->base.name = cpp->currentInput->name; + t->base.line = cpp->currentInput->line; + cpp->currentInput = &t->base; +} + + +void DumpTokenStream(FILE *fp, TokenStream *s, yystypepp * yylvalpp) { + int token; + char str[100]; + + if (fp == 0) fp = stdout; + RewindTokenStream(s); + while ((token = ReadToken(s, yylvalpp)) > 0) { + switch (token) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + snprintf(str, sizeof(str), "%s ", GetAtomString(atable, yylvalpp->sc_ident)); + break; + case CPP_STRCONSTANT: + snprintf(str, sizeof(str), "\"%s\"", GetAtomString(atable, yylvalpp->sc_ident)); + break; + case CPP_FLOATCONSTANT: + //printf("%g9.6 ", yylvalpp->sc_fval); + break; + case CPP_INTCONSTANT: + //printf("%d ", yylvalpp->sc_int); + break; + default: + if (token >= 127) + snprintf(str, sizeof(str), "%s ", GetAtomString(atable, token)); + else + snprintf(str, sizeof(str), "%c", token); + break; + } + CPPDebugLogMsg(str); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////// End of tokens.c /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/3rdparty/angle/src/compiler/preprocessor/tokens.h b/src/3rdparty/angle/src/compiler/preprocessor/tokens.h new file mode 100644 index 0000000000..dbf4a2ccfe --- /dev/null +++ b/src/3rdparty/angle/src/compiler/preprocessor/tokens.h @@ -0,0 +1,90 @@ +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// tokens.h +// + +#if !defined(__TOKENS_H) +#define __TOKENS_H 1 + +#include +#include "compiler/preprocessor/parser.h" + +#define EOF_SY (-1) + +typedef struct TokenBlock_Rec TokenBlock; + +typedef struct TokenStream_Rec { + struct TokenStream_Rec *next; + char *name; + TokenBlock *head; + TokenBlock *current; +} TokenStream; + +struct TokenBlock_Rec { + TokenBlock *next; + int current; + int count; + int max; + unsigned char *data; +}; + +extern TokenStream stdlib_cpp_stream; + + +TokenStream *NewTokenStream(const char *name, MemoryPool *pool); +void DeleteTokenStream(TokenStream *pTok); +void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp); +void RewindTokenStream(TokenStream *pTok); +int ReadToken(TokenStream *pTok, yystypepp * yylvalpp); +int ReadFromTokenStream(TokenStream *pTok, int name, int (*final)(CPPStruct *)); +void UngetToken(int, yystypepp * yylvalpp); + +#if defined(CPPC_ENABLE_TOOLS) + +void DumpTokenStream(FILE *, TokenStream *, yystypepp * yylvalpp); + +#endif // defined(CPPC_ENABLE_TOOLS) + +#endif // !defined(__TOKENS_H) diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp new file mode 100644 index 0000000000..538b731b8e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp @@ -0,0 +1,127 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/InfoSink.h" +#include "compiler/ParseHelper.h" +#include "compiler/depgraph/DependencyGraphOutput.h" +#include "compiler/timing/RestrictFragmentShaderTiming.h" + +RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink) + : mSink(sink) + , mNumErrors(0) +{ + // Sampling ops found only in fragment shaders. + mSamplingOps.insert("texture2D(s21;vf2;f1;"); + mSamplingOps.insert("texture2DProj(s21;vf3;f1;"); + mSamplingOps.insert("texture2DProj(s21;vf4;f1;"); + mSamplingOps.insert("textureCube(sC1;vf3;f1;"); + // Sampling ops found in both vertex and fragment shaders. + mSamplingOps.insert("texture2D(s21;vf2;"); + mSamplingOps.insert("texture2DProj(s21;vf3;"); + mSamplingOps.insert("texture2DProj(s21;vf4;"); + mSamplingOps.insert("textureCube(sC1;vf3;"); + // Sampling ops provided by OES_EGL_image_external. + mSamplingOps.insert("texture2D(1;vf2;"); + mSamplingOps.insert("texture2DProj(1;vf3;"); + mSamplingOps.insert("texture2DProj(1;vf4;"); + // Sampling ops provided by ARB_texture_rectangle. + mSamplingOps.insert("texture2DRect(1;vf2;"); + mSamplingOps.insert("texture2DRectProj(1;vf3;"); + mSamplingOps.insert("texture2DRectProj(1;vf4;"); +} + +// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc. +// can vary based on the value of the input arguments. If so, we should restrict those as well. +void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph) +{ + mNumErrors = 0; + + // FIXME(mvujovic): The dependency graph does not support user defined function calls right now, + // so we generate errors for them. + validateUserDefinedFunctionCallUsage(graph); + + // Starting from each sampler, traverse the dependency graph and generate an error each time we + // hit a node where sampler dependent values are not allowed. + for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols(); + iter != graph.endSamplerSymbols(); + ++iter) + { + TGraphSymbol* samplerSymbol = *iter; + clearVisited(); + samplerSymbol->traverse(this); + } +} + +void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph) +{ + for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); + iter != graph.endUserDefinedFunctionCalls(); + ++iter) + { + TGraphFunctionCall* functionCall = *iter; + beginError(functionCall->getIntermFunctionCall()); + mSink << "A call to a user defined function is not permitted.\n"; + } +} + +void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) +{ + ++mNumErrors; + mSink.prefix(EPrefixError); + mSink.location(node->getLine()); +} + +bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const +{ + return !intermFunctionCall->isUserDefined() && + mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); +} + +void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter) +{ + // Texture cache access time might leak sensitive information. + // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a + // sampling operation. + if (isSamplingOp(parameter->getIntermFunctionCall())) { + switch (parameter->getArgumentNumber()) { + case 1: + // Second argument (coord) + beginError(parameter->getIntermFunctionCall()); + mSink << "An expression dependent on a sampler is not permitted to be the" + << " coordinate argument of a sampling operation.\n"; + break; + case 2: + // Third argument (bias) + beginError(parameter->getIntermFunctionCall()); + mSink << "An expression dependent on a sampler is not permitted to be the" + << " bias argument of a sampling operation.\n"; + break; + default: + // First argument (sampler) + break; + } + } +} + +void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection) +{ + beginError(selection->getIntermSelection()); + mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n"; +} + +void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop) +{ + beginError(loop->getIntermLoop()); + mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n"; +} + +void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp) +{ + beginError(logicalOp->getIntermLogicalOp()); + mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical " + << logicalOp->getOpString() + << " operator.\n"; +} diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h new file mode 100644 index 0000000000..899165ca28 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ +#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/intermediate.h" +#include "compiler/depgraph/DependencyGraph.h" + +class TInfoSinkBase; + +class RestrictFragmentShaderTiming : TDependencyGraphTraverser { +public: + RestrictFragmentShaderTiming(TInfoSinkBase& sink); + void enforceRestrictions(const TDependencyGraph& graph); + int numErrors() const { return mNumErrors; } + + virtual void visitArgument(TGraphArgument* parameter); + virtual void visitSelection(TGraphSelection* selection); + virtual void visitLoop(TGraphLoop* loop); + virtual void visitLogicalOp(TGraphLogicalOp* logicalOp); + +private: + void beginError(const TIntermNode* node); + void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph); + bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const; + + TInfoSinkBase& mSink; + int mNumErrors; + + typedef std::set StringSet; + StringSet mSamplingOps; +}; + +#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp new file mode 100644 index 0000000000..524c6cf53a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp @@ -0,0 +1,17 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/timing/RestrictVertexShaderTiming.h" + +void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node) +{ + if (IsSampler(node->getBasicType())) { + ++mNumErrors; + mSink.prefix(EPrefixError); + mSink.location(node->getLine()); + mSink << "Samplers are not permitted in vertex shaders.\n"; + } +} diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h new file mode 100644 index 0000000000..19a05fa68b --- /dev/null +++ b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ +#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/intermediate.h" +#include "compiler/InfoSink.h" + +class TInfoSinkBase; + +class RestrictVertexShaderTiming : public TIntermTraverser { +public: + RestrictVertexShaderTiming(TInfoSinkBase& sink) + : TIntermTraverser(true, false, false) + , mSink(sink) + , mNumErrors(0) {} + + void enforceRestrictions(TIntermNode* root) { root->traverse(this); } + int numErrors() { return mNumErrors; } + + virtual void visitSymbol(TIntermSymbol*); +private: + TInfoSinkBase& mSink; + int mNumErrors; +}; + +#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/util.cpp b/src/3rdparty/angle/src/compiler/util.cpp new file mode 100644 index 0000000000..b46e4d0e34 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/util.cpp @@ -0,0 +1,33 @@ +// +// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include +#include + +#include "util.h" + +#ifdef _MSC_VER + #include +#else + #include +#endif + +double atof_dot(const char *str) +{ +#ifdef _MSC_VER + _locale_t l = _create_locale(LC_NUMERIC, "C"); + double result = _atof_l(str, l); + _free_locale(l); + return result; +#else + double result; + std::istringstream s(str); + std::locale l("C"); + s.imbue(l); + s >> result; + return result; +#endif +} diff --git a/src/3rdparty/angle/src/compiler/util.h b/src/3rdparty/angle/src/compiler/util.h new file mode 100644 index 0000000000..35288b7396 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/util.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_UTIL_H +#define COMPILER_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +// atof_dot is like atof but forcing C locale, i.e. forcing '.' as decimal point. +double atof_dot(const char *str); + +#ifdef __cplusplus +} // end extern "C" +#endif + +#endif // COMPILER_UTIL_H diff --git a/src/3rdparty/angle/src/libEGL/Config.cpp b/src/3rdparty/angle/src/libEGL/Config.cpp new file mode 100644 index 0000000000..89bc8d89f4 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Config.cpp @@ -0,0 +1,399 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Config.cpp: Implements the egl::Config class, describing the format, type +// and size for an egl::Surface. Implements EGLConfig and related functionality. +// [EGL 1.4] section 3.4 page 15. + +#include "libEGL/Config.h" + +#include +#include + +#include "common/debug.h" + +using namespace std; + +namespace egl +{ +Config::Config(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight) + : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample) +{ + set(displayMode, minInterval, maxInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight); +} + +void Config::setDefaults() +{ + mBufferSize = 0; + mRedSize = 0; + mGreenSize = 0; + mBlueSize = 0; + mLuminanceSize = 0; + mAlphaSize = 0; + mAlphaMaskSize = 0; + mBindToTextureRGB = EGL_DONT_CARE; + mBindToTextureRGBA = EGL_DONT_CARE; + mColorBufferType = EGL_RGB_BUFFER; + mConfigCaveat = EGL_DONT_CARE; + mConfigID = EGL_DONT_CARE; + mConformant = 0; + mDepthSize = 0; + mLevel = 0; + mMatchNativePixmap = EGL_NONE; + mMaxPBufferWidth = 0; + mMaxPBufferHeight = 0; + mMaxPBufferPixels = 0; + mMaxSwapInterval = EGL_DONT_CARE; + mMinSwapInterval = EGL_DONT_CARE; + mNativeRenderable = EGL_DONT_CARE; + mNativeVisualID = 0; + mNativeVisualType = EGL_DONT_CARE; + mRenderableType = EGL_OPENGL_ES_BIT; + mSampleBuffers = 0; + mSamples = 0; + mStencilSize = 0; + mSurfaceType = EGL_WINDOW_BIT; + mTransparentType = EGL_NONE; + mTransparentRedValue = EGL_DONT_CARE; + mTransparentGreenValue = EGL_DONT_CARE; + mTransparentBlueValue = EGL_DONT_CARE; +} + +void Config::set(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight) +{ + mBindToTextureRGB = EGL_FALSE; + mBindToTextureRGBA = EGL_FALSE; + switch (renderTargetFormat) + { + case D3DFMT_A1R5G5B5: + mBufferSize = 16; + mRedSize = 5; + mGreenSize = 5; + mBlueSize = 5; + mAlphaSize = 1; + break; + case D3DFMT_A2R10G10B10: + mBufferSize = 32; + mRedSize = 10; + mGreenSize = 10; + mBlueSize = 10; + mAlphaSize = 2; + break; + case D3DFMT_A8R8G8B8: + mBufferSize = 32; + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + mAlphaSize = 8; + mBindToTextureRGBA = true; + break; + case D3DFMT_R5G6B5: + mBufferSize = 16; + mRedSize = 5; + mGreenSize = 6; + mBlueSize = 5; + mAlphaSize = 0; + break; + case D3DFMT_X8R8G8B8: + mBufferSize = 32; + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + mAlphaSize = 0; + mBindToTextureRGB = true; + break; + default: + UNREACHABLE(); // Other formats should not be valid + } + + mLuminanceSize = 0; + mAlphaMaskSize = 0; + mColorBufferType = EGL_RGB_BUFFER; + mConfigCaveat = (displayMode.Format == renderTargetFormat) ? EGL_NONE : EGL_SLOW_CONFIG; + mConfigID = 0; + mConformant = EGL_OPENGL_ES2_BIT; + + switch (depthStencilFormat) + { + case D3DFMT_UNKNOWN: + mDepthSize = 0; + mStencilSize = 0; + break; +// case D3DFMT_D16_LOCKABLE: +// mDepthSize = 16; +// mStencilSize = 0; +// break; + case D3DFMT_D32: + mDepthSize = 32; + mStencilSize = 0; + break; + case D3DFMT_D15S1: + mDepthSize = 15; + mStencilSize = 1; + break; + case D3DFMT_D24S8: + mDepthSize = 24; + mStencilSize = 8; + break; + case D3DFMT_D24X8: + mDepthSize = 24; + mStencilSize = 0; + break; + case D3DFMT_D24X4S4: + mDepthSize = 24; + mStencilSize = 4; + break; + case D3DFMT_D16: + mDepthSize = 16; + mStencilSize = 0; + break; +// case D3DFMT_D32F_LOCKABLE: +// mDepthSize = 32; +// mStencilSize = 0; +// break; +// case D3DFMT_D24FS8: +// mDepthSize = 24; +// mStencilSize = 8; +// break; + default: + UNREACHABLE(); + } + + mLevel = 0; + mMatchNativePixmap = EGL_NONE; + mMaxPBufferWidth = texWidth; + mMaxPBufferHeight = texHeight; + mMaxPBufferPixels = texWidth*texHeight; + mMaxSwapInterval = maxInterval; + mMinSwapInterval = minInterval; + mNativeRenderable = EGL_FALSE; + mNativeVisualID = 0; + mNativeVisualType = 0; + mRenderableType = EGL_OPENGL_ES2_BIT; + mSampleBuffers = multiSample ? 1 : 0; + mSamples = multiSample; + mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + mTransparentType = EGL_NONE; + mTransparentRedValue = 0; + mTransparentGreenValue = 0; + mTransparentBlueValue = 0; +} + +EGLConfig Config::getHandle() const +{ + return (EGLConfig)(size_t)mConfigID; +} + +SortConfig::SortConfig(const EGLint *attribList) + : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false) +{ + scanForWantedComponents(attribList); +} + +void SortConfig::scanForWantedComponents(const EGLint *attribList) +{ + // [EGL] section 3.4.1 page 24 + // Sorting rule #3: by larger total number of color bits, not considering + // components that are 0 or don't-care. + for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2) + { + if (attr[1] != 0 && attr[1] != EGL_DONT_CARE) + { + switch (attr[0]) + { + case EGL_RED_SIZE: mWantRed = true; break; + case EGL_GREEN_SIZE: mWantGreen = true; break; + case EGL_BLUE_SIZE: mWantBlue = true; break; + case EGL_ALPHA_SIZE: mWantAlpha = true; break; + case EGL_LUMINANCE_SIZE: mWantLuminance = true; break; + } + } + } +} + +EGLint SortConfig::wantedComponentsSize(const Config &config) const +{ + EGLint total = 0; + + if (mWantRed) total += config.mRedSize; + if (mWantGreen) total += config.mGreenSize; + if (mWantBlue) total += config.mBlueSize; + if (mWantAlpha) total += config.mAlphaSize; + if (mWantLuminance) total += config.mLuminanceSize; + + return total; +} + +bool SortConfig::operator()(const Config *x, const Config *y) const +{ + return (*this)(*x, *y); +} + +bool SortConfig::operator()(const Config &x, const Config &y) const +{ + #define SORT(attribute) \ + if (x.attribute != y.attribute) \ + { \ + return x.attribute < y.attribute; \ + } + + META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); + SORT(mConfigCaveat); + + META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); + SORT(mColorBufferType); + + // By larger total number of color bits, only considering those that are requested to be > 0. + EGLint xComponentsSize = wantedComponentsSize(x); + EGLint yComponentsSize = wantedComponentsSize(y); + if (xComponentsSize != yComponentsSize) + { + return xComponentsSize > yComponentsSize; + } + + SORT(mBufferSize); + SORT(mSampleBuffers); + SORT(mSamples); + SORT(mDepthSize); + SORT(mStencilSize); + SORT(mAlphaMaskSize); + SORT(mNativeVisualType); + SORT(mConfigID); + + #undef SORT + + return false; +} + +// We'd like to use SortConfig to also eliminate duplicate configs. +// This works as long as we never have two configs with different per-RGB-component layouts, +// but the same total. +// 5551 and 565 are different because R+G+B is different. +// 5551 and 555 are different because bufferSize is different. +const EGLint ConfigSet::mSortAttribs[] = +{ + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + EGL_LUMINANCE_SIZE, 1, + // BUT NOT ALPHA + EGL_NONE +}; + +ConfigSet::ConfigSet() + : mSet(SortConfig(mSortAttribs)) +{ +} + +void ConfigSet::add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight) +{ + Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight); + + mSet.insert(config); +} + +size_t ConfigSet::size() const +{ + return mSet.size(); +} + +bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) +{ + vector passed; + passed.reserve(mSet.size()); + + for (Iterator config = mSet.begin(); config != mSet.end(); config++) + { + bool match = true; + const EGLint *attribute = attribList; + + while (attribute[0] != EGL_NONE) + { + switch (attribute[0]) + { + case EGL_BUFFER_SIZE: match = config->mBufferSize >= attribute[1]; break; + case EGL_ALPHA_SIZE: match = config->mAlphaSize >= attribute[1]; break; + case EGL_BLUE_SIZE: match = config->mBlueSize >= attribute[1]; break; + case EGL_GREEN_SIZE: match = config->mGreenSize >= attribute[1]; break; + case EGL_RED_SIZE: match = config->mRedSize >= attribute[1]; break; + case EGL_DEPTH_SIZE: match = config->mDepthSize >= attribute[1]; break; + case EGL_STENCIL_SIZE: match = config->mStencilSize >= attribute[1]; break; + case EGL_CONFIG_CAVEAT: match = config->mConfigCaveat == (EGLenum) attribute[1]; break; + case EGL_CONFIG_ID: match = config->mConfigID == attribute[1]; break; + case EGL_LEVEL: match = config->mLevel >= attribute[1]; break; + case EGL_NATIVE_RENDERABLE: match = config->mNativeRenderable == (EGLBoolean) attribute[1]; break; + case EGL_NATIVE_VISUAL_TYPE: match = config->mNativeVisualType == attribute[1]; break; + case EGL_SAMPLES: match = config->mSamples >= attribute[1]; break; + case EGL_SAMPLE_BUFFERS: match = config->mSampleBuffers >= attribute[1]; break; + case EGL_SURFACE_TYPE: match = (config->mSurfaceType & attribute[1]) == attribute[1]; break; + case EGL_TRANSPARENT_TYPE: match = config->mTransparentType == (EGLenum) attribute[1]; break; + case EGL_TRANSPARENT_BLUE_VALUE: match = config->mTransparentBlueValue == attribute[1]; break; + case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribute[1]; break; + case EGL_TRANSPARENT_RED_VALUE: match = config->mTransparentRedValue == attribute[1]; break; + case EGL_BIND_TO_TEXTURE_RGB: match = config->mBindToTextureRGB == (EGLBoolean) attribute[1]; break; + case EGL_BIND_TO_TEXTURE_RGBA: match = config->mBindToTextureRGBA == (EGLBoolean) attribute[1]; break; + case EGL_MIN_SWAP_INTERVAL: match = config->mMinSwapInterval == attribute[1]; break; + case EGL_MAX_SWAP_INTERVAL: match = config->mMaxSwapInterval == attribute[1]; break; + case EGL_LUMINANCE_SIZE: match = config->mLuminanceSize >= attribute[1]; break; + case EGL_ALPHA_MASK_SIZE: match = config->mAlphaMaskSize >= attribute[1]; break; + case EGL_COLOR_BUFFER_TYPE: match = config->mColorBufferType == (EGLenum) attribute[1]; break; + case EGL_RENDERABLE_TYPE: match = (config->mRenderableType & attribute[1]) == attribute[1]; break; + case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: match = (config->mConformant & attribute[1]) == attribute[1]; break; + case EGL_MAX_PBUFFER_WIDTH: match = config->mMaxPBufferWidth >= attribute[1]; break; + case EGL_MAX_PBUFFER_HEIGHT: match = config->mMaxPBufferHeight >= attribute[1]; break; + case EGL_MAX_PBUFFER_PIXELS: match = config->mMaxPBufferPixels >= attribute[1]; break; + default: + return false; + } + + if (!match) + { + break; + } + + attribute += 2; + } + + if (match) + { + passed.push_back(&*config); + } + } + + if (configs) + { + sort(passed.begin(), passed.end(), SortConfig(attribList)); + + EGLint index; + for (index = 0; index < configSize && index < static_cast(passed.size()); index++) + { + configs[index] = passed[index]->getHandle(); + } + + *numConfig = index; + } + else + { + *numConfig = passed.size(); + } + + return true; +} + +const egl::Config *ConfigSet::get(EGLConfig configHandle) +{ + for (Iterator config = mSet.begin(); config != mSet.end(); config++) + { + if (config->getHandle() == configHandle) + { + return &(*config); + } + } + + return NULL; +} +} diff --git a/src/3rdparty/angle/src/libEGL/Config.h b/src/3rdparty/angle/src/libEGL/Config.h new file mode 100644 index 0000000000..95626ed1ad --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Config.h @@ -0,0 +1,118 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Config.h: Defines the egl::Config class, describing the format, type +// and size for an egl::Surface. Implements EGLConfig and related functionality. +// [EGL 1.4] section 3.4 page 15. + +#ifndef INCLUDE_CONFIG_H_ +#define INCLUDE_CONFIG_H_ + +#define EGLAPI +#include +#include + +#include + +#include "common/angleutils.h" + +namespace egl +{ +class Display; + +class Config +{ + public: + Config(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight); + + void setDefaults(); + void set(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight); + EGLConfig getHandle() const; + + const D3DDISPLAYMODE mDisplayMode; + const D3DFORMAT mRenderTargetFormat; + const D3DFORMAT mDepthStencilFormat; + const EGLint mMultiSample; + + EGLint mBufferSize; // Depth of the color buffer + EGLint mRedSize; // Bits of Red in the color buffer + EGLint mGreenSize; // Bits of Green in the color buffer + EGLint mBlueSize; // Bits of Blue in the color buffer + EGLint mLuminanceSize; // Bits of Luminance in the color buffer + EGLint mAlphaSize; // Bits of Alpha in the color buffer + EGLint mAlphaMaskSize; // Bits of Alpha Mask in the mask buffer + EGLBoolean mBindToTextureRGB; // True if bindable to RGB textures. + EGLBoolean mBindToTextureRGBA; // True if bindable to RGBA textures. + EGLenum mColorBufferType; // Color buffer type + EGLenum mConfigCaveat; // Any caveats for the configuration + EGLint mConfigID; // Unique EGLConfig identifier + EGLint mConformant; // Whether contexts created with this config are conformant + EGLint mDepthSize; // Bits of Z in the depth buffer + EGLint mLevel; // Frame buffer level + EGLBoolean mMatchNativePixmap; // Match the native pixmap format + EGLint mMaxPBufferWidth; // Maximum width of pbuffer + EGLint mMaxPBufferHeight; // Maximum height of pbuffer + EGLint mMaxPBufferPixels; // Maximum size of pbuffer + EGLint mMaxSwapInterval; // Maximum swap interval + EGLint mMinSwapInterval; // Minimum swap interval + EGLBoolean mNativeRenderable; // EGL_TRUE if native rendering APIs can render to surface + EGLint mNativeVisualID; // Handle of corresponding native visual + EGLint mNativeVisualType; // Native visual type of the associated visual + EGLint mRenderableType; // Which client rendering APIs are supported. + EGLint mSampleBuffers; // Number of multisample buffers + EGLint mSamples; // Number of samples per pixel + EGLint mStencilSize; // Bits of Stencil in the stencil buffer + EGLint mSurfaceType; // Which types of EGL surfaces are supported. + EGLenum mTransparentType; // Type of transparency supported + EGLint mTransparentRedValue; // Transparent red value + EGLint mTransparentGreenValue; // Transparent green value + EGLint mTransparentBlueValue; // Transparent blue value +}; + +// Function object used by STL sorting routines for ordering Configs according to [EGL] section 3.4.1 page 24. +class SortConfig +{ + public: + explicit SortConfig(const EGLint *attribList); + + bool operator()(const Config *x, const Config *y) const; + bool operator()(const Config &x, const Config &y) const; + + private: + void scanForWantedComponents(const EGLint *attribList); + EGLint wantedComponentsSize(const Config &config) const; + + bool mWantRed; + bool mWantGreen; + bool mWantBlue; + bool mWantAlpha; + bool mWantLuminance; +}; + +class ConfigSet +{ + friend Display; + + public: + ConfigSet(); + + void add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight); + size_t size() const; + bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); + const egl::Config *get(EGLConfig configHandle); + + private: + DISALLOW_COPY_AND_ASSIGN(ConfigSet); + + typedef std::set Set; + typedef Set::iterator Iterator; + Set mSet; + + static const EGLint mSortAttribs[]; +}; +} + +#endif // INCLUDE_CONFIG_H_ diff --git a/src/3rdparty/angle/src/libEGL/Display.cpp b/src/3rdparty/angle/src/libEGL/Display.cpp new file mode 100644 index 0000000000..a2dee6d964 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Display.cpp @@ -0,0 +1,1292 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.cpp: Implements the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#include "libEGL/Display.h" + +#include +#include +#include + +#include "common/debug.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/utilities.h" + +#include "libEGL/main.h" + +// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros +#define REF_RAST 0 + +// The "Debug This Pixel..." feature in PIX often fails when using the +// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7 +// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file. +#if !defined(ANGLE_ENABLE_D3D9EX) +// Enables use of the IDirect3D9Ex interface, when available +#define ANGLE_ENABLE_D3D9EX 1 +#endif // !defined(ANGLE_ENABLE_D3D9EX) + +namespace egl +{ +namespace +{ + typedef std::map DisplayMap; + DisplayMap displays; +} + +egl::Display *Display::getDisplay(EGLNativeDisplayType displayId) +{ + if (displays.find(displayId) != displays.end()) + { + return displays[displayId]; + } + + egl::Display *display = NULL; + + if (displayId == EGL_DEFAULT_DISPLAY) + { + display = new egl::Display(displayId, (HDC)NULL, false); + } + else if (displayId == EGL_SOFTWARE_DISPLAY_ANGLE) + { + display = new egl::Display(displayId, (HDC)NULL, true); + } + else + { + // FIXME: Check if displayId is a valid display device context + + display = new egl::Display(displayId, (HDC)displayId, false); + } + + displays[displayId] = display; + return display; +} + +Display::Display(EGLNativeDisplayType displayId, HDC deviceContext, bool software) : mDc(deviceContext) +{ + mD3d9Module = NULL; + + mD3d9 = NULL; + mD3d9Ex = NULL; + mDevice = NULL; + mDeviceEx = NULL; + mDeviceWindow = NULL; + + mAdapter = D3DADAPTER_DEFAULT; + + #if REF_RAST == 1 || defined(FORCE_REF_RAST) + mDeviceType = D3DDEVTYPE_REF; + #else + mDeviceType = D3DDEVTYPE_HAL; + #endif + + mMinSwapInterval = 1; + mMaxSwapInterval = 1; + mSoftwareDevice = software; + mDisplayId = displayId; + mDeviceLost = false; +} + +Display::~Display() +{ + terminate(); + + DisplayMap::iterator thisDisplay = displays.find(mDisplayId); + + if (thisDisplay != displays.end()) + { + displays.erase(thisDisplay); + } +} + +bool Display::initialize() +{ + if (isInitialized()) + { + return true; + } + + if (mSoftwareDevice) + { + mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); + } + else + { + mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); + } + if (mD3d9Module == NULL) + { + terminate(); + return false; + } + + typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + + // Use Direct3D9Ex if available. Among other things, this version is less + // inclined to report a lost context, for example when the user switches + // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available. + if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + { + ASSERT(mD3d9Ex); + mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); + ASSERT(mD3d9); + } + else + { + mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); + } + + if (mD3d9) + { + if (mDc != NULL) + { + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to + } + + HRESULT result; + + // Give up on getting device caps after about one second. + for (int i = 0; i < 10; ++i) + { + result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); + + if (SUCCEEDED(result)) + { + break; + } + else if (result == D3DERR_NOTAVAILABLE) + { + Sleep(100); // Give the driver some time to initialize/recover + } + else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from + { + terminate(); + return error(EGL_BAD_ALLOC, false); + } + } + + if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0)) + { + terminate(); + return error(EGL_NOT_INITIALIZED, false); + } + + // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported. + // This is required by Texture2D::convertToRenderTarget. + if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) + { + terminate(); + return error(EGL_NOT_INITIALIZED, false); + } + + mMinSwapInterval = 4; + mMaxSwapInterval = 0; + + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);} + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);} + + mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); + + // ATI cards on XP have problems with non-power-of-two textures. + mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD); + + const D3DFORMAT renderTargetFormats[] = + { + D3DFMT_A1R5G5B5, + // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value. + D3DFMT_A8R8G8B8, + D3DFMT_R5G6B5, + // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format + D3DFMT_X8R8G8B8 + }; + + const D3DFORMAT depthStencilFormats[] = + { + D3DFMT_UNKNOWN, + // D3DFMT_D16_LOCKABLE, + D3DFMT_D32, + // D3DFMT_D15S1, + D3DFMT_D24S8, + D3DFMT_D24X8, + // D3DFMT_D24X4S4, + D3DFMT_D16, + // D3DFMT_D32F_LOCKABLE, + // D3DFMT_D24FS8 + }; + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + ConfigSet configSet; + + for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++) + { + D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex]; + + HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat); + + if (SUCCEEDED(result)) + { + for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++) + { + D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex]; + HRESULT result = D3D_OK; + + if(depthStencilFormat != D3DFMT_UNKNOWN) + { + result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat); + } + + if (SUCCEEDED(result)) + { + if(depthStencilFormat != D3DFMT_UNKNOWN) + { + result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat); + } + + if (SUCCEEDED(result)) + { + // FIXME: enumerate multi-sampling + + configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0, + mDeviceCaps.MaxTextureWidth, mDeviceCaps.MaxTextureHeight); + } + } + } + } + } + + // Give the sorted configs a unique ID and store them internally + EGLint index = 1; + for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++) + { + Config configuration = *config; + configuration.mConfigID = index; + index++; + + mConfigSet.mSet.insert(configuration); + } + } + + if (!isInitialized()) + { + terminate(); + + return false; + } + + initExtensionString(); + + static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); + static const TCHAR className[] = TEXT("STATIC"); + + mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); + + if (!createDevice()) + { + terminate(); + return false; + } + + mVertexShaderCache.initialize(mDevice); + mPixelShaderCache.initialize(mDevice); + + return true; +} + +void Display::terminate() +{ + while (!mSurfaceSet.empty()) + { + destroySurface(*mSurfaceSet.begin()); + } + + while (!mContextSet.empty()) + { + destroyContext(*mContextSet.begin()); + } + + while (!mEventQueryPool.empty()) + { + mEventQueryPool.back()->Release(); + mEventQueryPool.pop_back(); + } + + mVertexShaderCache.clear(); + mPixelShaderCache.clear(); + + if (mDevice) + { + // If the device is lost, reset it first to prevent leaving the driver in an unstable state + if (testDeviceLost()) + { + resetDevice(); + } + + mDevice->Release(); + mDevice = NULL; + } + + if (mDeviceEx) + { + mDeviceEx->Release(); + mDeviceEx = NULL; + } + + if (mD3d9) + { + mD3d9->Release(); + mD3d9 = NULL; + } + + if (mDeviceWindow) + { + DestroyWindow(mDeviceWindow); + mDeviceWindow = NULL; + } + + if (mD3d9Ex) + { + mD3d9Ex->Release(); + mD3d9Ex = NULL; + } + + if (mD3d9Module) + { + mD3d9Module = NULL; + } +} + +void Display::startScene() +{ + if (!mSceneStarted) + { + long result = mDevice->BeginScene(); + if (SUCCEEDED(result)) { + // This is defensive checking against the device being + // lost at unexpected times. + mSceneStarted = true; + } + } +} + +void Display::endScene() +{ + if (mSceneStarted) + { + // EndScene can fail if the device was lost, for example due + // to a TDR during a draw call. + mDevice->EndScene(); + mSceneStarted = false; + } +} + +bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) +{ + return mConfigSet.getConfigs(configs, attribList, configSize, numConfig); +} + +bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) +{ + const egl::Config *configuration = mConfigSet.get(config); + + switch (attribute) + { + case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break; + case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break; + case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break; + case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break; + case EGL_RED_SIZE: *value = configuration->mRedSize; break; + case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break; + case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break; + case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break; + case EGL_CONFIG_ID: *value = configuration->mConfigID; break; + case EGL_LEVEL: *value = configuration->mLevel; break; + case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break; + case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break; + case EGL_SAMPLES: *value = configuration->mSamples; break; + case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break; + case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break; + case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break; + case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break; + case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break; + case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break; + case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break; + case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break; + case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break; + case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break; + case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break; + case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break; + case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break; + case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break; + case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: *value = configuration->mConformant; break; + case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break; + case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break; + case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break; + default: + return false; + } + + return true; +} + +bool Display::createDevice() +{ + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; + + HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) + { + return error(EGL_BAD_ALLOC, false); + } + + if (FAILED(result)) + { + result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST); + return error(EGL_BAD_ALLOC, false); + } + } + + if (mD3d9Ex) + { + result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + + initializeDevice(); + + return true; +} + +// do any one-time device initialization +// NOTE: this is also needed after a device lost/reset +// to reset the scene status and ensure the default states are reset. +void Display::initializeDevice() +{ + // Permanent non-default states + mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); + mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE); + + if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize); + } + else + { + mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f + } + + mSceneStarted = false; +} + +bool Display::resetDevice() +{ + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); + int attempts = 3; + + while (lost && attempts > 0) + { + if (mDeviceEx) + { + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, NULL); + } + else + { + result = mDevice->TestCooperativeLevel(); + + while (result == D3DERR_DEVICELOST) + { + Sleep(100); // Give the graphics driver some CPU time + result = mDevice->TestCooperativeLevel(); + } + + if (result == D3DERR_DEVICENOTRESET) + { + result = mDevice->Reset(&presentParameters); + } + } + + lost = testDeviceLost(); + attempts --; + } + + if (FAILED(result)) + { + ERR("Reset/ResetEx failed multiple times: 0x%08X", result); + return error(EGL_BAD_ALLOC, false); + } + + // reset device defaults + initializeDevice(); + + return true; +} + +EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList) +{ + const Config *configuration = mConfigSet.get(config); + EGLint postSubBufferSupported = EGL_FALSE; + + if (attribList) + { + while (*attribList != EGL_NONE) + { + switch (attribList[0]) + { + case EGL_RENDER_BUFFER: + switch (attribList[1]) + { + case EGL_BACK_BUFFER: + break; + case EGL_SINGLE_BUFFER: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + break; + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + postSubBufferSupported = attribList[1]; + break; + case EGL_VG_COLORSPACE: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + case EGL_VG_ALPHA_FORMAT: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + attribList += 2; + } + } + + if (hasExistingWindowSurface(window)) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + if (testDeviceLost()) + { + if (!restoreLostDevice()) + return EGL_NO_SURFACE; + } + + Surface *surface = new Surface(this, configuration, window, postSubBufferSupported); + + if (!surface->initialize()) + { + delete surface; + return EGL_NO_SURFACE; + } + + mSurfaceSet.insert(surface); + + return success(surface); +} + +EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList) +{ + EGLint width = 0, height = 0; + EGLenum textureFormat = EGL_NO_TEXTURE; + EGLenum textureTarget = EGL_NO_TEXTURE; + const Config *configuration = mConfigSet.get(config); + + if (attribList) + { + while (*attribList != EGL_NONE) + { + switch (attribList[0]) + { + case EGL_WIDTH: + width = attribList[1]; + break; + case EGL_HEIGHT: + height = attribList[1]; + break; + case EGL_LARGEST_PBUFFER: + if (attribList[1] != EGL_FALSE) + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_FORMAT: + switch (attribList[1]) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: + textureFormat = attribList[1]; + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + break; + case EGL_TEXTURE_TARGET: + switch (attribList[1]) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_2D: + textureTarget = attribList[1]; + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + break; + case EGL_MIPMAP_TEXTURE: + if (attribList[1] != EGL_FALSE) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + break; + case EGL_VG_COLORSPACE: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + case EGL_VG_ALPHA_FORMAT: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + attribList += 2; + } + } + + if (width < 0 || height < 0) + { + return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } + + if (width == 0 || height == 0) + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + if (textureFormat != EGL_NO_TEXTURE && !getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || + (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) + { + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) + { + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + } + + if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || + (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + + if (testDeviceLost()) + { + if (!restoreLostDevice()) + return EGL_NO_SURFACE; + } + + Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget); + + if (!surface->initialize()) + { + delete surface; + return EGL_NO_SURFACE; + } + + mSurfaceSet.insert(surface); + + return success(surface); +} + +EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess) +{ + if (!mDevice) + { + if (!createDevice()) + { + return NULL; + } + } + else if (testDeviceLost()) // Lost device + { + if (!restoreLostDevice()) + return NULL; + } + + const egl::Config *config = mConfigSet.get(configHandle); + + gl::Context *context = glCreateContext(config, shareContext, notifyResets, robustAccess); + mContextSet.insert(context); + mDeviceLost = false; + + return context; +} + +bool Display::restoreLostDevice() +{ + for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) + { + if ((*ctx)->isResetNotificationEnabled()) + return false; // If reset notifications have been requested, application must delete all contexts first + } + + // Release surface resources to make the Reset() succeed + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + (*surface)->release(); + } + + while (!mEventQueryPool.empty()) + { + mEventQueryPool.back()->Release(); + mEventQueryPool.pop_back(); + } + + mVertexShaderCache.clear(); + mPixelShaderCache.clear(); + + if (!resetDevice()) + { + return false; + } + + // Restore any surfaces that may have been lost + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + (*surface)->resetSwapChain(); + } + + return true; +} + + +void Display::destroySurface(egl::Surface *surface) +{ + delete surface; + mSurfaceSet.erase(surface); +} + +void Display::destroyContext(gl::Context *context) +{ + glDestroyContext(context); + mContextSet.erase(context); +} + +void Display::notifyDeviceLost() +{ + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + { + (*context)->markContextLost(); + } + mDeviceLost = true; + error(EGL_CONTEXT_LOST); +} + +bool Display::isDeviceLost() +{ + return mDeviceLost; +} + +bool Display::isInitialized() const +{ + return mD3d9 != NULL && mConfigSet.size() > 0; +} + +bool Display::isValidConfig(EGLConfig config) +{ + return mConfigSet.get(config) != NULL; +} + +bool Display::isValidContext(gl::Context *context) +{ + return mContextSet.find(context) != mContextSet.end(); +} + +bool Display::isValidSurface(egl::Surface *surface) +{ + return mSurfaceSet.find(surface) != mSurfaceSet.end(); +} + +bool Display::hasExistingWindowSurface(HWND window) +{ + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + if ((*surface)->getWindowHandle() == window) + { + return true; + } + } + + return false; +} + +EGLint Display::getMinSwapInterval() +{ + return mMinSwapInterval; +} + +EGLint Display::getMaxSwapInterval() +{ + return mMaxSwapInterval; +} + +IDirect3DDevice9 *Display::getDevice() +{ + if (!mDevice) + { + if (!createDevice()) + { + return NULL; + } + } + + return mDevice; +} + +D3DCAPS9 Display::getDeviceCaps() +{ + return mDeviceCaps; +} + +D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier() +{ + return &mAdapterIdentifier; +} + +bool Display::testDeviceLost() +{ + if (mDeviceEx) + { + return FAILED(mDeviceEx->CheckDeviceState(NULL)); + } + else if (mDevice) + { + return FAILED(mDevice->TestCooperativeLevel()); + } + + return false; // No device yet, so no reset required +} + +bool Display::testDeviceResettable() +{ + HRESULT status = D3D_OK; + + if (mDeviceEx) + { + status = mDeviceEx->CheckDeviceState(NULL); + } + else if (mDevice) + { + status = mDevice->TestCooperativeLevel(); + } + + switch (status) + { + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + default: + return false; + } +} + +void Display::sync(bool block) +{ + HRESULT result; + + IDirect3DQuery9* query = allocateEventQuery(); + if (!query) + { + return; + } + + result = query->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + + do + { + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + + if(block && result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + // explicitly check for device loss + // some drivers seem to return S_FALSE even if the device is lost + // instead of D3DERR_DEVICELOST like they should + if (testDeviceLost()) + { + result = D3DERR_DEVICELOST; + } + } + } + while(block && result == S_FALSE); + + freeEventQuery(query); + + if (isDeviceLostError(result)) + { + notifyDeviceLost(); + } +} + +IDirect3DQuery9* Display::allocateEventQuery() +{ + IDirect3DQuery9 *query = NULL; + + if (mEventQueryPool.empty()) + { + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); + ASSERT(SUCCEEDED(result)); + } + else + { + query = mEventQueryPool.back(); + mEventQueryPool.pop_back(); + } + + return query; +} + +void Display::freeEventQuery(IDirect3DQuery9* query) +{ + if (mEventQueryPool.size() > 1000) + { + query->Release(); + } + else + { + mEventQueryPool.push_back(query); + } +} + +void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray) +{ + for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++) + { + HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format, + TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL); + + multiSampleArray[multiSampleIndex] = SUCCEEDED(result); + } +} + +bool Display::getDXT1TextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1)); +} + +bool Display::getDXT3TextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3)); +} + +bool Display::getDXT5TextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5)); +} + +// we use INTZ for depth textures in Direct3D9 +// we also want NULL texture support to ensure the we can make depth-only FBOs +// see http://aras-p.info/texts/D3D9GPUHacks.html +bool Display::getDepthTextureSupport() const +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + bool intz = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ)); + bool null = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL)); + + return intz && null; +} + +bool Display::getFloat32TextureSupport(bool *filtering, bool *renderable) +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + + *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&& + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + + if (!*filtering && !*renderable) + { + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F)); + } + else + { + return true; + } +} + +bool Display::getFloat16TextureSupport(bool *filtering, bool *renderable) +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + + *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + + if (!*filtering && !*renderable) + { + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, + D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F)); + } + else + { + return true; + } +} + +bool Display::getLuminanceTextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8)); +} + +bool Display::getLuminanceAlphaTextureSupport() +{ + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8)); +} + +float Display::getTextureFilterAnisotropySupport() const +{ + // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec + if ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2)) + { + return mDeviceCaps.MaxAnisotropy; + } + return 1.0f; +} + +D3DPOOL Display::getBufferPool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & D3DUSAGE_DYNAMIC)) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +D3DPOOL Display::getTexturePool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +bool Display::getEventQuerySupport() +{ + IDirect3DQuery9 *query = allocateEventQuery(); + if (query) + { + freeEventQuery(query); + return true; + } + else + { + return false; + } +} + +D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters() +{ + D3DPRESENT_PARAMETERS presentParameters = {0}; + + // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters. + presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; + presentParameters.BackBufferWidth = 1; + presentParameters.BackBufferHeight = 1; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = mDeviceWindow; + presentParameters.MultiSampleQuality = 0; + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; + presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + + return presentParameters; +} + +void Display::initExtensionString() +{ + HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll")); + + mExtensionString = ""; + + // Multi-vendor (EXT) extensions + mExtensionString += "EGL_EXT_create_context_robustness "; + + // ANGLE-specific extensions + if (shareHandleSupported()) + { + mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer "; + } + + mExtensionString += "EGL_ANGLE_query_surface_pointer "; + + if (swiftShader) + { + mExtensionString += "EGL_ANGLE_software_display "; + } + + if (shareHandleSupported()) + { + mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle "; + } + + mExtensionString += "EGL_NV_post_sub_buffer"; + + std::string::size_type end = mExtensionString.find_last_not_of(' '); + if (end != std::string::npos) + { + mExtensionString.resize(end+1); + } +} + +const char *Display::getExtensionString() const +{ + return mExtensionString.c_str(); +} + +bool Display::shareHandleSupported() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return isD3d9ExDevice() && !gl::perfActive(); +} + +IDirect3DVertexShader9 *Display::createVertexShader(const DWORD *function, size_t length) +{ + return mVertexShaderCache.create(function, length); +} + +IDirect3DPixelShader9 *Display::createPixelShader(const DWORD *function, size_t length) +{ + return mPixelShaderCache.create(function, length); +} + +// Only Direct3D 10 ready devices support all the necessary vertex texture formats. +// We test this using D3D9 by checking support for the R16F format. +bool Display::getVertexTextureSupport() const +{ + if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0)) + { + return false; + } + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F); + + return SUCCEEDED(result); +} + +bool Display::getNonPower2TextureSupport() const +{ + return mSupportsNonPower2Textures; +} + +bool Display::getOcclusionQuerySupport() const +{ + if (!isInitialized()) + { + return false; + } + + IDirect3DQuery9 *query = NULL; + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query); + + if (SUCCEEDED(result) && query) + { + query->Release(); + return true; + } + else + { + return false; + } +} + +bool Display::getInstancingSupport() const +{ + return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); +} + +} diff --git a/src/3rdparty/angle/src/libEGL/Display.h b/src/3rdparty/angle/src/libEGL/Display.h new file mode 100644 index 0000000000..23b57b74c6 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Display.h @@ -0,0 +1,167 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.h: Defines the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#ifndef LIBEGL_DISPLAY_H_ +#define LIBEGL_DISPLAY_H_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +#include +#include + +#include "libGLESv2/Context.h" + +#include "libEGL/Config.h" +#include "libEGL/ShaderCache.h" +#include "libEGL/Surface.h" + +const int versionWindowsVista = MAKEWORD(0x00, 0x06); +const int versionWindows7 = MAKEWORD(0x01, 0x06); + +// Return the version of the operating system in a format suitable for ordering +// comparison. +inline int getComparableOSVersion() +{ + DWORD version = GetVersion(); + int majorVersion = LOBYTE(LOWORD(version)); + int minorVersion = HIBYTE(LOWORD(version)); + return MAKEWORD(minorVersion, majorVersion); +} + +namespace egl +{ +class Display +{ + public: + ~Display(); + + bool initialize(); + void terminate(); + + virtual void startScene(); + virtual void endScene(); + + static egl::Display *getDisplay(EGLNativeDisplayType displayId); + + bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); + bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); + + EGLSurface createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList); + EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList); + EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess); + + void destroySurface(egl::Surface *surface); + void destroyContext(gl::Context *context); + + bool isInitialized() const; + bool isValidConfig(EGLConfig config); + bool isValidContext(gl::Context *context); + bool isValidSurface(egl::Surface *surface); + bool hasExistingWindowSurface(HWND window); + + EGLint getMinSwapInterval(); + EGLint getMaxSwapInterval(); + + virtual IDirect3DDevice9 *getDevice(); + virtual D3DCAPS9 getDeviceCaps(); + virtual D3DADAPTER_IDENTIFIER9 *getAdapterIdentifier(); + virtual bool testDeviceLost(); + virtual bool testDeviceResettable(); + virtual void sync(bool block); + virtual IDirect3DQuery9* allocateEventQuery(); + virtual void freeEventQuery(IDirect3DQuery9* query); + virtual void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray); + virtual bool getDXT1TextureSupport(); + virtual bool getDXT3TextureSupport(); + virtual bool getDXT5TextureSupport(); + virtual bool getEventQuerySupport(); + virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable); + virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable); + virtual bool getLuminanceTextureSupport(); + virtual bool getLuminanceAlphaTextureSupport(); + virtual bool getVertexTextureSupport() const; + virtual bool getNonPower2TextureSupport() const; + virtual bool getDepthTextureSupport() const; + virtual bool getOcclusionQuerySupport() const; + virtual bool getInstancingSupport() const; + virtual float getTextureFilterAnisotropySupport() const; + virtual D3DPOOL getBufferPool(DWORD usage) const; + virtual D3DPOOL getTexturePool(DWORD usage) const; + + virtual void notifyDeviceLost(); + bool isDeviceLost(); + + bool isD3d9ExDevice() const { return mD3d9Ex != NULL; } + const char *getExtensionString() const; + bool shareHandleSupported() const; + + virtual IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length); + virtual IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length); + + private: + DISALLOW_COPY_AND_ASSIGN(Display); + + Display(EGLNativeDisplayType displayId, HDC deviceContext, bool software); + + D3DPRESENT_PARAMETERS getDefaultPresentParameters(); + + bool restoreLostDevice(); + + EGLNativeDisplayType mDisplayId; + const HDC mDc; + + HMODULE mD3d9Module; + + UINT mAdapter; + D3DDEVTYPE mDeviceType; + IDirect3D9 *mD3d9; // Always valid after successful initialization. + IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported. + IDirect3DDevice9 *mDevice; + IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported. + + // A pool of event queries that are currently unused. + std::vector mEventQueryPool; + + VertexShaderCache mVertexShaderCache; + PixelShaderCache mPixelShaderCache; + + D3DCAPS9 mDeviceCaps; + D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; + HWND mDeviceWindow; + + bool mSceneStarted; + EGLint mMaxSwapInterval; + EGLint mMinSwapInterval; + bool mSoftwareDevice; + bool mSupportsNonPower2Textures; + + typedef std::set SurfaceSet; + SurfaceSet mSurfaceSet; + + ConfigSet mConfigSet; + + typedef std::set ContextSet; + ContextSet mContextSet; + bool mDeviceLost; + + bool createDevice(); + void initializeDevice(); + bool resetDevice(); + + void initExtensionString(); + std::string mExtensionString; +}; +} + +#endif // LIBEGL_DISPLAY_H_ diff --git a/src/3rdparty/angle/src/libEGL/ShaderCache.h b/src/3rdparty/angle/src/libEGL/ShaderCache.h new file mode 100644 index 0000000000..cfe523ba09 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/ShaderCache.h @@ -0,0 +1,116 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Display.h: Defines egl::ShaderCache, a cache of Direct3D shader objects +// keyed by their byte code. + +#ifndef LIBEGL_SHADER_CACHE_H_ +#define LIBEGL_SHADER_CACHE_H_ + +#include + +#ifdef _MSC_VER +#include +#else +#include +#endif + +namespace egl +{ +template +class ShaderCache +{ + public: + ShaderCache() : mDevice(NULL) + { + } + + ~ShaderCache() + { + // Call clear while the device is still valid. + ASSERT(mMap.empty()); + } + + void initialize(IDirect3DDevice9* device) + { + mDevice = device; + } + + ShaderObject *create(const DWORD *function, size_t length) + { + std::string key(reinterpret_cast(function), length); + typename Map::iterator it = mMap.find(key); + if (it != mMap.end()) + { + it->second->AddRef(); + return it->second; + } + + ShaderObject *shader; + HRESULT result = createShader(function, &shader); + if (FAILED(result)) + { + return NULL; + } + + // Random eviction policy. + if (mMap.size() >= kMaxMapSize) + { + mMap.begin()->second->Release(); + mMap.erase(mMap.begin()); + } + + shader->AddRef(); + mMap[key] = shader; + + return shader; + } + + void clear() + { + for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) + { + it->second->Release(); + } + + mMap.clear(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShaderCache); + + const static size_t kMaxMapSize = 100; + + HRESULT createShader(const DWORD *function, IDirect3DVertexShader9 **shader) + { + return mDevice->CreateVertexShader(function, shader); + } + + HRESULT createShader(const DWORD *function, IDirect3DPixelShader9 **shader) + { + return mDevice->CreatePixelShader(function, shader); + } + +#ifndef HASH_MAP +# ifdef _MSC_VER +# define HASH_MAP stdext::hash_map +# else +# define HASH_MAP std::unordered_map +# endif +#endif + + typedef HASH_MAP Map; + Map mMap; + + IDirect3DDevice9 *mDevice; +}; + +typedef ShaderCache VertexShaderCache; +typedef ShaderCache PixelShaderCache; + +} + +#endif // LIBEGL_SHADER_CACHE_H_ diff --git a/src/3rdparty/angle/src/libEGL/Surface.cpp b/src/3rdparty/angle/src/libEGL/Surface.cpp new file mode 100644 index 0000000000..732c404b10 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Surface.cpp @@ -0,0 +1,674 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Surface.cpp: Implements the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#include + +#include "libEGL/Surface.h" + +#include "common/debug.h" +#include "libGLESv2/Texture.h" + +#include "libEGL/main.h" +#include "libEGL/Display.h" + +#include + +namespace egl +{ + +Surface::Surface(Display *display, const Config *config, HWND window, EGLint postSubBufferSupported) + : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported) +{ + mSwapChain = NULL; + mBackBuffer = NULL; + mDepthStencil = NULL; + mRenderTarget = NULL; + mOffscreenTexture = NULL; + mShareHandle = NULL; + mTexture = NULL; + mTextureFormat = EGL_NO_TEXTURE; + mTextureTarget = EGL_NO_TEXTURE; + + mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio + mRenderBuffer = EGL_BACK_BUFFER; + mSwapBehavior = EGL_BUFFER_PRESERVED; + mSwapInterval = -1; + setSwapInterval(1); + + subclassWindow(); +} + +Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType) + : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) +{ + mSwapChain = NULL; + mBackBuffer = NULL; + mDepthStencil = NULL; + mRenderTarget = NULL; + mOffscreenTexture = NULL; + mWindowSubclassed = false; + mTexture = NULL; + mTextureFormat = textureFormat; + mTextureTarget = textureType; + + mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio + mRenderBuffer = EGL_BACK_BUFFER; + mSwapBehavior = EGL_BUFFER_PRESERVED; + mSwapInterval = -1; + setSwapInterval(1); +} + +Surface::~Surface() +{ + unsubclassWindow(); + release(); +} + +bool Surface::initialize() +{ + ASSERT(!mSwapChain && !mOffscreenTexture && !mDepthStencil); + + if (!resetSwapChain()) + return false; + + // Modify present parameters for this window, if we are composited, + // to minimize the amount of queuing done by DWM between our calls to + // present and the actual screen. + if (mWindow && (getComparableOSVersion() >= versionWindowsVista)) { + BOOL isComposited; + HRESULT result = DwmIsCompositionEnabled(&isComposited); + if (SUCCEEDED(result) && isComposited) { + DWM_PRESENT_PARAMETERS presentParams; + memset(&presentParams, 0, sizeof(presentParams)); + presentParams.cbSize = sizeof(DWM_PRESENT_PARAMETERS); + presentParams.cBuffer = 2; + + result = DwmSetPresentParameters(mWindow, &presentParams); + if (FAILED(result)) + ERR("Unable to set present parameters: 0x%08X", result); + } + } + + return true; +} + +void Surface::release() +{ + if (mSwapChain) + { + mSwapChain->Release(); + mSwapChain = NULL; + } + + if (mBackBuffer) + { + mBackBuffer->Release(); + mBackBuffer = NULL; + } + + if (mDepthStencil) + { + mDepthStencil->Release(); + mDepthStencil = NULL; + } + + if (mRenderTarget) + { + mRenderTarget->Release(); + mRenderTarget = NULL; + } + + if (mOffscreenTexture) + { + mOffscreenTexture->Release(); + mOffscreenTexture = NULL; + } + + if (mTexture) + { + mTexture->releaseTexImage(); + mTexture = NULL; + } + + mShareHandle = NULL; +} + +bool Surface::resetSwapChain() +{ + if (!mWindow) + { + return resetSwapChain(mWidth, mHeight); + } + + RECT windowRect; + if (!GetClientRect(getWindowHandle(), &windowRect)) + { + ASSERT(false); + + ERR("Could not retrieve the window dimensions"); + return false; + } + + return resetSwapChain(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top); +} + +bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) +{ + IDirect3DDevice9 *device = mDisplay->getDevice(); + + if (device == NULL) + { + return false; + } + + // Evict all non-render target textures to system memory and release all resources + // before reallocating them to free up as much video memory as possible. + device->EvictManagedResources(); + + HRESULT result; + + // Release specific resources to free up memory for the new render target, while the + // old render target still exists for the purpose of preserving its contents. + if (mSwapChain) + { + mSwapChain->Release(); + mSwapChain = NULL; + } + + if (mBackBuffer) + { + mBackBuffer->Release(); + mBackBuffer = NULL; + } + + if (mOffscreenTexture) + { + mOffscreenTexture->Release(); + mOffscreenTexture = NULL; + } + + if (mDepthStencil) + { + mDepthStencil->Release(); + mDepthStencil = NULL; + } + + mShareHandle = NULL; + HANDLE *pShareHandle = NULL; + if (!mWindow && mDisplay->shareHandleSupported()) + { + pShareHandle = &mShareHandle; + } + + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + mConfig->mRenderTargetFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle); + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } + } + + IDirect3DSurface9 *oldRenderTarget = mRenderTarget; + + result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget); + ASSERT(SUCCEEDED(result)); + + if (oldRenderTarget) + { + RECT rect = + { + 0, 0, + mWidth, mHeight + }; + + if (rect.right > static_cast(backbufferWidth)) + { + rect.right = backbufferWidth; + } + + if (rect.bottom > static_cast(backbufferHeight)) + { + rect.bottom = backbufferHeight; + } + + mDisplay->endScene(); + + result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); + ASSERT(SUCCEEDED(result)); + + oldRenderTarget->Release(); + } + + if (mWindow) + { + D3DPRESENT_PARAMETERS presentParameters = {0}; + presentParameters.AutoDepthStencilFormat = mConfig->mDepthStencilFormat; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = mConfig->mRenderTargetFormat; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = getWindowHandle(); + presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented + presentParameters.PresentationInterval = mPresentInterval; + presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + presentParameters.Windowed = TRUE; + presentParameters.BackBufferWidth = backbufferWidth; + presentParameters.BackBufferHeight = backbufferHeight; + + // http://crbug.com/140239 + // http://crbug.com/143434 + // + // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width + // when using the integrated Intel. This rounds the width up rather than down. + // + // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID + // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur. + D3DADAPTER_IDENTIFIER9* adapterIdentifier = mDisplay->getAdapterIdentifier(); + if (adapterIdentifier->VendorId == VENDOR_ID_INTEL) + { + presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64; + } + + result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST); + + ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + release(); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } + } + + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + ASSERT(SUCCEEDED(result)); + } + + if (mConfig->mDepthStencilFormat != D3DFMT_UNKNOWN) + { + result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, mConfig->mDepthStencilFormat, D3DMULTISAMPLE_NONE, + 0, FALSE, &mDepthStencil, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL); + + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + release(); + + if(isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + else + { + return error(EGL_BAD_ALLOC, false); + } + } + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + + mPresentIntervalDirty = false; + return true; +} + +bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return true; + } + + if (x + width > mWidth) + { + width = mWidth - x; + } + + if (y + height > mHeight) + { + height = mHeight - y; + } + + if (width == 0 || height == 0) + { + return true; + } + + IDirect3DDevice9 *device = mDisplay->getDevice(); + + // Disable all pipeline operations + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + device->SetPixelShader(NULL); + device->SetVertexShader(NULL); + + device->SetRenderTarget(0, mBackBuffer); + device->SetDepthStencilSurface(NULL); + + device->SetTexture(0, mOffscreenTexture); + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f}; + device->SetViewport(&viewport); + + float x1 = x - 0.5f; + float y1 = (mHeight - y - height) - 0.5f; + float x2 = (x + width) - 0.5f; + float y2 = (mHeight - y) - 0.5f; + + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); + float v2 = (y + height) / float(mHeight); + + float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2}, + {x2, y1, 0.0f, 1.0f, u2, v2}, + {x2, y2, 0.0f, 1.0f, u2, v1}, + {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v + + mDisplay->startScene(); + device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); + mDisplay->endScene(); + + device->SetTexture(0, NULL); + + RECT rect = + { + x, mHeight - y - height, + x + width, mHeight - y + }; + + HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); + + gl::Context *context = static_cast(glGetCurrentContext()); + if (context) + { + context->markAllStateDirty(); + } + + if (isDeviceLostError(result)) + { + mDisplay->notifyDeviceLost(); + return false; + } + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) + { + return error(EGL_BAD_ALLOC, false); + } + + ASSERT(SUCCEEDED(result)); + + checkForOutOfDateSwapChain(); + + return true; +} + +HWND Surface::getWindowHandle() +{ + return mWindow; +} + + +#define kSurfaceProperty _TEXT("Egl::SurfaceOwner") +#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") + +static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_SIZE) + { + Surface* surf = reinterpret_cast(GetProp(hwnd, kSurfaceProperty)); + if(surf) + { + surf->checkForOutOfDateSwapChain(); + } + } + WNDPROC prevWndFunc = reinterpret_cast(GetProp(hwnd, kParentWndProc)); + return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam); +} + +void Surface::subclassWindow() +{ + if (!mWindow) + { + return; + } + + DWORD processId; + DWORD threadId = GetWindowThreadProcessId(mWindow, &processId); + if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId()) + { + return; + } + + SetLastError(0); + LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast(SurfaceWindowProc)); + if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) + { + mWindowSubclassed = false; + return; + } + + SetProp(mWindow, kSurfaceProperty, reinterpret_cast(this)); + SetProp(mWindow, kParentWndProc, reinterpret_cast(oldWndProc)); + mWindowSubclassed = true; +} + +void Surface::unsubclassWindow() +{ + if(!mWindowSubclassed) + { + return; + } + + // un-subclass + LONG_PTR parentWndFunc = reinterpret_cast(GetProp(mWindow, kParentWndProc)); + + // Check the windowproc is still SurfaceWindowProc. + // If this assert fails, then it is likely the application has subclassed the + // hwnd as well and did not unsubclass before destroying its EGL context. The + // application should be modified to either subclass before initializing the + // EGL context, or to unsubclass before destroying the EGL context. + if(parentWndFunc) + { + LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc); + ASSERT(prevWndFunc == reinterpret_cast(SurfaceWindowProc)); + } + + RemoveProp(mWindow, kSurfaceProperty); + RemoveProp(mWindow, kParentWndProc); + mWindowSubclassed = false; +} + +bool Surface::checkForOutOfDateSwapChain() +{ + RECT client; + if (!GetClientRect(getWindowHandle(), &client)) + { + ASSERT(false); + return false; + } + + // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. + int clientWidth = client.right - client.left; + int clientHeight = client.bottom - client.top; + bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); + + if (sizeDirty || mPresentIntervalDirty) + { + resetSwapChain(clientWidth, clientHeight); + if (static_cast(getCurrentDrawSurface()) == this) + { + glMakeCurrent(glGetCurrentContext(), static_cast(getCurrentDisplay()), this); + } + + return true; + } + return false; +} + +DWORD Surface::convertInterval(EGLint interval) +{ + switch(interval) + { + case 0: return D3DPRESENT_INTERVAL_IMMEDIATE; + case 1: return D3DPRESENT_INTERVAL_ONE; + case 2: return D3DPRESENT_INTERVAL_TWO; + case 3: return D3DPRESENT_INTERVAL_THREE; + case 4: return D3DPRESENT_INTERVAL_FOUR; + default: UNREACHABLE(); + } + + return D3DPRESENT_INTERVAL_DEFAULT; +} + +bool Surface::swap() +{ + return swapRect(0, 0, mWidth, mHeight); +} + +bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mPostSubBufferSupported) + { + // Spec is not clear about how this should be handled. + return true; + } + + return swapRect(x, y, width, height); +} + +EGLint Surface::getWidth() const +{ + return mWidth; +} + +EGLint Surface::getHeight() const +{ + return mHeight; +} + +EGLint Surface::isPostSubBufferSupported() const +{ + return mPostSubBufferSupported; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Surface::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Surface::getDepthStencil() +{ + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + return mDepthStencil; +} + +IDirect3DTexture9 *Surface::getOffscreenTexture() +{ + if (mOffscreenTexture) + { + mOffscreenTexture->AddRef(); + } + + return mOffscreenTexture; +} + +void Surface::setSwapInterval(EGLint interval) +{ + if (mSwapInterval == interval) + { + return; + } + + mSwapInterval = interval; + mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval()); + mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval()); + + mPresentInterval = convertInterval(mSwapInterval); + mPresentIntervalDirty = true; +} + +EGLenum Surface::getTextureFormat() const +{ + return mTextureFormat; +} + +EGLenum Surface::getTextureTarget() const +{ + return mTextureTarget; +} + +void Surface::setBoundTexture(gl::Texture2D *texture) +{ + mTexture = texture; +} + +gl::Texture2D *Surface::getBoundTexture() const +{ + return mTexture; +} + +D3DFORMAT Surface::getFormat() const +{ + return mConfig->mRenderTargetFormat; +} +} diff --git a/src/3rdparty/angle/src/libEGL/Surface.h b/src/3rdparty/angle/src/libEGL/Surface.h new file mode 100644 index 0000000000..40bd7028ab --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Surface.h @@ -0,0 +1,112 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Surface.h: Defines the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#ifndef INCLUDE_SURFACE_H_ +#define INCLUDE_SURFACE_H_ + +#define EGLAPI +#include +#include + +#include "common/angleutils.h" + +namespace gl +{ +class Texture2D; +} + +namespace egl +{ +class Display; +class Config; + +class Surface +{ + public: + Surface(Display *display, const egl::Config *config, HWND window, EGLint postSubBufferSupported); + Surface(Display *display, const egl::Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureTarget); + + ~Surface(); + + bool initialize(); + void release(); + bool resetSwapChain(); + + HWND getWindowHandle(); + bool swap(); + bool postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); + + virtual EGLint getWidth() const; + virtual EGLint getHeight() const; + + virtual EGLint isPostSubBufferSupported() const; + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + virtual IDirect3DTexture9 *getOffscreenTexture(); + + HANDLE getShareHandle() { return mShareHandle; } + + void setSwapInterval(EGLint interval); + bool checkForOutOfDateSwapChain(); // Returns true if swapchain changed due to resize or interval update + + virtual EGLenum getTextureFormat() const; + virtual EGLenum getTextureTarget() const; + virtual D3DFORMAT getFormat() const; + + virtual void setBoundTexture(gl::Texture2D *texture); + virtual gl::Texture2D *getBoundTexture() const; + +private: + DISALLOW_COPY_AND_ASSIGN(Surface); + + Display *const mDisplay; + IDirect3DSwapChain9 *mSwapChain; + IDirect3DSurface9 *mBackBuffer; + IDirect3DSurface9 *mDepthStencil; + IDirect3DSurface9* mRenderTarget; + IDirect3DTexture9* mOffscreenTexture; + + HANDLE mShareHandle; + + void subclassWindow(); + void unsubclassWindow(); + bool resetSwapChain(int backbufferWidth, int backbufferHeight); + bool swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + static DWORD convertInterval(EGLint interval); + + const HWND mWindow; // Window that the surface is created for. + bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking + const egl::Config *mConfig; // EGL config surface was created with + EGLint mHeight; // Height of surface + EGLint mWidth; // Width of surface +// EGLint horizontalResolution; // Horizontal dot pitch +// EGLint verticalResolution; // Vertical dot pitch +// EGLBoolean largestPBuffer; // If true, create largest pbuffer possible +// EGLBoolean mipmapTexture; // True if texture has mipmaps +// EGLint mipmapLevel; // Mipmap level to render to +// EGLenum multisampleResolve; // Multisample resolve behavior + EGLint mPixelAspectRatio; // Display aspect ratio + EGLenum mRenderBuffer; // Render buffer + EGLenum mSwapBehavior; // Buffer swap behavior + EGLenum mTextureFormat; // Format of texture: RGB, RGBA, or no texture + EGLenum mTextureTarget; // Type of texture: 2D or no texture +// EGLenum vgAlphaFormat; // Alpha format for OpenVG +// EGLenum vgColorSpace; // Color space for OpenVG + EGLint mSwapInterval; + EGLint mPostSubBufferSupported; + + DWORD mPresentInterval; + bool mPresentIntervalDirty; + gl::Texture2D *mTexture; +}; +} + +#endif // INCLUDE_SURFACE_H_ diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp new file mode 100644 index 0000000000..25df1c8c24 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp @@ -0,0 +1,1181 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// libEGL.cpp: Implements the exported EGL functions. + +#include + +#include "common/debug.h" +#include "common/version.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Texture.h" + +#include "libEGL/main.h" +#include "libEGL/Display.h" + + +bool validateDisplay(egl::Display *display) +{ + if (display == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, false); + } + + if (!display->isInitialized()) + { + return error(EGL_NOT_INITIALIZED, false); + } + + return true; +} + +bool validateConfig(egl::Display *display, EGLConfig config) +{ + if (!validateDisplay(display)) + { + return false; + } + + if (!display->isValidConfig(config)) + { + return error(EGL_BAD_CONFIG, false); + } + + return true; +} + +bool validateContext(egl::Display *display, gl::Context *context) +{ + if (!validateDisplay(display)) + { + return false; + } + + if (!display->isValidContext(context)) + { + return error(EGL_BAD_CONTEXT, false); + } + + return true; +} + +bool validateSurface(egl::Display *display, egl::Surface *surface) +{ + if (!validateDisplay(display)) + { + return false; + } + + if (!display->isValidSurface(surface)) + { + return error(EGL_BAD_SURFACE, false); + } + + return true; +} + +extern "C" +{ +EGLint __stdcall eglGetError(void) +{ + EVENT("()"); + + EGLint error = egl::getCurrentError(); + + if (error != EGL_SUCCESS) + { + egl::setCurrentError(EGL_SUCCESS); + } + + return error; +} + +EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id) +{ + EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id); + + try + { + return egl::Display::getDisplay(display_id); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY); + } +} + +EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)", + dpy, major, minor); + + try + { + if (dpy == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + egl::Display *display = static_cast(dpy); + + if (!display->initialize()) + { + return error(EGL_NOT_INITIALIZED, EGL_FALSE); + } + + if (major) *major = 1; + if (minor) *minor = 4; + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglTerminate(EGLDisplay dpy) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy); + + try + { + if (dpy == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + egl::Display *display = static_cast(dpy); + + display->terminate(); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateDisplay(display)) + { + return NULL; + } + + switch (name) + { + case EGL_CLIENT_APIS: + return success("OpenGL_ES"); + case EGL_EXTENSIONS: + return display->getExtensionString(); + case EGL_VENDOR: + return success("Google Inc."); + case EGL_VERSION: + return success("1.4 (ANGLE " VERSION_STRING ")"); + } + + return error(EGL_BAD_PARAMETER, (const char*)NULL); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, (const char*)NULL); + } +} + +EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, " + "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", + dpy, configs, config_size, num_config); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateDisplay(display)) + { + return EGL_FALSE; + } + + if (!num_config) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + const EGLint attribList[] = {EGL_NONE}; + + if (!display->getConfigs(configs, attribList, config_size, num_config)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, " + "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)", + dpy, attrib_list, configs, config_size, num_config); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateDisplay(display)) + { + return EGL_FALSE; + } + + if (!num_config) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + const EGLint attribList[] = {EGL_NONE}; + + if (!attrib_list) + { + attrib_list = attribList; + } + + display->getConfigs(configs, attrib_list, config_size, num_config); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", + dpy, config, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateConfig(display, config)) + { + return EGL_FALSE; + } + + if (!display->getConfigAttrib(config, attribute, value)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", dpy, config, win, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + HWND window = (HWND)win; + + if (!IsWindow(window)) + { + return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + return display->createWindowSurface(window, config, attrib_list); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", + dpy, config, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + return display->createOffscreenSurface(config, NULL, attrib_list); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", dpy, config, pixmap, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_SURFACE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = static_cast(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + display->destroySurface((egl::Surface*)surface); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", + dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = (egl::Surface*)surface; + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + switch (attribute) + { + case EGL_VG_ALPHA_FORMAT: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VG_COLORSPACE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_CONFIG_ID: + UNIMPLEMENTED(); // FIXME + break; + case EGL_HEIGHT: + *value = eglSurface->getHeight(); + break; + case EGL_HORIZONTAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_LARGEST_PBUFFER: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MIPMAP_TEXTURE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MIPMAP_LEVEL: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MULTISAMPLE_RESOLVE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_PIXEL_ASPECT_RATIO: + UNIMPLEMENTED(); // FIXME + break; + case EGL_RENDER_BUFFER: + UNIMPLEMENTED(); // FIXME + break; + case EGL_SWAP_BEHAVIOR: + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_FORMAT: + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_TARGET: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VERTICAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_WIDTH: + *value = eglSurface->getWidth(); + break; + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + *value = eglSurface->isPostSubBufferSupported(); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) +{ + TRACE("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)", + dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = (egl::Surface*)surface; + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + switch (attribute) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + *value = (void*) eglSurface->getShareHandle(); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglBindAPI(EGLenum api) +{ + EVENT("(EGLenum api = 0x%X)", api); + + try + { + switch (api) + { + case EGL_OPENGL_API: + case EGL_OPENVG_API: + return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation + case EGL_OPENGL_ES_API: + break; + default: + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + egl::setCurrentAPI(api); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLenum __stdcall eglQueryAPI(void) +{ + EVENT("()"); + + try + { + EGLenum API = egl::getCurrentAPI(); + + return success(API); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglWaitClient(void) +{ + EVENT("()"); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglReleaseThread(void) +{ + EVENT("()"); + + try + { + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, " + "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", + dpy, buftype, buffer, config, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_SURFACE; + } + + if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || !buffer) + { + return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } + + return display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)", + dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = static_cast(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = static_cast(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->getBoundTexture()) + { + return error(EGL_BAD_ACCESS, EGL_FALSE); + } + + if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } + + if (!glBindTexImage(eglSurface)) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = static_cast(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) + { + return error(EGL_BAD_MATCH, EGL_FALSE); + } + + gl::Texture2D *texture = eglSurface->getBoundTexture(); + + if (texture) + { + texture->releaseTexImage(); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validateDisplay(display)) + { + return EGL_FALSE; + } + + egl::Surface *draw_surface = static_cast(egl::getCurrentDrawSurface()); + + if (draw_surface == NULL) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + draw_surface->setSwapInterval(interval); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, " + "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list); + + try + { + // Get the requested client version (default is 1) and check it is two. + EGLint client_version = 1; + bool reset_notification = false; + bool robust_access = false; + + if (attrib_list) + { + for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2) + { + switch (attribute[0]) + { + case EGL_CONTEXT_CLIENT_VERSION: + client_version = attribute[1]; + break; + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: + if (attribute[1] == EGL_TRUE) + { + return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); // Unimplemented + // robust_access = true; + } + else if (attribute[1] != EGL_FALSE) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: + if (attribute[1] == EGL_LOSE_CONTEXT_ON_RESET_EXT) + reset_notification = true; + else if (attribute[1] != EGL_NO_RESET_NOTIFICATION_EXT) + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + } + } + } + + if (client_version != 2) + { + return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); + } + + if (share_context && static_cast(share_context)->isResetNotificationEnabled() != reset_notification) + { + return error(EGL_BAD_MATCH, EGL_NO_CONTEXT); + } + + egl::Display *display = static_cast(dpy); + + if (!validateConfig(display, config)) + { + return EGL_NO_CONTEXT; + } + + EGLContext context = display->createContext(config, static_cast(share_context), reset_notification, robust_access); + + if (context) + return success(context); + else + return error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + } +} + +EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx); + + try + { + egl::Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); + + if (!validateContext(display, context)) + { + return EGL_FALSE; + } + + if (ctx == EGL_NO_CONTEXT) + { + return error(EGL_BAD_CONTEXT, EGL_FALSE); + } + + display->destroyContext(context); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)", + dpy, draw, read, ctx); + + try + { + egl::Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); + IDirect3DDevice9 *device = display->getDevice(); + + if (!device || display->testDeviceLost()) + { + display->notifyDeviceLost(); + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + if (ctx != EGL_NO_CONTEXT && !validateContext(display, context)) + { + return EGL_FALSE; + } + + if ((draw != EGL_NO_SURFACE && !validateSurface(display, static_cast(draw))) || + (read != EGL_NO_SURFACE && !validateSurface(display, static_cast(read)))) + { + return EGL_FALSE; + } + + if (draw != read) + { + UNIMPLEMENTED(); // FIXME + } + + egl::setCurrentDisplay(dpy); + egl::setCurrentDrawSurface(draw); + egl::setCurrentReadSurface(read); + + glMakeCurrent(context, display, static_cast(draw)); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLContext __stdcall eglGetCurrentContext(void) +{ + EVENT("()"); + + try + { + EGLContext context = glGetCurrentContext(); + + return success(context); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + } +} + +EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw) +{ + EVENT("(EGLint readdraw = %d)", readdraw); + + try + { + if (readdraw == EGL_READ) + { + EGLSurface read = egl::getCurrentReadSurface(); + return success(read); + } + else if (readdraw == EGL_DRAW) + { + EGLSurface draw = egl::getCurrentDrawSurface(); + return success(draw); + } + else + { + return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } +} + +EGLDisplay __stdcall eglGetCurrentDisplay(void) +{ + EVENT("()"); + + try + { + EGLDisplay dpy = egl::getCurrentDisplay(); + + return success(dpy); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY); + } +} + +EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", + dpy, ctx, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); + + if (!validateContext(display, context)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglWaitGL(void) +{ + EVENT("()"); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglWaitNative(EGLint engine) +{ + EVENT("(EGLint engine = %d)", engine); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = (egl::Surface*)surface; + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->swap()) + { + return success(EGL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target); + + try + { + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = static_cast(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } +} + +EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint x = %d, EGLint y = %d, EGLint width = %d, EGLint height = %d)", dpy, surface, x, y, width, height); + + try + { + if (x < 0 || y < 0 || width < 0 || height < 0) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + egl::Display *display = static_cast(dpy); + egl::Surface *eglSurface = static_cast(surface); + + if (!validateSurface(display, eglSurface)) + { + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + return error(EGL_CONTEXT_LOST, EGL_FALSE); + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + if (eglSurface->postSubBuffer(x, y, width, height)) + { + return success(EGL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +__eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname) +{ + EVENT("(const char *procname = \"%s\")", procname); + + try + { + struct Extension + { + const char *name; + __eglMustCastToProperFunctionPointerType address; + }; + + static const Extension eglExtensions[] = + { + {"eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)eglQuerySurfacePointerANGLE}, + {"eglPostSubBufferNV", (__eglMustCastToProperFunctionPointerType)eglPostSubBufferNV}, + {"", NULL}, + }; + + for (int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++) + { + if (strcmp(procname, eglExtensions[ext].name) == 0) + { + return (__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address; + } + } + + return glGetProcAddress(procname); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, (__eglMustCastToProperFunctionPointerType)NULL); + } +} +} diff --git a/src/3rdparty/angle/src/libEGL/libEGL.def b/src/3rdparty/angle/src/libEGL/libEGL.def new file mode 100644 index 0000000000..71a5e67977 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/libEGL.def @@ -0,0 +1,36 @@ +LIBRARY libEGL +EXPORTS + eglBindAPI @14 + eglBindTexImage @20 + eglChooseConfig @7 + eglCopyBuffers @33 + eglCreateContext @23 + eglCreatePbufferFromClientBuffer @18 + eglCreatePbufferSurface @10 + eglCreatePixmapSurface @11 + eglCreateWindowSurface @9 + eglDestroyContext @24 + eglDestroySurface @12 + eglGetConfigAttrib @8 + eglGetConfigs @6 + eglGetCurrentContext @26 + eglGetCurrentDisplay @28 + eglGetCurrentSurface @27 + eglGetDisplay @2 + eglGetError @1 + eglGetProcAddress @34 + eglInitialize @3 + eglMakeCurrent @25 + eglQueryAPI @15 + eglQueryContext @29 + eglQueryString @5 + eglQuerySurface @13 + eglReleaseTexImage @21 + eglReleaseThread @17 + eglSurfaceAttrib @19 + eglSwapBuffers @32 + eglSwapInterval @22 + eglTerminate @4 + eglWaitClient @16 + eglWaitGL @30 + eglWaitNative @31 \ No newline at end of file diff --git a/src/3rdparty/angle/src/libEGL/libEGL.rc b/src/3rdparty/angle/src/libEGL/libEGL.rc new file mode 100644 index 0000000000..5d1f32f1c9 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/libEGL.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include +#include "../common/version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""../common/version.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "ANGLE libEGL Dynamic Link Library" + VALUE "FileVersion", VERSION_STRING + VALUE "InternalName", "libEGL" + VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc." + VALUE "OriginalFilename", "libEGL.dll" + VALUE "PrivateBuild", VERSION_STRING + VALUE "ProductName", "ANGLE libEGL Dynamic Link Library" + VALUE "ProductVersion", VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src/3rdparty/angle/src/libEGL/main.cpp b/src/3rdparty/angle/src/libEGL/main.cpp new file mode 100644 index 0000000000..dc24c4fb04 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/main.cpp @@ -0,0 +1,165 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// main.cpp: DLL entry point and management of thread-local data. + +#include "libEGL/main.h" + +#include "common/debug.h" + +static DWORD currentTLS = TLS_OUT_OF_INDEXES; + +extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + { +#if !defined(ANGLE_DISABLE_TRACE) + FILE *debug = fopen(TRACE_OUTPUT_FILE, "rt"); + + if (debug) + { + fclose(debug); + debug = fopen(TRACE_OUTPUT_FILE, "wt"); // Erase + + if (debug) + { + fclose(debug); + } + } +#endif + + currentTLS = TlsAlloc(); + + if (currentTLS == TLS_OUT_OF_INDEXES) + { + return FALSE; + } + } + // Fall throught to initialize index + case DLL_THREAD_ATTACH: + { + egl::Current *current = (egl::Current*)LocalAlloc(LPTR, sizeof(egl::Current)); + + if (current) + { + TlsSetValue(currentTLS, current); + + current->error = EGL_SUCCESS; + current->API = EGL_OPENGL_ES_API; + current->display = EGL_NO_DISPLAY; + current->drawSurface = EGL_NO_SURFACE; + current->readSurface = EGL_NO_SURFACE; + } + } + break; + case DLL_THREAD_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + } + break; + case DLL_PROCESS_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + + TlsFree(currentTLS); + } + break; + default: + break; + } + + return TRUE; +} + +namespace egl +{ +void setCurrentError(EGLint error) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->error = error; +} + +EGLint getCurrentError() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->error; +} + +void setCurrentAPI(EGLenum API) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->API = API; +} + +EGLenum getCurrentAPI() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->API; +} + +void setCurrentDisplay(EGLDisplay dpy) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->display = dpy; +} + +EGLDisplay getCurrentDisplay() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->display; +} + +void setCurrentDrawSurface(EGLSurface surface) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->drawSurface = surface; +} + +EGLSurface getCurrentDrawSurface() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->drawSurface; +} + +void setCurrentReadSurface(EGLSurface surface) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->readSurface = surface; +} + +EGLSurface getCurrentReadSurface() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->readSurface; +} +} + +void error(EGLint errorCode) +{ + egl::setCurrentError(errorCode); +} diff --git a/src/3rdparty/angle/src/libEGL/main.h b/src/3rdparty/angle/src/libEGL/main.h new file mode 100644 index 0000000000..d09d9e6bc3 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/main.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// main.h: Management of thread-local data. + +#ifndef LIBEGL_MAIN_H_ +#define LIBEGL_MAIN_H_ + +#define EGLAPI +#include +#include + +namespace egl +{ +struct Current +{ + EGLint error; + EGLenum API; + EGLDisplay display; + EGLSurface drawSurface; + EGLSurface readSurface; +}; + +void setCurrentError(EGLint error); +EGLint getCurrentError(); + +void setCurrentAPI(EGLenum API); +EGLenum getCurrentAPI(); + +void setCurrentDisplay(EGLDisplay dpy); +EGLDisplay getCurrentDisplay(); + +void setCurrentDrawSurface(EGLSurface surface); +EGLSurface getCurrentDrawSurface(); + +void setCurrentReadSurface(EGLSurface surface); +EGLSurface getCurrentReadSurface(); +} + +void error(EGLint errorCode); + +template +const T &error(EGLint errorCode, const T &returnValue) +{ + error(errorCode); + + return returnValue; +} + +template +const T &success(const T &returnValue) +{ + egl::setCurrentError(EGL_SUCCESS); + + return returnValue; +} + +#endif // LIBEGL_MAIN_H_ diff --git a/src/3rdparty/angle/src/libEGL/resource.h b/src/3rdparty/angle/src/libEGL/resource.h new file mode 100644 index 0000000000..3921f4c077 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by libEGL.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h new file mode 100644 index 0000000000..5f7213b8da --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h @@ -0,0 +1,167 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BinaryStream.h: Provides binary serialization of simple types. + +#ifndef LIBGLESV2_BINARYSTREAM_H_ +#define LIBGLESV2_BINARYSTREAM_H_ + +#include +#include + +#include "common/angleutils.h" + +namespace gl +{ + +class BinaryInputStream +{ + public: + BinaryInputStream(const void *data, size_t length) + { + mError = false; + mOffset = 0; + mData = static_cast(data); + mLength = length; + } + + template + void read(T *v, size_t num) + { + union + { + T dummy; // Compilation error for non-trivial types + } dummy; + (void) dummy; + + if (mError) + { + return; + } + + size_t length = num * sizeof(T); + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + memcpy(v, mData + mOffset, length); + mOffset += length; + } + + template + void read(T * v) + { + read(v, 1); + } + + void read(std::string *v) + { + size_t length; + read(&length); + + if (mError) + { + return; + } + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + v->assign(mData + mOffset, length); + mOffset += length; + } + + void skip(size_t length) + { + if (mOffset + length > mLength) + { + mError = true; + return; + } + + mOffset += length; + } + + size_t offset() const + { + return mOffset; + } + + bool error() const + { + return mError; + } + + bool endOfStream() const + { + return mOffset == mLength; + } + + private: + DISALLOW_COPY_AND_ASSIGN(BinaryInputStream); + bool mError; + size_t mOffset; + const char *mData; + size_t mLength; +}; + +class BinaryOutputStream +{ + public: + BinaryOutputStream() + { + } + + template + void write(const T *v, size_t num) + { + union + { + T dummy; // Compilation error for non-trivial types + } dummy; + (void) dummy; + + const char *asBytes = reinterpret_cast(v); + mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); + } + + template + void write(const T &v) + { + write(&v, 1); + } + + void write(const std::string &v) + { + size_t length = v.length(); + write(length); + + write(v.c_str(), length); + } + + size_t length() const + { + return mData.size(); + } + + const void* data() const + { + return mData.size() ? &mData[0] : NULL; + } + + private: + DISALLOW_COPY_AND_ASSIGN(BinaryOutputStream); + std::vector mData; +}; +} + +#endif // LIBGLESV2_BINARYSTREAM_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Blit.cpp b/src/3rdparty/angle/src/libGLESv2/Blit.cpp new file mode 100644 index 0000000000..28f3fbffbb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Blit.cpp @@ -0,0 +1,518 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit.cpp: Surface copy utility class. + +#include "libGLESv2/Blit.h" + +#include "common/debug.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/utilities.h" + +namespace +{ +#include "libGLESv2/shaders/standardvs.h" +#include "libGLESv2/shaders/flipyvs.h" +#include "libGLESv2/shaders/passthroughps.h" +#include "libGLESv2/shaders/luminanceps.h" +#include "libGLESv2/shaders/componentmaskps.h" + +const BYTE* const g_shaderCode[] = +{ + g_vs20_standardvs, + g_vs20_flipyvs, + g_ps20_passthroughps, + g_ps20_luminanceps, + g_ps20_componentmaskps +}; + +const size_t g_shaderSize[] = +{ + sizeof(g_vs20_standardvs), + sizeof(g_vs20_flipyvs), + sizeof(g_ps20_passthroughps), + sizeof(g_ps20_luminanceps), + sizeof(g_ps20_componentmaskps) +}; +} + +namespace gl +{ +Blit::Blit(Context *context) + : mContext(context), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL), mSavedStateBlock(NULL) +{ + initGeometry(); + memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); +} + +Blit::~Blit() +{ + if (mSavedStateBlock) mSavedStateBlock->Release(); + if (mQuadVertexBuffer) mQuadVertexBuffer->Release(); + if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release(); + + for (int i = 0; i < SHADER_COUNT; i++) + { + if (mCompiledShaders[i]) + { + mCompiledShaders[i]->Release(); + } + } +} + +void Blit::initGeometry() +{ + static const float quad[] = + { + -1, -1, + -1, 1, + 1, -1, + 1, 1 + }; + + IDirect3DDevice9 *device = getDevice(); + + HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY); + } + + void *lockPtr = NULL; + result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); + + if (FAILED(result) || lockPtr == NULL) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY); + } + + memcpy(lockPtr, quad, sizeof(quad)); + mQuadVertexBuffer->Unlock(); + + static const D3DVERTEXELEMENT9 elements[] = + { + { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + D3DDECL_END() + }; + + result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY); + } +} + +template +bool Blit::setShader(ShaderId source, const char *profile, + D3DShaderType *(egl::Display::*createShader)(const DWORD *, size_t length), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + D3DShaderType *shader; + + if (mCompiledShaders[source] != NULL) + { + shader = static_cast(mCompiledShaders[source]); + } + else + { + const BYTE* shaderCode = g_shaderCode[source]; + size_t shaderSize = g_shaderSize[source]; + + shader = (display->*createShader)(reinterpret_cast(shaderCode), shaderSize); + if (!shader) + { + ERR("Failed to create shader for blit operation"); + return false; + } + + mCompiledShaders[source] = shader; + } + + HRESULT hr = (device->*setShader)(shader); + + if (FAILED(hr)) + { + ERR("Failed to set shader for blit operation"); + return false; + } + + return true; +} + +bool Blit::setVertexShader(ShaderId shader) +{ + return setShader(shader, "vs_2_0", &egl::Display::createVertexShader, &IDirect3DDevice9::SetVertexShader); +} + +bool Blit::setPixelShader(ShaderId shader) +{ + return setShader(shader, "ps_2_0", &egl::Display::createPixelShader, &IDirect3DDevice9::SetPixelShader); +} + +RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = desc.Width; + rect.bottom = desc.Height; + + return rect; +} + +bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source)); + if (!texture) + { + return false; + } + + IDirect3DDevice9 *device = getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setVertexShader(SHADER_VS_STANDARD); + setPixelShader(SHADER_PS_PASSTHROUGH); + + setCommonBlitState(); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + setViewport(getSurfaceRect(dest), 0, 0); + + render(); + + texture->Release(); + + restoreState(); + + return true; +} + +bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +{ + IDirect3DDevice9 *device = getDevice(); + + D3DSURFACE_DESC sourceDesc; + D3DSURFACE_DESC destDesc; + source->GetDesc(&sourceDesc); + dest->GetDesc(&destDesc); + + if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET && + dx2es::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect + { + RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)}; + HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY, false); + } + } + else + { + return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest); + } + + return true; +} + +bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +{ + IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect); + if (!texture) + { + return false; + } + + IDirect3DDevice9 *device = getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setViewport(sourceRect, xoffset, yoffset); + + setCommonBlitState(); + if (setFormatConvertShaders(destFormat)) + { + render(); + } + + texture->Release(); + + restoreState(); + + return true; +} + +bool Blit::setFormatConvertShaders(GLenum destFormat) +{ + bool okay = setVertexShader(SHADER_VS_STANDARD); + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_ALPHA: + okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK); + break; + + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + okay = okay && setPixelShader(SHADER_PS_LUMINANCE); + break; + } + + if (!okay) + { + return false; + } + + enum { X = 0, Y = 1, Z = 2, W = 3 }; + + // The meaning of this constant depends on the shader that was selected. + // See the shader assembly code above for details. + float psConst0[4] = { 0, 0, 0, 0 }; + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + psConst0[X] = 1; + psConst0[Z] = 1; + break; + + case GL_RGB: + psConst0[X] = 1; + psConst0[W] = 1; + break; + + case GL_ALPHA: + psConst0[Z] = 1; + break; + + case GL_LUMINANCE: + psConst0[Y] = 1; + break; + + case GL_LUMINANCE_ALPHA: + psConst0[X] = 1; + break; + } + + getDevice()->SetPixelShaderConstantF(0, psConst0, 1); + + return true; +} + +IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect) +{ + if (!surface) + { + return NULL; + } + + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = getDevice(); + + D3DSURFACE_DESC sourceDesc; + surface->GetDesc(&sourceDesc); + + // Copy the render target into a texture + IDirect3DTexture9 *texture; + HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + } + + IDirect3DSurface9 *textureSurface; + result = texture->GetSurfaceLevel(0, &textureSurface); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + texture->Release(); + return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + } + + display->endScene(); + result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); + + textureSurface->Release(); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + texture->Release(); + return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + } + + return texture; +} + +void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) +{ + IDirect3DDevice9 *device = getDevice(); + + D3DVIEWPORT9 vp; + vp.X = xoffset; + vp.Y = yoffset; + vp.Width = sourceRect.right - sourceRect.left; + vp.Height = sourceRect.bottom - sourceRect.top; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + device->SetViewport(&vp); + + float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 }; + device->SetVertexShaderConstantF(0, halfPixelAdjust, 1); +} + +void Blit::setCommonBlitState() +{ + IDirect3DDevice9 *device = getDevice(); + + device->SetDepthStencilSurface(NULL); + + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle + device->SetScissorRect(&scissorRect); + + for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } +} + +void Blit::render() +{ + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = getDevice(); + + HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float)); + hr = device->SetVertexDeclaration(mQuadVertexDeclaration); + + display->startScene(); + hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); +} + +void Blit::saveState() +{ + IDirect3DDevice9 *device = getDevice(); + + HRESULT hr; + + device->GetDepthStencilSurface(&mSavedDepthStencil); + device->GetRenderTarget(0, &mSavedRenderTarget); + + if (mSavedStateBlock == NULL) + { + hr = device->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + setCommonBlitState(); + + static const float dummyConst[4] = { 0, 0, 0, 0 }; + + device->SetVertexShader(NULL); + device->SetVertexShaderConstantF(0, dummyConst, 1); + device->SetPixelShader(NULL); + device->SetPixelShaderConstantF(0, dummyConst, 1); + + D3DVIEWPORT9 dummyVp; + dummyVp.X = 0; + dummyVp.Y = 0; + dummyVp.Width = 1; + dummyVp.Height = 1; + dummyVp.MinZ = 0; + dummyVp.MaxZ = 1; + + device->SetViewport(&dummyVp); + + device->SetTexture(0, NULL); + + device->SetStreamSource(0, mQuadVertexBuffer, 0, 0); + + device->SetVertexDeclaration(mQuadVertexDeclaration); + + hr = device->EndStateBlock(&mSavedStateBlock); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + } + + ASSERT(mSavedStateBlock != NULL); + + if (mSavedStateBlock != NULL) + { + hr = mSavedStateBlock->Capture(); + ASSERT(SUCCEEDED(hr)); + } +} + +void Blit::restoreState() +{ + IDirect3DDevice9 *device = getDevice(); + + device->SetDepthStencilSurface(mSavedDepthStencil); + if (mSavedDepthStencil != NULL) + { + mSavedDepthStencil->Release(); + mSavedDepthStencil = NULL; + } + + device->SetRenderTarget(0, mSavedRenderTarget); + if (mSavedRenderTarget != NULL) + { + mSavedRenderTarget->Release(); + mSavedRenderTarget = NULL; + } + + ASSERT(mSavedStateBlock != NULL); + + if (mSavedStateBlock != NULL) + { + mSavedStateBlock->Apply(); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Blit.h b/src/3rdparty/angle/src/libGLESv2/Blit.h new file mode 100644 index 0000000000..a9bb4956eb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Blit.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Blit.cpp: Surface copy utility class. + +#ifndef LIBGLESV2_BLIT_H_ +#define LIBGLESV2_BLIT_H_ + +#include + +#define GL_APICALL +#include + +#include + +#include "common/angleutils.h" + +#include "libEGL/Display.h" + +namespace gl +{ +class Context; + +class Blit +{ + public: + explicit Blit(Context *context); + ~Blit(); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + bool copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0. + bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); + + // 2x2 box filter sample from source to dest. + // Requires that source is RGB(A) and dest has the same format as source. + bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + private: + Context *mContext; + + IDirect3DVertexBuffer9 *mQuadVertexBuffer; + IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; + + void initGeometry(); + + bool setFormatConvertShaders(GLenum destFormat); + + IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect); + void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset); + void setCommonBlitState(); + RECT getSurfaceRect(IDirect3DSurface9 *surface) const; + + // This enum is used to index mCompiledShaders and mShaderSource. + enum ShaderId + { + SHADER_VS_STANDARD, + SHADER_VS_FLIPY, + SHADER_PS_PASSTHROUGH, + SHADER_PS_LUMINANCE, + SHADER_PS_COMPONENTMASK, + SHADER_COUNT + }; + + // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown. + IUnknown *mCompiledShaders[SHADER_COUNT]; + + template + bool setShader(ShaderId source, const char *profile, + D3DShaderType *(egl::Display::*createShader)(const DWORD *, size_t length), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); + + bool setVertexShader(ShaderId shader); + bool setPixelShader(ShaderId shader); + void render(); + + void saveState(); + void restoreState(); + IDirect3DStateBlock9 *mSavedStateBlock; + IDirect3DSurface9 *mSavedRenderTarget; + IDirect3DSurface9 *mSavedDepthStencil; + + DISALLOW_COPY_AND_ASSIGN(Blit); +}; +} + +#endif // LIBGLESV2_BLIT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.cpp b/src/3rdparty/angle/src/libGLESv2/Buffer.cpp new file mode 100644 index 0000000000..dd12e3c077 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Buffer.cpp @@ -0,0 +1,117 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#include "libGLESv2/Buffer.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/VertexDataManager.h" +#include "libGLESv2/IndexDataManager.h" + +namespace gl +{ + +Buffer::Buffer(GLuint id) : RefCountObject(id) +{ + mContents = NULL; + mSize = 0; + mUsage = GL_DYNAMIC_DRAW; + + mStaticVertexBuffer = NULL; + mStaticIndexBuffer = NULL; + mUnmodifiedDataUse = 0; +} + +Buffer::~Buffer() +{ + delete[] mContents; + delete mStaticVertexBuffer; + delete mStaticIndexBuffer; +} + +void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) +{ + if (size == 0) + { + delete[] mContents; + mContents = NULL; + } + else if (size != mSize) + { + delete[] mContents; + mContents = new GLubyte[size]; + memset(mContents, 0, size); + } + + if (data != NULL && size > 0) + { + memcpy(mContents, data, size); + } + + mSize = size; + mUsage = usage; + + invalidateStaticData(); + + if (usage == GL_STATIC_DRAW) + { + mStaticVertexBuffer = new StaticVertexBuffer(getDevice()); + mStaticIndexBuffer = new StaticIndexBuffer(getDevice()); + } +} + +void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) +{ + memcpy(mContents + offset, data, size); + + if ((mStaticVertexBuffer && mStaticVertexBuffer->size() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->size() != 0)) + { + invalidateStaticData(); + } + + mUnmodifiedDataUse = 0; +} + +StaticVertexBuffer *Buffer::getStaticVertexBuffer() +{ + return mStaticVertexBuffer; +} + +StaticIndexBuffer *Buffer::getStaticIndexBuffer() +{ + return mStaticIndexBuffer; +} + +void Buffer::invalidateStaticData() +{ + delete mStaticVertexBuffer; + mStaticVertexBuffer = NULL; + + delete mStaticIndexBuffer; + mStaticIndexBuffer = NULL; + + mUnmodifiedDataUse = 0; +} + +// Creates static buffers if sufficient used data has been left unmodified +void Buffer::promoteStaticUsage(int dataSize) +{ + if (!mStaticVertexBuffer && !mStaticIndexBuffer) + { + mUnmodifiedDataUse += dataSize; + + if (mUnmodifiedDataUse > 3 * mSize) + { + mStaticVertexBuffer = new StaticVertexBuffer(getDevice()); + mStaticIndexBuffer = new StaticIndexBuffer(getDevice()); + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.h b/src/3rdparty/angle/src/libGLESv2/Buffer.h new file mode 100644 index 0000000000..7019c4e160 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Buffer.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Buffer.h: Defines the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#ifndef LIBGLESV2_BUFFER_H_ +#define LIBGLESV2_BUFFER_H_ + +#include +#include + +#define GL_APICALL +#include + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ +class StaticVertexBuffer; +class StaticIndexBuffer; + +class Buffer : public RefCountObject +{ + public: + explicit Buffer(GLuint id); + + virtual ~Buffer(); + + void bufferData(const void *data, GLsizeiptr size, GLenum usage); + void bufferSubData(const void *data, GLsizeiptr size, GLintptr offset); + + void *data() { return mContents; } + size_t size() const { return mSize; } + GLenum usage() const { return mUsage; } + + StaticVertexBuffer *getStaticVertexBuffer(); + StaticIndexBuffer *getStaticIndexBuffer(); + void invalidateStaticData(); + void promoteStaticUsage(int dataSize); + + private: + DISALLOW_COPY_AND_ASSIGN(Buffer); + + GLubyte *mContents; + GLsizeiptr mSize; + GLenum mUsage; + + StaticVertexBuffer *mStaticVertexBuffer; + StaticIndexBuffer *mStaticIndexBuffer; + GLsizeiptr mUnmodifiedDataUse; +}; + +} + +#endif // LIBGLESV2_BUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp new file mode 100644 index 0000000000..414bfa968d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp @@ -0,0 +1,4501 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Context.cpp: Implements the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#include "libGLESv2/Context.h" + +#include + +#include "libEGL/Display.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/utilities.h" +#include "libGLESv2/Blit.h" +#include "libGLESv2/ResourceManager.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Fence.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Query.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/VertexDataManager.h" +#include "libGLESv2/IndexDataManager.h" + +#undef near +#undef far + +namespace gl +{ +Context::Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) : mConfig(config) +{ + ASSERT(robustAccess == false); // Unimplemented + + mDisplay = NULL; + mDevice = NULL; + + mFenceHandleAllocator.setBaseHandle(0); + + setClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + mState.depthClearValue = 1.0f; + mState.stencilClearValue = 0; + + mState.cullFace = false; + mState.cullMode = GL_BACK; + mState.frontFace = GL_CCW; + mState.depthTest = false; + mState.depthFunc = GL_LESS; + mState.blend = false; + mState.sourceBlendRGB = GL_ONE; + mState.sourceBlendAlpha = GL_ONE; + mState.destBlendRGB = GL_ZERO; + mState.destBlendAlpha = GL_ZERO; + mState.blendEquationRGB = GL_FUNC_ADD; + mState.blendEquationAlpha = GL_FUNC_ADD; + mState.blendColor.red = 0; + mState.blendColor.green = 0; + mState.blendColor.blue = 0; + mState.blendColor.alpha = 0; + mState.stencilTest = false; + mState.stencilFunc = GL_ALWAYS; + mState.stencilRef = 0; + mState.stencilMask = -1; + mState.stencilWritemask = -1; + mState.stencilBackFunc = GL_ALWAYS; + mState.stencilBackRef = 0; + mState.stencilBackMask = - 1; + mState.stencilBackWritemask = -1; + mState.stencilFail = GL_KEEP; + mState.stencilPassDepthFail = GL_KEEP; + mState.stencilPassDepthPass = GL_KEEP; + mState.stencilBackFail = GL_KEEP; + mState.stencilBackPassDepthFail = GL_KEEP; + mState.stencilBackPassDepthPass = GL_KEEP; + mState.polygonOffsetFill = false; + mState.polygonOffsetFactor = 0.0f; + mState.polygonOffsetUnits = 0.0f; + mState.sampleAlphaToCoverage = false; + mState.sampleCoverage = false; + mState.sampleCoverageValue = 1.0f; + mState.sampleCoverageInvert = false; + mState.scissorTest = false; + mState.dither = true; + mState.generateMipmapHint = GL_DONT_CARE; + mState.fragmentShaderDerivativeHint = GL_DONT_CARE; + + mState.lineWidth = 1.0f; + + mState.viewportX = 0; + mState.viewportY = 0; + mState.viewportWidth = config->mDisplayMode.Width; + mState.viewportHeight = config->mDisplayMode.Height; + mState.zNear = 0.0f; + mState.zFar = 1.0f; + + mState.scissorX = 0; + mState.scissorY = 0; + mState.scissorWidth = config->mDisplayMode.Width; + mState.scissorHeight = config->mDisplayMode.Height; + + mState.colorMaskRed = true; + mState.colorMaskGreen = true; + mState.colorMaskBlue = true; + mState.colorMaskAlpha = true; + mState.depthMask = true; + + if (shareContext != NULL) + { + mResourceManager = shareContext->mResourceManager; + mResourceManager->addRef(); + } + else + { + mResourceManager = new ResourceManager(); + } + + // [OpenGL ES 2.0.24] section 3.7 page 83: + // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional + // and cube map texture state vectors respectively associated with them. + // In order that access to these initial textures not be lost, they are treated as texture + // objects all of whose names are 0. + + mTexture2DZero.set(new Texture2D(0)); + mTextureCubeMapZero.set(new TextureCubeMap(0)); + + mState.activeSampler = 0; + bindArrayBuffer(0); + bindElementArrayBuffer(0); + bindTextureCubeMap(0); + bindTexture2D(0); + bindReadFramebuffer(0); + bindDrawFramebuffer(0); + bindRenderbuffer(0); + + mState.currentProgram = 0; + mCurrentProgramBinary.set(NULL); + + mState.packAlignment = 4; + mState.unpackAlignment = 4; + mState.packReverseRowOrder = false; + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + mBlit = NULL; + mLineLoopIB = NULL; + + mInvalidEnum = false; + mInvalidValue = false; + mInvalidOperation = false; + mOutOfMemory = false; + mInvalidFramebufferOperation = false; + + mHasBeenCurrent = false; + mContextLost = false; + mResetStatus = GL_NO_ERROR; + mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); + mRobustAccess = robustAccess; + + mSupportsDXT1Textures = false; + mSupportsDXT3Textures = false; + mSupportsDXT5Textures = false; + mSupportsEventQueries = false; + mSupportsOcclusionQueries = false; + mNumCompressedTextureFormats = 0; + mMaxSupportedSamples = 0; + mMaskedClearSavedState = NULL; + markAllStateDirty(); +} + +Context::~Context() +{ + if (mState.currentProgram != 0) + { + Program *programObject = mResourceManager->getProgram(mState.currentProgram); + if (programObject) + { + programObject->release(); + } + mState.currentProgram = 0; + } + mCurrentProgramBinary.set(NULL); + + while (!mFramebufferMap.empty()) + { + deleteFramebuffer(mFramebufferMap.begin()->first); + } + + while (!mFenceMap.empty()) + { + deleteFence(mFenceMap.begin()->first); + } + + while (!mQueryMap.empty()) + { + deleteQuery(mQueryMap.begin()->first); + } + + while (!mMultiSampleSupport.empty()) + { + delete [] mMultiSampleSupport.begin()->second; + mMultiSampleSupport.erase(mMultiSampleSupport.begin()); + } + + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + { + for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++) + { + mState.samplerTexture[type][sampler].set(NULL); + } + } + + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + { + mIncompleteTextures[type].set(NULL); + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mState.vertexAttribute[i].mBoundBuffer.set(NULL); + } + + for (int i = 0; i < QUERY_TYPE_COUNT; i++) + { + mState.activeQuery[i].set(NULL); + } + + mState.arrayBuffer.set(NULL); + mState.elementArrayBuffer.set(NULL); + mState.renderbuffer.set(NULL); + + mTexture2DZero.set(NULL); + mTextureCubeMapZero.set(NULL); + + delete mVertexDataManager; + delete mIndexDataManager; + delete mBlit; + delete mLineLoopIB; + + if (mMaskedClearSavedState) + { + mMaskedClearSavedState->Release(); + } + + mResourceManager->release(); +} + +void Context::makeCurrent(egl::Display *display, egl::Surface *surface) +{ + mDisplay = display; + mDevice = mDisplay->getDevice(); + + if (!mHasBeenCurrent) + { + mDeviceCaps = mDisplay->getDeviceCaps(); + + mVertexDataManager = new VertexDataManager(this, mDevice); + mIndexDataManager = new IndexDataManager(this, mDevice); + mBlit = new Blit(this); + + mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + mMaximumPointSize = mDeviceCaps.MaxPointSize; + mSupportsVertexTexture = mDisplay->getVertexTextureSupport(); + mSupportsNonPower2Texture = mDisplay->getNonPower2TextureSupport(); + mSupportsInstancing = mDisplay->getInstancingSupport(); + + mMaxTextureDimension = std::min(std::min((int)mDeviceCaps.MaxTextureWidth, (int)mDeviceCaps.MaxTextureHeight), + (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE); + mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE); + mMaxRenderbufferDimension = mMaxTextureDimension; + mMaxTextureLevel = log2(mMaxTextureDimension) + 1; + mMaxTextureAnisotropy = mDisplay->getTextureFilterAnisotropySupport(); + TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d, MaxTextureAnisotropy=%f", + mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel, mMaxTextureAnisotropy); + + const D3DFORMAT renderBufferFormats[] = + { + D3DFMT_A8R8G8B8, + D3DFMT_X8R8G8B8, + D3DFMT_R5G6B5, + D3DFMT_D24S8 + }; + + int max = 0; + for (int i = 0; i < sizeof(renderBufferFormats) / sizeof(D3DFORMAT); ++i) + { + bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1]; + mDisplay->getMultiSampleSupport(renderBufferFormats[i], multisampleArray); + mMultiSampleSupport[renderBufferFormats[i]] = multisampleArray; + + for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j) + { + if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max) + { + max = j; + } + } + } + + mMaxSupportedSamples = max; + + mSupportsEventQueries = mDisplay->getEventQuerySupport(); + mSupportsOcclusionQueries = mDisplay->getOcclusionQuerySupport(); + mSupportsDXT1Textures = mDisplay->getDXT1TextureSupport(); + mSupportsDXT3Textures = mDisplay->getDXT3TextureSupport(); + mSupportsDXT5Textures = mDisplay->getDXT5TextureSupport(); + mSupportsFloat32Textures = mDisplay->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures); + mSupportsFloat16Textures = mDisplay->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures); + mSupportsLuminanceTextures = mDisplay->getLuminanceTextureSupport(); + mSupportsLuminanceAlphaTextures = mDisplay->getLuminanceAlphaTextureSupport(); + mSupportsDepthTextures = mDisplay->getDepthTextureSupport(); + mSupportsTextureFilterAnisotropy = mMaxTextureAnisotropy >= 2.0f; + + mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16); + + mNumCompressedTextureFormats = 0; + if (supportsDXT1Textures()) + { + mNumCompressedTextureFormats += 2; + } + if (supportsDXT3Textures()) + { + mNumCompressedTextureFormats += 1; + } + if (supportsDXT5Textures()) + { + mNumCompressedTextureFormats += 1; + } + + initExtensionString(); + initRendererString(); + + mState.viewportX = 0; + mState.viewportY = 0; + mState.viewportWidth = surface->getWidth(); + mState.viewportHeight = surface->getHeight(); + + mState.scissorX = 0; + mState.scissorY = 0; + mState.scissorWidth = surface->getWidth(); + mState.scissorHeight = surface->getHeight(); + + mHasBeenCurrent = true; + } + + // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names + IDirect3DSurface9 *defaultRenderTarget = surface->getRenderTarget(); + IDirect3DSurface9 *depthStencil = surface->getDepthStencil(); + + Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget); + DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(depthStencil); + Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero); + + setFramebufferZero(framebufferZero); + + if (defaultRenderTarget) + { + defaultRenderTarget->Release(); + } + + if (depthStencil) + { + depthStencil->Release(); + } + + // Reset pixel shader to null to work around a bug that only happens with Intel GPUs. + // http://crbug.com/110343 + mDevice->SetPixelShader(NULL); + + markAllStateDirty(); +} + +// This function will set all of the state-related dirty flags, so that all state is set during next pre-draw. +void Context::markAllStateDirty() +{ + for (int t = 0; t < MAX_TEXTURE_IMAGE_UNITS; t++) + { + mAppliedTextureSerialPS[t] = 0; + } + + for (int t = 0; t < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; t++) + { + mAppliedTextureSerialVS[t] = 0; + } + + mAppliedProgramBinarySerial = 0; + mAppliedRenderTargetSerial = 0; + mAppliedDepthbufferSerial = 0; + mAppliedStencilbufferSerial = 0; + mAppliedIBSerial = 0; + mDepthStencilInitialized = false; + mViewportInitialized = false; + mRenderTargetDescInitialized = false; + + mVertexDeclarationCache.markStateDirty(); + + mClearStateDirty = true; + mCullStateDirty = true; + mDepthStateDirty = true; + mMaskStateDirty = true; + mBlendStateDirty = true; + mStencilStateDirty = true; + mPolygonOffsetStateDirty = true; + mScissorStateDirty = true; + mSampleStateDirty = true; + mDitherStateDirty = true; + mFrontFaceDirty = true; + mDxUniformsDirty = true; +} + +void Context::markDxUniformsDirty() +{ + mDxUniformsDirty = true; +} + +void Context::markContextLost() +{ + if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; +} + +void Context::setClearColor(float red, float green, float blue, float alpha) +{ + mState.colorClearValue.red = red; + mState.colorClearValue.green = green; + mState.colorClearValue.blue = blue; + mState.colorClearValue.alpha = alpha; +} + +void Context::setClearDepth(float depth) +{ + mState.depthClearValue = depth; +} + +void Context::setClearStencil(int stencil) +{ + mState.stencilClearValue = stencil; +} + +void Context::setCullFace(bool enabled) +{ + if (mState.cullFace != enabled) + { + mState.cullFace = enabled; + mCullStateDirty = true; + } +} + +bool Context::isCullFaceEnabled() const +{ + return mState.cullFace; +} + +void Context::setCullMode(GLenum mode) +{ + if (mState.cullMode != mode) + { + mState.cullMode = mode; + mCullStateDirty = true; + } +} + +void Context::setFrontFace(GLenum front) +{ + if (mState.frontFace != front) + { + mState.frontFace = front; + mFrontFaceDirty = true; + } +} + +void Context::setDepthTest(bool enabled) +{ + if (mState.depthTest != enabled) + { + mState.depthTest = enabled; + mDepthStateDirty = true; + } +} + +bool Context::isDepthTestEnabled() const +{ + return mState.depthTest; +} + +void Context::setDepthFunc(GLenum depthFunc) +{ + if (mState.depthFunc != depthFunc) + { + mState.depthFunc = depthFunc; + mDepthStateDirty = true; + } +} + +void Context::setDepthRange(float zNear, float zFar) +{ + mState.zNear = zNear; + mState.zFar = zFar; +} + +void Context::setBlend(bool enabled) +{ + if (mState.blend != enabled) + { + mState.blend = enabled; + mBlendStateDirty = true; + } +} + +bool Context::isBlendEnabled() const +{ + return mState.blend; +} + +void Context::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) +{ + if (mState.sourceBlendRGB != sourceRGB || + mState.sourceBlendAlpha != sourceAlpha || + mState.destBlendRGB != destRGB || + mState.destBlendAlpha != destAlpha) + { + mState.sourceBlendRGB = sourceRGB; + mState.destBlendRGB = destRGB; + mState.sourceBlendAlpha = sourceAlpha; + mState.destBlendAlpha = destAlpha; + mBlendStateDirty = true; + } +} + +void Context::setBlendColor(float red, float green, float blue, float alpha) +{ + if (mState.blendColor.red != red || + mState.blendColor.green != green || + mState.blendColor.blue != blue || + mState.blendColor.alpha != alpha) + { + mState.blendColor.red = red; + mState.blendColor.green = green; + mState.blendColor.blue = blue; + mState.blendColor.alpha = alpha; + mBlendStateDirty = true; + } +} + +void Context::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) +{ + if (mState.blendEquationRGB != rgbEquation || + mState.blendEquationAlpha != alphaEquation) + { + mState.blendEquationRGB = rgbEquation; + mState.blendEquationAlpha = alphaEquation; + mBlendStateDirty = true; + } +} + +void Context::setStencilTest(bool enabled) +{ + if (mState.stencilTest != enabled) + { + mState.stencilTest = enabled; + mStencilStateDirty = true; + } +} + +bool Context::isStencilTestEnabled() const +{ + return mState.stencilTest; +} + +void Context::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) +{ + if (mState.stencilFunc != stencilFunc || + mState.stencilRef != stencilRef || + mState.stencilMask != stencilMask) + { + mState.stencilFunc = stencilFunc; + mState.stencilRef = (stencilRef > 0) ? stencilRef : 0; + mState.stencilMask = stencilMask; + mStencilStateDirty = true; + } +} + +void Context::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) +{ + if (mState.stencilBackFunc != stencilBackFunc || + mState.stencilBackRef != stencilBackRef || + mState.stencilBackMask != stencilBackMask) + { + mState.stencilBackFunc = stencilBackFunc; + mState.stencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; + mState.stencilBackMask = stencilBackMask; + mStencilStateDirty = true; + } +} + +void Context::setStencilWritemask(GLuint stencilWritemask) +{ + if (mState.stencilWritemask != stencilWritemask) + { + mState.stencilWritemask = stencilWritemask; + mStencilStateDirty = true; + } +} + +void Context::setStencilBackWritemask(GLuint stencilBackWritemask) +{ + if (mState.stencilBackWritemask != stencilBackWritemask) + { + mState.stencilBackWritemask = stencilBackWritemask; + mStencilStateDirty = true; + } +} + +void Context::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) +{ + if (mState.stencilFail != stencilFail || + mState.stencilPassDepthFail != stencilPassDepthFail || + mState.stencilPassDepthPass != stencilPassDepthPass) + { + mState.stencilFail = stencilFail; + mState.stencilPassDepthFail = stencilPassDepthFail; + mState.stencilPassDepthPass = stencilPassDepthPass; + mStencilStateDirty = true; + } +} + +void Context::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) +{ + if (mState.stencilBackFail != stencilBackFail || + mState.stencilBackPassDepthFail != stencilBackPassDepthFail || + mState.stencilBackPassDepthPass != stencilBackPassDepthPass) + { + mState.stencilBackFail = stencilBackFail; + mState.stencilBackPassDepthFail = stencilBackPassDepthFail; + mState.stencilBackPassDepthPass = stencilBackPassDepthPass; + mStencilStateDirty = true; + } +} + +void Context::setPolygonOffsetFill(bool enabled) +{ + if (mState.polygonOffsetFill != enabled) + { + mState.polygonOffsetFill = enabled; + mPolygonOffsetStateDirty = true; + } +} + +bool Context::isPolygonOffsetFillEnabled() const +{ + return mState.polygonOffsetFill; + +} + +void Context::setPolygonOffsetParams(GLfloat factor, GLfloat units) +{ + if (mState.polygonOffsetFactor != factor || + mState.polygonOffsetUnits != units) + { + mState.polygonOffsetFactor = factor; + mState.polygonOffsetUnits = units; + mPolygonOffsetStateDirty = true; + } +} + +void Context::setSampleAlphaToCoverage(bool enabled) +{ + if (mState.sampleAlphaToCoverage != enabled) + { + mState.sampleAlphaToCoverage = enabled; + mSampleStateDirty = true; + } +} + +bool Context::isSampleAlphaToCoverageEnabled() const +{ + return mState.sampleAlphaToCoverage; +} + +void Context::setSampleCoverage(bool enabled) +{ + if (mState.sampleCoverage != enabled) + { + mState.sampleCoverage = enabled; + mSampleStateDirty = true; + } +} + +bool Context::isSampleCoverageEnabled() const +{ + return mState.sampleCoverage; +} + +void Context::setSampleCoverageParams(GLclampf value, bool invert) +{ + if (mState.sampleCoverageValue != value || + mState.sampleCoverageInvert != invert) + { + mState.sampleCoverageValue = value; + mState.sampleCoverageInvert = invert; + mSampleStateDirty = true; + } +} + +void Context::setScissorTest(bool enabled) +{ + if (mState.scissorTest != enabled) + { + mState.scissorTest = enabled; + mScissorStateDirty = true; + } +} + +bool Context::isScissorTestEnabled() const +{ + return mState.scissorTest; +} + +void Context::setDither(bool enabled) +{ + if (mState.dither != enabled) + { + mState.dither = enabled; + mDitherStateDirty = true; + } +} + +bool Context::isDitherEnabled() const +{ + return mState.dither; +} + +void Context::setLineWidth(GLfloat width) +{ + mState.lineWidth = width; +} + +void Context::setGenerateMipmapHint(GLenum hint) +{ + mState.generateMipmapHint = hint; +} + +void Context::setFragmentShaderDerivativeHint(GLenum hint) +{ + mState.fragmentShaderDerivativeHint = hint; + // TODO: Propagate the hint to shader translator so we can write + // ddx, ddx_coarse, or ddx_fine depending on the hint. + // Ignore for now. It is valid for implementations to ignore hint. +} + +void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mState.viewportX = x; + mState.viewportY = y; + mState.viewportWidth = width; + mState.viewportHeight = height; +} + +void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (mState.scissorX != x || mState.scissorY != y || + mState.scissorWidth != width || mState.scissorHeight != height) + { + mState.scissorX = x; + mState.scissorY = y; + mState.scissorWidth = width; + mState.scissorHeight = height; + mScissorStateDirty = true; + } +} + +void Context::setColorMask(bool red, bool green, bool blue, bool alpha) +{ + if (mState.colorMaskRed != red || mState.colorMaskGreen != green || + mState.colorMaskBlue != blue || mState.colorMaskAlpha != alpha) + { + mState.colorMaskRed = red; + mState.colorMaskGreen = green; + mState.colorMaskBlue = blue; + mState.colorMaskAlpha = alpha; + mMaskStateDirty = true; + } +} + +void Context::setDepthMask(bool mask) +{ + if (mState.depthMask != mask) + { + mState.depthMask = mask; + mMaskStateDirty = true; + } +} + +void Context::setActiveSampler(unsigned int active) +{ + mState.activeSampler = active; +} + +GLuint Context::getReadFramebufferHandle() const +{ + return mState.readFramebuffer; +} + +GLuint Context::getDrawFramebufferHandle() const +{ + return mState.drawFramebuffer; +} + +GLuint Context::getRenderbufferHandle() const +{ + return mState.renderbuffer.id(); +} + +GLuint Context::getArrayBufferHandle() const +{ + return mState.arrayBuffer.id(); +} + +GLuint Context::getActiveQuery(GLenum target) const +{ + Query *queryObject = NULL; + + switch (target) + { + case GL_ANY_SAMPLES_PASSED_EXT: + queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED].get(); + break; + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE].get(); + break; + default: + ASSERT(false); + } + + if (queryObject) + { + return queryObject->id(); + } + else + { + return 0; + } +} + +void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) +{ + mState.vertexAttribute[attribNum].mArrayEnabled = enabled; +} + +const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum) +{ + return mState.vertexAttribute[attribNum]; +} + +void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, + GLsizei stride, const void *pointer) +{ + mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer); + mState.vertexAttribute[attribNum].mSize = size; + mState.vertexAttribute[attribNum].mType = type; + mState.vertexAttribute[attribNum].mNormalized = normalized; + mState.vertexAttribute[attribNum].mStride = stride; + mState.vertexAttribute[attribNum].mPointer = pointer; +} + +const void *Context::getVertexAttribPointer(unsigned int attribNum) const +{ + return mState.vertexAttribute[attribNum].mPointer; +} + +const VertexAttributeArray &Context::getVertexAttributes() +{ + return mState.vertexAttribute; +} + +void Context::setPackAlignment(GLint alignment) +{ + mState.packAlignment = alignment; +} + +GLint Context::getPackAlignment() const +{ + return mState.packAlignment; +} + +void Context::setUnpackAlignment(GLint alignment) +{ + mState.unpackAlignment = alignment; +} + +GLint Context::getUnpackAlignment() const +{ + return mState.unpackAlignment; +} + +void Context::setPackReverseRowOrder(bool reverseRowOrder) +{ + mState.packReverseRowOrder = reverseRowOrder; +} + +bool Context::getPackReverseRowOrder() const +{ + return mState.packReverseRowOrder; +} + +GLuint Context::createBuffer() +{ + return mResourceManager->createBuffer(); +} + +GLuint Context::createProgram() +{ + return mResourceManager->createProgram(); +} + +GLuint Context::createShader(GLenum type) +{ + return mResourceManager->createShader(type); +} + +GLuint Context::createTexture() +{ + return mResourceManager->createTexture(); +} + +GLuint Context::createRenderbuffer() +{ + return mResourceManager->createRenderbuffer(); +} + +// Returns an unused framebuffer name +GLuint Context::createFramebuffer() +{ + GLuint handle = mFramebufferHandleAllocator.allocate(); + + mFramebufferMap[handle] = NULL; + + return handle; +} + +GLuint Context::createFence() +{ + GLuint handle = mFenceHandleAllocator.allocate(); + + mFenceMap[handle] = new Fence(mDisplay); + + return handle; +} + +// Returns an unused query name +GLuint Context::createQuery() +{ + GLuint handle = mQueryHandleAllocator.allocate(); + + mQueryMap[handle] = NULL; + + return handle; +} + +void Context::deleteBuffer(GLuint buffer) +{ + if (mResourceManager->getBuffer(buffer)) + { + detachBuffer(buffer); + } + + mResourceManager->deleteBuffer(buffer); +} + +void Context::deleteShader(GLuint shader) +{ + mResourceManager->deleteShader(shader); +} + +void Context::deleteProgram(GLuint program) +{ + mResourceManager->deleteProgram(program); +} + +void Context::deleteTexture(GLuint texture) +{ + if (mResourceManager->getTexture(texture)) + { + detachTexture(texture); + } + + mResourceManager->deleteTexture(texture); +} + +void Context::deleteRenderbuffer(GLuint renderbuffer) +{ + if (mResourceManager->getRenderbuffer(renderbuffer)) + { + detachRenderbuffer(renderbuffer); + } + + mResourceManager->deleteRenderbuffer(renderbuffer); +} + +void Context::deleteFramebuffer(GLuint framebuffer) +{ + FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); + + if (framebufferObject != mFramebufferMap.end()) + { + detachFramebuffer(framebuffer); + + mFramebufferHandleAllocator.release(framebufferObject->first); + delete framebufferObject->second; + mFramebufferMap.erase(framebufferObject); + } +} + +void Context::deleteFence(GLuint fence) +{ + FenceMap::iterator fenceObject = mFenceMap.find(fence); + + if (fenceObject != mFenceMap.end()) + { + mFenceHandleAllocator.release(fenceObject->first); + delete fenceObject->second; + mFenceMap.erase(fenceObject); + } +} + +void Context::deleteQuery(GLuint query) +{ + QueryMap::iterator queryObject = mQueryMap.find(query); + if (queryObject != mQueryMap.end()) + { + mQueryHandleAllocator.release(queryObject->first); + if (queryObject->second) + { + queryObject->second->release(); + } + mQueryMap.erase(queryObject); + } +} + +Buffer *Context::getBuffer(GLuint handle) +{ + return mResourceManager->getBuffer(handle); +} + +Shader *Context::getShader(GLuint handle) +{ + return mResourceManager->getShader(handle); +} + +Program *Context::getProgram(GLuint handle) +{ + return mResourceManager->getProgram(handle); +} + +Texture *Context::getTexture(GLuint handle) +{ + return mResourceManager->getTexture(handle); +} + +Renderbuffer *Context::getRenderbuffer(GLuint handle) +{ + return mResourceManager->getRenderbuffer(handle); +} + +Framebuffer *Context::getReadFramebuffer() +{ + return getFramebuffer(mState.readFramebuffer); +} + +Framebuffer *Context::getDrawFramebuffer() +{ + return mBoundDrawFramebuffer; +} + +void Context::bindArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.arrayBuffer.set(getBuffer(buffer)); +} + +void Context::bindElementArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.elementArrayBuffer.set(getBuffer(buffer)); +} + +void Context::bindTexture2D(GLuint texture) +{ + mResourceManager->checkTextureAllocation(texture, TEXTURE_2D); + + mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture)); +} + +void Context::bindTextureCubeMap(GLuint texture) +{ + mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE); + + mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture)); +} + +void Context::bindReadFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(); + } + + mState.readFramebuffer = framebuffer; +} + +void Context::bindDrawFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(); + } + + mState.drawFramebuffer = framebuffer; + + mBoundDrawFramebuffer = getFramebuffer(framebuffer); +} + +void Context::bindRenderbuffer(GLuint renderbuffer) +{ + mResourceManager->checkRenderbufferAllocation(renderbuffer); + + mState.renderbuffer.set(getRenderbuffer(renderbuffer)); +} + +void Context::useProgram(GLuint program) +{ + GLuint priorProgram = mState.currentProgram; + mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged. + + if (priorProgram != program) + { + Program *newProgram = mResourceManager->getProgram(program); + Program *oldProgram = mResourceManager->getProgram(priorProgram); + mCurrentProgramBinary.set(NULL); + mDxUniformsDirty = true; + + if (newProgram) + { + newProgram->addRef(); + mCurrentProgramBinary.set(newProgram->getProgramBinary()); + } + + if (oldProgram) + { + oldProgram->release(); + } + } +} + +void Context::linkProgram(GLuint program) +{ + Program *programObject = mResourceManager->getProgram(program); + + bool linked = programObject->link(); + + // if the current program was relinked successfully we + // need to install the new executables + if (linked && program == mState.currentProgram) + { + mCurrentProgramBinary.set(programObject->getProgramBinary()); + mDxUniformsDirty = true; + } +} + +void Context::setProgramBinary(GLuint program, const void *binary, GLint length) +{ + Program *programObject = mResourceManager->getProgram(program); + + bool loaded = programObject->setProgramBinary(binary, length); + + // if the current program was reloaded successfully we + // need to install the new executables + if (loaded && program == mState.currentProgram) + { + mCurrentProgramBinary.set(programObject->getProgramBinary()); + mDxUniformsDirty = true; + } + +} + +void Context::beginQuery(GLenum target, GLuint query) +{ + // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an + // of zero, if the active query object name for is non-zero (for the + // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if + // the active query for either target is non-zero), if is the name of an + // existing query object whose type does not match , or if is the + // active query object name for any query type, the error INVALID_OPERATION is + // generated. + + // Ensure no other queries are active + // NOTE: If other queries than occlusion are supported, we will need to check + // separately that: + // a) The query ID passed is not the current active query for any target/type + // b) There are no active queries for the requested target (and in the case + // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, + // no query may be active for either if glBeginQuery targets either. + for (int i = 0; i < QUERY_TYPE_COUNT; i++) + { + if (mState.activeQuery[i].get() != NULL) + { + return error(GL_INVALID_OPERATION); + } + } + + QueryType qType; + switch (target) + { + case GL_ANY_SAMPLES_PASSED_EXT: + qType = QUERY_ANY_SAMPLES_PASSED; + break; + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; + break; + default: + ASSERT(false); + return; + } + + Query *queryObject = getQuery(query, true, target); + + // check that name was obtained with glGenQueries + if (!queryObject) + { + return error(GL_INVALID_OPERATION); + } + + // check for type mismatch + if (queryObject->getType() != target) + { + return error(GL_INVALID_OPERATION); + } + + // set query as active for specified target + mState.activeQuery[qType].set(queryObject); + + // begin query + queryObject->begin(); +} + +void Context::endQuery(GLenum target) +{ + QueryType qType; + + switch (target) + { + case GL_ANY_SAMPLES_PASSED_EXT: + qType = QUERY_ANY_SAMPLES_PASSED; + break; + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE; + break; + default: + ASSERT(false); + return; + } + + Query *queryObject = mState.activeQuery[qType].get(); + + if (queryObject == NULL) + { + return error(GL_INVALID_OPERATION); + } + + queryObject->end(); + + mState.activeQuery[qType].set(NULL); +} + +void Context::setFramebufferZero(Framebuffer *buffer) +{ + delete mFramebufferMap[0]; + mFramebufferMap[0] = buffer; + if (mState.drawFramebuffer == 0) + { + mBoundDrawFramebuffer = buffer; + } +} + +void Context::setRenderbufferStorage(RenderbufferStorage *renderbuffer) +{ + Renderbuffer *renderbufferObject = mState.renderbuffer.get(); + renderbufferObject->setStorage(renderbuffer); +} + +Framebuffer *Context::getFramebuffer(unsigned int handle) +{ + FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle); + + if (framebuffer == mFramebufferMap.end()) + { + return NULL; + } + else + { + return framebuffer->second; + } +} + +Fence *Context::getFence(unsigned int handle) +{ + FenceMap::iterator fence = mFenceMap.find(handle); + + if (fence == mFenceMap.end()) + { + return NULL; + } + else + { + return fence->second; + } +} + +Query *Context::getQuery(unsigned int handle, bool create, GLenum type) +{ + QueryMap::iterator query = mQueryMap.find(handle); + + if (query == mQueryMap.end()) + { + return NULL; + } + else + { + if (!query->second && create) + { + query->second = new Query(handle, type); + query->second->addRef(); + } + return query->second; + } +} + +Buffer *Context::getArrayBuffer() +{ + return mState.arrayBuffer.get(); +} + +Buffer *Context::getElementArrayBuffer() +{ + return mState.elementArrayBuffer.get(); +} + +ProgramBinary *Context::getCurrentProgramBinary() +{ + return mCurrentProgramBinary.get(); +} + +Texture2D *Context::getTexture2D() +{ + return static_cast(getSamplerTexture(mState.activeSampler, TEXTURE_2D)); +} + +TextureCubeMap *Context::getTextureCubeMap() +{ + return static_cast(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE)); +} + +Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type) +{ + GLuint texid = mState.samplerTexture[type][sampler].id(); + + if (texid == 0) // Special case: 0 refers to different initial textures based on the target + { + switch (type) + { + default: UNREACHABLE(); + case TEXTURE_2D: return mTexture2DZero.get(); + case TEXTURE_CUBE: return mTextureCubeMapZero.get(); + } + } + + return mState.samplerTexture[type][sampler].get(); +} + +bool Context::getBooleanv(GLenum pname, GLboolean *params) +{ + switch (pname) + { + case GL_SHADER_COMPILER: *params = GL_TRUE; break; + case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break; + case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break; + case GL_COLOR_WRITEMASK: + params[0] = mState.colorMaskRed; + params[1] = mState.colorMaskGreen; + params[2] = mState.colorMaskBlue; + params[3] = mState.colorMaskAlpha; + break; + case GL_CULL_FACE: *params = mState.cullFace; break; + case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break; + case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break; + case GL_SCISSOR_TEST: *params = mState.scissorTest; break; + case GL_STENCIL_TEST: *params = mState.stencilTest; break; + case GL_DEPTH_TEST: *params = mState.depthTest; break; + case GL_BLEND: *params = mState.blend; break; + case GL_DITHER: *params = mState.dither; break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; + default: + return false; + } + + return true; +} + +bool Context::getFloatv(GLenum pname, GLfloat *params) +{ + // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. + switch (pname) + { + case GL_LINE_WIDTH: *params = mState.lineWidth; break; + case GL_SAMPLE_COVERAGE_VALUE: *params = mState.sampleCoverageValue; break; + case GL_DEPTH_CLEAR_VALUE: *params = mState.depthClearValue; break; + case GL_POLYGON_OFFSET_FACTOR: *params = mState.polygonOffsetFactor; break; + case GL_POLYGON_OFFSET_UNITS: *params = mState.polygonOffsetUnits; break; + case GL_ALIASED_LINE_WIDTH_RANGE: + params[0] = gl::ALIASED_LINE_WIDTH_RANGE_MIN; + params[1] = gl::ALIASED_LINE_WIDTH_RANGE_MAX; + break; + case GL_ALIASED_POINT_SIZE_RANGE: + params[0] = gl::ALIASED_POINT_SIZE_RANGE_MIN; + params[1] = getMaximumPointSize(); + break; + case GL_DEPTH_RANGE: + params[0] = mState.zNear; + params[1] = mState.zFar; + break; + case GL_COLOR_CLEAR_VALUE: + params[0] = mState.colorClearValue.red; + params[1] = mState.colorClearValue.green; + params[2] = mState.colorClearValue.blue; + params[3] = mState.colorClearValue.alpha; + break; + case GL_BLEND_COLOR: + params[0] = mState.blendColor.red; + params[1] = mState.blendColor.green; + params[2] = mState.blendColor.blue; + params[3] = mState.blendColor.alpha; + break; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + if (!supportsTextureFilterAnisotropy()) + { + return false; + } + *params = mMaxTextureAnisotropy; + break; + default: + return false; + } + + return true; +} + +bool Context::getIntegerv(GLenum pname, GLint *params) +{ + // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation + // because it is stored as a float, despite the fact that the GL ES 2.0 spec names + // GetIntegerv as its native query function. As it would require conversion in any + // case, this should make no difference to the calling application. You may find it in + // Context::getFloatv. + switch (pname) + { + case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = gl::MAX_VERTEX_UNIFORM_VECTORS; break; + case GL_MAX_VARYING_VECTORS: *params = getMaximumVaryingVectors(); break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = getMaximumCombinedTextureImageUnits(); break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = getMaximumVertexTextureImageUnits(); break; + case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break; + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = getMaximumFragmentUniformVectors(); break; + case GL_MAX_RENDERBUFFER_SIZE: *params = getMaximumRenderbufferDimension(); break; + case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; + case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break; + case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.id(); break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.id(); break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break; + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break; + case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break; + case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break; + case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break; + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mState.packReverseRowOrder; break; + case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break; + case GL_GENERATE_MIPMAP_HINT: *params = mState.generateMipmapHint; break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break; + case GL_ACTIVE_TEXTURE: *params = (mState.activeSampler + GL_TEXTURE0); break; + case GL_STENCIL_FUNC: *params = mState.stencilFunc; break; + case GL_STENCIL_REF: *params = mState.stencilRef; break; + case GL_STENCIL_VALUE_MASK: *params = mState.stencilMask; break; + case GL_STENCIL_BACK_FUNC: *params = mState.stencilBackFunc; break; + case GL_STENCIL_BACK_REF: *params = mState.stencilBackRef; break; + case GL_STENCIL_BACK_VALUE_MASK: *params = mState.stencilBackMask; break; + case GL_STENCIL_FAIL: *params = mState.stencilFail; break; + case GL_STENCIL_PASS_DEPTH_FAIL: *params = mState.stencilPassDepthFail; break; + case GL_STENCIL_PASS_DEPTH_PASS: *params = mState.stencilPassDepthPass; break; + case GL_STENCIL_BACK_FAIL: *params = mState.stencilBackFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mState.stencilBackPassDepthFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mState.stencilBackPassDepthPass; break; + case GL_DEPTH_FUNC: *params = mState.depthFunc; break; + case GL_BLEND_SRC_RGB: *params = mState.sourceBlendRGB; break; + case GL_BLEND_SRC_ALPHA: *params = mState.sourceBlendAlpha; break; + case GL_BLEND_DST_RGB: *params = mState.destBlendRGB; break; + case GL_BLEND_DST_ALPHA: *params = mState.destBlendAlpha; break; + case GL_BLEND_EQUATION_RGB: *params = mState.blendEquationRGB; break; + case GL_BLEND_EQUATION_ALPHA: *params = mState.blendEquationAlpha; break; + case GL_STENCIL_WRITEMASK: *params = mState.stencilWritemask; break; + case GL_STENCIL_BACK_WRITEMASK: *params = mState.stencilBackWritemask; break; + case GL_STENCIL_CLEAR_VALUE: *params = mState.stencilClearValue; break; + case GL_SUBPIXEL_BITS: *params = 4; break; + case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + params[0] = mNumCompressedTextureFormats; + break; + case GL_MAX_SAMPLES_ANGLE: + { + GLsizei maxSamples = getMaxSupportedSamples(); + if (maxSamples != 0) + { + *params = maxSamples; + } + else + { + return false; + } + + break; + } + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) + { + switch (pname) + { + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples() != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(); + break; + } + } + else + { + *params = 0; + } + } + break; + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + { + GLenum format, type; + if (getCurrentReadFormatType(&format, &type)) + { + if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT) + *params = format; + else + *params = type; + } + } + break; + case GL_MAX_VIEWPORT_DIMS: + { + int maxDimension = std::max(getMaximumRenderbufferDimension(), getMaximumTextureDimension()); + params[0] = maxDimension; + params[1] = maxDimension; + } + break; + case GL_COMPRESSED_TEXTURE_FORMATS: + { + if (supportsDXT1Textures()) + { + *params++ = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + *params++ = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + } + if (supportsDXT3Textures()) + { + *params++ = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + } + if (supportsDXT5Textures()) + { + *params++ = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + } + } + break; + case GL_VIEWPORT: + params[0] = mState.viewportX; + params[1] = mState.viewportY; + params[2] = mState.viewportWidth; + params[3] = mState.viewportHeight; + break; + case GL_SCISSOR_BOX: + params[0] = mState.scissorX; + params[1] = mState.scissorY; + params[2] = mState.scissorWidth; + params[3] = mState.scissorHeight; + break; + case GL_CULL_FACE_MODE: *params = mState.cullMode; break; + case GL_FRONT_FACE: *params = mState.frontFace; break; + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(); + + if (colorbuffer) + { + switch (pname) + { + case GL_RED_BITS: *params = colorbuffer->getRedSize(); break; + case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break; + case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break; + case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break; + } + } + else + { + *params = 0; + } + } + break; + case GL_DEPTH_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer(); + + if (depthbuffer) + { + *params = depthbuffer->getDepthSize(); + } + else + { + *params = 0; + } + } + break; + case GL_STENCIL_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + + if (stencilbuffer) + { + *params = stencilbuffer->getStencilSize(); + } + else + { + *params = 0; + } + } + break; + case GL_TEXTURE_BINDING_2D: + { + if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1) + { + error(GL_INVALID_OPERATION); + return false; + } + + *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id(); + } + break; + case GL_TEXTURE_BINDING_CUBE_MAP: + { + if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1) + { + error(GL_INVALID_OPERATION); + return false; + } + + *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id(); + } + break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + *params = 1; + break; + case GL_PROGRAM_BINARY_FORMATS_OES: + *params = GL_PROGRAM_BINARY_ANGLE; + break; + default: + return false; + } + + return true; +} + +bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +{ + // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation + // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due + // to the fact that it is stored internally as a float, and so would require conversion + // if returned from Context::getIntegerv. Since this conversion is already implemented + // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we + // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling + // application. + switch (pname) + { + case GL_COMPRESSED_TEXTURE_FORMATS: + { + *type = GL_INT; + *numParams = mNumCompressedTextureFormats; + } + break; + case GL_SHADER_BINARY_FORMATS: + { + *type = GL_INT; + *numParams = 0; + } + break; + case GL_MAX_VERTEX_ATTRIBS: + case GL_MAX_VERTEX_UNIFORM_VECTORS: + case GL_MAX_VARYING_VECTORS: + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: + case GL_MAX_TEXTURE_IMAGE_UNITS: + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: + case GL_MAX_RENDERBUFFER_SIZE: + case GL_NUM_SHADER_BINARY_FORMATS: + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_ARRAY_BUFFER_BINDING: + case GL_FRAMEBUFFER_BINDING: + case GL_RENDERBUFFER_BINDING: + case GL_CURRENT_PROGRAM: + case GL_PACK_ALIGNMENT: + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + case GL_UNPACK_ALIGNMENT: + case GL_GENERATE_MIPMAP_HINT: + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + case GL_DEPTH_BITS: + case GL_STENCIL_BITS: + case GL_ELEMENT_ARRAY_BUFFER_BINDING: + case GL_CULL_FACE_MODE: + case GL_FRONT_FACE: + case GL_ACTIVE_TEXTURE: + case GL_STENCIL_FUNC: + case GL_STENCIL_VALUE_MASK: + case GL_STENCIL_REF: + case GL_STENCIL_FAIL: + case GL_STENCIL_PASS_DEPTH_FAIL: + case GL_STENCIL_PASS_DEPTH_PASS: + case GL_STENCIL_BACK_FUNC: + case GL_STENCIL_BACK_VALUE_MASK: + case GL_STENCIL_BACK_REF: + case GL_STENCIL_BACK_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: + case GL_STENCIL_BACK_PASS_DEPTH_PASS: + case GL_DEPTH_FUNC: + case GL_BLEND_SRC_RGB: + case GL_BLEND_SRC_ALPHA: + case GL_BLEND_DST_RGB: + case GL_BLEND_DST_ALPHA: + case GL_BLEND_EQUATION_RGB: + case GL_BLEND_EQUATION_ALPHA: + case GL_STENCIL_WRITEMASK: + case GL_STENCIL_BACK_WRITEMASK: + case GL_STENCIL_CLEAR_VALUE: + case GL_SUBPIXEL_BITS: + case GL_MAX_TEXTURE_SIZE: + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + case GL_NUM_PROGRAM_BINARY_FORMATS_OES: + case GL_PROGRAM_BINARY_FORMATS_OES: + { + *type = GL_INT; + *numParams = 1; + } + break; + case GL_MAX_SAMPLES_ANGLE: + { + if (getMaxSupportedSamples() != 0) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + break; + case GL_MAX_VIEWPORT_DIMS: + { + *type = GL_INT; + *numParams = 2; + } + break; + case GL_VIEWPORT: + case GL_SCISSOR_BOX: + { + *type = GL_INT; + *numParams = 4; + } + break; + case GL_SHADER_COMPILER: + case GL_SAMPLE_COVERAGE_INVERT: + case GL_DEPTH_WRITEMASK: + case GL_CULL_FACE: // CULL_FACE through DITHER are natural to IsEnabled, + case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries. + case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as bool-natural + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + case GL_CONTEXT_ROBUST_ACCESS_EXT: + { + *type = GL_BOOL; + *numParams = 1; + } + break; + case GL_COLOR_WRITEMASK: + { + *type = GL_BOOL; + *numParams = 4; + } + break; + case GL_POLYGON_OFFSET_FACTOR: + case GL_POLYGON_OFFSET_UNITS: + case GL_SAMPLE_COVERAGE_VALUE: + case GL_DEPTH_CLEAR_VALUE: + case GL_LINE_WIDTH: + { + *type = GL_FLOAT; + *numParams = 1; + } + break; + case GL_ALIASED_LINE_WIDTH_RANGE: + case GL_ALIASED_POINT_SIZE_RANGE: + case GL_DEPTH_RANGE: + { + *type = GL_FLOAT; + *numParams = 2; + } + break; + case GL_COLOR_CLEAR_VALUE: + case GL_BLEND_COLOR: + { + *type = GL_FLOAT; + *numParams = 4; + } + break; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + if (!supportsTextureFilterAnisotropy()) + { + return false; + } + *type = GL_FLOAT; + *numParams = 1; + break; + default: + return false; + } + + return true; +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the Direct3D 9 device +bool Context::applyRenderTarget(bool ignoreViewport) +{ + Framebuffer *framebufferObject = getDrawFramebuffer(); + + if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION, false); + } + + // if there is no color attachment we must synthesize a NULL colorattachment + // to keep the D3D runtime happy. This should only be possible if depth texturing. + Renderbuffer *renderbufferObject = NULL; + if (framebufferObject->getColorbufferType() != GL_NONE) + { + renderbufferObject = framebufferObject->getColorbuffer(); + } + else + { + renderbufferObject = framebufferObject->getNullColorbuffer(); + } + if (!renderbufferObject) + { + ERR("unable to locate renderbuffer for FBO."); + return false; + } + + bool renderTargetChanged = false; + unsigned int renderTargetSerial = renderbufferObject->getSerial(); + if (renderTargetSerial != mAppliedRenderTargetSerial) + { + IDirect3DSurface9 *renderTarget = renderbufferObject->getRenderTarget(); + if (!renderTarget) + { + ERR("render target pointer unexpectedly null."); + return false; // Context must be lost + } + mDevice->SetRenderTarget(0, renderTarget); + mAppliedRenderTargetSerial = renderTargetSerial; + mScissorStateDirty = true; // Scissor area must be clamped to render target's size-- this is different for different render targets. + renderTargetChanged = true; + renderTarget->Release(); + } + + IDirect3DSurface9 *depthStencil = NULL; + unsigned int depthbufferSerial = 0; + unsigned int stencilbufferSerial = 0; + if (framebufferObject->getDepthbufferType() != GL_NONE) + { + Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer(); + depthStencil = depthbuffer->getDepthStencil(); + if (!depthStencil) + { + ERR("Depth stencil pointer unexpectedly null."); + return false; + } + + depthbufferSerial = depthbuffer->getSerial(); + } + else if (framebufferObject->getStencilbufferType() != GL_NONE) + { + Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); + depthStencil = stencilbuffer->getDepthStencil(); + if (!depthStencil) + { + ERR("Depth stencil pointer unexpectedly null."); + return false; + } + + stencilbufferSerial = stencilbuffer->getSerial(); + } + + if (depthbufferSerial != mAppliedDepthbufferSerial || + stencilbufferSerial != mAppliedStencilbufferSerial || + !mDepthStencilInitialized) + { + mDevice->SetDepthStencilSurface(depthStencil); + mAppliedDepthbufferSerial = depthbufferSerial; + mAppliedStencilbufferSerial = stencilbufferSerial; + mDepthStencilInitialized = true; + } + + if (depthStencil) + { + depthStencil->Release(); + } + + if (!mRenderTargetDescInitialized || renderTargetChanged) + { + IDirect3DSurface9 *renderTarget = renderbufferObject->getRenderTarget(); + if (!renderTarget) + { + return false; // Context must be lost + } + renderTarget->GetDesc(&mRenderTargetDesc); + mRenderTargetDescInitialized = true; + renderTarget->Release(); + } + + D3DVIEWPORT9 viewport; + + float zNear = clamp01(mState.zNear); + float zFar = clamp01(mState.zFar); + + if (ignoreViewport) + { + viewport.X = 0; + viewport.Y = 0; + viewport.Width = mRenderTargetDesc.Width; + viewport.Height = mRenderTargetDesc.Height; + viewport.MinZ = 0.0f; + viewport.MaxZ = 1.0f; + } + else + { + viewport.X = clamp(mState.viewportX, 0L, static_cast(mRenderTargetDesc.Width)); + viewport.Y = clamp(mState.viewportY, 0L, static_cast(mRenderTargetDesc.Height)); + viewport.Width = clamp(mState.viewportWidth, 0L, static_cast(mRenderTargetDesc.Width) - static_cast(viewport.X)); + viewport.Height = clamp(mState.viewportHeight, 0L, static_cast(mRenderTargetDesc.Height) - static_cast(viewport.Y)); + viewport.MinZ = zNear; + viewport.MaxZ = zFar; + } + + if (viewport.Width <= 0 || viewport.Height <= 0) + { + return false; // Nothing to render + } + + if (renderTargetChanged || !mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0) + { + mDevice->SetViewport(&viewport); + mSetViewport = viewport; + mViewportInitialized = true; + mDxUniformsDirty = true; + } + + if (mScissorStateDirty) + { + if (mState.scissorTest) + { + RECT rect; + rect.left = clamp(mState.scissorX, 0L, static_cast(mRenderTargetDesc.Width)); + rect.top = clamp(mState.scissorY, 0L, static_cast(mRenderTargetDesc.Height)); + rect.right = clamp(mState.scissorX + mState.scissorWidth, 0L, static_cast(mRenderTargetDesc.Width)); + rect.bottom = clamp(mState.scissorY + mState.scissorHeight, 0L, static_cast(mRenderTargetDesc.Height)); + mDevice->SetScissorRect(&rect); + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + } + else + { + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + } + + mScissorStateDirty = false; + } + + if (mState.currentProgram && mDxUniformsDirty) + { + ProgramBinary *programBinary = getCurrentProgramBinary(); + + GLint halfPixelSize = programBinary->getDxHalfPixelSizeLocation(); + GLfloat xy[2] = {1.0f / viewport.Width, -1.0f / viewport.Height}; + programBinary->setUniform2fv(halfPixelSize, 1, xy); + + // These values are used for computing gl_FragCoord in Program::linkVaryings(). + GLint coord = programBinary->getDxCoordLocation(); + GLfloat whxy[4] = {mState.viewportWidth / 2.0f, mState.viewportHeight / 2.0f, + (float)mState.viewportX + mState.viewportWidth / 2.0f, + (float)mState.viewportY + mState.viewportHeight / 2.0f}; + programBinary->setUniform4fv(coord, 1, whxy); + + GLint depth = programBinary->getDxDepthLocation(); + GLfloat dz[2] = {(zFar - zNear) / 2.0f, (zNear + zFar) / 2.0f}; + programBinary->setUniform2fv(depth, 1, dz); + + GLint depthRange = programBinary->getDxDepthRangeLocation(); + GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear}; + programBinary->setUniform3fv(depthRange, 1, nearFarDiff); + mDxUniformsDirty = false; + } + + return true; +} + +// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device +void Context::applyState(GLenum drawMode) +{ + ProgramBinary *programBinary = getCurrentProgramBinary(); + + Framebuffer *framebufferObject = getDrawFramebuffer(); + + GLint frontCCW = programBinary->getDxFrontCCWLocation(); + GLint ccw = (mState.frontFace == GL_CCW); + programBinary->setUniform1iv(frontCCW, 1, &ccw); + + GLint pointsOrLines = programBinary->getDxPointsOrLinesLocation(); + GLint alwaysFront = !isTriangleMode(drawMode); + programBinary->setUniform1iv(pointsOrLines, 1, &alwaysFront); + + D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier(); + bool zeroColorMaskAllowed = identifier->VendorId != 0x1002; + // Apparently some ATI cards have a bug where a draw with a zero color + // write mask can cause later draws to have incorrect results. Instead, + // set a nonzero color write mask but modify the blend state so that no + // drawing is done. + // http://code.google.com/p/angleproject/issues/detail?id=169 + + if (mCullStateDirty || mFrontFaceDirty) + { + if (mState.cullFace) + { + mDevice->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, mState.frontFace)); + } + else + { + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + mCullStateDirty = false; + } + + if (mDepthStateDirty) + { + if (mState.depthTest) + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + mDevice->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc)); + } + else + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + + mDepthStateDirty = false; + } + + if (!zeroColorMaskAllowed && (mMaskStateDirty || mBlendStateDirty)) + { + mBlendStateDirty = true; + mMaskStateDirty = true; + } + + if (mBlendStateDirty) + { + if (mState.blend) + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + if (mState.sourceBlendRGB != GL_CONSTANT_ALPHA && mState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && + mState.destBlendRGB != GL_CONSTANT_ALPHA && mState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor)); + } + else + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha), + unorm<8>(mState.blendColor.alpha), + unorm<8>(mState.blendColor.alpha), + unorm<8>(mState.blendColor.alpha))); + } + + mDevice->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB)); + mDevice->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB)); + mDevice->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB)); + + if (mState.sourceBlendRGB != mState.sourceBlendAlpha || + mState.destBlendRGB != mState.destBlendAlpha || + mState.blendEquationRGB != mState.blendEquationAlpha) + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha)); + mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha)); + mDevice->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } + } + else + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + mBlendStateDirty = false; + } + + if (mStencilStateDirty || mFrontFaceDirty) + { + if (mState.stencilTest && framebufferObject->hasStencil()) + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); + + // FIXME: Unsupported by D3D9 + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; + if (mState.stencilWritemask != mState.stencilBackWritemask || + mState.stencilRef != mState.stencilBackRef || + mState.stencilMask != mState.stencilBackMask) + { + ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL."); + return error(GL_INVALID_OPERATION); + } + + // get the maximum size of the stencil ref + gl::Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer(); + GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1; + + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + es2dx::ConvertComparison(mState.stencilFunc)); + + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask); + + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + es2dx::ConvertStencilOp(mState.stencilFail)); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + es2dx::ConvertStencilOp(mState.stencilPassDepthFail)); + mDevice->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + es2dx::ConvertStencilOp(mState.stencilPassDepthPass)); + + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + es2dx::ConvertComparison(mState.stencilBackFunc)); + + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask); + + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + es2dx::ConvertStencilOp(mState.stencilBackFail)); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + es2dx::ConvertStencilOp(mState.stencilBackPassDepthFail)); + mDevice->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + es2dx::ConvertStencilOp(mState.stencilBackPassDepthPass)); + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mStencilStateDirty = false; + mFrontFaceDirty = false; + } + + if (mMaskStateDirty) + { + int colorMask = es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, + mState.colorMaskBlue, mState.colorMaskAlpha); + if (colorMask == 0 && !zeroColorMaskAllowed) + { + // Enable green channel, but set blending so nothing will be drawn. + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask); + } + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE); + + mMaskStateDirty = false; + } + + if (mPolygonOffsetStateDirty) + { + if (mState.polygonOffsetFill) + { + gl::Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer(); + if (depthbuffer) + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor)); + float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize())); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias)); + } + } + else + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); + } + + mPolygonOffsetStateDirty = false; + } + + if (mSampleStateDirty) + { + if (mState.sampleAlphaToCoverage) + { + FIXME("Sample alpha to coverage is unimplemented."); + } + + mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + if (mState.sampleCoverage) + { + unsigned int mask = 0; + if (mState.sampleCoverageValue != 0) + { + float threshold = 0.5f; + + for (int i = 0; i < framebufferObject->getSamples(); ++i) + { + mask <<= 1; + + if ((i + 1) * mState.sampleCoverageValue >= threshold) + { + threshold += 1.0f; + mask |= 1; + } + } + } + + if (mState.sampleCoverageInvert) + { + mask = ~mask; + } + + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, mask); + } + else + { + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + } + + mSampleStateDirty = false; + } + + if (mDitherStateDirty) + { + mDevice->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE); + + mDitherStateDirty = false; + } +} + +GLenum Context::applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw) +{ + TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS]; + + GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes, instances); + if (err != GL_NO_ERROR) + { + return err; + } + + ProgramBinary *programBinary = getCurrentProgramBinary(); + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, repeatDraw); +} + +// Applies the indices and element array bindings to the Direct3D 9 device +GLenum Context::applyIndexBuffer(const GLvoid *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo); + + if (err == GL_NO_ERROR) + { + if (indexInfo->serial != mAppliedIBSerial) + { + mDevice->SetIndices(indexInfo->indexBuffer); + mAppliedIBSerial = indexInfo->serial; + } + } + + return err; +} + +// Applies the shaders and shader constants to the Direct3D 9 device +void Context::applyShaders() +{ + ProgramBinary *programBinary = getCurrentProgramBinary(); + + if (programBinary->getSerial() != mAppliedProgramBinarySerial) + { + IDirect3DVertexShader9 *vertexShader = programBinary->getVertexShader(); + IDirect3DPixelShader9 *pixelShader = programBinary->getPixelShader(); + + mDevice->SetPixelShader(pixelShader); + mDevice->SetVertexShader(vertexShader); + programBinary->dirtyAllUniforms(); + mAppliedProgramBinarySerial = programBinary->getSerial(); + } + + programBinary->applyUniforms(); +} + +// Applies the textures and sampler states to the Direct3D 9 device +void Context::applyTextures() +{ + applyTextures(SAMPLER_PIXEL); + + if (mSupportsVertexTexture) + { + applyTextures(SAMPLER_VERTEX); + } +} + +// For each Direct3D 9 sampler of either the pixel or vertex stage, +// looks up the corresponding OpenGL texture image unit and texture type, +// and sets the texture and its addressing/filtering state (or NULL when inactive). +void Context::applyTextures(SamplerType type) +{ + ProgramBinary *programBinary = getCurrentProgramBinary(); + + int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; // Range of Direct3D 9 samplers of given sampler type + unsigned int *appliedTextureSerial = (type == SAMPLER_PIXEL) ? mAppliedTextureSerialPS : mAppliedTextureSerialVS; + int d3dSamplerOffset = (type == SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int samplerRange = programBinary->getUsedSamplerRange(type); + + for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + int textureUnit = programBinary->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index + int d3dSampler = samplerIndex + d3dSamplerOffset; + + if (textureUnit != -1) + { + TextureType textureType = programBinary->getSamplerTextureType(type, samplerIndex); + + Texture *texture = getSamplerTexture(textureUnit, textureType); + unsigned int texSerial = texture->getTextureSerial(); + + if (appliedTextureSerial[samplerIndex] != texSerial || texture->hasDirtyParameters() || texture->hasDirtyImages()) + { + IDirect3DBaseTexture9 *d3dTexture = texture->getTexture(); + + if (d3dTexture) + { + if (appliedTextureSerial[samplerIndex] != texSerial || texture->hasDirtyParameters()) + { + GLenum wrapS = texture->getWrapS(); + GLenum wrapT = texture->getWrapT(); + GLenum minFilter = texture->getMinFilter(); + GLenum magFilter = texture->getMagFilter(); + float maxAnisotropy = texture->getMaxAnisotropy(); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS)); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT)); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter, maxAnisotropy)); + D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; + es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter, maxAnisotropy); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, texture->getLodOffset()); + + if (supportsTextureFilterAnisotropy()) + { + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)maxAnisotropy); + } + } + + if (appliedTextureSerial[samplerIndex] != texSerial || texture->hasDirtyImages()) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } + } + else + { + mDevice->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture()); + } + + appliedTextureSerial[samplerIndex] = texSerial; + texture->resetDirty(); + } + } + else + { + if (appliedTextureSerial[samplerIndex] != 0) + { + mDevice->SetTexture(d3dSampler, NULL); + appliedTextureSerial[samplerIndex] = 0; + } + } + } + + for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + if (appliedTextureSerial[samplerIndex] != 0) + { + mDevice->SetTexture(samplerIndex + d3dSamplerOffset, NULL); + appliedTextureSerial[samplerIndex] = 0; + } + } +} + +void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) +{ + Framebuffer *framebuffer = getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + GLsizei outputPitch = ComputePitch(width, ConvertSizedInternalFormat(format, type), mState.packAlignment); + // sized query sanity check + if (bufSize) + { + int requiredSize = outputPitch * height; + if (requiredSize > *bufSize) + { + return error(GL_INVALID_OPERATION); + } + } + + IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget(); + if (!renderTarget) + { + return; // Context must be lost, return silently + } + + D3DSURFACE_DESC desc; + renderTarget->GetDesc(&desc); + + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + renderTarget->Release(); + return error(GL_OUT_OF_MEMORY); + } + + HRESULT result; + IDirect3DSurface9 *systemSurface = NULL; + bool directToPixels = !getPackReverseRowOrder() && getPackAlignment() <= 4 && mDisplay->isD3d9ExDevice() && + x == 0 && y == 0 && UINT(width) == desc.Width && UINT(height) == desc.Height && + desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE; + if (directToPixels) + { + // Use the pixels ptr as a shared handle to write directly into client's memory + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, &pixels); + if (FAILED(result)) + { + // Try again without the shared handle + directToPixels = false; + } + } + + if (!directToPixels) + { + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, NULL); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + renderTarget->Release(); + return error(GL_OUT_OF_MEMORY); + } + } + + result = mDevice->GetRenderTargetData(renderTarget, systemSurface); + renderTarget->Release(); + renderTarget = NULL; + + if (FAILED(result)) + { + systemSurface->Release(); + + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (checkDeviceLost(result)) + return error(GL_OUT_OF_MEMORY); + else + { + UNREACHABLE(); + return; + } + + } + + if (directToPixels) + { + systemSurface->Release(); + return; + } + + RECT rect; + rect.left = clamp(x, 0L, static_cast(desc.Width)); + rect.top = clamp(y, 0L, static_cast(desc.Height)); + rect.right = clamp(x + width, 0L, static_cast(desc.Width)); + rect.bottom = clamp(y + height, 0L, static_cast(desc.Height)); + + D3DLOCKED_RECT lock; + result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); + + if (FAILED(result)) + { + UNREACHABLE(); + systemSurface->Release(); + + return; // No sensible error to generate + } + + unsigned char *dest = (unsigned char*)pixels; + unsigned short *dest16 = (unsigned short*)pixels; + + unsigned char *source; + int inputPitch; + if (getPackReverseRowOrder()) + { + source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); + inputPitch = -lock.Pitch; + } + else + { + source = (unsigned char*)lock.pBits; + inputPitch = lock.Pitch; + } + + unsigned int fastPixelSize = 0; + + if (desc.Format == D3DFMT_A8R8G8B8 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_BYTE) + { + fastPixelSize = 4; + } + else if ((desc.Format == D3DFMT_A4R4G4B4 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT) || + (desc.Format == D3DFMT_A1R5G5B5 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)) + { + fastPixelSize = 2; + } + else if (desc.Format == D3DFMT_A16B16G16R16F && + format == GL_RGBA && + type == GL_HALF_FLOAT_OES) + { + fastPixelSize = 8; + } + else if (desc.Format == D3DFMT_A32B32G32R32F && + format == GL_RGBA && + type == GL_FLOAT) + { + fastPixelSize = 16; + } + + for (int j = 0; j < rect.bottom - rect.top; j++) + { + if (fastPixelSize != 0) + { + // Fast path for formats which require no translation: + // D3DFMT_A8R8G8B8 to BGRA/UNSIGNED_BYTE + // D3DFMT_A4R4G4B4 to BGRA/UNSIGNED_SHORT_4_4_4_4_REV_EXT + // D3DFMT_A1R5G5B5 to BGRA/UNSIGNED_SHORT_1_5_5_5_REV_EXT + // D3DFMT_A16B16G16R16F to RGBA/HALF_FLOAT_OES + // D3DFMT_A32B32G32R32F to RGBA/FLOAT + // + // Note that buffers with no alpha go through the slow path below. + memcpy(dest + j * outputPitch, + source + j * inputPitch, + (rect.right - rect.left) * fastPixelSize); + continue; + } + + for (int i = 0; i < rect.right - rect.left; i++) + { + float r; + float g; + float b; + float a; + + switch (desc.Format) + { + case D3DFMT_R5G6B5: + { + unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch); + + a = 1.0f; + b = (rgb & 0x001F) * (1.0f / 0x001F); + g = (rgb & 0x07E0) * (1.0f / 0x07E0); + r = (rgb & 0xF800) * (1.0f / 0xF800); + } + break; + case D3DFMT_A1R5G5B5: + { + unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch); + + a = (argb & 0x8000) ? 1.0f : 0.0f; + b = (argb & 0x001F) * (1.0f / 0x001F); + g = (argb & 0x03E0) * (1.0f / 0x03E0); + r = (argb & 0x7C00) * (1.0f / 0x7C00); + } + break; + case D3DFMT_A8R8G8B8: + { + unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); + + a = (argb & 0xFF000000) * (1.0f / 0xFF000000); + b = (argb & 0x000000FF) * (1.0f / 0x000000FF); + g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00); + r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000); + } + break; + case D3DFMT_X8R8G8B8: + { + unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch); + + a = 1.0f; + b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF); + g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00); + r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000); + } + break; + case D3DFMT_A2R10G10B10: + { + unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); + + a = (argb & 0xC0000000) * (1.0f / 0xC0000000); + b = (argb & 0x000003FF) * (1.0f / 0x000003FF); + g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00); + r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000); + } + break; + case D3DFMT_A32B32G32R32F: + { + // float formats in D3D are stored rgba, rather than the other way round + r = *((float*)(source + 16 * i + j * inputPitch) + 0); + g = *((float*)(source + 16 * i + j * inputPitch) + 1); + b = *((float*)(source + 16 * i + j * inputPitch) + 2); + a = *((float*)(source + 16 * i + j * inputPitch) + 3); + } + break; + case D3DFMT_A16B16G16R16F: + { + // float formats in D3D are stored rgba, rather than the other way round + r = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 0)); + g = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 1)); + b = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 2)); + a = float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 3)); + } + break; + default: + UNIMPLEMENTED(); // FIXME + UNREACHABLE(); + return; + } + + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); + dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); + dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); + dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); + break; + default: UNREACHABLE(); + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f); + dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); + dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f); + dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f); + break; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section + // this type is packed as follows: + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // -------------------------------------------------------------------------------- + // | 4th | 3rd | 2nd | 1st component | + // -------------------------------------------------------------------------------- + // in the case of BGRA_EXT, B is the first component, G the second, and so forth. + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)(15 * a + 0.5f) << 12)| + ((unsigned short)(15 * r + 0.5f) << 8) | + ((unsigned short)(15 * g + 0.5f) << 4) | + ((unsigned short)(15 * b + 0.5f) << 0); + break; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section + // this type is packed as follows: + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // -------------------------------------------------------------------------------- + // | 4th | 3rd | 2nd | 1st component | + // -------------------------------------------------------------------------------- + // in the case of BGRA_EXT, B is the first component, G the second, and so forth. + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)( a + 0.5f) << 15) | + ((unsigned short)(31 * r + 0.5f) << 10) | + ((unsigned short)(31 * g + 0.5f) << 5) | + ((unsigned short)(31 * b + 0.5f) << 0); + break; + default: UNREACHABLE(); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_SHORT_5_6_5: + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)(31 * b + 0.5f) << 0) | + ((unsigned short)(63 * g + 0.5f) << 5) | + ((unsigned short)(31 * r + 0.5f) << 11); + break; + case GL_UNSIGNED_BYTE: + dest[3 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f); + dest[3 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f); + dest[3 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f); + break; + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + } + } + + systemSurface->UnlockRect(); + + systemSurface->Release(); +} + +void Context::clear(GLbitfield mask) +{ + Framebuffer *framebufferObject = getDrawFramebuffer(); + + if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + DWORD flags = 0; + + if (mask & GL_COLOR_BUFFER_BIT) + { + mask &= ~GL_COLOR_BUFFER_BIT; + + if (framebufferObject->getColorbufferType() != GL_NONE) + { + flags |= D3DCLEAR_TARGET; + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) + { + mask &= ~GL_DEPTH_BUFFER_BIT; + if (mState.depthMask && framebufferObject->getDepthbufferType() != GL_NONE) + { + flags |= D3DCLEAR_ZBUFFER; + } + } + + GLuint stencilUnmasked = 0x0; + + if (mask & GL_STENCIL_BUFFER_BIT) + { + mask &= ~GL_STENCIL_BUFFER_BIT; + if (framebufferObject->getStencilbufferType() != GL_NONE) + { + IDirect3DSurface9 *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil(); + if (!depthStencil) + { + ERR("Depth stencil pointer unexpectedly null."); + return; + } + + D3DSURFACE_DESC desc; + depthStencil->GetDesc(&desc); + depthStencil->Release(); + + unsigned int stencilSize = dx2es::GetStencilSize(desc.Format); + stencilUnmasked = (0x1 << stencilSize) - 1; + + if (stencilUnmasked != 0x0) + { + flags |= D3DCLEAR_STENCIL; + } + } + } + + if (mask != 0) + { + return error(GL_INVALID_VALUE); + } + + if (!applyRenderTarget(true)) // Clips the clear to the scissor rectangle but not the viewport + { + return; + } + + D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(mState.colorClearValue.alpha), + unorm<8>(mState.colorClearValue.red), + unorm<8>(mState.colorClearValue.green), + unorm<8>(mState.colorClearValue.blue)); + float depth = clamp01(mState.depthClearValue); + int stencil = mState.stencilClearValue & 0x000000FF; + + bool alphaUnmasked = (dx2es::GetAlphaSize(mRenderTargetDesc.Format) == 0) || mState.colorMaskAlpha; + + const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) && + (mState.stencilWritemask & stencilUnmasked) != stencilUnmasked; + const bool needMaskedColorClear = (flags & D3DCLEAR_TARGET) && + !(mState.colorMaskRed && mState.colorMaskGreen && + mState.colorMaskBlue && alphaUnmasked); + + if (needMaskedColorClear || needMaskedStencilClear) + { + // State which is altered in all paths from this point to the clear call is saved. + // State which is altered in only some paths will be flagged dirty in the case that + // that path is taken. + HRESULT hr; + if (mMaskedClearSavedState == NULL) + { + hr = mDevice->BeginStateBlock(); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); + mDevice->SetStreamSource(0, NULL, 0, 0); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + hr = mDevice->EndStateBlock(&mMaskedClearSavedState); + ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY); + } + + ASSERT(mMaskedClearSavedState != NULL); + + if (mMaskedClearSavedState != NULL) + { + hr = mMaskedClearSavedState->Capture(); + ASSERT(SUCCEEDED(hr)); + } + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + + if (flags & D3DCLEAR_TARGET) + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + } + + if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL)) + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); + mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + mDevice->SetRenderState(D3DRS_STENCILREF, stencil); + mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask); + mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + mStencilStateDirty = true; + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mDevice->SetPixelShader(NULL); + mDevice->SetVertexShader(NULL); + mDevice->SetFVF(D3DFVF_XYZRHW); + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); + mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + + for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mDevice->SetStreamSourceFreq(i, 1); + } + + float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges + quad[0][0] = -0.5f; + quad[0][1] = mRenderTargetDesc.Height - 0.5f; + quad[0][2] = 0.0f; + quad[0][3] = 1.0f; + + quad[1][0] = mRenderTargetDesc.Width - 0.5f; + quad[1][1] = mRenderTargetDesc.Height - 0.5f; + quad[1][2] = 0.0f; + quad[1][3] = 1.0f; + + quad[2][0] = -0.5f; + quad[2][1] = -0.5f; + quad[2][2] = 0.0f; + quad[2][3] = 1.0f; + + quad[3][0] = mRenderTargetDesc.Width - 0.5f; + quad[3][1] = -0.5f; + quad[3][2] = 0.0f; + quad[3][3] = 1.0f; + + mDisplay->startScene(); + mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); + + if (flags & D3DCLEAR_ZBUFFER) + { + mDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); + } + + if (mMaskedClearSavedState != NULL) + { + mMaskedClearSavedState->Apply(); + } + } + else if (flags) + { + mDevice->Clear(0, NULL, flags, color, depth, stencil); + } +} + +void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) +{ + if (!mState.currentProgram) + { + return error(GL_INVALID_OPERATION); + } + + D3DPRIMITIVETYPE primitiveType; + int primitiveCount; + + if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount)) + return error(GL_INVALID_ENUM); + + if (primitiveCount <= 0) + { + return; + } + + if (!applyRenderTarget(false)) + { + return; + } + + applyState(mode); + + GLsizei repeatDraw = 1; + GLenum err = applyVertexBuffer(first, count, instances, &repeatDraw); + if (err != GL_NO_ERROR) + { + return error(err); + } + + applyShaders(); + applyTextures(); + + if (!getCurrentProgramBinary()->validateSamplers(NULL)) + { + return error(GL_INVALID_OPERATION); + } + + if (!skipDraw(mode)) + { + mDisplay->startScene(); + + if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, GL_NONE, NULL, 0); + } + else if (instances > 0) + { + StaticIndexBuffer *countingIB = mIndexDataManager->getCountingIndices(count); + if (countingIB) + { + if (mAppliedIBSerial != countingIB->getSerial()) + { + mDevice->SetIndices(countingIB->getBuffer()); + mAppliedIBSerial = countingIB->getSerial(); + } + + for (int i = 0; i < repeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(primitiveType, 0, 0, count, 0, primitiveCount); + } + } + else + { + ERR("Could not create a counting index buffer for glDrawArraysInstanced."); + return error(GL_OUT_OF_MEMORY); + } + } + else // Regular case + { + mDevice->DrawPrimitive(primitiveType, 0, primitiveCount); + } + } +} + +void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances) +{ + if (!mState.currentProgram) + { + return error(GL_INVALID_OPERATION); + } + + if (!indices && !mState.elementArrayBuffer) + { + return error(GL_INVALID_OPERATION); + } + + D3DPRIMITIVETYPE primitiveType; + int primitiveCount; + + if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount)) + return error(GL_INVALID_ENUM); + + if (primitiveCount <= 0) + { + return; + } + + if (!applyRenderTarget(false)) + { + return; + } + + applyState(mode); + + TranslatedIndexData indexInfo; + GLenum err = applyIndexBuffer(indices, count, mode, type, &indexInfo); + if (err != GL_NO_ERROR) + { + return error(err); + } + + GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1; + GLsizei repeatDraw = 1; + err = applyVertexBuffer(indexInfo.minIndex, vertexCount, instances, &repeatDraw); + if (err != GL_NO_ERROR) + { + return error(err); + } + + applyShaders(); + applyTextures(); + + if (!getCurrentProgramBinary()->validateSamplers(false)) + { + return error(GL_INVALID_OPERATION); + } + + if (!skipDraw(mode)) + { + mDisplay->startScene(); + + if (mode == GL_LINE_LOOP) + { + drawLineLoop(count, type, indices, indexInfo.minIndex); + } + else + { + for (int i = 0; i < repeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount); + } + } + } +} + +// Implements glFlush when block is false, glFinish when block is true +void Context::sync(bool block) +{ + mDisplay->sync(block); +} + +void Context::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && mState.elementArrayBuffer.get()) + { + Buffer *indexBuffer = mState.elementArrayBuffer.get(); + intptr_t offset = reinterpret_cast(indices); + indices = static_cast(indexBuffer->data()) + offset; + } + + UINT startIndex = 0; + bool succeeded = false; + + if (supports32bitIndices()) + { + const int spaceNeeded = (count + 1) * sizeof(unsigned int); + + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32); + } + + if (mLineLoopIB) + { + mLineLoopIB->reserveSpace(spaceNeeded, GL_UNSIGNED_INT); + + UINT offset = 0; + unsigned int *data = static_cast(mLineLoopIB->map(spaceNeeded, &offset)); + startIndex = offset / 4; + + if (data) + { + switch (type) + { + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case GL_UNSIGNED_BYTE: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + default: UNREACHABLE(); + } + + mLineLoopIB->unmap(); + succeeded = true; + } + } + } + else + { + const int spaceNeeded = (count + 1) * sizeof(unsigned short); + + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16); + } + + if (mLineLoopIB) + { + mLineLoopIB->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT); + + UINT offset = 0; + unsigned short *data = static_cast(mLineLoopIB->map(spaceNeeded, &offset)); + startIndex = offset / 2; + + if (data) + { + switch (type) + { + case GL_NONE: // Non-indexed draw + for (int i = 0; i < count; i++) + { + data[i] = i; + } + data[count] = 0; + break; + case GL_UNSIGNED_BYTE: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_SHORT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + case GL_UNSIGNED_INT: + for (int i = 0; i < count; i++) + { + data[i] = static_cast(indices)[i]; + } + data[count] = static_cast(indices)[0]; + break; + default: UNREACHABLE(); + } + + mLineLoopIB->unmap(); + succeeded = true; + } + } + } + + if (succeeded) + { + if (mAppliedIBSerial != mLineLoopIB->getSerial()) + { + mDevice->SetIndices(mLineLoopIB->getBuffer()); + mAppliedIBSerial = mLineLoopIB->getSerial(); + } + + mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); + } + else + { + ERR("Could not create a looping index buffer for GL_LINE_LOOP."); + return error(GL_OUT_OF_MEMORY); + } +} + +void Context::recordInvalidEnum() +{ + mInvalidEnum = true; +} + +void Context::recordInvalidValue() +{ + mInvalidValue = true; +} + +void Context::recordInvalidOperation() +{ + mInvalidOperation = true; +} + +void Context::recordOutOfMemory() +{ + mOutOfMemory = true; +} + +void Context::recordInvalidFramebufferOperation() +{ + mInvalidFramebufferOperation = true; +} + +// Get one of the recorded errors and clear its flag, if any. +// [OpenGL ES 2.0.24] section 2.5 page 13. +GLenum Context::getError() +{ + if (mInvalidEnum) + { + mInvalidEnum = false; + + return GL_INVALID_ENUM; + } + + if (mInvalidValue) + { + mInvalidValue = false; + + return GL_INVALID_VALUE; + } + + if (mInvalidOperation) + { + mInvalidOperation = false; + + return GL_INVALID_OPERATION; + } + + if (mOutOfMemory) + { + mOutOfMemory = false; + + return GL_OUT_OF_MEMORY; + } + + if (mInvalidFramebufferOperation) + { + mInvalidFramebufferOperation = false; + + return GL_INVALID_FRAMEBUFFER_OPERATION; + } + + return GL_NO_ERROR; +} + +GLenum Context::getResetStatus() +{ + if (mResetStatus == GL_NO_ERROR) + { + bool lost = mDisplay->testDeviceLost(); + + if (lost) + { + mDisplay->notifyDeviceLost(); // Sets mResetStatus + } + } + + GLenum status = mResetStatus; + + if (mResetStatus != GL_NO_ERROR) + { + if (mDisplay->testDeviceResettable()) + { + mResetStatus = GL_NO_ERROR; + } + } + + return status; +} + +bool Context::isResetNotificationEnabled() +{ + return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + +bool Context::supportsShaderModel3() const +{ + return mSupportsShaderModel3; +} + +float Context::getMaximumPointSize() const +{ + return mSupportsShaderModel3 ? mMaximumPointSize : ALIASED_POINT_SIZE_RANGE_MAX_SM2; +} + +int Context::getMaximumVaryingVectors() const +{ + return mSupportsShaderModel3 ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2; +} + +unsigned int Context::getMaximumVertexTextureImageUnits() const +{ + return mSupportsVertexTexture ? MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF : 0; +} + +unsigned int Context::getMaximumCombinedTextureImageUnits() const +{ + return MAX_TEXTURE_IMAGE_UNITS + getMaximumVertexTextureImageUnits(); +} + +int Context::getMaximumFragmentUniformVectors() const +{ + return mSupportsShaderModel3 ? MAX_FRAGMENT_UNIFORM_VECTORS_SM3 : MAX_FRAGMENT_UNIFORM_VECTORS_SM2; +} + +int Context::getMaxSupportedSamples() const +{ + return mMaxSupportedSamples; +} + +int Context::getNearestSupportedSamples(D3DFORMAT format, int requested) const +{ + if (requested == 0) + { + return requested; + } + + std::map::const_iterator itr = mMultiSampleSupport.find(format); + if (itr == mMultiSampleSupport.end()) + { + return -1; + } + + for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i) + { + if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE) + { + return i; + } + } + + return -1; +} + +bool Context::supportsEventQueries() const +{ + return mSupportsEventQueries; +} + +bool Context::supportsOcclusionQueries() const +{ + return mSupportsOcclusionQueries; +} + +bool Context::supportsDXT1Textures() const +{ + return mSupportsDXT1Textures; +} + +bool Context::supportsDXT3Textures() const +{ + return mSupportsDXT3Textures; +} + +bool Context::supportsDXT5Textures() const +{ + return mSupportsDXT5Textures; +} + +bool Context::supportsFloat32Textures() const +{ + return mSupportsFloat32Textures; +} + +bool Context::supportsFloat32LinearFilter() const +{ + return mSupportsFloat32LinearFilter; +} + +bool Context::supportsFloat32RenderableTextures() const +{ + return mSupportsFloat32RenderableTextures; +} + +bool Context::supportsFloat16Textures() const +{ + return mSupportsFloat16Textures; +} + +bool Context::supportsFloat16LinearFilter() const +{ + return mSupportsFloat16LinearFilter; +} + +bool Context::supportsFloat16RenderableTextures() const +{ + return mSupportsFloat16RenderableTextures; +} + +int Context::getMaximumRenderbufferDimension() const +{ + return mMaxRenderbufferDimension; +} + +int Context::getMaximumTextureDimension() const +{ + return mMaxTextureDimension; +} + +int Context::getMaximumCubeTextureDimension() const +{ + return mMaxCubeTextureDimension; +} + +int Context::getMaximumTextureLevel() const +{ + return mMaxTextureLevel; +} + +bool Context::supportsLuminanceTextures() const +{ + return mSupportsLuminanceTextures; +} + +bool Context::supportsLuminanceAlphaTextures() const +{ + return mSupportsLuminanceAlphaTextures; +} + +bool Context::supportsDepthTextures() const +{ + return mSupportsDepthTextures; +} + +bool Context::supports32bitIndices() const +{ + return mSupports32bitIndices; +} + +bool Context::supportsNonPower2Texture() const +{ + return mSupportsNonPower2Texture; +} + +bool Context::supportsInstancing() const +{ + return mSupportsInstancing; +} + +bool Context::supportsTextureFilterAnisotropy() const +{ + return mSupportsTextureFilterAnisotropy; +} + +float Context::getTextureMaxAnisotropy() const +{ + return mMaxTextureAnisotropy; +} + +bool Context::getCurrentReadFormatType(GLenum *format, GLenum *type) +{ + Framebuffer *framebuffer = getReadFramebuffer(); + if (!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_OPERATION, false); + } + + Renderbuffer *renderbuffer = framebuffer->getColorbuffer(); + if (!renderbuffer) + { + return error(GL_INVALID_OPERATION, false); + } + + if(!dx2es::ConvertReadBufferFormat(renderbuffer->getD3DFormat(), format, type)) + { + ASSERT(false); + return false; + } + + return true; +} + +void Context::detachBuffer(GLuint buffer) +{ + // [OpenGL ES 2.0.24] section 2.9 page 22: + // If a buffer object is deleted while it is bound, all bindings to that object in the current context + // (i.e. in the thread that called Delete-Buffers) are reset to zero. + + if (mState.arrayBuffer.id() == buffer) + { + mState.arrayBuffer.set(NULL); + } + + if (mState.elementArrayBuffer.id() == buffer) + { + mState.elementArrayBuffer.set(NULL); + } + + for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) + { + if (mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer) + { + mState.vertexAttribute[attribute].mBoundBuffer.set(NULL); + } + } +} + +void Context::detachTexture(GLuint texture) +{ + // [OpenGL ES 2.0.24] section 3.8 page 84: + // If a texture object is deleted, it is as if all texture units which are bound to that texture object are + // rebound to texture object zero + + for (int type = 0; type < TEXTURE_TYPE_COUNT; type++) + { + for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++) + { + if (mState.samplerTexture[type][sampler].id() == texture) + { + mState.samplerTexture[type][sampler].set(NULL); + } + } + } + + // [OpenGL ES 2.0.24] section 4.4 page 112: + // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is + // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this + // image was attached in the currently bound framebuffer. + + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); + + if (readFramebuffer) + { + readFramebuffer->detachTexture(texture); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachTexture(texture); + } +} + +void Context::detachFramebuffer(GLuint framebuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 107: + // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though + // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. + + if (mState.readFramebuffer == framebuffer) + { + bindReadFramebuffer(0); + } + + if (mState.drawFramebuffer == framebuffer) + { + bindDrawFramebuffer(0); + } +} + +void Context::detachRenderbuffer(GLuint renderbuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 109: + // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer + // had been executed with the target RENDERBUFFER and name of zero. + + if (mState.renderbuffer.id() == renderbuffer) + { + bindRenderbuffer(0); + } + + // [OpenGL ES 2.0.24] section 4.4 page 111: + // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, + // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment + // point to which this image was attached in the currently bound framebuffer. + + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); + + if (readFramebuffer) + { + readFramebuffer->detachRenderbuffer(renderbuffer); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachRenderbuffer(renderbuffer); + } +} + +Texture *Context::getIncompleteTexture(TextureType type) +{ + Texture *t = mIncompleteTextures[type].get(); + + if (t == NULL) + { + static const GLubyte color[] = { 0, 0, 0, 255 }; + + switch (type) + { + default: + UNREACHABLE(); + // default falls through to TEXTURE_2D + + case TEXTURE_2D: + { + Texture2D *incomplete2d = new Texture2D(Texture::INCOMPLETE_TEXTURE_ID); + incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + t = incomplete2d; + } + break; + + case TEXTURE_CUBE: + { + TextureCubeMap *incompleteCube = new TextureCubeMap(Texture::INCOMPLETE_TEXTURE_ID); + + incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color); + + t = incompleteCube; + } + break; + } + + mIncompleteTextures[type].set(t); + } + + return t; +} + +bool Context::skipDraw(GLenum drawMode) +{ + if (drawMode == GL_POINTS) + { + // ProgramBinary assumes non-point rendering if gl_PointSize isn't written, + // which affects varying interpolation. Since the value of gl_PointSize is + // undefined when not written, just skip drawing to avoid unexpected results. + if (!getCurrentProgramBinary()->usesPointSize()) + { + // This is stictly speaking not an error, but developers should be + // notified of risking undefined behavior. + ERR("Point rendering without writing to gl_PointSize."); + + return true; + } + } + else if (isTriangleMode(drawMode)) + { + if (mState.cullFace && mState.cullMode == GL_FRONT_AND_BACK) + { + return true; + } + } + + return false; +} + +bool Context::isTriangleMode(GLenum drawMode) +{ + switch (drawMode) + { + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + case GL_TRIANGLE_STRIP: + return true; + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + return false; + default: UNREACHABLE(); + } + + return false; +} + +void Context::setVertexAttrib(GLuint index, const GLfloat *values) +{ + ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + + mState.vertexAttribute[index].mCurrentValue[0] = values[0]; + mState.vertexAttribute[index].mCurrentValue[1] = values[1]; + mState.vertexAttribute[index].mCurrentValue[2] = values[2]; + mState.vertexAttribute[index].mCurrentValue[3] = values[3]; + + mVertexDataManager->dirtyCurrentValue(index); +} + +void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) +{ + ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + + mState.vertexAttribute[index].mDivisor = divisor; +} + +// keep list sorted in following order +// OES extensions +// EXT extensions +// Vendor extensions +void Context::initExtensionString() +{ + mExtensionString = ""; + + // OES extensions + if (supports32bitIndices()) + { + mExtensionString += "GL_OES_element_index_uint "; + } + + mExtensionString += "GL_OES_packed_depth_stencil "; + mExtensionString += "GL_OES_get_program_binary "; + mExtensionString += "GL_OES_rgb8_rgba8 "; + mExtensionString += "GL_OES_standard_derivatives "; + + if (supportsFloat16Textures()) + { + mExtensionString += "GL_OES_texture_half_float "; + } + if (supportsFloat16LinearFilter()) + { + mExtensionString += "GL_OES_texture_half_float_linear "; + } + if (supportsFloat32Textures()) + { + mExtensionString += "GL_OES_texture_float "; + } + if (supportsFloat32LinearFilter()) + { + mExtensionString += "GL_OES_texture_float_linear "; + } + + if (supportsNonPower2Texture()) + { + mExtensionString += "GL_OES_texture_npot "; + } + + // Multi-vendor (EXT) extensions + if (supportsOcclusionQueries()) + { + mExtensionString += "GL_EXT_occlusion_query_boolean "; + } + + mExtensionString += "GL_EXT_read_format_bgra "; + mExtensionString += "GL_EXT_robustness "; + + if (supportsDXT1Textures()) + { + mExtensionString += "GL_EXT_texture_compression_dxt1 "; + } + + if (supportsTextureFilterAnisotropy()) + { + mExtensionString += "GL_EXT_texture_filter_anisotropic "; + } + + mExtensionString += "GL_EXT_texture_format_BGRA8888 "; + mExtensionString += "GL_EXT_texture_storage "; + + // ANGLE-specific extensions + if (supportsDepthTextures()) + { + mExtensionString += "GL_ANGLE_depth_texture "; + } + + mExtensionString += "GL_ANGLE_framebuffer_blit "; + if (getMaxSupportedSamples() != 0) + { + mExtensionString += "GL_ANGLE_framebuffer_multisample "; + } + + if (supportsInstancing()) + { + mExtensionString += "GL_ANGLE_instanced_arrays "; + } + + mExtensionString += "GL_ANGLE_pack_reverse_row_order "; + + if (supportsDXT3Textures()) + { + mExtensionString += "GL_ANGLE_texture_compression_dxt3 "; + } + if (supportsDXT5Textures()) + { + mExtensionString += "GL_ANGLE_texture_compression_dxt5 "; + } + + mExtensionString += "GL_ANGLE_texture_usage "; + mExtensionString += "GL_ANGLE_translated_shader_source "; + + // Other vendor-specific extensions + if (supportsEventQueries()) + { + mExtensionString += "GL_NV_fence "; + } + + std::string::size_type end = mExtensionString.find_last_not_of(' '); + if (end != std::string::npos) + { + mExtensionString.resize(end+1); + } +} + +const char *Context::getExtensionString() const +{ + return mExtensionString.c_str(); +} + +void Context::initRendererString() +{ + D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier(); + + mRendererString = "ANGLE ("; + mRendererString += identifier->Description; + mRendererString += ")"; +} + +const char *Context::getRendererString() const +{ + return mRendererString.c_str(); +} + +void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask) +{ + Framebuffer *readFramebuffer = getReadFramebuffer(); + Framebuffer *drawFramebuffer = getDrawFramebuffer(); + + if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || + !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (drawFramebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth(); + int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight(); + int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth(); + int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight(); + + RECT sourceRect; + RECT destRect; + + if (srcX0 < srcX1) + { + sourceRect.left = srcX0; + sourceRect.right = srcX1; + destRect.left = dstX0; + destRect.right = dstX1; + } + else + { + sourceRect.left = srcX1; + destRect.left = dstX1; + sourceRect.right = srcX0; + destRect.right = dstX0; + } + + if (srcY0 < srcY1) + { + sourceRect.bottom = srcY1; + destRect.bottom = dstY1; + sourceRect.top = srcY0; + destRect.top = dstY0; + } + else + { + sourceRect.bottom = srcY0; + destRect.bottom = dstY0; + sourceRect.top = srcY1; + destRect.top = dstY1; + } + + RECT sourceScissoredRect = sourceRect; + RECT destScissoredRect = destRect; + + if (mState.scissorTest) + { + // Only write to parts of the destination framebuffer which pass the scissor test + // Please note: the destRect is now in D3D-style coordinates, so the *top* of the + // rect will be checked against scissorY, rather than the bottom. + if (destRect.left < mState.scissorX) + { + int xDiff = mState.scissorX - destRect.left; + destScissoredRect.left = mState.scissorX; + sourceScissoredRect.left += xDiff; + } + + if (destRect.right > mState.scissorX + mState.scissorWidth) + { + int xDiff = destRect.right - (mState.scissorX + mState.scissorWidth); + destScissoredRect.right = mState.scissorX + mState.scissorWidth; + sourceScissoredRect.right -= xDiff; + } + + if (destRect.top < mState.scissorY) + { + int yDiff = mState.scissorY - destRect.top; + destScissoredRect.top = mState.scissorY; + sourceScissoredRect.top += yDiff; + } + + if (destRect.bottom > mState.scissorY + mState.scissorHeight) + { + int yDiff = destRect.bottom - (mState.scissorY + mState.scissorHeight); + destScissoredRect.bottom = mState.scissorY + mState.scissorHeight; + sourceScissoredRect.bottom -= yDiff; + } + } + + bool blitRenderTarget = false; + bool blitDepthStencil = false; + + RECT sourceTrimmedRect = sourceScissoredRect; + RECT destTrimmedRect = destScissoredRect; + + // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of + // the actual draw and read surfaces. + if (sourceTrimmedRect.left < 0) + { + int xDiff = 0 - sourceTrimmedRect.left; + sourceTrimmedRect.left = 0; + destTrimmedRect.left += xDiff; + } + + if (sourceTrimmedRect.right > readBufferWidth) + { + int xDiff = sourceTrimmedRect.right - readBufferWidth; + sourceTrimmedRect.right = readBufferWidth; + destTrimmedRect.right -= xDiff; + } + + if (sourceTrimmedRect.top < 0) + { + int yDiff = 0 - sourceTrimmedRect.top; + sourceTrimmedRect.top = 0; + destTrimmedRect.top += yDiff; + } + + if (sourceTrimmedRect.bottom > readBufferHeight) + { + int yDiff = sourceTrimmedRect.bottom - readBufferHeight; + sourceTrimmedRect.bottom = readBufferHeight; + destTrimmedRect.bottom -= yDiff; + } + + if (destTrimmedRect.left < 0) + { + int xDiff = 0 - destTrimmedRect.left; + destTrimmedRect.left = 0; + sourceTrimmedRect.left += xDiff; + } + + if (destTrimmedRect.right > drawBufferWidth) + { + int xDiff = destTrimmedRect.right - drawBufferWidth; + destTrimmedRect.right = drawBufferWidth; + sourceTrimmedRect.right -= xDiff; + } + + if (destTrimmedRect.top < 0) + { + int yDiff = 0 - destTrimmedRect.top; + destTrimmedRect.top = 0; + sourceTrimmedRect.top += yDiff; + } + + if (destTrimmedRect.bottom > drawBufferHeight) + { + int yDiff = destTrimmedRect.bottom - drawBufferHeight; + destTrimmedRect.bottom = drawBufferHeight; + sourceTrimmedRect.bottom -= yDiff; + } + + bool partialBufferCopy = false; + if (sourceTrimmedRect.bottom - sourceTrimmedRect.top < readBufferHeight || + sourceTrimmedRect.right - sourceTrimmedRect.left < readBufferWidth || + destTrimmedRect.bottom - destTrimmedRect.top < drawBufferHeight || + destTrimmedRect.right - destTrimmedRect.left < drawBufferWidth || + sourceTrimmedRect.top != 0 || destTrimmedRect.top != 0 || sourceTrimmedRect.left != 0 || destTrimmedRect.left != 0) + { + partialBufferCopy = true; + } + + if (mask & GL_COLOR_BUFFER_BIT) + { + const bool validReadType = readFramebuffer->getColorbufferType() == GL_TEXTURE_2D || + readFramebuffer->getColorbufferType() == GL_RENDERBUFFER; + const bool validDrawType = drawFramebuffer->getColorbufferType() == GL_TEXTURE_2D || + drawFramebuffer->getColorbufferType() == GL_RENDERBUFFER; + if (!validReadType || !validDrawType || + readFramebuffer->getColorbuffer()->getD3DFormat() != drawFramebuffer->getColorbuffer()->getD3DFormat()) + { + ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation"); + return error(GL_INVALID_OPERATION); + } + + if (partialBufferCopy && readFramebuffer->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + blitRenderTarget = true; + + } + + if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) + { + Renderbuffer *readDSBuffer = NULL; + Renderbuffer *drawDSBuffer = NULL; + + // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have + // both a depth and stencil buffer, it will be the same buffer. + + if (mask & GL_DEPTH_BUFFER_BIT) + { + if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) + { + if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() || + readFramebuffer->getDepthbuffer()->getD3DFormat() != drawFramebuffer->getDepthbuffer()->getD3DFormat()) + { + return error(GL_INVALID_OPERATION); + } + + blitDepthStencil = true; + readDSBuffer = readFramebuffer->getDepthbuffer(); + drawDSBuffer = drawFramebuffer->getDepthbuffer(); + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) + { + if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) + { + if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() || + readFramebuffer->getStencilbuffer()->getD3DFormat() != drawFramebuffer->getStencilbuffer()->getD3DFormat()) + { + return error(GL_INVALID_OPERATION); + } + + blitDepthStencil = true; + readDSBuffer = readFramebuffer->getStencilbuffer(); + drawDSBuffer = drawFramebuffer->getStencilbuffer(); + } + } + + if (partialBufferCopy) + { + ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); + return error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted + } + + if ((drawDSBuffer && drawDSBuffer->getSamples() != 0) || + (readDSBuffer && readDSBuffer->getSamples() != 0)) + { + return error(GL_INVALID_OPERATION); + } + } + + if (blitRenderTarget || blitDepthStencil) + { + mDisplay->endScene(); + + if (blitRenderTarget) + { + IDirect3DSurface9* readRenderTarget = readFramebuffer->getRenderTarget(); + IDirect3DSurface9* drawRenderTarget = drawFramebuffer->getRenderTarget(); + + HRESULT result = mDevice->StretchRect(readRenderTarget, &sourceTrimmedRect, + drawRenderTarget, &destTrimmedRect, D3DTEXF_NONE); + + readRenderTarget->Release(); + drawRenderTarget->Release(); + + if (FAILED(result)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return; + } + } + + if (blitDepthStencil) + { + IDirect3DSurface9* readDepthStencil = readFramebuffer->getDepthStencil(); + IDirect3DSurface9* drawDepthStencil = drawFramebuffer->getDepthStencil(); + + HRESULT result = mDevice->StretchRect(readDepthStencil, NULL, drawDepthStencil, NULL, D3DTEXF_NONE); + + readDepthStencil->Release(); + drawDepthStencil->Release(); + + if (FAILED(result)) + { + ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); + return; + } + } + } +} + +VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + mVertexDeclCache[i].vertexDeclaration = NULL; + mVertexDeclCache[i].lruCount = 0; + } +} + +VertexDeclarationCache::~VertexDeclarationCache() +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + if (mVertexDeclCache[i].vertexDeclaration) + { + mVertexDeclCache[i].vertexDeclaration->Release(); + } + } +} + +GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw) +{ + *repeatDraw = 1; + + int indexedAttribute = MAX_VERTEX_ATTRIBS; + int instancedAttribute = MAX_VERTEX_ATTRIBS; + + if (instances > 0) + { + // Find an indexed attribute to be mapped to D3D stream 0 + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + if (indexedAttribute == MAX_VERTEX_ATTRIBS) + { + if (attributes[i].divisor == 0) + { + indexedAttribute = i; + } + } + else if (instancedAttribute == MAX_VERTEX_ATTRIBS) + { + if (attributes[i].divisor != 0) + { + instancedAttribute = i; + } + } + else break; // Found both an indexed and instanced attribute + } + } + + if (indexedAttribute == MAX_VERTEX_ATTRIBS) + { + return GL_INVALID_OPERATION; + } + } + + D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS + 1]; + D3DVERTEXELEMENT9 *element = &elements[0]; + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + int stream = i; + + if (instances > 0) + { + // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced. + if (instancedAttribute == MAX_VERTEX_ATTRIBS) + { + *repeatDraw = instances; + } + else + { + if (i == indexedAttribute) + { + stream = 0; + } + else if (i == 0) + { + stream = indexedAttribute; + } + + UINT frequency = 1; + + if (attributes[i].divisor == 0) + { + frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances; + } + else + { + frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor; + } + + device->SetStreamSourceFreq(stream, frequency); + mInstancingEnabled = true; + } + } + + if (mAppliedVBs[stream].serial != attributes[i].serial || + mAppliedVBs[stream].stride != attributes[i].stride || + mAppliedVBs[stream].offset != attributes[i].offset) + { + device->SetStreamSource(stream, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride); + mAppliedVBs[stream].serial = attributes[i].serial; + mAppliedVBs[stream].stride = attributes[i].stride; + mAppliedVBs[stream].offset = attributes[i].offset; + } + + element->Stream = stream; + element->Offset = 0; + element->Type = attributes[i].type; + element->Method = D3DDECLMETHOD_DEFAULT; + element->Usage = D3DDECLUSAGE_TEXCOORD; + element->UsageIndex = programBinary->getSemanticIndex(i); + element++; + } + } + + if (instances == 0 || instancedAttribute == MAX_VERTEX_ATTRIBS) + { + if (mInstancingEnabled) + { + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } + + mInstancingEnabled = false; + } + } + + static const D3DVERTEXELEMENT9 end = D3DDECL_END(); + *(element++) = end; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + VertexDeclCacheEntry *entry = &mVertexDeclCache[i]; + if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration) + { + entry->lruCount = ++mMaxLru; + if(entry->vertexDeclaration != mLastSetVDecl) + { + device->SetVertexDeclaration(entry->vertexDeclaration); + mLastSetVDecl = entry->vertexDeclaration; + } + + return GL_NO_ERROR; + } + } + + VertexDeclCacheEntry *lastCache = mVertexDeclCache; + + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + if (mVertexDeclCache[i].lruCount < lastCache->lruCount) + { + lastCache = &mVertexDeclCache[i]; + } + } + + if (lastCache->vertexDeclaration != NULL) + { + lastCache->vertexDeclaration->Release(); + lastCache->vertexDeclaration = NULL; + // mLastSetVDecl is set to the replacement, so we don't have to worry + // about it. + } + + memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); + device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); + device->SetVertexDeclaration(lastCache->vertexDeclaration); + mLastSetVDecl = lastCache->vertexDeclaration; + lastCache->lruCount = ++mMaxLru; + + return GL_NO_ERROR; +} + +void VertexDeclarationCache::markStateDirty() +{ + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; // Forces it to be disabled when not used +} + +} + +extern "C" +{ +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) +{ + return new gl::Context(config, shareContext, notifyResets, robustAccess); +} + +void glDestroyContext(gl::Context *context) +{ + delete context; + + if (context == gl::getContext()) + { + gl::makeCurrent(NULL, NULL, NULL); + } +} + +void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface) +{ + gl::makeCurrent(context, display, surface); +} + +gl::Context *glGetCurrentContext() +{ + return gl::getContext(); +} +} diff --git a/src/3rdparty/angle/src/libGLESv2/Context.h b/src/3rdparty/angle/src/libGLESv2/Context.h new file mode 100644 index 0000000000..2bbae76ef8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Context.h @@ -0,0 +1,685 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Context.h: Defines the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#ifndef LIBGLESV2_CONTEXT_H_ +#define LIBGLESV2_CONTEXT_H_ + +#define GL_APICALL +#include +#include +#define EGLAPI +#include +#include + +#include +#include +#ifdef _MSC_VER +#include +#else +#include +#endif + +#include "common/angleutils.h" +#include "common/RefCountObject.h" +#include "libGLESv2/ResourceManager.h" +#include "libGLESv2/HandleAllocator.h" + +namespace egl +{ +class Display; +class Surface; +class Config; +} + +namespace gl +{ +struct TranslatedAttribute; +struct TranslatedIndexData; + +class Buffer; +class Shader; +class Program; +class ProgramBinary; +class Texture; +class Texture2D; +class TextureCubeMap; +class Framebuffer; +class Renderbuffer; +class RenderbufferStorage; +class Colorbuffer; +class Depthbuffer; +class StreamingIndexBuffer; +class Stencilbuffer; +class DepthStencilbuffer; +class VertexDataManager; +class IndexDataManager; +class Blit; +class Fence; +class Query; + +enum +{ + D3D9_MAX_FLOAT_CONSTANTS = 256, + D3D9_MAX_BOOL_CONSTANTS = 16, + D3D9_MAX_INT_CONSTANTS = 16, + + MAX_VERTEX_ATTRIBS = 16, + MAX_VERTEX_UNIFORM_VECTORS = D3D9_MAX_FLOAT_CONSTANTS - 2, // Reserve space for dx_HalfPixelSize and dx_DepthRange. + MAX_VARYING_VECTORS_SM2 = 8, + MAX_VARYING_VECTORS_SM3 = 10, + MAX_TEXTURE_IMAGE_UNITS = 16, + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF = 4, // For devices supporting vertex texture fetch + MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF, + MAX_FRAGMENT_UNIFORM_VECTORS_SM2 = 32 - 3, // Reserve space for dx_Coord, dx_Depth, and dx_DepthRange. dx_PointOrLines and dx_FrontCCW use separate bool registers. + MAX_FRAGMENT_UNIFORM_VECTORS_SM3 = 224 - 3, + MAX_DRAW_BUFFERS = 1, + + GL_BGRA4_ANGLEX = 0x6ABC, + GL_BGR5_A1_ANGLEX = 0x6ABD +}; + +enum QueryType +{ + QUERY_ANY_SAMPLES_PASSED, + QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE, + + QUERY_TYPE_COUNT +}; + +const float ALIASED_LINE_WIDTH_RANGE_MIN = 1.0f; +const float ALIASED_LINE_WIDTH_RANGE_MAX = 1.0f; +const float ALIASED_POINT_SIZE_RANGE_MIN = 1.0f; +const float ALIASED_POINT_SIZE_RANGE_MAX_SM2 = 1.0f; + +struct Color +{ + float red; + float green; + float blue; + float alpha; +}; + +// Helper structure describing a single vertex attribute +class VertexAttribute +{ + public: + VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false), mDivisor(0) + { + mCurrentValue[0] = 0.0f; + mCurrentValue[1] = 0.0f; + mCurrentValue[2] = 0.0f; + mCurrentValue[3] = 1.0f; + } + + int typeSize() const + { + switch (mType) + { + case GL_BYTE: return mSize * sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return mSize * sizeof(GLubyte); + case GL_SHORT: return mSize * sizeof(GLshort); + case GL_UNSIGNED_SHORT: return mSize * sizeof(GLushort); + case GL_FIXED: return mSize * sizeof(GLfixed); + case GL_FLOAT: return mSize * sizeof(GLfloat); + default: UNREACHABLE(); return mSize * sizeof(GLfloat); + } + } + + GLsizei stride() const + { + return mStride ? mStride : typeSize(); + } + + // From glVertexAttribPointer + GLenum mType; + GLint mSize; + bool mNormalized; + GLsizei mStride; // 0 means natural stride + + union + { + const void *mPointer; + intptr_t mOffset; + }; + + BindingPointer mBoundBuffer; // Captured when glVertexAttribPointer is called. + + bool mArrayEnabled; // From glEnable/DisableVertexAttribArray + float mCurrentValue[4]; // From glVertexAttrib + unsigned int mDivisor; +}; + +typedef VertexAttribute VertexAttributeArray[MAX_VERTEX_ATTRIBS]; + +// Helper structure to store all raw state +struct State +{ + Color colorClearValue; + GLclampf depthClearValue; + int stencilClearValue; + + bool cullFace; + GLenum cullMode; + GLenum frontFace; + bool depthTest; + GLenum depthFunc; + bool blend; + GLenum sourceBlendRGB; + GLenum destBlendRGB; + GLenum sourceBlendAlpha; + GLenum destBlendAlpha; + GLenum blendEquationRGB; + GLenum blendEquationAlpha; + Color blendColor; + bool stencilTest; + GLenum stencilFunc; + GLint stencilRef; + GLuint stencilMask; + GLenum stencilFail; + GLenum stencilPassDepthFail; + GLenum stencilPassDepthPass; + GLuint stencilWritemask; + GLenum stencilBackFunc; + GLint stencilBackRef; + GLuint stencilBackMask; + GLenum stencilBackFail; + GLenum stencilBackPassDepthFail; + GLenum stencilBackPassDepthPass; + GLuint stencilBackWritemask; + bool polygonOffsetFill; + GLfloat polygonOffsetFactor; + GLfloat polygonOffsetUnits; + bool sampleAlphaToCoverage; + bool sampleCoverage; + GLclampf sampleCoverageValue; + bool sampleCoverageInvert; + bool scissorTest; + bool dither; + + GLfloat lineWidth; + + GLenum generateMipmapHint; + GLenum fragmentShaderDerivativeHint; + + GLint viewportX; + GLint viewportY; + GLsizei viewportWidth; + GLsizei viewportHeight; + float zNear; + float zFar; + + GLint scissorX; + GLint scissorY; + GLsizei scissorWidth; + GLsizei scissorHeight; + + bool colorMaskRed; + bool colorMaskGreen; + bool colorMaskBlue; + bool colorMaskAlpha; + bool depthMask; + + unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0 + BindingPointer arrayBuffer; + BindingPointer elementArrayBuffer; + GLuint readFramebuffer; + GLuint drawFramebuffer; + BindingPointer renderbuffer; + GLuint currentProgram; + + VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS]; + BindingPointer samplerTexture[TEXTURE_TYPE_COUNT][MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF]; + BindingPointer activeQuery[QUERY_TYPE_COUNT]; + + GLint unpackAlignment; + GLint packAlignment; + bool packReverseRowOrder; +}; + +// Helper class to construct and cache vertex declarations +class VertexDeclarationCache +{ + public: + VertexDeclarationCache(); + ~VertexDeclarationCache(); + + GLenum applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw); + + void markStateDirty(); + + private: + UINT mMaxLru; + + enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 32 }; + + struct VBData + { + unsigned int serial; + unsigned int stride; + unsigned int offset; + }; + + VBData mAppliedVBs[MAX_VERTEX_ATTRIBS]; + IDirect3DVertexDeclaration9 *mLastSetVDecl; + bool mInstancingEnabled; + + struct VertexDeclCacheEntry + { + D3DVERTEXELEMENT9 cachedElements[MAX_VERTEX_ATTRIBS + 1]; + UINT lruCount; + IDirect3DVertexDeclaration9 *vertexDeclaration; + } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES]; +}; + +class Context +{ + public: + Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess); + + ~Context(); + + void makeCurrent(egl::Display *display, egl::Surface *surface); + + virtual void markAllStateDirty(); + void markDxUniformsDirty(); + + virtual void markContextLost(); + bool isContextLost(); + + // State manipulation + void setClearColor(float red, float green, float blue, float alpha); + + void setClearDepth(float depth); + + void setClearStencil(int stencil); + + void setCullFace(bool enabled); + bool isCullFaceEnabled() const; + + void setCullMode(GLenum mode); + + void setFrontFace(GLenum front); + + void setDepthTest(bool enabled); + bool isDepthTestEnabled() const; + + void setDepthFunc(GLenum depthFunc); + + void setDepthRange(float zNear, float zFar); + + void setBlend(bool enabled); + bool isBlendEnabled() const; + + void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha); + void setBlendColor(float red, float green, float blue, float alpha); + void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation); + + void setStencilTest(bool enabled); + bool isStencilTestEnabled() const; + + void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask); + void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask); + void setStencilWritemask(GLuint stencilWritemask); + void setStencilBackWritemask(GLuint stencilBackWritemask); + void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass); + void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass); + + void setPolygonOffsetFill(bool enabled); + bool isPolygonOffsetFillEnabled() const; + + void setPolygonOffsetParams(GLfloat factor, GLfloat units); + + void setSampleAlphaToCoverage(bool enabled); + bool isSampleAlphaToCoverageEnabled() const; + + void setSampleCoverage(bool enabled); + bool isSampleCoverageEnabled() const; + + void setSampleCoverageParams(GLclampf value, bool invert); + + void setScissorTest(bool enabled); + bool isScissorTestEnabled() const; + + void setDither(bool enabled); + bool isDitherEnabled() const; + + void setLineWidth(GLfloat width); + + void setGenerateMipmapHint(GLenum hint); + void setFragmentShaderDerivativeHint(GLenum hint); + + void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); + + void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height); + + void setColorMask(bool red, bool green, bool blue, bool alpha); + void setDepthMask(bool mask); + + void setActiveSampler(unsigned int active); + + GLuint getReadFramebufferHandle() const; + GLuint getDrawFramebufferHandle() const; + GLuint getRenderbufferHandle() const; + + GLuint getArrayBufferHandle() const; + + GLuint getActiveQuery(GLenum target) const; + + void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); + const VertexAttribute &getVertexAttribState(unsigned int attribNum); + void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, GLsizei stride, const void *pointer); + const void *getVertexAttribPointer(unsigned int attribNum) const; + + const VertexAttributeArray &getVertexAttributes(); + + void setUnpackAlignment(GLint alignment); + GLint getUnpackAlignment() const; + + void setPackAlignment(GLint alignment); + GLint getPackAlignment() const; + + void setPackReverseRowOrder(bool reverseRowOrder); + bool getPackReverseRowOrder() const; + + // These create and destroy methods are merely pass-throughs to + // ResourceManager, which owns these object types + GLuint createBuffer(); + GLuint createShader(GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createRenderbuffer(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + + // Framebuffers are owned by the Context, so these methods do not pass through + GLuint createFramebuffer(); + void deleteFramebuffer(GLuint framebuffer); + + // Fences are owned by the Context. + GLuint createFence(); + void deleteFence(GLuint fence); + + // Queries are owned by the Context; + GLuint createQuery(); + void deleteQuery(GLuint query); + + void bindArrayBuffer(GLuint buffer); + void bindElementArrayBuffer(GLuint buffer); + void bindTexture2D(GLuint texture); + void bindTextureCubeMap(GLuint texture); + void bindReadFramebuffer(GLuint framebuffer); + void bindDrawFramebuffer(GLuint framebuffer); + void bindRenderbuffer(GLuint renderbuffer); + void useProgram(GLuint program); + void linkProgram(GLuint program); + void setProgramBinary(GLuint program, const void *binary, GLint length); + + void beginQuery(GLenum target, GLuint query); + void endQuery(GLenum target); + + void setFramebufferZero(Framebuffer *framebuffer); + + void setRenderbufferStorage(RenderbufferStorage *renderbuffer); + + void setVertexAttrib(GLuint index, const GLfloat *values); + void setVertexAttribDivisor(GLuint index, GLuint divisor); + + Buffer *getBuffer(GLuint handle); + Fence *getFence(GLuint handle); + Shader *getShader(GLuint handle); + Program *getProgram(GLuint handle); + Texture *getTexture(GLuint handle); + Framebuffer *getFramebuffer(GLuint handle); + Renderbuffer *getRenderbuffer(GLuint handle); + Query *getQuery(GLuint handle, bool create, GLenum type); + + Buffer *getArrayBuffer(); + Buffer *getElementArrayBuffer(); + ProgramBinary *getCurrentProgramBinary(); + Texture2D *getTexture2D(); + TextureCubeMap *getTextureCubeMap(); + Texture *getSamplerTexture(unsigned int sampler, TextureType type); + Framebuffer *getReadFramebuffer(); + Framebuffer *getDrawFramebuffer(); + + bool getFloatv(GLenum pname, GLfloat *params); + bool getIntegerv(GLenum pname, GLint *params); + bool getBooleanv(GLenum pname, GLboolean *params); + + bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); + + void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); + void clear(GLbitfield mask); + void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances); + void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances); + void sync(bool block); // flush/finish + + void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex); + + void recordInvalidEnum(); + void recordInvalidValue(); + void recordInvalidOperation(); + void recordOutOfMemory(); + void recordInvalidFramebufferOperation(); + + GLenum getError(); + GLenum getResetStatus(); + virtual bool isResetNotificationEnabled(); + + bool supportsShaderModel3() const; + float getMaximumPointSize() const; + int getMaximumVaryingVectors() const; + unsigned int getMaximumVertexTextureImageUnits() const; + unsigned int getMaximumCombinedTextureImageUnits() const; + int getMaximumFragmentUniformVectors() const; + int getMaximumRenderbufferDimension() const; + int getMaximumTextureDimension() const; + int getMaximumCubeTextureDimension() const; + int getMaximumTextureLevel() const; + GLsizei getMaxSupportedSamples() const; + int getNearestSupportedSamples(D3DFORMAT format, int requested) const; + const char *getExtensionString() const; + const char *getRendererString() const; + bool supportsEventQueries() const; + bool supportsOcclusionQueries() const; + bool supportsDXT1Textures() const; + bool supportsDXT3Textures() const; + bool supportsDXT5Textures() const; + bool supportsFloat32Textures() const; + bool supportsFloat32LinearFilter() const; + bool supportsFloat32RenderableTextures() const; + bool supportsFloat16Textures() const; + bool supportsFloat16LinearFilter() const; + bool supportsFloat16RenderableTextures() const; + bool supportsLuminanceTextures() const; + bool supportsLuminanceAlphaTextures() const; + bool supportsDepthTextures() const; + bool supports32bitIndices() const; + bool supportsNonPower2Texture() const; + bool supportsInstancing() const; + bool supportsTextureFilterAnisotropy() const; + + bool getCurrentReadFormatType(GLenum *format, GLenum *type); + + float getTextureMaxAnisotropy() const; + + void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask); + + Blit *getBlitter() { return mBlit; } + + const D3DCAPS9 &getDeviceCaps() { return mDeviceCaps; } + + private: + DISALLOW_COPY_AND_ASSIGN(Context); + + bool applyRenderTarget(bool ignoreViewport); + void applyState(GLenum drawMode); + GLenum applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw); + GLenum applyIndexBuffer(const GLvoid *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + void applyShaders(); + void applyTextures(); + void applyTextures(SamplerType type); + + void detachBuffer(GLuint buffer); + void detachTexture(GLuint texture); + void detachFramebuffer(GLuint framebuffer); + void detachRenderbuffer(GLuint renderbuffer); + + Texture *getIncompleteTexture(TextureType type); + + bool skipDraw(GLenum drawMode); + bool isTriangleMode(GLenum drawMode); + + void initExtensionString(); + void initRendererString(); + + const egl::Config *const mConfig; + egl::Display *mDisplay; + IDirect3DDevice9 *mDevice; + + State mState; + + BindingPointer mTexture2DZero; + BindingPointer mTextureCubeMapZero; + +#ifndef HASH_MAP +# ifdef _MSC_VER +# define HASH_MAP stdext::hash_map +# else +# define HASH_MAP std::unordered_map +# endif +#endif + + typedef HASH_MAP FramebufferMap; + FramebufferMap mFramebufferMap; + HandleAllocator mFramebufferHandleAllocator; + + typedef HASH_MAP FenceMap; + FenceMap mFenceMap; + HandleAllocator mFenceHandleAllocator; + + typedef HASH_MAP QueryMap; + QueryMap mQueryMap; + HandleAllocator mQueryHandleAllocator; + + std::string mExtensionString; + std::string mRendererString; + + VertexDataManager *mVertexDataManager; + IndexDataManager *mIndexDataManager; + + Blit *mBlit; + + StreamingIndexBuffer *mLineLoopIB; + + BindingPointer mIncompleteTextures[TEXTURE_TYPE_COUNT]; + + // Recorded errors + bool mInvalidEnum; + bool mInvalidValue; + bool mInvalidOperation; + bool mOutOfMemory; + bool mInvalidFramebufferOperation; + + // Current/lost context flags + bool mHasBeenCurrent; + bool mContextLost; + GLenum mResetStatus; + GLenum mResetStrategy; + bool mRobustAccess; + + unsigned int mAppliedTextureSerialPS[MAX_TEXTURE_IMAGE_UNITS]; + unsigned int mAppliedTextureSerialVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; + unsigned int mAppliedProgramBinarySerial; + unsigned int mAppliedRenderTargetSerial; + unsigned int mAppliedDepthbufferSerial; + unsigned int mAppliedStencilbufferSerial; + unsigned int mAppliedIBSerial; + bool mDepthStencilInitialized; + bool mViewportInitialized; + D3DVIEWPORT9 mSetViewport; + bool mRenderTargetDescInitialized; + D3DSURFACE_DESC mRenderTargetDesc; + bool mDxUniformsDirty; + BindingPointer mCurrentProgramBinary; + Framebuffer *mBoundDrawFramebuffer; + + bool mSupportsShaderModel3; + float mMaximumPointSize; + bool mSupportsVertexTexture; + bool mSupportsNonPower2Texture; + bool mSupportsInstancing; + int mMaxRenderbufferDimension; + int mMaxTextureDimension; + int mMaxCubeTextureDimension; + int mMaxTextureLevel; + float mMaxTextureAnisotropy; + std::map mMultiSampleSupport; + GLsizei mMaxSupportedSamples; + bool mSupportsEventQueries; + bool mSupportsOcclusionQueries; + bool mSupportsDXT1Textures; + bool mSupportsDXT3Textures; + bool mSupportsDXT5Textures; + bool mSupportsFloat32Textures; + bool mSupportsFloat32LinearFilter; + bool mSupportsFloat32RenderableTextures; + bool mSupportsFloat16Textures; + bool mSupportsFloat16LinearFilter; + bool mSupportsFloat16RenderableTextures; + bool mSupportsLuminanceTextures; + bool mSupportsLuminanceAlphaTextures; + bool mSupportsDepthTextures; + bool mSupports32bitIndices; + bool mSupportsTextureFilterAnisotropy; + int mNumCompressedTextureFormats; + + // state caching flags + bool mClearStateDirty; + bool mCullStateDirty; + bool mDepthStateDirty; + bool mMaskStateDirty; + bool mPixelPackingStateDirty; + bool mBlendStateDirty; + bool mStencilStateDirty; + bool mPolygonOffsetStateDirty; + bool mScissorStateDirty; + bool mSampleStateDirty; + bool mFrontFaceDirty; + bool mDitherStateDirty; + + IDirect3DStateBlock9 *mMaskedClearSavedState; + + D3DCAPS9 mDeviceCaps; + + ResourceManager *mResourceManager; + + VertexDeclarationCache mVertexDeclarationCache; +}; +} + +extern "C" +{ +// Exported functions for use by EGL +gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess); +void glDestroyContext(gl::Context *context); +void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); +gl::Context *glGetCurrentContext(); +__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname); +bool __stdcall glBindTexImage(egl::Surface *surface); +} + +#endif // INCLUDE_CONTEXT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp new file mode 100644 index 0000000000..e136951bec --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.cpp @@ -0,0 +1,231 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// D3DConstantTable.cpp: Implements the D3DConstantTable class which parses +// information about constants from the CTAB comment in a D3D shader blob. +// Restructures the constant table as a hierarchy of constants in the same +// way as D3DX. + +#include "libGLESv2/D3DConstantTable.h" + +#include +#include +#include +#include + +#include "libGLESv2/BinaryStream.h" + +const static int SHADER_VERSION_MASK = D3DVS_VERSION(0, 0); +const static int FOURCC_CTAB = MAKEFOURCC('C','T','A','B'); + +namespace gl +{ +// These structs and constants correspond to the format of the constant table in a shader binary. +// They match the corresponding structures in d3dx9shader.h. +namespace ctab +{ +struct ConstantTable +{ + DWORD size; + DWORD creator; + DWORD version; + DWORD constants; + DWORD constantInfos; + DWORD flags; + DWORD target; +}; + +struct ConstantInfo +{ + DWORD name; + WORD registerSet; + WORD registerIndex; + WORD registerCount; + WORD reserved; + DWORD typeInfo; + DWORD defaultValue; +}; + +struct TypeInfo +{ + WORD typeClass; + WORD type; + WORD rows; + WORD columns; + WORD elements; + WORD structMembers; + DWORD structMemberInfos; +}; + +struct StructMemberInfo +{ + DWORD name; + DWORD typeInfo; +}; +} + +D3DConstant::D3DConstant(const char *base, const ctab::ConstantInfo *constantInfo) +{ + const ctab::TypeInfo *typeInfo = reinterpret_cast(base + constantInfo->typeInfo); + + name = base + constantInfo->name; + registerSet = static_cast(constantInfo->registerSet); + registerIndex = constantInfo->registerIndex; + registerCount = constantInfo->registerCount; + typeClass = static_cast(typeInfo->typeClass); + type = static_cast(typeInfo->type); + rows = typeInfo->rows; + columns = typeInfo->columns; + elements = typeInfo->elements; + + if (typeClass == CLASS_STRUCT) + { + addStructMembers(base, registerSet, registerIndex, typeInfo); + } +} + +D3DConstant::D3DConstant(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::StructMemberInfo *memberInfo) + : registerSet(registerSet), registerIndex(registerIndex) +{ + const ctab::TypeInfo *typeInfo = reinterpret_cast(base + memberInfo->typeInfo); + + name = base + memberInfo->name; + registerCount = typeInfo->rows * typeInfo->elements; + typeClass = static_cast(typeInfo->typeClass); + type = static_cast(typeInfo->type); + rows = typeInfo->rows; + columns = typeInfo->columns; + elements = typeInfo->elements; + + if (typeClass == CLASS_STRUCT) + { + registerCount = addStructMembers(base, registerSet, registerIndex, typeInfo); + } +} + +D3DConstant::~D3DConstant() +{ + for (size_t j = 0; j < structMembers.size(); ++j) + { + for (size_t i = 0; i < structMembers[j].size(); ++i) + { + delete structMembers[j][i]; + } + } +} + +unsigned D3DConstant::addStructMembers(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::TypeInfo *typeInfo) +{ + const ctab::StructMemberInfo *memberInfos = reinterpret_cast( + base + typeInfo->structMemberInfos); + + unsigned memberIndex = registerIndex; + + structMembers.resize(elements); + + for (unsigned j = 0; j < elements; ++j) + { + structMembers[j].resize(typeInfo->structMembers); + + for (unsigned i = 0; i < typeInfo->structMembers; ++i) + { + const ctab::TypeInfo *memberTypeInfo = reinterpret_cast( + base + memberInfos[i].typeInfo); + + D3DConstant *member = new D3DConstant(base, registerSet, memberIndex, memberInfos + i); + memberIndex += member->registerCount; + + structMembers[j][i] = member; + } + } + + return memberIndex - registerIndex; +} + +D3DConstantTable::D3DConstantTable(void *blob, size_t size) : mError(false) +{ + BinaryInputStream stream(blob, size); + + int version; + stream.read(&version); + if ((version & SHADER_VERSION_MASK) != SHADER_VERSION_MASK) + { + mError = true; + return; + } + + const ctab::ConstantTable* constantTable = NULL; + + while (!stream.error()) + { + int token; + stream.read(&token); + + if ((token & D3DSI_OPCODE_MASK) == D3DSIO_COMMENT) + { + size_t length = ((token & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT) * sizeof(DWORD); + + int fourcc; + stream.read(&fourcc); + if (fourcc == FOURCC_CTAB) + { + constantTable = reinterpret_cast(static_cast(blob) + stream.offset()); + break; + } + + stream.skip(length - sizeof(fourcc)); + } + else if (token == D3DSIO_END) + { + break; + } + } + + mError = !constantTable || stream.error(); + if (mError) + { + return; + } + + const char *base = reinterpret_cast(constantTable); + + mConstants.resize(constantTable->constants); + const ctab::ConstantInfo *constantInfos = + reinterpret_cast(base + constantTable->constantInfos); + for (size_t i = 0; i < constantTable->constants; ++i) + { + mConstants[i] = new D3DConstant(base, constantInfos + i); + } +} + +D3DConstantTable::~D3DConstantTable() +{ + for (size_t i = 0; i < mConstants.size(); ++i) + { + delete mConstants[i]; + } +} + +const D3DConstant *D3DConstantTable::getConstant(unsigned index) const +{ + return mConstants[index]; +} + +const D3DConstant *D3DConstantTable::getConstantByName(const char *name) const +{ + for (size_t i = 0; i < mConstants.size(); ++i) + { + const D3DConstant *constant = getConstant(i); + if (constant->name == name) + { + return constant; + } + } + + return NULL; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h new file mode 100644 index 0000000000..ca6f3b9a3f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/D3DConstantTable.h @@ -0,0 +1,117 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// D3DConstantTable.h: Implements the D3DConstantTable class which parses +// information about constants from the CTAB comment in a D3D shader blob. +// Restructures the constant table as a hierarchy of constants in the same +// way as D3DX. + +#ifndef LIBGLESV2_D3DCONSTANTTABLE_H_ +#define LIBGLESV2_D3DCONSTANTTABLE_H_ + +#include +#include + +#include "common/angleutils.h" + +namespace gl +{ + +namespace ctab +{ +struct ConstantTable; +struct ConstantInfo; +struct TypeInfo; +struct StructMemberInfo; +} + +struct D3DConstant +{ + // These enums match those in d3dx9shader.h. + enum Class + { + CLASS_SCALAR, + CLASS_VECTOR, + CLASS_MATRIX_ROWS, + CLASS_MATRIX_COLUMNS, + CLASS_OBJECT, + CLASS_STRUCT, + }; + + enum RegisterSet + { + RS_BOOL, + RS_INT4, + RS_FLOAT4, + RS_SAMPLER, + }; + + enum Type + { + PT_VOID, + PT_BOOL, + PT_INT, + PT_FLOAT, + PT_STRING, + PT_TEXTURE, + PT_TEXTURE1D, + PT_TEXTURE2D, + PT_TEXTURE3D, + PT_TEXTURECUBE, + PT_SAMPLER, + PT_SAMPLER1D, + PT_SAMPLER2D, + PT_SAMPLER3D, + PT_SAMPLERCUBE, + PT_PIXELSHADER, + PT_VERTEXSHADER, + PT_PIXELFRAGMENT, + PT_VERTEXFRAGMENT, + PT_UNSUPPORTED, + }; + + D3DConstant(const char *base, const ctab::ConstantInfo *constantInfo); + ~D3DConstant(); + + std::string name; + RegisterSet registerSet; + unsigned registerIndex; + unsigned registerCount; + Class typeClass; + Type type; + unsigned rows; + unsigned columns; + unsigned elements; + + // Array of structure members. + std::vector > structMembers; + + private: + D3DConstant(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::StructMemberInfo *memberInfo); + unsigned addStructMembers(const char *base, RegisterSet registerSet, unsigned registerIndex, const ctab::TypeInfo *typeInfo); +}; + +class D3DConstantTable +{ + public: + D3DConstantTable(void *blob, size_t size); + ~D3DConstantTable(); + + bool error() const { return mError; } + + unsigned constants() const { return mConstants.size(); } + const D3DConstant *getConstant(unsigned index) const; + const D3DConstant *getConstantByName(const char *name) const; + + private: + DISALLOW_COPY_AND_ASSIGN(D3DConstantTable); + std::vector mConstants; + bool mError; +}; + +} + +#endif // LIBGLESV2_D3DCONSTANTTABLE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.cpp b/src/3rdparty/angle/src/libGLESv2/Fence.cpp new file mode 100644 index 0000000000..14d1239abf --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Fence.cpp @@ -0,0 +1,132 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension. + +#include "libGLESv2/Fence.h" + +#include "libGLESv2/main.h" + +namespace gl +{ + +Fence::Fence(egl::Display* display) +{ + mDisplay = display; + mQuery = NULL; + mCondition = GL_NONE; + mStatus = GL_FALSE; +} + +Fence::~Fence() +{ + if (mQuery != NULL) + { + mDisplay->freeEventQuery(mQuery); + } +} + +GLboolean Fence::isFence() +{ + // GL_NV_fence spec: + // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. + return mQuery != NULL; +} + +void Fence::setFence(GLenum condition) +{ + if (!mQuery) + { + mQuery = mDisplay->allocateEventQuery(); + if (!mQuery) + { + return error(GL_OUT_OF_MEMORY); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + + mCondition = condition; + mStatus = GL_FALSE; +} + +GLboolean Fence::testFence() +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION, GL_TRUE); + } + + HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH); + + if (checkDeviceLost(result)) + { + return error(GL_OUT_OF_MEMORY, GL_TRUE); + } + + ASSERT(result == S_OK || result == S_FALSE); + mStatus = result == S_OK; + return mStatus; +} + +void Fence::finishFence() +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION); + } + + while (!testFence()) + { + Sleep(0); + } +} + +void Fence::getFenceiv(GLenum pname, GLint *params) +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION); + } + + switch (pname) + { + case GL_FENCE_STATUS_NV: + { + // GL_NV_fence spec: + // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV + // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. + if (mStatus) + { + params[0] = GL_TRUE; + return; + } + + HRESULT result = mQuery->GetData(NULL, 0, 0); + + if (checkDeviceLost(result)) + { + params[0] = GL_TRUE; + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(result == S_OK || result == S_FALSE); + mStatus = result == S_OK; + params[0] = mStatus; + + break; + } + case GL_FENCE_CONDITION_NV: + params[0] = mCondition; + break; + default: + return error(GL_INVALID_ENUM); + break; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.h b/src/3rdparty/angle/src/libGLESv2/Fence.h new file mode 100644 index 0000000000..9626cb0ff0 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Fence.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence.h: Defines the gl::Fence class, which supports the GL_NV_fence extension. + +#ifndef LIBGLESV2_FENCE_H_ +#define LIBGLESV2_FENCE_H_ + +#define GL_APICALL +#include +#include + +#include "common/angleutils.h" + +namespace egl +{ +class Display; +} + +namespace gl +{ + +class Fence +{ + public: + explicit Fence(egl::Display* display); + virtual ~Fence(); + + GLboolean isFence(); + void setFence(GLenum condition); + GLboolean testFence(); + void finishFence(); + void getFenceiv(GLenum pname, GLint *params); + + private: + DISALLOW_COPY_AND_ASSIGN(Fence); + + egl::Display* mDisplay; + IDirect3DQuery9* mQuery; + GLenum mCondition; + GLboolean mStatus; +}; + +} + +#endif // LIBGLESV2_FENCE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp new file mode 100644 index 0000000000..5bf7b3fce8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp @@ -0,0 +1,2203 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is automatically generated. + +namespace gl +{ + +const static unsigned g_mantissa[2048] = { + 0x00000000, + 0x33800000, + 0x34000000, + 0x34400000, + 0x34800000, + 0x34a00000, + 0x34c00000, + 0x34e00000, + 0x35000000, + 0x35100000, + 0x35200000, + 0x35300000, + 0x35400000, + 0x35500000, + 0x35600000, + 0x35700000, + 0x35800000, + 0x35880000, + 0x35900000, + 0x35980000, + 0x35a00000, + 0x35a80000, + 0x35b00000, + 0x35b80000, + 0x35c00000, + 0x35c80000, + 0x35d00000, + 0x35d80000, + 0x35e00000, + 0x35e80000, + 0x35f00000, + 0x35f80000, + 0x36000000, + 0x36040000, + 0x36080000, + 0x360c0000, + 0x36100000, + 0x36140000, + 0x36180000, + 0x361c0000, + 0x36200000, + 0x36240000, + 0x36280000, + 0x362c0000, + 0x36300000, + 0x36340000, + 0x36380000, + 0x363c0000, + 0x36400000, + 0x36440000, + 0x36480000, + 0x364c0000, + 0x36500000, + 0x36540000, + 0x36580000, + 0x365c0000, + 0x36600000, + 0x36640000, + 0x36680000, + 0x366c0000, + 0x36700000, + 0x36740000, + 0x36780000, + 0x367c0000, + 0x36800000, + 0x36820000, + 0x36840000, + 0x36860000, + 0x36880000, + 0x368a0000, + 0x368c0000, + 0x368e0000, + 0x36900000, + 0x36920000, + 0x36940000, + 0x36960000, + 0x36980000, + 0x369a0000, + 0x369c0000, + 0x369e0000, + 0x36a00000, + 0x36a20000, + 0x36a40000, + 0x36a60000, + 0x36a80000, + 0x36aa0000, + 0x36ac0000, + 0x36ae0000, + 0x36b00000, + 0x36b20000, + 0x36b40000, + 0x36b60000, + 0x36b80000, + 0x36ba0000, + 0x36bc0000, + 0x36be0000, + 0x36c00000, + 0x36c20000, + 0x36c40000, + 0x36c60000, + 0x36c80000, + 0x36ca0000, + 0x36cc0000, + 0x36ce0000, + 0x36d00000, + 0x36d20000, + 0x36d40000, + 0x36d60000, + 0x36d80000, + 0x36da0000, + 0x36dc0000, + 0x36de0000, + 0x36e00000, + 0x36e20000, + 0x36e40000, + 0x36e60000, + 0x36e80000, + 0x36ea0000, + 0x36ec0000, + 0x36ee0000, + 0x36f00000, + 0x36f20000, + 0x36f40000, + 0x36f60000, + 0x36f80000, + 0x36fa0000, + 0x36fc0000, + 0x36fe0000, + 0x37000000, + 0x37010000, + 0x37020000, + 0x37030000, + 0x37040000, + 0x37050000, + 0x37060000, + 0x37070000, + 0x37080000, + 0x37090000, + 0x370a0000, + 0x370b0000, + 0x370c0000, + 0x370d0000, + 0x370e0000, + 0x370f0000, + 0x37100000, + 0x37110000, + 0x37120000, + 0x37130000, + 0x37140000, + 0x37150000, + 0x37160000, + 0x37170000, + 0x37180000, + 0x37190000, + 0x371a0000, + 0x371b0000, + 0x371c0000, + 0x371d0000, + 0x371e0000, + 0x371f0000, + 0x37200000, + 0x37210000, + 0x37220000, + 0x37230000, + 0x37240000, + 0x37250000, + 0x37260000, + 0x37270000, + 0x37280000, + 0x37290000, + 0x372a0000, + 0x372b0000, + 0x372c0000, + 0x372d0000, + 0x372e0000, + 0x372f0000, + 0x37300000, + 0x37310000, + 0x37320000, + 0x37330000, + 0x37340000, + 0x37350000, + 0x37360000, + 0x37370000, + 0x37380000, + 0x37390000, + 0x373a0000, + 0x373b0000, + 0x373c0000, + 0x373d0000, + 0x373e0000, + 0x373f0000, + 0x37400000, + 0x37410000, + 0x37420000, + 0x37430000, + 0x37440000, + 0x37450000, + 0x37460000, + 0x37470000, + 0x37480000, + 0x37490000, + 0x374a0000, + 0x374b0000, + 0x374c0000, + 0x374d0000, + 0x374e0000, + 0x374f0000, + 0x37500000, + 0x37510000, + 0x37520000, + 0x37530000, + 0x37540000, + 0x37550000, + 0x37560000, + 0x37570000, + 0x37580000, + 0x37590000, + 0x375a0000, + 0x375b0000, + 0x375c0000, + 0x375d0000, + 0x375e0000, + 0x375f0000, + 0x37600000, + 0x37610000, + 0x37620000, + 0x37630000, + 0x37640000, + 0x37650000, + 0x37660000, + 0x37670000, + 0x37680000, + 0x37690000, + 0x376a0000, + 0x376b0000, + 0x376c0000, + 0x376d0000, + 0x376e0000, + 0x376f0000, + 0x37700000, + 0x37710000, + 0x37720000, + 0x37730000, + 0x37740000, + 0x37750000, + 0x37760000, + 0x37770000, + 0x37780000, + 0x37790000, + 0x377a0000, + 0x377b0000, + 0x377c0000, + 0x377d0000, + 0x377e0000, + 0x377f0000, + 0x37800000, + 0x37808000, + 0x37810000, + 0x37818000, + 0x37820000, + 0x37828000, + 0x37830000, + 0x37838000, + 0x37840000, + 0x37848000, + 0x37850000, + 0x37858000, + 0x37860000, + 0x37868000, + 0x37870000, + 0x37878000, + 0x37880000, + 0x37888000, + 0x37890000, + 0x37898000, + 0x378a0000, + 0x378a8000, + 0x378b0000, + 0x378b8000, + 0x378c0000, + 0x378c8000, + 0x378d0000, + 0x378d8000, + 0x378e0000, + 0x378e8000, + 0x378f0000, + 0x378f8000, + 0x37900000, + 0x37908000, + 0x37910000, + 0x37918000, + 0x37920000, + 0x37928000, + 0x37930000, + 0x37938000, + 0x37940000, + 0x37948000, + 0x37950000, + 0x37958000, + 0x37960000, + 0x37968000, + 0x37970000, + 0x37978000, + 0x37980000, + 0x37988000, + 0x37990000, + 0x37998000, + 0x379a0000, + 0x379a8000, + 0x379b0000, + 0x379b8000, + 0x379c0000, + 0x379c8000, + 0x379d0000, + 0x379d8000, + 0x379e0000, + 0x379e8000, + 0x379f0000, + 0x379f8000, + 0x37a00000, + 0x37a08000, + 0x37a10000, + 0x37a18000, + 0x37a20000, + 0x37a28000, + 0x37a30000, + 0x37a38000, + 0x37a40000, + 0x37a48000, + 0x37a50000, + 0x37a58000, + 0x37a60000, + 0x37a68000, + 0x37a70000, + 0x37a78000, + 0x37a80000, + 0x37a88000, + 0x37a90000, + 0x37a98000, + 0x37aa0000, + 0x37aa8000, + 0x37ab0000, + 0x37ab8000, + 0x37ac0000, + 0x37ac8000, + 0x37ad0000, + 0x37ad8000, + 0x37ae0000, + 0x37ae8000, + 0x37af0000, + 0x37af8000, + 0x37b00000, + 0x37b08000, + 0x37b10000, + 0x37b18000, + 0x37b20000, + 0x37b28000, + 0x37b30000, + 0x37b38000, + 0x37b40000, + 0x37b48000, + 0x37b50000, + 0x37b58000, + 0x37b60000, + 0x37b68000, + 0x37b70000, + 0x37b78000, + 0x37b80000, + 0x37b88000, + 0x37b90000, + 0x37b98000, + 0x37ba0000, + 0x37ba8000, + 0x37bb0000, + 0x37bb8000, + 0x37bc0000, + 0x37bc8000, + 0x37bd0000, + 0x37bd8000, + 0x37be0000, + 0x37be8000, + 0x37bf0000, + 0x37bf8000, + 0x37c00000, + 0x37c08000, + 0x37c10000, + 0x37c18000, + 0x37c20000, + 0x37c28000, + 0x37c30000, + 0x37c38000, + 0x37c40000, + 0x37c48000, + 0x37c50000, + 0x37c58000, + 0x37c60000, + 0x37c68000, + 0x37c70000, + 0x37c78000, + 0x37c80000, + 0x37c88000, + 0x37c90000, + 0x37c98000, + 0x37ca0000, + 0x37ca8000, + 0x37cb0000, + 0x37cb8000, + 0x37cc0000, + 0x37cc8000, + 0x37cd0000, + 0x37cd8000, + 0x37ce0000, + 0x37ce8000, + 0x37cf0000, + 0x37cf8000, + 0x37d00000, + 0x37d08000, + 0x37d10000, + 0x37d18000, + 0x37d20000, + 0x37d28000, + 0x37d30000, + 0x37d38000, + 0x37d40000, + 0x37d48000, + 0x37d50000, + 0x37d58000, + 0x37d60000, + 0x37d68000, + 0x37d70000, + 0x37d78000, + 0x37d80000, + 0x37d88000, + 0x37d90000, + 0x37d98000, + 0x37da0000, + 0x37da8000, + 0x37db0000, + 0x37db8000, + 0x37dc0000, + 0x37dc8000, + 0x37dd0000, + 0x37dd8000, + 0x37de0000, + 0x37de8000, + 0x37df0000, + 0x37df8000, + 0x37e00000, + 0x37e08000, + 0x37e10000, + 0x37e18000, + 0x37e20000, + 0x37e28000, + 0x37e30000, + 0x37e38000, + 0x37e40000, + 0x37e48000, + 0x37e50000, + 0x37e58000, + 0x37e60000, + 0x37e68000, + 0x37e70000, + 0x37e78000, + 0x37e80000, + 0x37e88000, + 0x37e90000, + 0x37e98000, + 0x37ea0000, + 0x37ea8000, + 0x37eb0000, + 0x37eb8000, + 0x37ec0000, + 0x37ec8000, + 0x37ed0000, + 0x37ed8000, + 0x37ee0000, + 0x37ee8000, + 0x37ef0000, + 0x37ef8000, + 0x37f00000, + 0x37f08000, + 0x37f10000, + 0x37f18000, + 0x37f20000, + 0x37f28000, + 0x37f30000, + 0x37f38000, + 0x37f40000, + 0x37f48000, + 0x37f50000, + 0x37f58000, + 0x37f60000, + 0x37f68000, + 0x37f70000, + 0x37f78000, + 0x37f80000, + 0x37f88000, + 0x37f90000, + 0x37f98000, + 0x37fa0000, + 0x37fa8000, + 0x37fb0000, + 0x37fb8000, + 0x37fc0000, + 0x37fc8000, + 0x37fd0000, + 0x37fd8000, + 0x37fe0000, + 0x37fe8000, + 0x37ff0000, + 0x37ff8000, + 0x38000000, + 0x38004000, + 0x38008000, + 0x3800c000, + 0x38010000, + 0x38014000, + 0x38018000, + 0x3801c000, + 0x38020000, + 0x38024000, + 0x38028000, + 0x3802c000, + 0x38030000, + 0x38034000, + 0x38038000, + 0x3803c000, + 0x38040000, + 0x38044000, + 0x38048000, + 0x3804c000, + 0x38050000, + 0x38054000, + 0x38058000, + 0x3805c000, + 0x38060000, + 0x38064000, + 0x38068000, + 0x3806c000, + 0x38070000, + 0x38074000, + 0x38078000, + 0x3807c000, + 0x38080000, + 0x38084000, + 0x38088000, + 0x3808c000, + 0x38090000, + 0x38094000, + 0x38098000, + 0x3809c000, + 0x380a0000, + 0x380a4000, + 0x380a8000, + 0x380ac000, + 0x380b0000, + 0x380b4000, + 0x380b8000, + 0x380bc000, + 0x380c0000, + 0x380c4000, + 0x380c8000, + 0x380cc000, + 0x380d0000, + 0x380d4000, + 0x380d8000, + 0x380dc000, + 0x380e0000, + 0x380e4000, + 0x380e8000, + 0x380ec000, + 0x380f0000, + 0x380f4000, + 0x380f8000, + 0x380fc000, + 0x38100000, + 0x38104000, + 0x38108000, + 0x3810c000, + 0x38110000, + 0x38114000, + 0x38118000, + 0x3811c000, + 0x38120000, + 0x38124000, + 0x38128000, + 0x3812c000, + 0x38130000, + 0x38134000, + 0x38138000, + 0x3813c000, + 0x38140000, + 0x38144000, + 0x38148000, + 0x3814c000, + 0x38150000, + 0x38154000, + 0x38158000, + 0x3815c000, + 0x38160000, + 0x38164000, + 0x38168000, + 0x3816c000, + 0x38170000, + 0x38174000, + 0x38178000, + 0x3817c000, + 0x38180000, + 0x38184000, + 0x38188000, + 0x3818c000, + 0x38190000, + 0x38194000, + 0x38198000, + 0x3819c000, + 0x381a0000, + 0x381a4000, + 0x381a8000, + 0x381ac000, + 0x381b0000, + 0x381b4000, + 0x381b8000, + 0x381bc000, + 0x381c0000, + 0x381c4000, + 0x381c8000, + 0x381cc000, + 0x381d0000, + 0x381d4000, + 0x381d8000, + 0x381dc000, + 0x381e0000, + 0x381e4000, + 0x381e8000, + 0x381ec000, + 0x381f0000, + 0x381f4000, + 0x381f8000, + 0x381fc000, + 0x38200000, + 0x38204000, + 0x38208000, + 0x3820c000, + 0x38210000, + 0x38214000, + 0x38218000, + 0x3821c000, + 0x38220000, + 0x38224000, + 0x38228000, + 0x3822c000, + 0x38230000, + 0x38234000, + 0x38238000, + 0x3823c000, + 0x38240000, + 0x38244000, + 0x38248000, + 0x3824c000, + 0x38250000, + 0x38254000, + 0x38258000, + 0x3825c000, + 0x38260000, + 0x38264000, + 0x38268000, + 0x3826c000, + 0x38270000, + 0x38274000, + 0x38278000, + 0x3827c000, + 0x38280000, + 0x38284000, + 0x38288000, + 0x3828c000, + 0x38290000, + 0x38294000, + 0x38298000, + 0x3829c000, + 0x382a0000, + 0x382a4000, + 0x382a8000, + 0x382ac000, + 0x382b0000, + 0x382b4000, + 0x382b8000, + 0x382bc000, + 0x382c0000, + 0x382c4000, + 0x382c8000, + 0x382cc000, + 0x382d0000, + 0x382d4000, + 0x382d8000, + 0x382dc000, + 0x382e0000, + 0x382e4000, + 0x382e8000, + 0x382ec000, + 0x382f0000, + 0x382f4000, + 0x382f8000, + 0x382fc000, + 0x38300000, + 0x38304000, + 0x38308000, + 0x3830c000, + 0x38310000, + 0x38314000, + 0x38318000, + 0x3831c000, + 0x38320000, + 0x38324000, + 0x38328000, + 0x3832c000, + 0x38330000, + 0x38334000, + 0x38338000, + 0x3833c000, + 0x38340000, + 0x38344000, + 0x38348000, + 0x3834c000, + 0x38350000, + 0x38354000, + 0x38358000, + 0x3835c000, + 0x38360000, + 0x38364000, + 0x38368000, + 0x3836c000, + 0x38370000, + 0x38374000, + 0x38378000, + 0x3837c000, + 0x38380000, + 0x38384000, + 0x38388000, + 0x3838c000, + 0x38390000, + 0x38394000, + 0x38398000, + 0x3839c000, + 0x383a0000, + 0x383a4000, + 0x383a8000, + 0x383ac000, + 0x383b0000, + 0x383b4000, + 0x383b8000, + 0x383bc000, + 0x383c0000, + 0x383c4000, + 0x383c8000, + 0x383cc000, + 0x383d0000, + 0x383d4000, + 0x383d8000, + 0x383dc000, + 0x383e0000, + 0x383e4000, + 0x383e8000, + 0x383ec000, + 0x383f0000, + 0x383f4000, + 0x383f8000, + 0x383fc000, + 0x38400000, + 0x38404000, + 0x38408000, + 0x3840c000, + 0x38410000, + 0x38414000, + 0x38418000, + 0x3841c000, + 0x38420000, + 0x38424000, + 0x38428000, + 0x3842c000, + 0x38430000, + 0x38434000, + 0x38438000, + 0x3843c000, + 0x38440000, + 0x38444000, + 0x38448000, + 0x3844c000, + 0x38450000, + 0x38454000, + 0x38458000, + 0x3845c000, + 0x38460000, + 0x38464000, + 0x38468000, + 0x3846c000, + 0x38470000, + 0x38474000, + 0x38478000, + 0x3847c000, + 0x38480000, + 0x38484000, + 0x38488000, + 0x3848c000, + 0x38490000, + 0x38494000, + 0x38498000, + 0x3849c000, + 0x384a0000, + 0x384a4000, + 0x384a8000, + 0x384ac000, + 0x384b0000, + 0x384b4000, + 0x384b8000, + 0x384bc000, + 0x384c0000, + 0x384c4000, + 0x384c8000, + 0x384cc000, + 0x384d0000, + 0x384d4000, + 0x384d8000, + 0x384dc000, + 0x384e0000, + 0x384e4000, + 0x384e8000, + 0x384ec000, + 0x384f0000, + 0x384f4000, + 0x384f8000, + 0x384fc000, + 0x38500000, + 0x38504000, + 0x38508000, + 0x3850c000, + 0x38510000, + 0x38514000, + 0x38518000, + 0x3851c000, + 0x38520000, + 0x38524000, + 0x38528000, + 0x3852c000, + 0x38530000, + 0x38534000, + 0x38538000, + 0x3853c000, + 0x38540000, + 0x38544000, + 0x38548000, + 0x3854c000, + 0x38550000, + 0x38554000, + 0x38558000, + 0x3855c000, + 0x38560000, + 0x38564000, + 0x38568000, + 0x3856c000, + 0x38570000, + 0x38574000, + 0x38578000, + 0x3857c000, + 0x38580000, + 0x38584000, + 0x38588000, + 0x3858c000, + 0x38590000, + 0x38594000, + 0x38598000, + 0x3859c000, + 0x385a0000, + 0x385a4000, + 0x385a8000, + 0x385ac000, + 0x385b0000, + 0x385b4000, + 0x385b8000, + 0x385bc000, + 0x385c0000, + 0x385c4000, + 0x385c8000, + 0x385cc000, + 0x385d0000, + 0x385d4000, + 0x385d8000, + 0x385dc000, + 0x385e0000, + 0x385e4000, + 0x385e8000, + 0x385ec000, + 0x385f0000, + 0x385f4000, + 0x385f8000, + 0x385fc000, + 0x38600000, + 0x38604000, + 0x38608000, + 0x3860c000, + 0x38610000, + 0x38614000, + 0x38618000, + 0x3861c000, + 0x38620000, + 0x38624000, + 0x38628000, + 0x3862c000, + 0x38630000, + 0x38634000, + 0x38638000, + 0x3863c000, + 0x38640000, + 0x38644000, + 0x38648000, + 0x3864c000, + 0x38650000, + 0x38654000, + 0x38658000, + 0x3865c000, + 0x38660000, + 0x38664000, + 0x38668000, + 0x3866c000, + 0x38670000, + 0x38674000, + 0x38678000, + 0x3867c000, + 0x38680000, + 0x38684000, + 0x38688000, + 0x3868c000, + 0x38690000, + 0x38694000, + 0x38698000, + 0x3869c000, + 0x386a0000, + 0x386a4000, + 0x386a8000, + 0x386ac000, + 0x386b0000, + 0x386b4000, + 0x386b8000, + 0x386bc000, + 0x386c0000, + 0x386c4000, + 0x386c8000, + 0x386cc000, + 0x386d0000, + 0x386d4000, + 0x386d8000, + 0x386dc000, + 0x386e0000, + 0x386e4000, + 0x386e8000, + 0x386ec000, + 0x386f0000, + 0x386f4000, + 0x386f8000, + 0x386fc000, + 0x38700000, + 0x38704000, + 0x38708000, + 0x3870c000, + 0x38710000, + 0x38714000, + 0x38718000, + 0x3871c000, + 0x38720000, + 0x38724000, + 0x38728000, + 0x3872c000, + 0x38730000, + 0x38734000, + 0x38738000, + 0x3873c000, + 0x38740000, + 0x38744000, + 0x38748000, + 0x3874c000, + 0x38750000, + 0x38754000, + 0x38758000, + 0x3875c000, + 0x38760000, + 0x38764000, + 0x38768000, + 0x3876c000, + 0x38770000, + 0x38774000, + 0x38778000, + 0x3877c000, + 0x38780000, + 0x38784000, + 0x38788000, + 0x3878c000, + 0x38790000, + 0x38794000, + 0x38798000, + 0x3879c000, + 0x387a0000, + 0x387a4000, + 0x387a8000, + 0x387ac000, + 0x387b0000, + 0x387b4000, + 0x387b8000, + 0x387bc000, + 0x387c0000, + 0x387c4000, + 0x387c8000, + 0x387cc000, + 0x387d0000, + 0x387d4000, + 0x387d8000, + 0x387dc000, + 0x387e0000, + 0x387e4000, + 0x387e8000, + 0x387ec000, + 0x387f0000, + 0x387f4000, + 0x387f8000, + 0x387fc000, + 0x38000000, + 0x38002000, + 0x38004000, + 0x38006000, + 0x38008000, + 0x3800a000, + 0x3800c000, + 0x3800e000, + 0x38010000, + 0x38012000, + 0x38014000, + 0x38016000, + 0x38018000, + 0x3801a000, + 0x3801c000, + 0x3801e000, + 0x38020000, + 0x38022000, + 0x38024000, + 0x38026000, + 0x38028000, + 0x3802a000, + 0x3802c000, + 0x3802e000, + 0x38030000, + 0x38032000, + 0x38034000, + 0x38036000, + 0x38038000, + 0x3803a000, + 0x3803c000, + 0x3803e000, + 0x38040000, + 0x38042000, + 0x38044000, + 0x38046000, + 0x38048000, + 0x3804a000, + 0x3804c000, + 0x3804e000, + 0x38050000, + 0x38052000, + 0x38054000, + 0x38056000, + 0x38058000, + 0x3805a000, + 0x3805c000, + 0x3805e000, + 0x38060000, + 0x38062000, + 0x38064000, + 0x38066000, + 0x38068000, + 0x3806a000, + 0x3806c000, + 0x3806e000, + 0x38070000, + 0x38072000, + 0x38074000, + 0x38076000, + 0x38078000, + 0x3807a000, + 0x3807c000, + 0x3807e000, + 0x38080000, + 0x38082000, + 0x38084000, + 0x38086000, + 0x38088000, + 0x3808a000, + 0x3808c000, + 0x3808e000, + 0x38090000, + 0x38092000, + 0x38094000, + 0x38096000, + 0x38098000, + 0x3809a000, + 0x3809c000, + 0x3809e000, + 0x380a0000, + 0x380a2000, + 0x380a4000, + 0x380a6000, + 0x380a8000, + 0x380aa000, + 0x380ac000, + 0x380ae000, + 0x380b0000, + 0x380b2000, + 0x380b4000, + 0x380b6000, + 0x380b8000, + 0x380ba000, + 0x380bc000, + 0x380be000, + 0x380c0000, + 0x380c2000, + 0x380c4000, + 0x380c6000, + 0x380c8000, + 0x380ca000, + 0x380cc000, + 0x380ce000, + 0x380d0000, + 0x380d2000, + 0x380d4000, + 0x380d6000, + 0x380d8000, + 0x380da000, + 0x380dc000, + 0x380de000, + 0x380e0000, + 0x380e2000, + 0x380e4000, + 0x380e6000, + 0x380e8000, + 0x380ea000, + 0x380ec000, + 0x380ee000, + 0x380f0000, + 0x380f2000, + 0x380f4000, + 0x380f6000, + 0x380f8000, + 0x380fa000, + 0x380fc000, + 0x380fe000, + 0x38100000, + 0x38102000, + 0x38104000, + 0x38106000, + 0x38108000, + 0x3810a000, + 0x3810c000, + 0x3810e000, + 0x38110000, + 0x38112000, + 0x38114000, + 0x38116000, + 0x38118000, + 0x3811a000, + 0x3811c000, + 0x3811e000, + 0x38120000, + 0x38122000, + 0x38124000, + 0x38126000, + 0x38128000, + 0x3812a000, + 0x3812c000, + 0x3812e000, + 0x38130000, + 0x38132000, + 0x38134000, + 0x38136000, + 0x38138000, + 0x3813a000, + 0x3813c000, + 0x3813e000, + 0x38140000, + 0x38142000, + 0x38144000, + 0x38146000, + 0x38148000, + 0x3814a000, + 0x3814c000, + 0x3814e000, + 0x38150000, + 0x38152000, + 0x38154000, + 0x38156000, + 0x38158000, + 0x3815a000, + 0x3815c000, + 0x3815e000, + 0x38160000, + 0x38162000, + 0x38164000, + 0x38166000, + 0x38168000, + 0x3816a000, + 0x3816c000, + 0x3816e000, + 0x38170000, + 0x38172000, + 0x38174000, + 0x38176000, + 0x38178000, + 0x3817a000, + 0x3817c000, + 0x3817e000, + 0x38180000, + 0x38182000, + 0x38184000, + 0x38186000, + 0x38188000, + 0x3818a000, + 0x3818c000, + 0x3818e000, + 0x38190000, + 0x38192000, + 0x38194000, + 0x38196000, + 0x38198000, + 0x3819a000, + 0x3819c000, + 0x3819e000, + 0x381a0000, + 0x381a2000, + 0x381a4000, + 0x381a6000, + 0x381a8000, + 0x381aa000, + 0x381ac000, + 0x381ae000, + 0x381b0000, + 0x381b2000, + 0x381b4000, + 0x381b6000, + 0x381b8000, + 0x381ba000, + 0x381bc000, + 0x381be000, + 0x381c0000, + 0x381c2000, + 0x381c4000, + 0x381c6000, + 0x381c8000, + 0x381ca000, + 0x381cc000, + 0x381ce000, + 0x381d0000, + 0x381d2000, + 0x381d4000, + 0x381d6000, + 0x381d8000, + 0x381da000, + 0x381dc000, + 0x381de000, + 0x381e0000, + 0x381e2000, + 0x381e4000, + 0x381e6000, + 0x381e8000, + 0x381ea000, + 0x381ec000, + 0x381ee000, + 0x381f0000, + 0x381f2000, + 0x381f4000, + 0x381f6000, + 0x381f8000, + 0x381fa000, + 0x381fc000, + 0x381fe000, + 0x38200000, + 0x38202000, + 0x38204000, + 0x38206000, + 0x38208000, + 0x3820a000, + 0x3820c000, + 0x3820e000, + 0x38210000, + 0x38212000, + 0x38214000, + 0x38216000, + 0x38218000, + 0x3821a000, + 0x3821c000, + 0x3821e000, + 0x38220000, + 0x38222000, + 0x38224000, + 0x38226000, + 0x38228000, + 0x3822a000, + 0x3822c000, + 0x3822e000, + 0x38230000, + 0x38232000, + 0x38234000, + 0x38236000, + 0x38238000, + 0x3823a000, + 0x3823c000, + 0x3823e000, + 0x38240000, + 0x38242000, + 0x38244000, + 0x38246000, + 0x38248000, + 0x3824a000, + 0x3824c000, + 0x3824e000, + 0x38250000, + 0x38252000, + 0x38254000, + 0x38256000, + 0x38258000, + 0x3825a000, + 0x3825c000, + 0x3825e000, + 0x38260000, + 0x38262000, + 0x38264000, + 0x38266000, + 0x38268000, + 0x3826a000, + 0x3826c000, + 0x3826e000, + 0x38270000, + 0x38272000, + 0x38274000, + 0x38276000, + 0x38278000, + 0x3827a000, + 0x3827c000, + 0x3827e000, + 0x38280000, + 0x38282000, + 0x38284000, + 0x38286000, + 0x38288000, + 0x3828a000, + 0x3828c000, + 0x3828e000, + 0x38290000, + 0x38292000, + 0x38294000, + 0x38296000, + 0x38298000, + 0x3829a000, + 0x3829c000, + 0x3829e000, + 0x382a0000, + 0x382a2000, + 0x382a4000, + 0x382a6000, + 0x382a8000, + 0x382aa000, + 0x382ac000, + 0x382ae000, + 0x382b0000, + 0x382b2000, + 0x382b4000, + 0x382b6000, + 0x382b8000, + 0x382ba000, + 0x382bc000, + 0x382be000, + 0x382c0000, + 0x382c2000, + 0x382c4000, + 0x382c6000, + 0x382c8000, + 0x382ca000, + 0x382cc000, + 0x382ce000, + 0x382d0000, + 0x382d2000, + 0x382d4000, + 0x382d6000, + 0x382d8000, + 0x382da000, + 0x382dc000, + 0x382de000, + 0x382e0000, + 0x382e2000, + 0x382e4000, + 0x382e6000, + 0x382e8000, + 0x382ea000, + 0x382ec000, + 0x382ee000, + 0x382f0000, + 0x382f2000, + 0x382f4000, + 0x382f6000, + 0x382f8000, + 0x382fa000, + 0x382fc000, + 0x382fe000, + 0x38300000, + 0x38302000, + 0x38304000, + 0x38306000, + 0x38308000, + 0x3830a000, + 0x3830c000, + 0x3830e000, + 0x38310000, + 0x38312000, + 0x38314000, + 0x38316000, + 0x38318000, + 0x3831a000, + 0x3831c000, + 0x3831e000, + 0x38320000, + 0x38322000, + 0x38324000, + 0x38326000, + 0x38328000, + 0x3832a000, + 0x3832c000, + 0x3832e000, + 0x38330000, + 0x38332000, + 0x38334000, + 0x38336000, + 0x38338000, + 0x3833a000, + 0x3833c000, + 0x3833e000, + 0x38340000, + 0x38342000, + 0x38344000, + 0x38346000, + 0x38348000, + 0x3834a000, + 0x3834c000, + 0x3834e000, + 0x38350000, + 0x38352000, + 0x38354000, + 0x38356000, + 0x38358000, + 0x3835a000, + 0x3835c000, + 0x3835e000, + 0x38360000, + 0x38362000, + 0x38364000, + 0x38366000, + 0x38368000, + 0x3836a000, + 0x3836c000, + 0x3836e000, + 0x38370000, + 0x38372000, + 0x38374000, + 0x38376000, + 0x38378000, + 0x3837a000, + 0x3837c000, + 0x3837e000, + 0x38380000, + 0x38382000, + 0x38384000, + 0x38386000, + 0x38388000, + 0x3838a000, + 0x3838c000, + 0x3838e000, + 0x38390000, + 0x38392000, + 0x38394000, + 0x38396000, + 0x38398000, + 0x3839a000, + 0x3839c000, + 0x3839e000, + 0x383a0000, + 0x383a2000, + 0x383a4000, + 0x383a6000, + 0x383a8000, + 0x383aa000, + 0x383ac000, + 0x383ae000, + 0x383b0000, + 0x383b2000, + 0x383b4000, + 0x383b6000, + 0x383b8000, + 0x383ba000, + 0x383bc000, + 0x383be000, + 0x383c0000, + 0x383c2000, + 0x383c4000, + 0x383c6000, + 0x383c8000, + 0x383ca000, + 0x383cc000, + 0x383ce000, + 0x383d0000, + 0x383d2000, + 0x383d4000, + 0x383d6000, + 0x383d8000, + 0x383da000, + 0x383dc000, + 0x383de000, + 0x383e0000, + 0x383e2000, + 0x383e4000, + 0x383e6000, + 0x383e8000, + 0x383ea000, + 0x383ec000, + 0x383ee000, + 0x383f0000, + 0x383f2000, + 0x383f4000, + 0x383f6000, + 0x383f8000, + 0x383fa000, + 0x383fc000, + 0x383fe000, + 0x38400000, + 0x38402000, + 0x38404000, + 0x38406000, + 0x38408000, + 0x3840a000, + 0x3840c000, + 0x3840e000, + 0x38410000, + 0x38412000, + 0x38414000, + 0x38416000, + 0x38418000, + 0x3841a000, + 0x3841c000, + 0x3841e000, + 0x38420000, + 0x38422000, + 0x38424000, + 0x38426000, + 0x38428000, + 0x3842a000, + 0x3842c000, + 0x3842e000, + 0x38430000, + 0x38432000, + 0x38434000, + 0x38436000, + 0x38438000, + 0x3843a000, + 0x3843c000, + 0x3843e000, + 0x38440000, + 0x38442000, + 0x38444000, + 0x38446000, + 0x38448000, + 0x3844a000, + 0x3844c000, + 0x3844e000, + 0x38450000, + 0x38452000, + 0x38454000, + 0x38456000, + 0x38458000, + 0x3845a000, + 0x3845c000, + 0x3845e000, + 0x38460000, + 0x38462000, + 0x38464000, + 0x38466000, + 0x38468000, + 0x3846a000, + 0x3846c000, + 0x3846e000, + 0x38470000, + 0x38472000, + 0x38474000, + 0x38476000, + 0x38478000, + 0x3847a000, + 0x3847c000, + 0x3847e000, + 0x38480000, + 0x38482000, + 0x38484000, + 0x38486000, + 0x38488000, + 0x3848a000, + 0x3848c000, + 0x3848e000, + 0x38490000, + 0x38492000, + 0x38494000, + 0x38496000, + 0x38498000, + 0x3849a000, + 0x3849c000, + 0x3849e000, + 0x384a0000, + 0x384a2000, + 0x384a4000, + 0x384a6000, + 0x384a8000, + 0x384aa000, + 0x384ac000, + 0x384ae000, + 0x384b0000, + 0x384b2000, + 0x384b4000, + 0x384b6000, + 0x384b8000, + 0x384ba000, + 0x384bc000, + 0x384be000, + 0x384c0000, + 0x384c2000, + 0x384c4000, + 0x384c6000, + 0x384c8000, + 0x384ca000, + 0x384cc000, + 0x384ce000, + 0x384d0000, + 0x384d2000, + 0x384d4000, + 0x384d6000, + 0x384d8000, + 0x384da000, + 0x384dc000, + 0x384de000, + 0x384e0000, + 0x384e2000, + 0x384e4000, + 0x384e6000, + 0x384e8000, + 0x384ea000, + 0x384ec000, + 0x384ee000, + 0x384f0000, + 0x384f2000, + 0x384f4000, + 0x384f6000, + 0x384f8000, + 0x384fa000, + 0x384fc000, + 0x384fe000, + 0x38500000, + 0x38502000, + 0x38504000, + 0x38506000, + 0x38508000, + 0x3850a000, + 0x3850c000, + 0x3850e000, + 0x38510000, + 0x38512000, + 0x38514000, + 0x38516000, + 0x38518000, + 0x3851a000, + 0x3851c000, + 0x3851e000, + 0x38520000, + 0x38522000, + 0x38524000, + 0x38526000, + 0x38528000, + 0x3852a000, + 0x3852c000, + 0x3852e000, + 0x38530000, + 0x38532000, + 0x38534000, + 0x38536000, + 0x38538000, + 0x3853a000, + 0x3853c000, + 0x3853e000, + 0x38540000, + 0x38542000, + 0x38544000, + 0x38546000, + 0x38548000, + 0x3854a000, + 0x3854c000, + 0x3854e000, + 0x38550000, + 0x38552000, + 0x38554000, + 0x38556000, + 0x38558000, + 0x3855a000, + 0x3855c000, + 0x3855e000, + 0x38560000, + 0x38562000, + 0x38564000, + 0x38566000, + 0x38568000, + 0x3856a000, + 0x3856c000, + 0x3856e000, + 0x38570000, + 0x38572000, + 0x38574000, + 0x38576000, + 0x38578000, + 0x3857a000, + 0x3857c000, + 0x3857e000, + 0x38580000, + 0x38582000, + 0x38584000, + 0x38586000, + 0x38588000, + 0x3858a000, + 0x3858c000, + 0x3858e000, + 0x38590000, + 0x38592000, + 0x38594000, + 0x38596000, + 0x38598000, + 0x3859a000, + 0x3859c000, + 0x3859e000, + 0x385a0000, + 0x385a2000, + 0x385a4000, + 0x385a6000, + 0x385a8000, + 0x385aa000, + 0x385ac000, + 0x385ae000, + 0x385b0000, + 0x385b2000, + 0x385b4000, + 0x385b6000, + 0x385b8000, + 0x385ba000, + 0x385bc000, + 0x385be000, + 0x385c0000, + 0x385c2000, + 0x385c4000, + 0x385c6000, + 0x385c8000, + 0x385ca000, + 0x385cc000, + 0x385ce000, + 0x385d0000, + 0x385d2000, + 0x385d4000, + 0x385d6000, + 0x385d8000, + 0x385da000, + 0x385dc000, + 0x385de000, + 0x385e0000, + 0x385e2000, + 0x385e4000, + 0x385e6000, + 0x385e8000, + 0x385ea000, + 0x385ec000, + 0x385ee000, + 0x385f0000, + 0x385f2000, + 0x385f4000, + 0x385f6000, + 0x385f8000, + 0x385fa000, + 0x385fc000, + 0x385fe000, + 0x38600000, + 0x38602000, + 0x38604000, + 0x38606000, + 0x38608000, + 0x3860a000, + 0x3860c000, + 0x3860e000, + 0x38610000, + 0x38612000, + 0x38614000, + 0x38616000, + 0x38618000, + 0x3861a000, + 0x3861c000, + 0x3861e000, + 0x38620000, + 0x38622000, + 0x38624000, + 0x38626000, + 0x38628000, + 0x3862a000, + 0x3862c000, + 0x3862e000, + 0x38630000, + 0x38632000, + 0x38634000, + 0x38636000, + 0x38638000, + 0x3863a000, + 0x3863c000, + 0x3863e000, + 0x38640000, + 0x38642000, + 0x38644000, + 0x38646000, + 0x38648000, + 0x3864a000, + 0x3864c000, + 0x3864e000, + 0x38650000, + 0x38652000, + 0x38654000, + 0x38656000, + 0x38658000, + 0x3865a000, + 0x3865c000, + 0x3865e000, + 0x38660000, + 0x38662000, + 0x38664000, + 0x38666000, + 0x38668000, + 0x3866a000, + 0x3866c000, + 0x3866e000, + 0x38670000, + 0x38672000, + 0x38674000, + 0x38676000, + 0x38678000, + 0x3867a000, + 0x3867c000, + 0x3867e000, + 0x38680000, + 0x38682000, + 0x38684000, + 0x38686000, + 0x38688000, + 0x3868a000, + 0x3868c000, + 0x3868e000, + 0x38690000, + 0x38692000, + 0x38694000, + 0x38696000, + 0x38698000, + 0x3869a000, + 0x3869c000, + 0x3869e000, + 0x386a0000, + 0x386a2000, + 0x386a4000, + 0x386a6000, + 0x386a8000, + 0x386aa000, + 0x386ac000, + 0x386ae000, + 0x386b0000, + 0x386b2000, + 0x386b4000, + 0x386b6000, + 0x386b8000, + 0x386ba000, + 0x386bc000, + 0x386be000, + 0x386c0000, + 0x386c2000, + 0x386c4000, + 0x386c6000, + 0x386c8000, + 0x386ca000, + 0x386cc000, + 0x386ce000, + 0x386d0000, + 0x386d2000, + 0x386d4000, + 0x386d6000, + 0x386d8000, + 0x386da000, + 0x386dc000, + 0x386de000, + 0x386e0000, + 0x386e2000, + 0x386e4000, + 0x386e6000, + 0x386e8000, + 0x386ea000, + 0x386ec000, + 0x386ee000, + 0x386f0000, + 0x386f2000, + 0x386f4000, + 0x386f6000, + 0x386f8000, + 0x386fa000, + 0x386fc000, + 0x386fe000, + 0x38700000, + 0x38702000, + 0x38704000, + 0x38706000, + 0x38708000, + 0x3870a000, + 0x3870c000, + 0x3870e000, + 0x38710000, + 0x38712000, + 0x38714000, + 0x38716000, + 0x38718000, + 0x3871a000, + 0x3871c000, + 0x3871e000, + 0x38720000, + 0x38722000, + 0x38724000, + 0x38726000, + 0x38728000, + 0x3872a000, + 0x3872c000, + 0x3872e000, + 0x38730000, + 0x38732000, + 0x38734000, + 0x38736000, + 0x38738000, + 0x3873a000, + 0x3873c000, + 0x3873e000, + 0x38740000, + 0x38742000, + 0x38744000, + 0x38746000, + 0x38748000, + 0x3874a000, + 0x3874c000, + 0x3874e000, + 0x38750000, + 0x38752000, + 0x38754000, + 0x38756000, + 0x38758000, + 0x3875a000, + 0x3875c000, + 0x3875e000, + 0x38760000, + 0x38762000, + 0x38764000, + 0x38766000, + 0x38768000, + 0x3876a000, + 0x3876c000, + 0x3876e000, + 0x38770000, + 0x38772000, + 0x38774000, + 0x38776000, + 0x38778000, + 0x3877a000, + 0x3877c000, + 0x3877e000, + 0x38780000, + 0x38782000, + 0x38784000, + 0x38786000, + 0x38788000, + 0x3878a000, + 0x3878c000, + 0x3878e000, + 0x38790000, + 0x38792000, + 0x38794000, + 0x38796000, + 0x38798000, + 0x3879a000, + 0x3879c000, + 0x3879e000, + 0x387a0000, + 0x387a2000, + 0x387a4000, + 0x387a6000, + 0x387a8000, + 0x387aa000, + 0x387ac000, + 0x387ae000, + 0x387b0000, + 0x387b2000, + 0x387b4000, + 0x387b6000, + 0x387b8000, + 0x387ba000, + 0x387bc000, + 0x387be000, + 0x387c0000, + 0x387c2000, + 0x387c4000, + 0x387c6000, + 0x387c8000, + 0x387ca000, + 0x387cc000, + 0x387ce000, + 0x387d0000, + 0x387d2000, + 0x387d4000, + 0x387d6000, + 0x387d8000, + 0x387da000, + 0x387dc000, + 0x387de000, + 0x387e0000, + 0x387e2000, + 0x387e4000, + 0x387e6000, + 0x387e8000, + 0x387ea000, + 0x387ec000, + 0x387ee000, + 0x387f0000, + 0x387f2000, + 0x387f4000, + 0x387f6000, + 0x387f8000, + 0x387fa000, + 0x387fc000, + 0x387fe000, +}; + +const static unsigned g_exponent[64] = { + 0x00000000, + 0x00800000, + 0x01000000, + 0x01800000, + 0x02000000, + 0x02800000, + 0x03000000, + 0x03800000, + 0x04000000, + 0x04800000, + 0x05000000, + 0x05800000, + 0x06000000, + 0x06800000, + 0x07000000, + 0x07800000, + 0x08000000, + 0x08800000, + 0x09000000, + 0x09800000, + 0x0a000000, + 0x0a800000, + 0x0b000000, + 0x0b800000, + 0x0c000000, + 0x0c800000, + 0x0d000000, + 0x0d800000, + 0x0e000000, + 0x0e800000, + 0x0f000000, + 0x47800000, + 0x80000000, + 0x80800000, + 0x81000000, + 0x81800000, + 0x82000000, + 0x82800000, + 0x83000000, + 0x83800000, + 0x84000000, + 0x84800000, + 0x85000000, + 0x85800000, + 0x86000000, + 0x86800000, + 0x87000000, + 0x87800000, + 0x88000000, + 0x88800000, + 0x89000000, + 0x89800000, + 0x8a000000, + 0x8a800000, + 0x8b000000, + 0x8b800000, + 0x8c000000, + 0x8c800000, + 0x8d000000, + 0x8d800000, + 0x8e000000, + 0x8e800000, + 0x8f000000, + 0xc7800000, +}; + +const static unsigned g_offset[64] = { + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, +}; + +float float16ToFloat32(unsigned short h) +{ + unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return *(float*) &i32; +} +} + diff --git a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py new file mode 100644 index 0000000000..ae646ffa12 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py @@ -0,0 +1,78 @@ +# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# + +# This script generates a function that converts 16-bit precision floating +# point numbers to 32-bit. +# It is based on ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf. + +def convertMantissa(i): + if i == 0: + return 0 + elif i < 1024: + m = i << 13 + e = 0 + while not (m & 0x00800000): + e -= 0x00800000 + m = m << 1 + m &= ~0x00800000 + e += 0x38800000 + return m | e + else: + return 0x38000000 + ((i - 1024) << 13) + +def convertExponent(i): + if i == 0: + return 0 + elif i in range(1, 31): + return i << 23 + elif i == 31: + return 0x47800000 + elif i == 32: + return 0x80000000 + elif i in range(33, 63): + return 0x80000000 + ((i - 32) << 23) + else: + return 0xC7800000 + +def convertOffset(i): + if i == 0 or i == 32: + return 0 + else: + return 1024 + +print """// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is automatically generated. + +namespace gl +{ +""" + +print "const static unsigned g_mantissa[2048] = {" +for i in range(0, 2048): + print " %08x," % convertMantissa(i) +print "};\n" + +print "const static unsigned g_exponent[64] = {" +for i in range(0, 64): + print " %08x," % convertExponent(i) +print "};\n" + +print "const static unsigned g_offset[64] = {" +for i in range(0, 64): + print " %08x," % convertOffset(i) +print "};\n" + +print """float float16ToFloat32(unsigned short h) +{ + unsigned i32 = =g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return *(float*) &i32; +} +} +""" diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp new file mode 100644 index 0000000000..77d79c0be2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp @@ -0,0 +1,509 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#include "libGLESv2/Framebuffer.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/utilities.h" + +namespace gl +{ + +Framebuffer::Framebuffer() +{ + mColorbufferType = GL_NONE; + mDepthbufferType = GL_NONE; + mStencilbufferType = GL_NONE; +} + +Framebuffer::~Framebuffer() +{ + mColorbufferPointer.set(NULL); + mDepthbufferPointer.set(NULL); + mStencilbufferPointer.set(NULL); + mNullColorbufferPointer.set(NULL); +} + +Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const +{ + gl::Context *context = gl::getContext(); + Renderbuffer *buffer = NULL; + + if (type == GL_NONE) + { + buffer = NULL; + } + else if (type == GL_RENDERBUFFER) + { + buffer = context->getRenderbuffer(handle); + } + else if (IsInternalTextureTarget(type)) + { + buffer = context->getTexture(handle)->getRenderbuffer(type); + } + else + { + UNREACHABLE(); + } + + return buffer; +} + +void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) +{ + mColorbufferType = (colorbuffer != 0) ? type : GL_NONE; + mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer)); +} + +void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) +{ + mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE; + mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer)); +} + +void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) +{ + mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE; + mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer)); +} + +void Framebuffer::detachTexture(GLuint texture) +{ + if (mColorbufferPointer.id() == texture && IsInternalTextureTarget(mColorbufferType)) + { + mColorbufferType = GL_NONE; + mColorbufferPointer.set(NULL); + } + + if (mDepthbufferPointer.id() == texture && IsInternalTextureTarget(mDepthbufferType)) + { + mDepthbufferType = GL_NONE; + mDepthbufferPointer.set(NULL); + } + + if (mStencilbufferPointer.id() == texture && IsInternalTextureTarget(mStencilbufferType)) + { + mStencilbufferType = GL_NONE; + mStencilbufferPointer.set(NULL); + } +} + +void Framebuffer::detachRenderbuffer(GLuint renderbuffer) +{ + if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER) + { + mColorbufferType = GL_NONE; + mColorbufferPointer.set(NULL); + } + + if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER) + { + mDepthbufferType = GL_NONE; + mDepthbufferPointer.set(NULL); + } + + if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER) + { + mStencilbufferType = GL_NONE; + mStencilbufferPointer.set(NULL); + } +} + +unsigned int Framebuffer::getRenderTargetSerial() +{ + Renderbuffer *colorbuffer = mColorbufferPointer.get(); + + if (colorbuffer) + { + return colorbuffer->getSerial(); + } + + return 0; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Framebuffer::getRenderTarget() +{ + Renderbuffer *colorbuffer = mColorbufferPointer.get(); + + if (colorbuffer) + { + return colorbuffer->getRenderTarget(); + } + + return NULL; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Framebuffer::getDepthStencil() +{ + Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get(); + + if (!depthstencilbuffer) + { + depthstencilbuffer = mStencilbufferPointer.get(); + } + + if (depthstencilbuffer) + { + return depthstencilbuffer->getDepthStencil(); + } + + return NULL; +} + +unsigned int Framebuffer::getDepthbufferSerial() +{ + Renderbuffer *depthbuffer = mDepthbufferPointer.get(); + + if (depthbuffer) + { + return depthbuffer->getSerial(); + } + + return 0; +} + +unsigned int Framebuffer::getStencilbufferSerial() +{ + Renderbuffer *stencilbuffer = mStencilbufferPointer.get(); + + if (stencilbuffer) + { + return stencilbuffer->getSerial(); + } + + return 0; +} + +Renderbuffer *Framebuffer::getColorbuffer() +{ + return mColorbufferPointer.get(); +} + +Renderbuffer *Framebuffer::getDepthbuffer() +{ + return mDepthbufferPointer.get(); +} + +Renderbuffer *Framebuffer::getStencilbuffer() +{ + return mStencilbufferPointer.get(); +} + +Renderbuffer *Framebuffer::getNullColorbuffer() +{ + Renderbuffer *nullbuffer = mNullColorbufferPointer.get(); + Renderbuffer *depthbuffer = getDepthbuffer(); + + if (!depthbuffer) + { + ERR("Unexpected null depthbuffer for depth-only FBO."); + return NULL; + } + + GLsizei width = depthbuffer->getWidth(); + GLsizei height = depthbuffer->getHeight(); + + if (!nullbuffer || + width != nullbuffer->getWidth() || height != nullbuffer->getHeight()) + { + nullbuffer = new Renderbuffer(0, new Colorbuffer(width, height, GL_NONE, 0)); + mNullColorbufferPointer.set(nullbuffer); + } + + return nullbuffer; +} + +GLenum Framebuffer::getColorbufferType() +{ + return mColorbufferType; +} + +GLenum Framebuffer::getDepthbufferType() +{ + return mDepthbufferType; +} + +GLenum Framebuffer::getStencilbufferType() +{ + return mStencilbufferType; +} + +GLuint Framebuffer::getColorbufferHandle() +{ + return mColorbufferPointer.id(); +} + +GLuint Framebuffer::getDepthbufferHandle() +{ + return mDepthbufferPointer.id(); +} + +GLuint Framebuffer::getStencilbufferHandle() +{ + return mStencilbufferPointer.id(); +} + +bool Framebuffer::hasStencil() +{ + if (mStencilbufferType != GL_NONE) + { + Renderbuffer *stencilbufferObject = getStencilbuffer(); + + if (stencilbufferObject) + { + return stencilbufferObject->getStencilSize() > 0; + } + } + + return false; +} + +GLenum Framebuffer::completeness() +{ + gl::Context *context = gl::getContext(); + int width = 0; + int height = 0; + int samples = -1; + bool missingAttachment = true; + + if (mColorbufferType != GL_NONE) + { + Renderbuffer *colorbuffer = getColorbuffer(); + + if (!colorbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (mColorbufferType == GL_RENDERBUFFER) + { + if (!gl::IsColorRenderable(colorbuffer->getInternalFormat())) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (IsInternalTextureTarget(mColorbufferType)) + { + GLint internalformat = colorbuffer->getInternalFormat(); + GLenum format = gl::ExtractFormat(internalformat); + + if (IsCompressed(format) || + format == GL_ALPHA || + format == GL_LUMINANCE || + format == GL_LUMINANCE_ALPHA) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if ((gl::IsFloat32Format(internalformat) && !context->supportsFloat32RenderableTextures()) || + (gl::IsFloat16Format(internalformat) && !context->supportsFloat16RenderableTextures())) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (gl::IsDepthTexture(internalformat) || gl::IsStencilTexture(internalformat)) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else + { + UNREACHABLE(); + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + width = colorbuffer->getWidth(); + height = colorbuffer->getHeight(); + samples = colorbuffer->getSamples(); + missingAttachment = false; + } + + Renderbuffer *depthbuffer = NULL; + Renderbuffer *stencilbuffer = NULL; + + if (mDepthbufferType != GL_NONE) + { + depthbuffer = getDepthbuffer(); + + if (!depthbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (mDepthbufferType == GL_RENDERBUFFER) + { + if (!gl::IsDepthRenderable(depthbuffer->getInternalFormat())) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (IsInternalTextureTarget(mDepthbufferType)) + { + GLint internalformat = depthbuffer->getInternalFormat(); + + // depth texture attachments require OES/ANGLE_depth_texture + if (!context->supportsDepthTextures()) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!gl::IsDepthTexture(internalformat)) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else + { + UNREACHABLE(); + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (missingAttachment) + { + width = depthbuffer->getWidth(); + height = depthbuffer->getHeight(); + samples = depthbuffer->getSamples(); + missingAttachment = false; + } + else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != depthbuffer->getSamples()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + } + } + + if (mStencilbufferType != GL_NONE) + { + stencilbuffer = getStencilbuffer(); + + if (!stencilbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (mStencilbufferType == GL_RENDERBUFFER) + { + if (!gl::IsStencilRenderable(stencilbuffer->getInternalFormat())) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (IsInternalTextureTarget(mStencilbufferType)) + { + GLint internalformat = stencilbuffer->getInternalFormat(); + + // texture stencil attachments come along as part + // of OES_packed_depth_stencil + OES/ANGLE_depth_texture + if (!context->supportsDepthTextures()) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!gl::IsStencilTexture(internalformat)) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else + { + UNREACHABLE(); + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (missingAttachment) + { + width = stencilbuffer->getWidth(); + height = stencilbuffer->getHeight(); + samples = stencilbuffer->getSamples(); + missingAttachment = false; + } + else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != stencilbuffer->getSamples()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + } + } + + // if we have both a depth and stencil buffer, they must refer to the same object + // since we only support packed_depth_stencil and not separate depth and stencil + if (depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer)) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + // we need to have at least one attachment to be complete + if (missingAttachment) + { + return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + } + + return GL_FRAMEBUFFER_COMPLETE; +} + +DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) +{ + mColorbufferPointer.set(new Renderbuffer(0, colorbuffer)); + + Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); + mDepthbufferPointer.set(depthStencilRenderbuffer); + mStencilbufferPointer.set(depthStencilRenderbuffer); + + mColorbufferType = GL_RENDERBUFFER; + mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; + mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; +} + +int Framebuffer::getSamples() +{ + if (completeness() == GL_FRAMEBUFFER_COMPLETE) + { + return getColorbuffer()->getSamples(); + } + else + { + return 0; + } +} + +GLenum DefaultFramebuffer::completeness() +{ + // The default framebuffer should always be complete + ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE); + + return GL_FRAMEBUFFER_COMPLETE; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h new file mode 100644 index 0000000000..14d9c2a74c --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Framebuffer.h: Defines the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#ifndef LIBGLESV2_FRAMEBUFFER_H_ +#define LIBGLESV2_FRAMEBUFFER_H_ + +#define GL_APICALL +#include +#include + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ +class Renderbuffer; +class Colorbuffer; +class Depthbuffer; +class Stencilbuffer; +class DepthStencilbuffer; + +class Framebuffer +{ + public: + Framebuffer(); + + virtual ~Framebuffer(); + + void setColorbuffer(GLenum type, GLuint colorbuffer); + void setDepthbuffer(GLenum type, GLuint depthbuffer); + void setStencilbuffer(GLenum type, GLuint stencilbuffer); + + void detachTexture(GLuint texture); + void detachRenderbuffer(GLuint renderbuffer); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + unsigned int getRenderTargetSerial(); + unsigned int getDepthbufferSerial(); + unsigned int getStencilbufferSerial(); + + Renderbuffer *getColorbuffer(); + Renderbuffer *getDepthbuffer(); + Renderbuffer *getStencilbuffer(); + Renderbuffer *getNullColorbuffer(); + + GLenum getColorbufferType(); + GLenum getDepthbufferType(); + GLenum getStencilbufferType(); + + GLuint getColorbufferHandle(); + GLuint getDepthbufferHandle(); + GLuint getStencilbufferHandle(); + + bool hasStencil(); + int getSamples(); + + virtual GLenum completeness(); + + protected: + GLenum mColorbufferType; + BindingPointer mColorbufferPointer; + + GLenum mDepthbufferType; + BindingPointer mDepthbufferPointer; + + GLenum mStencilbufferType; + BindingPointer mStencilbufferPointer; + + BindingPointer mNullColorbufferPointer; + + private: + DISALLOW_COPY_AND_ASSIGN(Framebuffer); + + Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const; +}; + +class DefaultFramebuffer : public Framebuffer +{ + public: + DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil); + + virtual GLenum completeness(); + + private: + DISALLOW_COPY_AND_ASSIGN(DefaultFramebuffer); +}; + +} + +#endif // LIBGLESV2_FRAMEBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp new file mode 100644 index 0000000000..c498f8a178 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HandleAllocator.cpp: Implements the gl::HandleAllocator class, which is used +// to allocate GL handles. + +#include "libGLESv2/HandleAllocator.h" + +#include "libGLESv2/main.h" + +namespace gl +{ + +HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1) +{ +} + +HandleAllocator::~HandleAllocator() +{ +} + +void HandleAllocator::setBaseHandle(GLuint value) +{ + ASSERT(mBaseValue == mNextValue); + mBaseValue = value; + mNextValue = value; +} + +GLuint HandleAllocator::allocate() +{ + if (mFreeValues.size()) + { + GLuint handle = mFreeValues.back(); + mFreeValues.pop_back(); + return handle; + } + return mNextValue++; +} + +void HandleAllocator::release(GLuint handle) +{ + if (handle == mNextValue - 1) + { + // Don't drop below base value + if(mNextValue > mBaseValue) + { + mNextValue--; + } + } + else + { + // Only free handles that we own - don't drop below the base value + if (handle >= mBaseValue) + { + mFreeValues.push_back(handle); + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h new file mode 100644 index 0000000000..a92e1684d4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HandleAllocator.h: Defines the gl::HandleAllocator class, which is used to +// allocate GL handles. + +#ifndef LIBGLESV2_HANDLEALLOCATOR_H_ +#define LIBGLESV2_HANDLEALLOCATOR_H_ + +#define GL_APICALL +#include + +#include + +#include "common/angleutils.h" + +namespace gl +{ + +class HandleAllocator +{ + public: + HandleAllocator(); + virtual ~HandleAllocator(); + + void setBaseHandle(GLuint value); + + GLuint allocate(); + void release(GLuint handle); + + private: + DISALLOW_COPY_AND_ASSIGN(HandleAllocator); + + GLuint mBaseValue; + GLuint mNextValue; + typedef std::vector HandleList; + HandleList mFreeValues; +}; + +} + +#endif // LIBGLESV2_HANDLEALLOCATOR_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp new file mode 100644 index 0000000000..3dc0aef3f1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp @@ -0,0 +1,473 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexDataManager.cpp: Defines the IndexDataManager, a class that +// runs the Buffer translation process for index buffers. + +#include "libGLESv2/IndexDataManager.h" + +#include "common/debug.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/main.h" + +namespace gl +{ +unsigned int IndexBuffer::mCurrentSerial = 1; + +IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device) +{ + mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16); + + if (context->supports32bitIndices()) + { + mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32); + + if (!mStreamingBufferInt) + { + // Don't leave it in a half-initialized state + delete mStreamingBufferShort; + mStreamingBufferShort = NULL; + } + } + else + { + mStreamingBufferInt = NULL; + } + + if (!mStreamingBufferShort) + { + ERR("Failed to allocate the streaming index buffer(s)."); + } + + mCountingBuffer = NULL; +} + +IndexDataManager::~IndexDataManager() +{ + delete mStreamingBufferShort; + delete mStreamingBufferInt; + delete mCountingBuffer; +} + +void convertIndices(GLenum type, const void *input, GLsizei count, void *output) +{ + if (type == GL_UNSIGNED_BYTE) + { + const GLubyte *in = static_cast(input); + GLushort *out = static_cast(output); + + for (GLsizei i = 0; i < count; i++) + { + out[i] = in[i]; + } + } + else if (type == GL_UNSIGNED_INT) + { + memcpy(output, input, count * sizeof(GLuint)); + } + else if (type == GL_UNSIGNED_SHORT) + { + memcpy(output, input, count * sizeof(GLushort)); + } + else UNREACHABLE(); +} + +template +void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) +{ + *minIndex = indices[0]; + *maxIndex = indices[0]; + + for (GLsizei i = 0; i < count; i++) + { + if (*minIndex > indices[i]) *minIndex = indices[i]; + if (*maxIndex < indices[i]) *maxIndex = indices[i]; + } +} + +void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) +{ + if (type == GL_UNSIGNED_BYTE) + { + computeRange(static_cast(indices), count, minIndex, maxIndex); + } + else if (type == GL_UNSIGNED_INT) + { + computeRange(static_cast(indices), count, minIndex, maxIndex); + } + else if (type == GL_UNSIGNED_SHORT) + { + computeRange(static_cast(indices), count, minIndex, maxIndex); + } + else UNREACHABLE(); +} + +GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) +{ + if (!mStreamingBufferShort) + { + return GL_OUT_OF_MEMORY; + } + + D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16; + intptr_t offset = reinterpret_cast(indices); + bool alignedOffset = false; + + if (buffer != NULL) + { + switch (type) + { + case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; + case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; + case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; + default: UNREACHABLE(); alignedOffset = false; + } + + if (typeSize(type) * count + offset > static_cast(buffer->size())) + { + return GL_INVALID_OPERATION; + } + + indices = static_cast(buffer->data()) + offset; + } + + StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; + + StaticIndexBuffer *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL; + IndexBuffer *indexBuffer = streamingBuffer; + UINT streamOffset = 0; + + if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset) + { + indexBuffer = staticBuffer; + streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex); + + if (streamOffset == -1) + { + streamOffset = (offset / typeSize(type)) * indexSize(format); + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); + staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset); + } + } + else + { + int convertCount = count; + + if (staticBuffer) + { + if (staticBuffer->size() == 0 && alignedOffset) + { + indexBuffer = staticBuffer; + convertCount = buffer->size() / typeSize(type); + } + else + { + buffer->invalidateStaticData(); + staticBuffer = NULL; + } + } + + void *output = NULL; + + if (indexBuffer) + { + indexBuffer->reserveSpace(convertCount * indexSize(format), type); + output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset); + } + + if (output == NULL) + { + ERR("Failed to map index buffer."); + return GL_OUT_OF_MEMORY; + } + + convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output); + indexBuffer->unmap(); + + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); + + if (staticBuffer) + { + streamOffset = (offset / typeSize(type)) * indexSize(format); + staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset); + } + } + + translated->indexBuffer = indexBuffer->getBuffer(); + translated->serial = indexBuffer->getSerial(); + translated->startIndex = streamOffset / indexSize(format); + + if (buffer) + { + buffer->promoteStaticUsage(count * typeSize(type)); + } + + return GL_NO_ERROR; +} + +std::size_t IndexDataManager::indexSize(D3DFORMAT format) const +{ + return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short); +} + +std::size_t IndexDataManager::typeSize(GLenum type) const +{ + switch (type) + { + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + default: UNREACHABLE(); return sizeof(GLushort); + } +} + +StaticIndexBuffer *IndexDataManager::getCountingIndices(GLsizei count) +{ + if (count <= 65536) // 16-bit indices + { + const unsigned int spaceNeeded = count * sizeof(unsigned short); + + if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded) + { + delete mCountingBuffer; + mCountingBuffer = new StaticIndexBuffer(mDevice); + mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT); + + UINT offset; + unsigned short *data = static_cast(mCountingBuffer->map(spaceNeeded, &offset)); + + if (data) + { + for(int i = 0; i < count; i++) + { + data[i] = i; + } + + mCountingBuffer->unmap(); + } + } + } + else if (mStreamingBufferInt) // 32-bit indices supported + { + const unsigned int spaceNeeded = count * sizeof(unsigned int); + + if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded) + { + delete mCountingBuffer; + mCountingBuffer = new StaticIndexBuffer(mDevice); + mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_INT); + + UINT offset; + unsigned int *data = static_cast(mCountingBuffer->map(spaceNeeded, &offset)); + + if (data) + { + for(int i = 0; i < count; i++) + { + data[i] = i; + } + + mCountingBuffer->unmap(); + } + } + } + else return NULL; + + return mCountingBuffer; +} + +IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL) +{ + if (size > 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating an index buffer of size %lu.", size); + } + } +} + +IndexBuffer::~IndexBuffer() +{ + if (mIndexBuffer) + { + mIndexBuffer->Release(); + } +} + +IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const +{ + return mIndexBuffer; +} + +unsigned int IndexBuffer::getSerial() const +{ + return mSerial; +} + +unsigned int IndexBuffer::issueSerial() +{ + return mCurrentSerial++; +} + +void IndexBuffer::unmap() +{ + if (mIndexBuffer) + { + mIndexBuffer->Unlock(); + } +} + +StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format) +{ + mWritePosition = 0; +} + +StreamingIndexBuffer::~StreamingIndexBuffer() +{ +} + +void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset) +{ + void *mapPtr = NULL; + + if (mIndexBuffer) + { + HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE); + + if (FAILED(result)) + { + ERR(" Lock failed with error 0x%08x", result); + return NULL; + } + + *offset = mWritePosition; + mWritePosition += requiredSpace; + } + + return mapPtr; +} + +void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type) +{ + if (requiredSpace > mBufferSize) + { + if (mIndexBuffer) + { + mIndexBuffer->Release(); + mIndexBuffer = NULL; + } + + mBufferSize = std::max(requiredSpace, 2 * mBufferSize); + + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } + + mWritePosition = 0; + } + else if (mWritePosition + requiredSpace > mBufferSize) // Recycle + { + void *dummy; + mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + mIndexBuffer->Unlock(); + + mWritePosition = 0; + } +} + +StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN) +{ + mCacheType = GL_NONE; +} + +StaticIndexBuffer::~StaticIndexBuffer() +{ +} + +void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset) +{ + void *mapPtr = NULL; + + if (mIndexBuffer) + { + HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0); + + if (FAILED(result)) + { + ERR(" Lock failed with error 0x%08x", result); + return NULL; + } + + *offset = 0; + } + + return mapPtr; +} + +void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type) +{ + if (!mIndexBuffer && mBufferSize == 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } + + mBufferSize = requiredSpace; + mCacheType = type; + } + else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type) + { + // Already allocated + } + else UNREACHABLE(); // Static index buffers can't be resized +} + +bool StaticIndexBuffer::lookupType(GLenum type) +{ + return mCacheType == type; +} + +UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex) +{ + IndexRange range = {offset, count}; + + std::map::iterator res = mCache.find(range); + + if (res == mCache.end()) + { + return -1; + } + + *minIndex = res->second.minIndex; + *maxIndex = res->second.maxIndex; + return res->second.streamOffset; +} + +void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset) +{ + IndexRange indexRange = {offset, count}; + IndexResult indexResult = {minIndex, maxIndex, streamOffset}; + mCache[indexRange] = indexResult; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/IndexDataManager.h b/src/3rdparty/angle/src/libGLESv2/IndexDataManager.h new file mode 100644 index 0000000000..c1d4168315 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/IndexDataManager.h @@ -0,0 +1,149 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// IndexDataManager.h: Defines the IndexDataManager, a class that +// runs the Buffer translation process for index buffers. + +#ifndef LIBGLESV2_INDEXDATAMANAGER_H_ +#define LIBGLESV2_INDEXDATAMANAGER_H_ + +#include +#include + +#define GL_APICALL +#include + +#include "libGLESv2/Context.h" + +namespace +{ + enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; +} + +namespace gl +{ + +struct TranslatedIndexData +{ + UINT minIndex; + UINT maxIndex; + UINT startIndex; + + IDirect3DIndexBuffer9 *indexBuffer; + unsigned int serial; +}; + +class IndexBuffer +{ + public: + IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format); + virtual ~IndexBuffer(); + + UINT size() const { return mBufferSize; } + virtual void *map(UINT requiredSpace, UINT *offset) = 0; + void unmap(); + virtual void reserveSpace(UINT requiredSpace, GLenum type) = 0; + + IDirect3DIndexBuffer9 *getBuffer() const; + unsigned int getSerial() const; + + protected: + IDirect3DDevice9 *const mDevice; + + IDirect3DIndexBuffer9 *mIndexBuffer; + UINT mBufferSize; + + unsigned int mSerial; + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; + + private: + DISALLOW_COPY_AND_ASSIGN(IndexBuffer); +}; + +class StreamingIndexBuffer : public IndexBuffer +{ + public: + StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format); + ~StreamingIndexBuffer(); + + virtual void *map(UINT requiredSpace, UINT *offset); + virtual void reserveSpace(UINT requiredSpace, GLenum type); + + private: + UINT mWritePosition; +}; + +class StaticIndexBuffer : public IndexBuffer +{ + public: + explicit StaticIndexBuffer(IDirect3DDevice9 *device); + ~StaticIndexBuffer(); + + virtual void *map(UINT requiredSpace, UINT *offset); + virtual void reserveSpace(UINT requiredSpace, GLenum type); + + bool lookupType(GLenum type); + UINT lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex); // Returns the offset into the index buffer, or -1 if not found + void addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset); + + private: + GLenum mCacheType; + + struct IndexRange + { + intptr_t offset; + GLsizei count; + + bool operator<(const IndexRange& rhs) const + { + if (offset != rhs.offset) + { + return offset < rhs.offset; + } + if (count != rhs.count) + { + return count < rhs.count; + } + return false; + } + }; + + struct IndexResult + { + UINT minIndex; + UINT maxIndex; + UINT streamOffset; + }; + + std::map mCache; +}; + +class IndexDataManager +{ + public: + IndexDataManager(Context *context, IDirect3DDevice9 *evice); + virtual ~IndexDataManager(); + + GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated); + StaticIndexBuffer *getCountingIndices(GLsizei count); + + private: + DISALLOW_COPY_AND_ASSIGN(IndexDataManager); + + std::size_t typeSize(GLenum type) const; + std::size_t indexSize(D3DFORMAT format) const; + + IDirect3DDevice9 *const mDevice; + + StreamingIndexBuffer *mStreamingBufferShort; + StreamingIndexBuffer *mStreamingBufferInt; + StaticIndexBuffer *mCountingBuffer; +}; + +} + +#endif // LIBGLESV2_INDEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Program.cpp b/src/3rdparty/angle/src/libGLESv2/Program.cpp new file mode 100644 index 0000000000..5f53a1f581 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Program.cpp @@ -0,0 +1,528 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Program.cpp: Implements the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" + +#include "common/debug.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/utilities.h" + +#include + +namespace gl +{ +const char * const g_fakepath = "C:\\fakepath"; + +AttributeBindings::AttributeBindings() +{ +} + +AttributeBindings::~AttributeBindings() +{ +} + +InfoLog::InfoLog() : mInfoLog(NULL) +{ +} + +InfoLog::~InfoLog() +{ + delete[] mInfoLog; +} + + +int InfoLog::getLength() const +{ + if (!mInfoLog) + { + return 0; + } + else + { + return strlen(mInfoLog) + 1; + } +} + +void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + int index = 0; + + if (bufSize > 0) + { + if (mInfoLog) + { + index = std::min(bufSize - 1, (int)strlen(mInfoLog)); + memcpy(infoLog, mInfoLog, index); + } + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +// append a santized message to the program info log. +// The D3D compiler includes a fake file path in some of the warning or error +// messages, so lets remove all occurrences of this fake file path from the log. +void InfoLog::appendSanitized(const char *message) +{ + std::string msg(message); + + size_t found; + do + { + found = msg.find(g_fakepath); + if (found != std::string::npos) + { + msg.erase(found, strlen(g_fakepath)); + } + } + while (found != std::string::npos); + + append("%s\n", msg.c_str()); +} + +void InfoLog::append(const char *format, ...) +{ + if (!format) + { + return; + } + + char info[1024]; + + va_list vararg; + va_start(vararg, format); + vsnprintf(info, sizeof(info), format, vararg); + va_end(vararg); + + size_t infoLength = strlen(info); + + if (!mInfoLog) + { + mInfoLog = new char[infoLength + 1]; + strcpy(mInfoLog, info); + } + else + { + size_t logLength = strlen(mInfoLog); + char *newLog = new char[logLength + infoLength + 1]; + strcpy(newLog, mInfoLog); + strcpy(newLog + logLength, info); + + delete[] mInfoLog; + mInfoLog = newLog; + } +} + +void InfoLog::reset() +{ + if (mInfoLog) + { + delete [] mInfoLog; + mInfoLog = NULL; + } +} + +Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle) +{ + mFragmentShader = NULL; + mVertexShader = NULL; + mProgramBinary.set(NULL); + mDeleteStatus = false; + mLinked = false; + mRefCount = 0; +} + +Program::~Program() +{ + unlink(true); + + if (mVertexShader != NULL) + { + mVertexShader->release(); + } + + if (mFragmentShader != NULL) + { + mFragmentShader->release(); + } +} + +bool Program::attachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader) + { + return false; + } + + mVertexShader = (VertexShader*)shader; + mVertexShader->addRef(); + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader) + { + return false; + } + + mFragmentShader = (FragmentShader*)shader; + mFragmentShader->addRef(); + } + else UNREACHABLE(); + + return true; +} + +bool Program::detachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader != shader) + { + return false; + } + + mVertexShader->release(); + mVertexShader = NULL; + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader != shader) + { + return false; + } + + mFragmentShader->release(); + mFragmentShader = NULL; + } + else UNREACHABLE(); + + return true; +} + +int Program::getAttachedShadersCount() const +{ + return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0); +} + +void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) +{ + if (index < MAX_VERTEX_ATTRIBS) + { + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mAttributeBinding[i].erase(name); + } + + mAttributeBinding[index].insert(name); + } +} + +void Program::bindAttributeLocation(GLuint index, const char *name) +{ + mAttributeBindings.bindAttributeLocation(index, name); +} + +// Links the HLSL code of the vertex and pixel shader by matching up their varyings, +// compiling them into binaries, determining the attribute mappings, and collecting +// a list of uniforms +bool Program::link() +{ + unlink(false); + + mInfoLog.reset(); + + mProgramBinary.set(new ProgramBinary()); + mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader); + + return mLinked; +} + +int AttributeBindings::getAttributeBinding(const std::string &name) const +{ + for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) + { + if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) + { + return location; + } + } + + return -1; +} + +// Returns the program object to an unlinked state, before re-linking, or at destruction +void Program::unlink(bool destroy) +{ + if (destroy) // Object being destructed + { + if (mFragmentShader) + { + mFragmentShader->release(); + mFragmentShader = NULL; + } + + if (mVertexShader) + { + mVertexShader->release(); + mVertexShader = NULL; + } + } + + mProgramBinary.set(NULL); + mLinked = false; +} + +bool Program::isLinked() +{ + return mLinked; +} + +ProgramBinary* Program::getProgramBinary() +{ + return mProgramBinary.get(); +} + +bool Program::setProgramBinary(const void *binary, GLsizei length) +{ + unlink(false); + + mInfoLog.reset(); + + mProgramBinary.set(new ProgramBinary()); + mLinked = mProgramBinary->load(mInfoLog, binary, length); + if (!mLinked) + { + mProgramBinary.set(NULL); + } + + return mLinked; +} + +void Program::release() +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteProgram(mHandle); + } +} + +void Program::addRef() +{ + mRefCount++; +} + +unsigned int Program::getRefCount() const +{ + return mRefCount; +} + +GLint Program::getProgramBinaryLength() const +{ + ProgramBinary *programBinary = mProgramBinary.get(); + if (programBinary) + { + return programBinary->getLength(); + } + else + { + return 0; + } +} + +int Program::getInfoLogLength() const +{ + return mInfoLog.getLength(); +} + +void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + return mInfoLog.getLog(bufSize, length, infoLog); +} + +void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) +{ + int total = 0; + + if (mVertexShader) + { + if (total < maxCount) + { + shaders[total] = mVertexShader->getHandle(); + } + + total++; + } + + if (mFragmentShader) + { + if (total < maxCount) + { + shaders[total] = mFragmentShader->getHandle(); + } + + total++; + } + + if (count) + { + *count = total; + } +} + +void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + programBinary->getActiveAttribute(index, bufsize, length, size, type, name); + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *type = GL_NONE; + *size = 1; + } +} + +GLint Program::getActiveAttributeCount() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveAttributeCount(); + } + else + { + return 0; + } +} + +GLint Program::getActiveAttributeMaxLength() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveAttributeMaxLength(); + } + else + { + return 0; + } +} + +void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveUniform(index, bufsize, length, size, type, name); + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *size = 0; + *type = GL_NONE; + } +} + +GLint Program::getActiveUniformCount() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveUniformCount(); + } + else + { + return 0; + } +} + +GLint Program::getActiveUniformMaxLength() +{ + ProgramBinary *programBinary = getProgramBinary(); + if (programBinary) + { + return programBinary->getActiveUniformMaxLength(); + } + else + { + return 0; + } +} + +void Program::flagForDeletion() +{ + mDeleteStatus = true; +} + +bool Program::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +void Program::validate() +{ + mInfoLog.reset(); + + ProgramBinary *programBinary = getProgramBinary(); + if (isLinked() && programBinary) + { + programBinary->validate(mInfoLog); + } + else + { + mInfoLog.append("Program has not been successfully linked."); + } +} + +bool Program::isValidated() const +{ + ProgramBinary *programBinary = mProgramBinary.get(); + if (programBinary) + { + return programBinary->isValidated(); + } + else + { + return false; + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Program.h b/src/3rdparty/angle/src/libGLESv2/Program.h new file mode 100644 index 0000000000..1c4716bfe8 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Program.h @@ -0,0 +1,121 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Program.h: Defines the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#ifndef LIBGLESV2_PROGRAM_H_ +#define LIBGLESV2_PROGRAM_H_ + +#include +#include + +#include "libGLESv2/Shader.h" +#include "libGLESv2/Context.h" + +namespace gl +{ +class ResourceManager; +class FragmentShader; +class VertexShader; + +extern const char * const g_fakepath; + +class AttributeBindings +{ + public: + AttributeBindings(); + ~AttributeBindings(); + + void bindAttributeLocation(GLuint index, const char *name); + int getAttributeBinding(const std::string &name) const; + + private: + std::set mAttributeBinding[MAX_VERTEX_ATTRIBS]; +}; + +class InfoLog +{ + public: + InfoLog(); + ~InfoLog(); + + int getLength() const; + void getLog(GLsizei bufSize, GLsizei *length, char *infoLog); + + void appendSanitized(const char *message); + void append(const char *info, ...); + void reset(); + private: + DISALLOW_COPY_AND_ASSIGN(InfoLog); + char *mInfoLog; +}; + +class Program +{ + public: + Program(ResourceManager *manager, GLuint handle); + + ~Program(); + + bool attachShader(Shader *shader); + bool detachShader(Shader *shader); + int getAttachedShadersCount() const; + + void bindAttributeLocation(GLuint index, const char *name); + + bool link(); + bool isLinked(); + bool setProgramBinary(const void *binary, GLsizei length); + ProgramBinary *getProgramBinary(); + + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); + void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); + + void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveAttributeCount(); + GLint getActiveAttributeMaxLength(); + + void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveUniformCount(); + GLint getActiveUniformMaxLength(); + + void addRef(); + void release(); + unsigned int getRefCount() const; + void flagForDeletion(); + bool isFlaggedForDeletion() const; + + void validate(); + bool isValidated() const; + + GLint getProgramBinaryLength() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Program); + + void unlink(bool destroy = false); + + FragmentShader *mFragmentShader; + VertexShader *mVertexShader; + + AttributeBindings mAttributeBindings; + + BindingPointer mProgramBinary; + bool mLinked; + bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use + + unsigned int mRefCount; + + ResourceManager *mResourceManager; + const GLuint mHandle; + + InfoLog mInfoLog; +}; +} + +#endif // LIBGLESV2_PROGRAM_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp new file mode 100644 index 0000000000..b3f5e3b867 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp @@ -0,0 +1,2794 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Program.cpp: Implements the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#include "libGLESv2/BinaryStream.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" + +#include "common/debug.h" +#include "common/version.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/utilities.h" + +#include + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#endif + +namespace gl +{ +std::string str(int i) +{ + char buffer[20]; + snprintf(buffer, sizeof(buffer), "%d", i); + return buffer; +} + +Uniform::Uniform(GLenum type, const std::string &_name, unsigned int arraySize) + : type(type), _name(_name), name(ProgramBinary::undecorateUniform(_name)), arraySize(arraySize) +{ + int bytes = UniformInternalSize(type) * arraySize; + data = new unsigned char[bytes]; + memset(data, 0, bytes); + dirty = true; +} + +Uniform::~Uniform() +{ + delete[] data; +} + +bool Uniform::isArray() +{ + size_t dot = _name.find_last_of('.'); + if (dot == std::string::npos) dot = -1; + + return _name.compare(dot + 1, dot + 4, "ar_") == 0; +} + +UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index) + : name(ProgramBinary::undecorateUniform(_name)), element(element), index(index) +{ +} + +unsigned int ProgramBinary::mCurrentSerial = 1; + +ProgramBinary::ProgramBinary() : RefCountObject(0), mSerial(issueSerial()) +{ + mDevice = getDevice(); + + mPixelExecutable = NULL; + mVertexExecutable = NULL; + mConstantTablePS = NULL; + mConstantTableVS = NULL; + + mValidated = false; + + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + mSemanticIndex[index] = -1; + } + + for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++) + { + mSamplersPS[index].active = false; + } + + for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++) + { + mSamplersVS[index].active = false; + } + + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + + mDxDepthRangeLocation = -1; + mDxDepthLocation = -1; + mDxCoordLocation = -1; + mDxHalfPixelSizeLocation = -1; + mDxFrontCCWLocation = -1; + mDxPointsOrLinesLocation = -1; +} + +ProgramBinary::~ProgramBinary() +{ + if (mPixelExecutable) + { + mPixelExecutable->Release(); + } + + if (mVertexExecutable) + { + mVertexExecutable->Release(); + } + + delete mConstantTablePS; + delete mConstantTableVS; + + while (!mUniforms.empty()) + { + delete mUniforms.back(); + mUniforms.pop_back(); + } +} + +unsigned int ProgramBinary::getSerial() const +{ + return mSerial; +} + +unsigned int ProgramBinary::issueSerial() +{ + return mCurrentSerial++; +} + +IDirect3DPixelShader9 *ProgramBinary::getPixelShader() +{ + return mPixelExecutable; +} + +IDirect3DVertexShader9 *ProgramBinary::getVertexShader() +{ + return mVertexExecutable; +} + +GLuint ProgramBinary::getAttributeLocation(const char *name) +{ + if (name) + { + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + if (mLinkedAttribute[index].name == std::string(name)) + { + return index; + } + } + } + + return -1; +} + +int ProgramBinary::getSemanticIndex(int attributeIndex) +{ + ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); + + return mSemanticIndex[attributeIndex]; +} + +// Returns one more than the highest sampler index used. +GLint ProgramBinary::getUsedSamplerRange(SamplerType type) +{ + switch (type) + { + case SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; + } +} + +bool ProgramBinary::usesPointSize() const +{ + return mUsesPointSize; +} + +// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler +// index (0-15 for the pixel shader and 0-3 for the vertex shader). +GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex) +{ + GLint logicalTextureUnit = -1; + + switch (type) + { + case SAMPLER_PIXEL: + ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + + if (mSamplersPS[samplerIndex].active) + { + logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; + } + break; + case SAMPLER_VERTEX: + ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + + if (mSamplersVS[samplerIndex].active) + { + logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; + } + break; + default: UNREACHABLE(); + } + + if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)getContext()->getMaximumCombinedTextureImageUnits()) + { + return logicalTextureUnit; + } + + return -1; +} + +// Returns the texture type for a given Direct3D 9 sampler type and +// index (0-15 for the pixel shader and 0-3 for the vertex shader). +TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) +{ + switch (type) + { + case SAMPLER_PIXEL: + ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0])); + ASSERT(mSamplersPS[samplerIndex].active); + return mSamplersPS[samplerIndex].textureType; + case SAMPLER_VERTEX: + ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0])); + ASSERT(mSamplersVS[samplerIndex].active); + return mSamplersVS[samplerIndex].textureType; + default: UNREACHABLE(); + } + + return TEXTURE_2D; +} + +GLint ProgramBinary::getUniformLocation(std::string name) +{ + unsigned int subscript = 0; + + // Strip any trailing array operator and retrieve the subscript + size_t open = name.find_last_of('['); + size_t close = name.find_last_of(']'); + if (open != std::string::npos && close == name.length() - 1) + { + subscript = atoi(name.substr(open + 1).c_str()); + name.erase(open); + } + + unsigned int numUniforms = mUniformIndex.size(); + for (unsigned int location = 0; location < numUniforms; location++) + { + if (mUniformIndex[location].name == name && + mUniformIndex[location].element == subscript) + { + return location; + } + } + + return -1; +} + +bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = 0; + target[2] = 0; + target[3] = 0; + target += 4; + v += 1; + } + } + else if (targetUniform->type == GL_BOOL) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element; + + for (int i = 0; i < count; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT_VEC2) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = v[1]; + target[2] = 0; + target[3] = 0; + target += 4; + v += 2; + } + } + else if (targetUniform->type == GL_BOOL_VEC2) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2; + + for (int i = 0; i < count * 2; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT_VEC3) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + target[0] = v[0]; + target[1] = v[1]; + target[2] = v[2]; + target[3] = 0; + target += 4; + v += 3; + } + } + else if (targetUniform->type == GL_BOOL_VEC3) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3; + + for (int i = 0; i < count * 3; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_FLOAT_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4, + v, 4 * sizeof(GLfloat) * count); + } + else if (targetUniform->type == GL_BOOL_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count * 4; ++i) + { + if (v[i] == 0.0f) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +template +void transposeMatrix(T *target, const GLfloat *value) +{ + int copyWidth = std::min(targetWidth, srcWidth); + int copyHeight = std::min(targetHeight, srcHeight); + + for (int x = 0; x < copyWidth; x++) + { + for (int y = 0; y < copyHeight; y++) + { + target[x * targetWidth + y] = (T)value[y * srcWidth + x]; + } + } + // clear unfilled right side + for (int y = 0; y < copyHeight; y++) + { + for (int x = srcWidth; x < targetWidth; x++) + { + target[y * targetWidth + x] = (T)0; + } + } + // clear unfilled bottom. + for (int y = srcHeight; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + target[y * targetWidth + x] = (T)0; + } + } +} + +bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type != GL_FLOAT_MAT2) + { + return false; + } + + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8; + for (int i = 0; i < count; i++) + { + transposeMatrix(target, value); + target += 8; + value += 4; + } + + return true; +} + +bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type != GL_FLOAT_MAT3) + { + return false; + } + + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12; + for (int i = 0; i < count; i++) + { + transposeMatrix(target, value); + target += 12; + value += 9; + } + + return true; +} + + +bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type != GL_FLOAT_MAT4) + { + return false; + } + + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16); + for (int i = 0; i < count; i++) + { + transposeMatrix(target, value); + target += 16; + value += 16; + } + + return true; +} + +bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT || + targetUniform->type == GL_SAMPLER_2D || + targetUniform->type == GL_SAMPLER_CUBE) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint), + v, sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element; + + for (int i = 0; i < count; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT_VEC2) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2, + v, 2 * sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL_VEC2) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 2; + + for (int i = 0; i < count * 2; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT_VEC3) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3, + v, 3 * sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL_VEC3) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 3; + + for (int i = 0; i < count * 3; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + targetUniform->dirty = true; + + if (targetUniform->type == GL_INT_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + + memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4, + v, 4 * sizeof(GLint) * count); + } + else if (targetUniform->type == GL_BOOL_VEC4) + { + int arraySize = targetUniform->arraySize; + + if (arraySize == 1 && count > 1) + return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION + + count = std::min(arraySize - (int)mUniformIndex[location].element, count); + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * 4; + + for (int i = 0; i < count * 4; ++i) + { + if (v[i] == 0) + { + boolParams[i] = GL_FALSE; + } + else + { + boolParams[i] = GL_TRUE; + } + } + } + else + { + return false; + } + + return true; +} + +bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + return false; + } + } + + switch (targetUniform->type) + { + case GL_FLOAT_MAT2: + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); + break; + case GL_FLOAT_MAT3: + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); + break; + case GL_FLOAT_MAT4: + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); + break; + default: + { + unsigned int count = UniformExternalComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); + + switch (UniformComponentType(targetUniform->type)) + { + case GL_BOOL: + { + GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f; + } + } + break; + case GL_FLOAT: + memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLfloat), + count * sizeof(GLfloat)); + break; + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (float)intParams[i]; + } + } + break; + default: UNREACHABLE(); + } + } + } + + return true; +} + +bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params) +{ + if (location < 0 || location >= (int)mUniformIndex.size()) + { + return false; + } + + Uniform *targetUniform = mUniforms[mUniformIndex[location].index]; + + // sized queries -- ensure the provided buffer is large enough + if (bufSize) + { + int requiredBytes = UniformExternalSize(targetUniform->type); + if (*bufSize < requiredBytes) + { + return false; + } + } + + switch (targetUniform->type) + { + case GL_FLOAT_MAT2: + { + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8); + } + break; + case GL_FLOAT_MAT3: + { + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12); + } + break; + case GL_FLOAT_MAT4: + { + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16); + } + break; + default: + { + unsigned int count = UniformExternalComponentCount(targetUniform->type); + unsigned int internalCount = UniformInternalComponentCount(targetUniform->type); + + switch (UniformComponentType(targetUniform->type)) + { + case GL_BOOL: + { + GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (GLint)boolParams[i]; + } + } + break; + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * internalCount; + + for (unsigned int i = 0; i < count; ++i) + { + params[i] = (GLint)floatParams[i]; + } + } + break; + case GL_INT: + memcpy(params, targetUniform->data + mUniformIndex[location].element * internalCount * sizeof(GLint), + count * sizeof(GLint)); + break; + default: UNREACHABLE(); + } + } + } + + return true; +} + +void ProgramBinary::dirtyAllUniforms() +{ + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + mUniforms[index]->dirty = true; + } +} + +// Applies all the uniforms set for this program object to the Direct3D 9 device +void ProgramBinary::applyUniforms() +{ + for (std::vector::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub) { + Uniform *targetUniform = *ub; + + if (targetUniform->dirty) + { + int arraySize = targetUniform->arraySize; + GLfloat *f = (GLfloat*)targetUniform->data; + GLint *i = (GLint*)targetUniform->data; + GLboolean *b = (GLboolean*)targetUniform->data; + + switch (targetUniform->type) + { + case GL_BOOL: applyUniformnbv(targetUniform, arraySize, 1, b); break; + case GL_BOOL_VEC2: applyUniformnbv(targetUniform, arraySize, 2, b); break; + case GL_BOOL_VEC3: applyUniformnbv(targetUniform, arraySize, 3, b); break; + case GL_BOOL_VEC4: applyUniformnbv(targetUniform, arraySize, 4, b); break; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: applyUniformnfv(targetUniform, f); break; + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + case GL_INT: applyUniform1iv(targetUniform, arraySize, i); break; + case GL_INT_VEC2: applyUniform2iv(targetUniform, arraySize, i); break; + case GL_INT_VEC3: applyUniform3iv(targetUniform, arraySize, i); break; + case GL_INT_VEC4: applyUniform4iv(targetUniform, arraySize, i); break; + default: + UNREACHABLE(); + } + + targetUniform->dirty = false; + } + } +} + +// Compiles the HLSL code of the attached shaders into executable binaries +ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable) +{ + if (!hlsl) + { + return NULL; + } + + DWORD result = NOERROR; + UINT flags = 0; + std::string sourceText; + if (perfActive()) + { + flags |= D3DCOMPILE_DEBUG; +#ifdef NDEBUG + flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL; +#else + flags |= D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + std::string sourcePath = getTempPath(); + sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } + else + { + flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL; + sourceText = hlsl; + } + + // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. + // Try the default flags first and if compilation fails, try some alternatives. + const static UINT extraFlags[] = + { + 0, + D3DCOMPILE_AVOID_FLOW_CONTROL, + D3DCOMPILE_PREFER_FLOW_CONTROL + }; + + const static char * const extraFlagNames[] = + { + "default", + "avoid flow control", + "prefer flow control" + }; + + for (int i = 0; i < sizeof(extraFlags) / sizeof(UINT); ++i) + { + ID3D10Blob *errorMessage = NULL; + ID3D10Blob *binary = NULL; + result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage); + + if (errorMessage) + { + const char *message = (const char*)errorMessage->GetBufferPointer(); + + infoLog.appendSanitized(message); + TRACE("\n%s", hlsl); + TRACE("\n%s", message); + + errorMessage->Release(); + errorMessage = NULL; + } + + if (SUCCEEDED(result)) + { + D3DConstantTable *table = new D3DConstantTable(binary->GetBufferPointer(), binary->GetBufferSize()); + if (table->error()) + { + delete table; + binary->Release(); + return NULL; + } + + *constantTable = table; + + return binary; + } + else + { + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY, (ID3D10Blob*) NULL); + } + + infoLog.append("Warning: D3D shader compilation failed with "); + infoLog.append(extraFlagNames[i]); + infoLog.append(" flags."); + if (i + 1 < sizeof(extraFlagNames) / sizeof(char*)) + { + infoLog.append(" Retrying with "); + infoLog.append(extraFlagNames[i + 1]); + infoLog.append(".\n"); + } + } + } + + return NULL; +} + +// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111 +// Returns the number of used varying registers, or -1 if unsuccesful +int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader) +{ + Context *context = getContext(); + const int maxVaryingVectors = context->getMaximumVaryingVectors(); + + for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + { + int n = VariableRowCount(varying->type) * varying->size; + int m = VariableColumnCount(varying->type); + bool success = false; + + if (m == 2 || m == 3 || m == 4) + { + for (int r = 0; r <= maxVaryingVectors - n && !success; r++) + { + bool available = true; + + for (int y = 0; y < n && available; y++) + { + for (int x = 0; x < m && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->reg = r; + varying->col = 0; + + for (int y = 0; y < n; y++) + { + for (int x = 0; x < m; x++) + { + packing[r + y][x] = &*varying; + } + } + + success = true; + } + } + + if (!success && m == 2) + { + for (int r = maxVaryingVectors - n; r >= 0 && !success; r--) + { + bool available = true; + + for (int y = 0; y < n && available; y++) + { + for (int x = 2; x < 4 && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->reg = r; + varying->col = 2; + + for (int y = 0; y < n; y++) + { + for (int x = 2; x < 4; x++) + { + packing[r + y][x] = &*varying; + } + } + + success = true; + } + } + } + } + else if (m == 1) + { + int space[4] = {0}; + + for (int y = 0; y < maxVaryingVectors; y++) + { + for (int x = 0; x < 4; x++) + { + space[x] += packing[y][x] ? 0 : 1; + } + } + + int column = 0; + + for (int x = 0; x < 4; x++) + { + if (space[x] >= n && space[x] < space[column]) + { + column = x; + } + } + + if (space[column] >= n) + { + for (int r = 0; r < maxVaryingVectors; r++) + { + if (!packing[r][column]) + { + varying->reg = r; + + for (int y = r; y < r + n; y++) + { + packing[y][column] = &*varying; + } + + break; + } + } + + varying->col = column; + + success = true; + } + } + else UNREACHABLE(); + + if (!success) + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + + return -1; + } + } + + // Return the number of used registers + int registers = 0; + + for (int r = 0; r < maxVaryingVectors; r++) + { + if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3]) + { + registers++; + } + } + + return registers; +} + +bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader) +{ + if (pixelHLSL.empty() || vertexHLSL.empty()) + { + return false; + } + + // Reset the varying register assignments + for (VaryingList::iterator fragVar = fragmentShader->mVaryings.begin(); fragVar != fragmentShader->mVaryings.end(); fragVar++) + { + fragVar->reg = -1; + fragVar->col = -1; + } + + for (VaryingList::iterator vtxVar = vertexShader->mVaryings.begin(); vtxVar != vertexShader->mVaryings.end(); vtxVar++) + { + vtxVar->reg = -1; + vtxVar->col = -1; + } + + // Map the varyings to the register file + const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL}; + int registers = packVaryings(infoLog, packing, fragmentShader); + + if (registers < 0) + { + return false; + } + + // Write the HLSL input/output declarations + Context *context = getContext(); + const bool sm3 = context->supportsShaderModel3(); + const int maxVaryingVectors = context->getMaximumVaryingVectors(); + + if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord) + { + infoLog.append("No varying registers left to support gl_FragCoord"); + + return false; + } + + for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++) + { + bool matched = false; + + for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++) + { + if (output->name == input->name) + { + if (output->type != input->type || output->size != input->size) + { + infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str()); + + return false; + } + + output->reg = input->reg; + output->col = input->col; + + matched = true; + break; + } + } + + if (!matched) + { + infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); + + return false; + } + } + + mUsesPointSize = vertexShader->mUsesPointSize; + std::string varyingSemantic = (mUsesPointSize && sm3) ? "COLOR" : "TEXCOORD"; + + vertexHLSL += "struct VS_INPUT\n" + "{\n"; + + int semanticIndex = 0; + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + switch (attribute->type) + { + case GL_FLOAT: vertexHLSL += " float "; break; + case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break; + case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break; + case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break; + case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break; + case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break; + case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break; + default: UNREACHABLE(); + } + + vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n"; + + semanticIndex += VariableRowCount(attribute->type); + } + + vertexHLSL += "};\n" + "\n" + "struct VS_OUTPUT\n" + "{\n" + " float4 gl_Position : POSITION;\n"; + + for (int r = 0; r < registers; r++) + { + int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1)); + + vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n"; + } + + if (fragmentShader->mUsesFragCoord) + { + vertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n"; + } + + if (vertexShader->mUsesPointSize && sm3) + { + vertexHLSL += " float gl_PointSize : PSIZE;\n"; + } + + vertexHLSL += "};\n" + "\n" + "VS_OUTPUT main(VS_INPUT input)\n" + "{\n"; + + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + vertexHLSL += " " + decorateAttribute(attribute->name) + " = "; + + if (VariableRowCount(attribute->type) > 1) // Matrix + { + vertexHLSL += "transpose"; + } + + vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n"; + } + + vertexHLSL += "\n" + " gl_main();\n" + "\n" + " VS_OUTPUT output;\n" + " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n" + " output.gl_Position.y = -(gl_Position.y + dx_HalfPixelSize.y * gl_Position.w);\n" + " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.gl_Position.w = gl_Position.w;\n"; + + if (vertexShader->mUsesPointSize && sm3) + { + vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; + } + + if (fragmentShader->mUsesFragCoord) + { + vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; + } + + for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++) + { + if (varying->reg >= 0) + { + for (int i = 0; i < varying->size; i++) + { + int rows = VariableRowCount(varying->type); + + for (int j = 0; j < rows; j++) + { + int r = varying->reg + i * rows + j; + vertexHLSL += " output.v" + str(r); + + bool sharedRegister = false; // Register used by multiple varyings + + for (int x = 0; x < 4; x++) + { + if (packing[r][x] && packing[r][x] != packing[r][0]) + { + sharedRegister = true; + break; + } + } + + if(sharedRegister) + { + vertexHLSL += "."; + + for (int x = 0; x < 4; x++) + { + if (packing[r][x] == &*varying) + { + switch(x) + { + case 0: vertexHLSL += "x"; break; + case 1: vertexHLSL += "y"; break; + case 2: vertexHLSL += "z"; break; + case 3: vertexHLSL += "w"; break; + } + } + } + } + + vertexHLSL += " = " + varying->name; + + if (varying->array) + { + vertexHLSL += "[" + str(i) + "]"; + } + + if (rows > 1) + { + vertexHLSL += "[" + str(j) + "]"; + } + + vertexHLSL += ";\n"; + } + } + } + } + + vertexHLSL += "\n" + " return output;\n" + "}\n"; + + pixelHLSL += "struct PS_INPUT\n" + "{\n"; + + for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + { + if (varying->reg >= 0) + { + for (int i = 0; i < varying->size; i++) + { + int rows = VariableRowCount(varying->type); + for (int j = 0; j < rows; j++) + { + std::string n = str(varying->reg + i * rows + j); + pixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n"; + } + } + } + else UNREACHABLE(); + } + + if (fragmentShader->mUsesFragCoord) + { + pixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n"; + if (sm3) { + pixelHLSL += " float2 dx_VPos : VPOS;\n"; + } + } + + if (fragmentShader->mUsesPointCoord && sm3) + { + pixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n"; + } + + if (fragmentShader->mUsesFrontFacing) + { + pixelHLSL += " float vFace : VFACE;\n"; + } + + pixelHLSL += "};\n" + "\n" + "struct PS_OUTPUT\n" + "{\n" + " float4 gl_Color[1] : COLOR;\n" + "};\n" + "\n" + "PS_OUTPUT main(PS_INPUT input)\n" + "{\n"; + + if (fragmentShader->mUsesFragCoord) + { + pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; + + if (sm3) + { + pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n" + " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n"; + } + else + { + // dx_Coord contains the viewport width/2, height/2, center.x and center.y. See Context::applyRenderTarget() + pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Coord.x + dx_Coord.z;\n" + " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_Coord.y + dx_Coord.w;\n"; + } + + pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n" + " gl_FragCoord.w = rhw;\n"; + } + + if (fragmentShader->mUsesPointCoord && sm3) + { + pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; + pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; + } + + if (fragmentShader->mUsesFrontFacing) + { + pixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n"; + } + + for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++) + { + if (varying->reg >= 0) + { + for (int i = 0; i < varying->size; i++) + { + int rows = VariableRowCount(varying->type); + for (int j = 0; j < rows; j++) + { + std::string n = str(varying->reg + i * rows + j); + pixelHLSL += " " + varying->name; + + if (varying->array) + { + pixelHLSL += "[" + str(i) + "]"; + } + + if (rows > 1) + { + pixelHLSL += "[" + str(j) + "]"; + } + + pixelHLSL += " = input.v" + n + ";\n"; + } + } + } + else UNREACHABLE(); + } + + pixelHLSL += "\n" + " gl_main();\n" + "\n" + " PS_OUTPUT output;\n" + " output.gl_Color[0] = gl_Color[0];\n" + "\n" + " return output;\n" + "}\n"; + + return true; +} + +bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length) +{ + BinaryInputStream stream(binary, length); + + int format = 0; + stream.read(&format); + if (format != GL_PROGRAM_BINARY_ANGLE) + { + infoLog.append("Invalid program binary format."); + return false; + } + + int version = 0; + stream.read(&version); + if (version != BUILD_REVISION) + { + infoLog.append("Invalid program binary version."); + return false; + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.read(&mLinkedAttribute[i].type); + std::string name; + stream.read(&name); + mLinkedAttribute[i].name = name; + stream.read(&mSemanticIndex[i]); + } + + for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + { + stream.read(&mSamplersPS[i].active); + stream.read(&mSamplersPS[i].logicalTextureUnit); + + int textureType; + stream.read(&textureType); + mSamplersPS[i].textureType = (TextureType) textureType; + } + + for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i) + { + stream.read(&mSamplersVS[i].active); + stream.read(&mSamplersVS[i].logicalTextureUnit); + + int textureType; + stream.read(&textureType); + mSamplersVS[i].textureType = (TextureType) textureType; + } + + stream.read(&mUsedVertexSamplerRange); + stream.read(&mUsedPixelSamplerRange); + + unsigned int size; + stream.read(&size); + if (stream.error()) + { + infoLog.append("Invalid program binary."); + return false; + } + + mUniforms.resize(size); + for (unsigned int i = 0; i < size; ++i) + { + GLenum type; + std::string _name; + unsigned int arraySize; + + stream.read(&type); + stream.read(&_name); + stream.read(&arraySize); + + mUniforms[i] = new Uniform(type, _name, arraySize); + + stream.read(&mUniforms[i]->ps.float4Index); + stream.read(&mUniforms[i]->ps.samplerIndex); + stream.read(&mUniforms[i]->ps.boolIndex); + stream.read(&mUniforms[i]->ps.registerCount); + + stream.read(&mUniforms[i]->vs.float4Index); + stream.read(&mUniforms[i]->vs.samplerIndex); + stream.read(&mUniforms[i]->vs.boolIndex); + stream.read(&mUniforms[i]->vs.registerCount); + } + + stream.read(&size); + if (stream.error()) + { + infoLog.append("Invalid program binary."); + return false; + } + + mUniformIndex.resize(size); + for (unsigned int i = 0; i < size; ++i) + { + stream.read(&mUniformIndex[i].name); + stream.read(&mUniformIndex[i].element); + stream.read(&mUniformIndex[i].index); + } + + stream.read(&mDxDepthRangeLocation); + stream.read(&mDxDepthLocation); + stream.read(&mDxCoordLocation); + stream.read(&mDxHalfPixelSizeLocation); + stream.read(&mDxFrontCCWLocation); + stream.read(&mDxPointsOrLinesLocation); + + unsigned int pixelShaderSize; + stream.read(&pixelShaderSize); + + unsigned int vertexShaderSize; + stream.read(&vertexShaderSize); + + const char *ptr = (const char*) binary + stream.offset(); + + const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr; + ptr += sizeof(GUID); + + D3DADAPTER_IDENTIFIER9 *currentIdentifier = getDisplay()->getAdapterIdentifier(); + if (memcmp(¤tIdentifier->DeviceIdentifier, binaryIdentifier, sizeof(GUID)) != 0) + { + infoLog.append("Invalid program binary."); + return false; + } + + const char *pixelShaderFunction = ptr; + ptr += pixelShaderSize; + + const char *vertexShaderFunction = ptr; + ptr += vertexShaderSize; + + mPixelExecutable = getDisplay()->createPixelShader(reinterpret_cast(pixelShaderFunction), pixelShaderSize); + if (!mPixelExecutable) + { + infoLog.append("Could not create pixel shader."); + return false; + } + + mVertexExecutable = getDisplay()->createVertexShader(reinterpret_cast(vertexShaderFunction), vertexShaderSize); + if (!mVertexExecutable) + { + infoLog.append("Could not create vertex shader."); + mPixelExecutable->Release(); + mPixelExecutable = NULL; + return false; + } + + return true; +} + +bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length) +{ + BinaryOutputStream stream; + + stream.write(GL_PROGRAM_BINARY_ANGLE); + stream.write(BUILD_REVISION); + + for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.write(mLinkedAttribute[i].type); + stream.write(mLinkedAttribute[i].name); + stream.write(mSemanticIndex[i]); + } + + for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) + { + stream.write(mSamplersPS[i].active); + stream.write(mSamplersPS[i].logicalTextureUnit); + stream.write((int) mSamplersPS[i].textureType); + } + + for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i) + { + stream.write(mSamplersVS[i].active); + stream.write(mSamplersVS[i].logicalTextureUnit); + stream.write((int) mSamplersVS[i].textureType); + } + + stream.write(mUsedVertexSamplerRange); + stream.write(mUsedPixelSamplerRange); + + stream.write(mUniforms.size()); + for (unsigned int i = 0; i < mUniforms.size(); ++i) + { + stream.write(mUniforms[i]->type); + stream.write(mUniforms[i]->_name); + stream.write(mUniforms[i]->arraySize); + + stream.write(mUniforms[i]->ps.float4Index); + stream.write(mUniforms[i]->ps.samplerIndex); + stream.write(mUniforms[i]->ps.boolIndex); + stream.write(mUniforms[i]->ps.registerCount); + + stream.write(mUniforms[i]->vs.float4Index); + stream.write(mUniforms[i]->vs.samplerIndex); + stream.write(mUniforms[i]->vs.boolIndex); + stream.write(mUniforms[i]->vs.registerCount); + } + + stream.write(mUniformIndex.size()); + for (unsigned int i = 0; i < mUniformIndex.size(); ++i) + { + stream.write(mUniformIndex[i].name); + stream.write(mUniformIndex[i].element); + stream.write(mUniformIndex[i].index); + } + + stream.write(mDxDepthRangeLocation); + stream.write(mDxDepthLocation); + stream.write(mDxCoordLocation); + stream.write(mDxHalfPixelSizeLocation); + stream.write(mDxFrontCCWLocation); + stream.write(mDxPointsOrLinesLocation); + + UINT pixelShaderSize; + HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize); + ASSERT(SUCCEEDED(result)); + stream.write(pixelShaderSize); + + UINT vertexShaderSize; + result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize); + ASSERT(SUCCEEDED(result)); + stream.write(vertexShaderSize); + + D3DADAPTER_IDENTIFIER9 *identifier = getDisplay()->getAdapterIdentifier(); + + GLsizei streamLength = stream.length(); + const void *streamData = stream.data(); + + GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize; + if (totalLength > bufSize) + { + if (length) + { + *length = 0; + } + + return false; + } + + if (binary) + { + char *ptr = (char*) binary; + + memcpy(ptr, streamData, streamLength); + ptr += streamLength; + + memcpy(ptr, &identifier->DeviceIdentifier, sizeof(GUID)); + ptr += sizeof(GUID); + + result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize); + ASSERT(SUCCEEDED(result)); + ptr += pixelShaderSize; + + result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize); + ASSERT(SUCCEEDED(result)); + ptr += vertexShaderSize; + + ASSERT(ptr - totalLength == binary); + } + + if (length) + { + *length = totalLength; + } + + return true; +} + +GLint ProgramBinary::getLength() +{ + GLint length; + if (save(NULL, INT_MAX, &length)) + { + return length; + } + else + { + return 0; + } +} + +bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) +{ + if (!fragmentShader || !fragmentShader->isCompiled()) + { + return false; + } + + if (!vertexShader || !vertexShader->isCompiled()) + { + return false; + } + + std::string pixelHLSL = fragmentShader->getHLSL(); + std::string vertexHLSL = vertexShader->getHLSL(); + + if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader)) + { + return false; + } + + Context *context = getContext(); + const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0"; + const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0"; + + ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS); + ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS); + + if (vertexBinary && pixelBinary) + { + mVertexExecutable = getDisplay()->createVertexShader((DWORD*)vertexBinary->GetBufferPointer(), vertexBinary->GetBufferSize()); + if (!mVertexExecutable) + { + return error(GL_OUT_OF_MEMORY, false); + } + + mPixelExecutable = getDisplay()->createPixelShader((DWORD*)pixelBinary->GetBufferPointer(), pixelBinary->GetBufferSize()); + if (!mPixelExecutable) + { + mVertexExecutable->Release(); + mVertexExecutable = NULL; + return error(GL_OUT_OF_MEMORY, false); + } + + vertexBinary->Release(); + pixelBinary->Release(); + vertexBinary = NULL; + pixelBinary = NULL; + + if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader)) + { + return false; + } + + if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS)) + { + return false; + } + + if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS)) + { + return false; + } + + // these uniforms are searched as already-decorated because gl_ and dx_ + // are reserved prefixes, and do not receive additional decoration + mDxDepthRangeLocation = getUniformLocation("dx_DepthRange"); + mDxDepthLocation = getUniformLocation("dx_Depth"); + mDxCoordLocation = getUniformLocation("dx_Coord"); + mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize"); + mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW"); + mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines"); + + context->markDxUniformsDirty(); + + return true; + } + + return false; +} + +// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices +bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader) +{ + unsigned int usedLocations = 0; + + // Link attributes that have a binding location + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + int location = attributeBindings.getAttributeBinding(attribute->name); + + if (location != -1) // Set by glBindAttribLocation + { + if (!mLinkedAttribute[location].name.empty()) + { + // Multiple active attributes bound to the same location; not an error + } + + mLinkedAttribute[location] = *attribute; + + int rows = VariableRowCount(attribute->type); + + if (rows + location > MAX_VERTEX_ATTRIBS) + { + infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location); + + return false; + } + + for (int i = 0; i < rows; i++) + { + usedLocations |= 1 << (location + i); + } + } + } + + // Link attributes that don't have a binding location + for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++) + { + int location = attributeBindings.getAttributeBinding(attribute->name); + + if (location == -1) // Not set by glBindAttribLocation + { + int rows = VariableRowCount(attribute->type); + int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS); + + if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS) + { + infoLog.append("Too many active attributes (%s)", attribute->name.c_str()); + + return false; // Fail to link + } + + mLinkedAttribute[availableIndex] = *attribute; + } + } + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; ) + { + int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name); + int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1); + + for (int r = 0; r < rows; r++) + { + mSemanticIndex[attributeIndex++] = index++; + } + } + + return true; +} + +bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable) +{ + for (unsigned int constantIndex = 0; constantIndex < constantTable->constants(); constantIndex++) + { + const D3DConstant *constant = constantTable->getConstant(constantIndex); + + if (!defineUniform(infoLog, shader, constant)) + { + return false; + } + } + + return true; +} + +// Adds the description of a constant found in the binary shader to the list of uniforms +// Returns true if succesful (uniform not already defined) +bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name) +{ + if (constant->registerSet == D3DConstant::RS_SAMPLER) + { + for (unsigned int i = 0; i < constant->registerCount; i++) + { + const D3DConstant *psConstant = mConstantTablePS->getConstantByName(constant->name.c_str()); + const D3DConstant *vsConstant = mConstantTableVS->getConstantByName(constant->name.c_str()); + + if (psConstant) + { + unsigned int samplerIndex = psConstant->registerIndex + i; + + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) + { + mSamplersPS[samplerIndex].active = true; + mSamplersPS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; + mSamplersPS[samplerIndex].logicalTextureUnit = 0; + mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange); + } + else + { + infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS); + return false; + } + } + + if (vsConstant) + { + unsigned int samplerIndex = vsConstant->registerIndex + i; + + if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits()) + { + mSamplersVS[samplerIndex].active = true; + mSamplersVS[samplerIndex].textureType = (constant->type == D3DConstant::PT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D; + mSamplersVS[samplerIndex].logicalTextureUnit = 0; + mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange); + } + else + { + infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits()); + return false; + } + } + } + } + + switch(constant->typeClass) + { + case D3DConstant::CLASS_STRUCT: + { + for (unsigned int arrayIndex = 0; arrayIndex < constant->elements; arrayIndex++) + { + for (unsigned int field = 0; field < constant->structMembers[arrayIndex].size(); field++) + { + const D3DConstant *fieldConstant = constant->structMembers[arrayIndex][field]; + + std::string structIndex = (constant->elements > 1) ? ("[" + str(arrayIndex) + "]") : ""; + + if (!defineUniform(infoLog, shader, fieldConstant, name + constant->name + structIndex + ".")) + { + return false; + } + } + } + + return true; + } + case D3DConstant::CLASS_SCALAR: + case D3DConstant::CLASS_VECTOR: + case D3DConstant::CLASS_MATRIX_COLUMNS: + case D3DConstant::CLASS_OBJECT: + return defineUniform(shader, constant, name + constant->name); + default: + UNREACHABLE(); + return false; + } +} + +bool ProgramBinary::defineUniform(GLenum shader, const D3DConstant *constant, const std::string &_name) +{ + Uniform *uniform = createUniform(constant, _name); + + if(!uniform) + { + return false; + } + + // Check if already defined + GLint location = getUniformLocation(uniform->name); + GLenum type = uniform->type; + + if (location >= 0) + { + delete uniform; + uniform = mUniforms[mUniformIndex[location].index]; + } + + if (shader == GL_FRAGMENT_SHADER) uniform->ps.set(constant); + if (shader == GL_VERTEX_SHADER) uniform->vs.set(constant); + + if (location >= 0) + { + return uniform->type == type; + } + + mUniforms.push_back(uniform); + unsigned int uniformIndex = mUniforms.size() - 1; + + for (unsigned int i = 0; i < uniform->arraySize; ++i) + { + mUniformIndex.push_back(UniformLocation(_name, i, uniformIndex)); + } + + return true; +} + +Uniform *ProgramBinary::createUniform(const D3DConstant *constant, const std::string &_name) +{ + if (constant->rows == 1) // Vectors and scalars + { + switch (constant->type) + { + case D3DConstant::PT_SAMPLER2D: + switch (constant->columns) + { + case 1: return new Uniform(GL_SAMPLER_2D, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_SAMPLERCUBE: + switch (constant->columns) + { + case 1: return new Uniform(GL_SAMPLER_CUBE, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_BOOL: + switch (constant->columns) + { + case 1: return new Uniform(GL_BOOL, _name, constant->elements); + case 2: return new Uniform(GL_BOOL_VEC2, _name, constant->elements); + case 3: return new Uniform(GL_BOOL_VEC3, _name, constant->elements); + case 4: return new Uniform(GL_BOOL_VEC4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_INT: + switch (constant->columns) + { + case 1: return new Uniform(GL_INT, _name, constant->elements); + case 2: return new Uniform(GL_INT_VEC2, _name, constant->elements); + case 3: return new Uniform(GL_INT_VEC3, _name, constant->elements); + case 4: return new Uniform(GL_INT_VEC4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + case D3DConstant::PT_FLOAT: + switch (constant->columns) + { + case 1: return new Uniform(GL_FLOAT, _name, constant->elements); + case 2: return new Uniform(GL_FLOAT_VEC2, _name, constant->elements); + case 3: return new Uniform(GL_FLOAT_VEC3, _name, constant->elements); + case 4: return new Uniform(GL_FLOAT_VEC4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + } + else if (constant->rows == constant->columns) // Square matrices + { + switch (constant->type) + { + case D3DConstant::PT_FLOAT: + switch (constant->rows) + { + case 2: return new Uniform(GL_FLOAT_MAT2, _name, constant->elements); + case 3: return new Uniform(GL_FLOAT_MAT3, _name, constant->elements); + case 4: return new Uniform(GL_FLOAT_MAT4, _name, constant->elements); + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + + return 0; +} + +// This method needs to match OutputHLSL::decorate +std::string ProgramBinary::decorateAttribute(const std::string &name) +{ + if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0) + { + return "_" + name; + } + + return name; +} + +std::string ProgramBinary::undecorateUniform(const std::string &_name) +{ + std::string name = _name; + + // Remove any structure field decoration + size_t pos = 0; + while ((pos = name.find("._", pos)) != std::string::npos) + { + name.replace(pos, 2, "."); + } + + // Remove the leading decoration + if (name[0] == '_') + { + return name.substr(1); + } + else if (name.compare(0, 3, "ar_") == 0) + { + return name.substr(3); + } + + return name; +} + +void ProgramBinary::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v) +{ + float vector[D3D9_MAX_FLOAT_CONSTANTS * 4]; + BOOL boolVector[D3D9_MAX_BOOL_CONSTANTS]; + + if (targetUniform->ps.float4Index >= 0 || targetUniform->vs.float4Index >= 0) + { + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + for (int i = 0; i < count; i++) + { + for (int j = 0; j < 4; j++) + { + if (j < width) + { + vector[i * 4 + j] = (v[i * width + j] == GL_FALSE) ? 0.0f : 1.0f; + } + else + { + vector[i * 4 + j] = 0.0f; + } + } + } + } + + if (targetUniform->ps.boolIndex >= 0 || targetUniform->vs.boolIndex >= 0) + { + int psCount = targetUniform->ps.boolIndex >= 0 ? targetUniform->ps.registerCount : 0; + int vsCount = targetUniform->vs.boolIndex >= 0 ? targetUniform->vs.registerCount : 0; + int copyCount = std::min(count * width, std::max(psCount, vsCount)); + ASSERT(copyCount <= D3D9_MAX_BOOL_CONSTANTS); + for (int i = 0; i < copyCount; i++) + { + boolVector[i] = v[i] != GL_FALSE; + } + } + + if (targetUniform->ps.float4Index >= 0) + { + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, vector, targetUniform->ps.registerCount); + } + + if (targetUniform->ps.boolIndex >= 0) + { + mDevice->SetPixelShaderConstantB(targetUniform->ps.boolIndex, boolVector, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.float4Index >= 0) + { + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, vector, targetUniform->vs.registerCount); + } + + if (targetUniform->vs.boolIndex >= 0) + { + mDevice->SetVertexShaderConstantB(targetUniform->vs.boolIndex, boolVector, targetUniform->vs.registerCount); + } +} + +bool ProgramBinary::applyUniformnfv(Uniform *targetUniform, const GLfloat *v) +{ + if (targetUniform->ps.registerCount) + { + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, v, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.registerCount) + { + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, v, targetUniform->vs.registerCount); + } + + return true; +} + +bool ProgramBinary::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[i], 0, 0, 0); + } + + if (targetUniform->ps.registerCount) + { + if (targetUniform->ps.samplerIndex >= 0) + { + unsigned int firstIndex = targetUniform->ps.samplerIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) + { + ASSERT(mSamplersPS[samplerIndex].active); + mSamplersPS[samplerIndex].logicalTextureUnit = v[i]; + } + } + } + else + { + ASSERT(targetUniform->ps.float4Index >= 0); + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float*)vector, targetUniform->ps.registerCount); + } + } + + if (targetUniform->vs.registerCount) + { + if (targetUniform->vs.samplerIndex >= 0) + { + unsigned int firstIndex = targetUniform->vs.samplerIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF) + { + ASSERT(mSamplersVS[samplerIndex].active); + mSamplersVS[samplerIndex].logicalTextureUnit = v[i]; + } + } + } + else + { + ASSERT(targetUniform->vs.float4Index >= 0); + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount); + } + } + + return true; +} + +bool ProgramBinary::applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[0], (float)v[1], 0, 0); + + v += 2; + } + + applyUniformniv(targetUniform, count, vector); + + return true; +} + +bool ProgramBinary::applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], 0); + + v += 3; + } + + applyUniformniv(targetUniform, count, vector); + + return true; +} + +bool ProgramBinary::applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v) +{ + ASSERT(count <= D3D9_MAX_FLOAT_CONSTANTS); + Vector4 vector[D3D9_MAX_FLOAT_CONSTANTS]; + + for (int i = 0; i < count; i++) + { + vector[i] = Vector4((float)v[0], (float)v[1], (float)v[2], (float)v[3]); + + v += 4; + } + + applyUniformniv(targetUniform, count, vector); + + return true; +} + +void ProgramBinary::applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector) +{ + if (targetUniform->ps.registerCount) + { + ASSERT(targetUniform->ps.float4Index >= 0); + mDevice->SetPixelShaderConstantF(targetUniform->ps.float4Index, (const float *)vector, targetUniform->ps.registerCount); + } + + if (targetUniform->vs.registerCount) + { + ASSERT(targetUniform->vs.float4Index >= 0); + mDevice->SetVertexShaderConstantF(targetUniform->vs.float4Index, (const float *)vector, targetUniform->vs.registerCount); + } +} + +bool ProgramBinary::isValidated() const +{ + return mValidated; +} + +void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + // Skip over inactive attributes + unsigned int activeAttribute = 0; + unsigned int attribute; + for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) + { + if (mLinkedAttribute[attribute].name.empty()) + { + continue; + } + + if (activeAttribute == index) + { + break; + } + + activeAttribute++; + } + + if (bufsize > 0) + { + const char *string = mLinkedAttribute[attribute].name.c_str(); + + strncpy(name, string, bufsize); + name[bufsize - 1] = '\0'; + + if (length) + { + *length = strlen(name); + } + } + + *size = 1; // Always a single 'type' instance + + *type = mLinkedAttribute[attribute].type; +} + +GLint ProgramBinary::getActiveAttributeCount() +{ + int count = 0; + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (!mLinkedAttribute[attributeIndex].name.empty()) + { + count++; + } + } + + return count; +} + +GLint ProgramBinary::getActiveAttributeMaxLength() +{ + int maxLength = 0; + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (!mLinkedAttribute[attributeIndex].name.empty()) + { + maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength); + } + } + + return maxLength; +} + +void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + // Skip over internal uniforms + unsigned int activeUniform = 0; + unsigned int uniform; + for (uniform = 0; uniform < mUniforms.size(); uniform++) + { + if (mUniforms[uniform]->name.compare(0, 3, "dx_") == 0) + { + continue; + } + + if (activeUniform == index) + { + break; + } + + activeUniform++; + } + + ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount() + + if (bufsize > 0) + { + std::string string = mUniforms[uniform]->name; + + if (mUniforms[uniform]->isArray()) + { + string += "[0]"; + } + + strncpy(name, string.c_str(), bufsize); + name[bufsize - 1] = '\0'; + + if (length) + { + *length = strlen(name); + } + } + + *size = mUniforms[uniform]->arraySize; + + *type = mUniforms[uniform]->type; +} + +GLint ProgramBinary::getActiveUniformCount() +{ + int count = 0; + + unsigned int numUniforms = mUniforms.size(); + for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) + { + if (mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0) + { + count++; + } + } + + return count; +} + +GLint ProgramBinary::getActiveUniformMaxLength() +{ + int maxLength = 0; + + unsigned int numUniforms = mUniforms.size(); + for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) + { + if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.compare(0, 3, "dx_") != 0) + { + int length = (int)(mUniforms[uniformIndex]->name.length() + 1); + if (mUniforms[uniformIndex]->isArray()) + { + length += 3; // Counting in "[0]". + } + maxLength = std::max(length, maxLength); + } + } + + return maxLength; +} + +void ProgramBinary::validate(InfoLog &infoLog) +{ + applyUniforms(); + if (!validateSamplers(&infoLog)) + { + mValidated = false; + } + else + { + mValidated = true; + } +} + +bool ProgramBinary::validateSamplers(InfoLog *infoLog) +{ + // if any two active samplers in a program are of different types, but refer to the same + // texture image unit, and this is the current program, then ValidateProgram will fail, and + // DrawArrays and DrawElements will issue the INVALID_OPERATION error. + + const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits(); + TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF]; + + for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i) + { + textureUnitType[i] = TEXTURE_UNKNOWN; + } + + for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) + { + if (mSamplersPS[i].active) + { + unsigned int unit = mSamplersPS[i].logicalTextureUnit; + + if (unit >= maxCombinedTextureImageUnits) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits); + } + + return false; + } + + if (textureUnitType[unit] != TEXTURE_UNKNOWN) + { + if (mSamplersPS[i].textureType != textureUnitType[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + textureUnitType[unit] = mSamplersPS[i].textureType; + } + } + } + + for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) + { + if (mSamplersVS[i].active) + { + unsigned int unit = mSamplersVS[i].logicalTextureUnit; + + if (unit >= maxCombinedTextureImageUnits) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits); + } + + return false; + } + + if (textureUnitType[unit] != TEXTURE_UNKNOWN) + { + if (mSamplersVS[i].textureType != textureUnitType[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + textureUnitType[unit] = mSamplersVS[i].textureType; + } + } + } + + return true; +} + +GLint ProgramBinary::getDxDepthRangeLocation() const +{ + return mDxDepthRangeLocation; +} + +GLint ProgramBinary::getDxDepthLocation() const +{ + return mDxDepthLocation; +} + +GLint ProgramBinary::getDxCoordLocation() const +{ + return mDxCoordLocation; +} + +GLint ProgramBinary::getDxHalfPixelSizeLocation() const +{ + return mDxHalfPixelSizeLocation; +} + +GLint ProgramBinary::getDxFrontCCWLocation() const +{ + return mDxFrontCCWLocation; +} + +GLint ProgramBinary::getDxPointsOrLinesLocation() const +{ + return mDxPointsOrLinesLocation; +} + +ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D) +{ +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h new file mode 100644 index 0000000000..9ffe70b617 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h @@ -0,0 +1,235 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Program.h: Defines the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#ifndef LIBGLESV2_PROGRAM_BINARY_H_ +#define LIBGLESV2_PROGRAM_BINARY_H_ + +#define GL_APICALL +#include +#include + +#include +#include +#include + +#include "libGLESv2/Context.h" +#include "libGLESv2/D3DConstantTable.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/Shader.h" + +namespace gl +{ +class FragmentShader; +class VertexShader; + +// Helper struct representing a single shader uniform +struct Uniform +{ + Uniform(GLenum type, const std::string &_name, unsigned int arraySize); + + ~Uniform(); + + bool isArray(); + + const GLenum type; + const std::string _name; // Decorated name + const std::string name; // Undecorated name + const unsigned int arraySize; + + unsigned char *data; + bool dirty; + + struct RegisterInfo + { + RegisterInfo() + { + float4Index = -1; + samplerIndex = -1; + boolIndex = -1; + registerCount = 0; + } + + void set(const D3DConstant *constant) + { + switch(constant->registerSet) + { + case D3DConstant::RS_BOOL: boolIndex = constant->registerIndex; break; + case D3DConstant::RS_FLOAT4: float4Index = constant->registerIndex; break; + case D3DConstant::RS_SAMPLER: samplerIndex = constant->registerIndex; break; + default: UNREACHABLE(); + } + + ASSERT(registerCount == 0 || registerCount == (int)constant->registerCount); + registerCount = constant->registerCount; + } + + int float4Index; + int samplerIndex; + int boolIndex; + + int registerCount; + }; + + RegisterInfo ps; + RegisterInfo vs; +}; + +// Struct used for correlating uniforms/elements of uniform arrays to handles +struct UniformLocation +{ + UniformLocation() + { + } + + UniformLocation(const std::string &_name, unsigned int element, unsigned int index); + + std::string name; + unsigned int element; + unsigned int index; +}; + +// This is the result of linking a program. It is the state that would be passed to ProgramBinary. +class ProgramBinary : public RefCountObject +{ + public: + ProgramBinary(); + ~ProgramBinary(); + + IDirect3DPixelShader9 *getPixelShader(); + IDirect3DVertexShader9 *getVertexShader(); + + GLuint getAttributeLocation(const char *name); + int getSemanticIndex(int attributeIndex); + + GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex); + TextureType getSamplerTextureType(SamplerType type, unsigned int samplerIndex); + GLint getUsedSamplerRange(SamplerType type); + bool usesPointSize() const; + + GLint getUniformLocation(std::string name); + bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniform1iv(GLint location, GLsizei count, const GLint *v); + bool setUniform2iv(GLint location, GLsizei count, const GLint *v); + bool setUniform3iv(GLint location, GLsizei count, const GLint *v); + bool setUniform4iv(GLint location, GLsizei count, const GLint *v); + + bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params); + bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params); + + GLint getDxDepthRangeLocation() const; + GLint getDxDepthLocation() const; + GLint getDxCoordLocation() const; + GLint getDxHalfPixelSizeLocation() const; + GLint getDxFrontCCWLocation() const; + GLint getDxPointsOrLinesLocation() const; + + void dirtyAllUniforms(); + void applyUniforms(); + + bool load(InfoLog &infoLog, const void *binary, GLsizei length); + bool save(void* binary, GLsizei bufSize, GLsizei *length); + GLint getLength(); + + bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader); + void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); + + void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveAttributeCount(); + GLint getActiveAttributeMaxLength(); + + void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveUniformCount(); + GLint getActiveUniformMaxLength(); + + void validate(InfoLog &infoLog); + bool validateSamplers(InfoLog *infoLog); + bool isValidated() const; + + unsigned int getSerial() const; + + static std::string decorateAttribute(const std::string &name); // Prepend an underscore + static std::string undecorateUniform(const std::string &_name); // Remove leading underscore + + private: + DISALLOW_COPY_AND_ASSIGN(ProgramBinary); + + ID3D10Blob *compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, D3DConstantTable **constantTable); + + int packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader); + bool linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader); + + bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader); + + bool linkUniforms(InfoLog &infoLog, GLenum shader, D3DConstantTable *constantTable); + bool defineUniform(InfoLog &infoLog, GLenum shader, const D3DConstant *constant, std::string name = ""); + bool defineUniform(GLenum shader, const D3DConstant *constant, const std::string &name); + Uniform *createUniform( const D3DConstant *constant, const std::string &name); + bool applyUniformnfv(Uniform *targetUniform, const GLfloat *v); + bool applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform2iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform3iv(Uniform *targetUniform, GLsizei count, const GLint *v); + bool applyUniform4iv(Uniform *targetUniform, GLsizei count, const GLint *v); + void applyUniformniv(Uniform *targetUniform, GLsizei count, const Vector4 *vector); + void applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v); + + IDirect3DDevice9 *mDevice; + + IDirect3DPixelShader9 *mPixelExecutable; + IDirect3DVertexShader9 *mVertexExecutable; + + // These are only used during linking. + D3DConstantTable *mConstantTablePS; + D3DConstantTable *mConstantTableVS; + + Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; + int mSemanticIndex[MAX_VERTEX_ATTRIBS]; + + struct Sampler + { + Sampler(); + + bool active; + GLint logicalTextureUnit; + TextureType textureType; + }; + + Sampler mSamplersPS[MAX_TEXTURE_IMAGE_UNITS]; + Sampler mSamplersVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF]; + GLuint mUsedVertexSamplerRange; + GLuint mUsedPixelSamplerRange; + bool mUsesPointSize; + + typedef std::vector UniformArray; + UniformArray mUniforms; + typedef std::vector UniformIndex; + UniformIndex mUniformIndex; + + GLint mDxDepthRangeLocation; + GLint mDxDepthLocation; + GLint mDxCoordLocation; + GLint mDxHalfPixelSizeLocation; + GLint mDxFrontCCWLocation; + GLint mDxPointsOrLinesLocation; + + bool mValidated; + + const unsigned int mSerial; + + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; +}; +} + +#endif // LIBGLESV2_PROGRAM_BINARY_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Query.cpp b/src/3rdparty/angle/src/libGLESv2/Query.cpp new file mode 100644 index 0000000000..10edda5c57 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Query.cpp @@ -0,0 +1,128 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query.cpp: Implements the gl::Query class + +#include "libGLESv2/Query.h" + +#include "libGLESv2/main.h" + +namespace gl +{ + +Query::Query(GLuint id, GLenum type) : RefCountObject(id) +{ + mQuery = NULL; + mStatus = GL_FALSE; + mResult = GL_FALSE; + mType = type; +} + +Query::~Query() +{ + if (mQuery != NULL) + { + mQuery->Release(); + mQuery = NULL; + } +} + +void Query::begin() +{ + if (mQuery == NULL) + { + if (FAILED(getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery))) + { + return error(GL_OUT_OF_MEMORY); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); +} + +void Query::end() +{ + if (mQuery == NULL) + { + return error(GL_INVALID_OPERATION); + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + + mStatus = GL_FALSE; + mResult = GL_FALSE; +} + +GLuint Query::getResult() +{ + if (mQuery != NULL) + { + while (!testQuery()) + { + Sleep(0); + // explicitly check for device loss + // some drivers seem to return S_FALSE even if the device is lost + // instead of D3DERR_DEVICELOST like they should + if (gl::getDisplay()->testDeviceLost()) + { + gl::getDisplay()->notifyDeviceLost(); + return error(GL_OUT_OF_MEMORY, 0); + } + } + } + + return (GLuint)mResult; +} + +GLboolean Query::isResultAvailable() +{ + if (mQuery != NULL) + { + testQuery(); + } + + return mStatus; +} + +GLenum Query::getType() const +{ + return mType; +} + +GLboolean Query::testQuery() +{ + if (mQuery != NULL && mStatus != GL_TRUE) + { + DWORD numPixels = 0; + + HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); + if (hres == S_OK) + { + mStatus = GL_TRUE; + + switch (mType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + break; + default: + ASSERT(false); + } + } + else if (checkDeviceLost(hres)) + { + return error(GL_OUT_OF_MEMORY, GL_TRUE); + } + + return mStatus; + } + + return GL_TRUE; // prevent blocking when query is null +} +} diff --git a/src/3rdparty/angle/src/libGLESv2/Query.h b/src/3rdparty/angle/src/libGLESv2/Query.h new file mode 100644 index 0000000000..79357a0583 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Query.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Query.h: Defines the gl::Query class + +#ifndef LIBGLESV2_QUERY_H_ +#define LIBGLESV2_QUERY_H_ + +#define GL_APICALL +#include +#include + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ + +class Query : public RefCountObject +{ + public: + Query(GLuint id, GLenum type); + virtual ~Query(); + + void begin(); + void end(); + GLuint getResult(); + GLboolean isResultAvailable(); + + GLenum getType() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Query); + + GLboolean testQuery(); + + IDirect3DQuery9* mQuery; + GLenum mType; + GLboolean mStatus; + GLint mResult; +}; + +} + +#endif // LIBGLESV2_QUERY_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp new file mode 100644 index 0000000000..4b911e8120 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp @@ -0,0 +1,577 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderbuffer.cpp: the gl::Renderbuffer class and its derived classes +// Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "libGLESv2/Renderbuffer.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/utilities.h" + +namespace gl +{ +unsigned int RenderbufferStorage::mCurrentSerial = 1; + +RenderbufferInterface::RenderbufferInterface() +{ +} + +// The default case for classes inherited from RenderbufferInterface is not to +// need to do anything upon the reference count to the parent Renderbuffer incrementing +// or decrementing. +void RenderbufferInterface::addProxyRef(const Renderbuffer *proxy) +{ +} + +void RenderbufferInterface::releaseProxy(const Renderbuffer *proxy) +{ +} + +GLuint RenderbufferInterface::getRedSize() const +{ + return dx2es::GetRedSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getGreenSize() const +{ + return dx2es::GetGreenSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getBlueSize() const +{ + return dx2es::GetBlueSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getAlphaSize() const +{ + return dx2es::GetAlphaSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getDepthSize() const +{ + return dx2es::GetDepthSize(getD3DFormat()); +} + +GLuint RenderbufferInterface::getStencilSize() const +{ + return dx2es::GetStencilSize(getD3DFormat()); +} + +///// RenderbufferTexture2D Implementation //////// + +RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture, GLenum target) : mTarget(target) +{ + mTexture2D.set(texture); +} + +RenderbufferTexture2D::~RenderbufferTexture2D() +{ + mTexture2D.set(NULL); +} + +// Textures need to maintain their own reference count for references via +// Renderbuffers acting as proxies. Here, we notify the texture of a reference. +void RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy) +{ + mTexture2D->addProxyRef(proxy); +} + +void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy) +{ + mTexture2D->releaseProxy(proxy); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTexture2D::getRenderTarget() +{ + return mTexture2D->getRenderTarget(mTarget); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTexture2D::getDepthStencil() +{ + return mTexture2D->getDepthStencil(mTarget); +} + +GLsizei RenderbufferTexture2D::getWidth() const +{ + return mTexture2D->getWidth(0); +} + +GLsizei RenderbufferTexture2D::getHeight() const +{ + return mTexture2D->getHeight(0); +} + +GLenum RenderbufferTexture2D::getInternalFormat() const +{ + return mTexture2D->getInternalFormat(0); +} + +D3DFORMAT RenderbufferTexture2D::getD3DFormat() const +{ + return mTexture2D->getD3DFormat(0); +} + +GLsizei RenderbufferTexture2D::getSamples() const +{ + return 0; +} + +unsigned int RenderbufferTexture2D::getSerial() const +{ + return mTexture2D->getRenderTargetSerial(mTarget); +} + +///// RenderbufferTextureCubeMap Implementation //////// + +RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target) : mTarget(target) +{ + mTextureCubeMap.set(texture); +} + +RenderbufferTextureCubeMap::~RenderbufferTextureCubeMap() +{ + mTextureCubeMap.set(NULL); +} + +// Textures need to maintain their own reference count for references via +// Renderbuffers acting as proxies. Here, we notify the texture of a reference. +void RenderbufferTextureCubeMap::addProxyRef(const Renderbuffer *proxy) +{ + mTextureCubeMap->addProxyRef(proxy); +} + +void RenderbufferTextureCubeMap::releaseProxy(const Renderbuffer *proxy) +{ + mTextureCubeMap->releaseProxy(proxy); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTextureCubeMap::getRenderTarget() +{ + return mTextureCubeMap->getRenderTarget(mTarget); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferTextureCubeMap::getDepthStencil() +{ + return NULL; +} + +GLsizei RenderbufferTextureCubeMap::getWidth() const +{ + return mTextureCubeMap->getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +GLsizei RenderbufferTextureCubeMap::getHeight() const +{ + return mTextureCubeMap->getHeight(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +GLenum RenderbufferTextureCubeMap::getInternalFormat() const +{ + return mTextureCubeMap->getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +D3DFORMAT RenderbufferTextureCubeMap::getD3DFormat() const +{ + return mTextureCubeMap->getD3DFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); +} + +GLsizei RenderbufferTextureCubeMap::getSamples() const +{ + return 0; +} + +unsigned int RenderbufferTextureCubeMap::getSerial() const +{ + return mTextureCubeMap->getRenderTargetSerial(mTarget); +} + +////// Renderbuffer Implementation ////// + +Renderbuffer::Renderbuffer(GLuint id, RenderbufferInterface *instance) : RefCountObject(id) +{ + ASSERT(instance != NULL); + mInstance = instance; +} + +Renderbuffer::~Renderbuffer() +{ + delete mInstance; +} + +// The RenderbufferInterface contained in this Renderbuffer may need to maintain +// its own reference count, so we pass it on here. +void Renderbuffer::addRef() const +{ + mInstance->addProxyRef(this); + + RefCountObject::addRef(); +} + +void Renderbuffer::release() const +{ + mInstance->releaseProxy(this); + + RefCountObject::release(); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Renderbuffer::getRenderTarget() +{ + return mInstance->getRenderTarget(); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Renderbuffer::getDepthStencil() +{ + return mInstance->getDepthStencil(); +} + +GLsizei Renderbuffer::getWidth() const +{ + return mInstance->getWidth(); +} + +GLsizei Renderbuffer::getHeight() const +{ + return mInstance->getHeight(); +} + +GLenum Renderbuffer::getInternalFormat() const +{ + return mInstance->getInternalFormat(); +} + +D3DFORMAT Renderbuffer::getD3DFormat() const +{ + return mInstance->getD3DFormat(); +} + +GLuint Renderbuffer::getRedSize() const +{ + return mInstance->getRedSize(); +} + +GLuint Renderbuffer::getGreenSize() const +{ + return mInstance->getGreenSize(); +} + +GLuint Renderbuffer::getBlueSize() const +{ + return mInstance->getBlueSize(); +} + +GLuint Renderbuffer::getAlphaSize() const +{ + return mInstance->getAlphaSize(); +} + +GLuint Renderbuffer::getDepthSize() const +{ + return mInstance->getDepthSize(); +} + +GLuint Renderbuffer::getStencilSize() const +{ + return mInstance->getStencilSize(); +} + +GLsizei Renderbuffer::getSamples() const +{ + return mInstance->getSamples(); +} + +unsigned int Renderbuffer::getSerial() const +{ + return mInstance->getSerial(); +} + +void Renderbuffer::setStorage(RenderbufferStorage *newStorage) +{ + ASSERT(newStorage != NULL); + + delete mInstance; + mInstance = newStorage; +} + +RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial()) +{ + mWidth = 0; + mHeight = 0; + mInternalFormat = GL_RGBA4; + mD3DFormat = D3DFMT_A8R8G8B8; + mSamples = 0; +} + +RenderbufferStorage::~RenderbufferStorage() +{ +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferStorage::getRenderTarget() +{ + return NULL; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *RenderbufferStorage::getDepthStencil() +{ + return NULL; +} + +GLsizei RenderbufferStorage::getWidth() const +{ + return mWidth; +} + +GLsizei RenderbufferStorage::getHeight() const +{ + return mHeight; +} + +GLenum RenderbufferStorage::getInternalFormat() const +{ + return mInternalFormat; +} + +D3DFORMAT RenderbufferStorage::getD3DFormat() const +{ + return mD3DFormat; +} + +GLsizei RenderbufferStorage::getSamples() const +{ + return mSamples; +} + +unsigned int RenderbufferStorage::getSerial() const +{ + return mSerial; +} + +unsigned int RenderbufferStorage::issueSerial() +{ + return mCurrentSerial++; +} + +unsigned int RenderbufferStorage::issueCubeSerials() +{ + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += 6; + return firstSerial; +} + +Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget) +{ + if (renderTarget) + { + renderTarget->AddRef(); + + D3DSURFACE_DESC description; + renderTarget->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + mInternalFormat = dx2es::ConvertBackBufferFormat(description.Format); + mD3DFormat = description.Format; + mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType); + } +} + +Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) +{ + IDirect3DDevice9 *device = getDevice(); + + D3DFORMAT requestedFormat = es2dx::ConvertRenderbufferFormat(format); + int supportedSamples = getContext()->getNearestSupportedSamples(requestedFormat, samples); + + if (supportedSamples == -1) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + if (width > 0 && height > 0) + { + HRESULT result = device->CreateRenderTarget(width, height, requestedFormat, + es2dx::GetMultisampleTypeFromSamples(supportedSamples), 0, FALSE, &mRenderTarget, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + ASSERT(SUCCEEDED(result)); + } + + mWidth = width; + mHeight = height; + mInternalFormat = format; + mD3DFormat = requestedFormat; + mSamples = supportedSamples; +} + +Colorbuffer::~Colorbuffer() +{ + if (mRenderTarget) + { + mRenderTarget->Release(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Colorbuffer::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +DepthStencilbuffer::DepthStencilbuffer(IDirect3DSurface9 *depthStencil) : mDepthStencil(depthStencil) +{ + if (depthStencil) + { + depthStencil->AddRef(); + + D3DSURFACE_DESC description; + depthStencil->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + mInternalFormat = dx2es::ConvertDepthStencilFormat(description.Format); + mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType); + mD3DFormat = description.Format; + } +} + +DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples) +{ + IDirect3DDevice9 *device = getDevice(); + + mDepthStencil = NULL; + + int supportedSamples = getContext()->getNearestSupportedSamples(D3DFMT_D24S8, samples); + + if (supportedSamples == -1) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + if (width > 0 && height > 0) + { + HRESULT result = device->CreateDepthStencilSurface(width, height, D3DFMT_D24S8, es2dx::GetMultisampleTypeFromSamples(supportedSamples), + 0, FALSE, &mDepthStencil, 0); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + ASSERT(SUCCEEDED(result)); + } + + mWidth = width; + mHeight = height; + mInternalFormat = GL_DEPTH24_STENCIL8_OES; + mD3DFormat = D3DFMT_D24S8; + mSamples = supportedSamples; +} + +DepthStencilbuffer::~DepthStencilbuffer() +{ + if (mDepthStencil) + { + mDepthStencil->Release(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *DepthStencilbuffer::getDepthStencil() +{ + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + return mDepthStencil; +} + +Depthbuffer::Depthbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) +{ + if (depthStencil) + { + mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage + } +} + +Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) +{ + if (mDepthStencil) + { + mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage + } +} + +Depthbuffer::~Depthbuffer() +{ +} + +Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil) +{ + if (depthStencil) + { + mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage + } +} + +Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples) +{ + if (mDepthStencil) + { + mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage + } +} + +Stencilbuffer::~Stencilbuffer() +{ +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h new file mode 100644 index 0000000000..e6d5ddb875 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h @@ -0,0 +1,257 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Renderbuffer.h: Defines the wrapper class gl::Renderbuffer, as well as the +// class hierarchy used to store its contents: RenderbufferStorage, Colorbuffer, +// DepthStencilbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBGLESV2_RENDERBUFFER_H_ +#define LIBGLESV2_RENDERBUFFER_H_ + +#define GL_APICALL +#include +#include + +#include "common/angleutils.h" +#include "common/RefCountObject.h" + +namespace gl +{ +class Texture2D; +class TextureCubeMap; +class Renderbuffer; +class Colorbuffer; +class DepthStencilbuffer; + +class RenderbufferInterface +{ + public: + RenderbufferInterface(); + + virtual ~RenderbufferInterface() {}; + + virtual void addProxyRef(const Renderbuffer *proxy); + virtual void releaseProxy(const Renderbuffer *proxy); + + virtual IDirect3DSurface9 *getRenderTarget() = 0; + virtual IDirect3DSurface9 *getDepthStencil() = 0; + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual D3DFORMAT getD3DFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + + virtual unsigned int getSerial() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferInterface); +}; + +class RenderbufferTexture2D : public RenderbufferInterface +{ + public: + RenderbufferTexture2D(Texture2D *texture, GLenum target); + + virtual ~RenderbufferTexture2D(); + + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual D3DFORMAT getD3DFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferTexture2D); + + BindingPointer mTexture2D; + GLenum mTarget; +}; + +class RenderbufferTextureCubeMap : public RenderbufferInterface +{ + public: + RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target); + + virtual ~RenderbufferTextureCubeMap(); + + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual D3DFORMAT getD3DFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferTextureCubeMap); + + BindingPointer mTextureCubeMap; + GLenum mTarget; +}; + +// A class derived from RenderbufferStorage is created whenever glRenderbufferStorage +// is called. The specific concrete type depends on whether the internal format is +// colour depth, stencil or packed depth/stencil. +class RenderbufferStorage : public RenderbufferInterface +{ + public: + RenderbufferStorage(); + + virtual ~RenderbufferStorage() = 0; + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual D3DFORMAT getD3DFormat() const; + virtual GLsizei getSamples() const; + + virtual unsigned int getSerial() const; + + static unsigned int issueSerial(); + static unsigned int issueCubeSerials(); + + protected: + GLsizei mWidth; + GLsizei mHeight; + GLenum mInternalFormat; + D3DFORMAT mD3DFormat; + GLsizei mSamples; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage); + + const unsigned int mSerial; + + static unsigned int mCurrentSerial; +}; + +// Renderbuffer implements the GL renderbuffer object. +// It's only a proxy for a RenderbufferInterface instance; the internal object +// can change whenever glRenderbufferStorage is called. +class Renderbuffer : public RefCountObject +{ + public: + Renderbuffer(GLuint id, RenderbufferInterface *storage); + + virtual ~Renderbuffer(); + + // These functions from RefCountObject are overloaded here because + // Textures need to maintain their own count of references to them via + // Renderbuffers/RenderbufferTextures. These functions invoke those + // reference counting functions on the RenderbufferInterface. + void addRef() const; + void release() const; + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + GLsizei getWidth() const; + GLsizei getHeight() const; + GLenum getInternalFormat() const; + D3DFORMAT getD3DFormat() const; + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + GLsizei getSamples() const; + + unsigned int getSerial() const; + + void setStorage(RenderbufferStorage *newStorage); + + private: + DISALLOW_COPY_AND_ASSIGN(Renderbuffer); + + RenderbufferInterface *mInstance; +}; + +class Colorbuffer : public RenderbufferStorage +{ + public: + explicit Colorbuffer(IDirect3DSurface9 *renderTarget); + Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples); + + virtual ~Colorbuffer(); + + virtual IDirect3DSurface9 *getRenderTarget(); + + private: + DISALLOW_COPY_AND_ASSIGN(Colorbuffer); + + IDirect3DSurface9 *mRenderTarget; +}; + +class DepthStencilbuffer : public RenderbufferStorage +{ + public: + explicit DepthStencilbuffer(IDirect3DSurface9 *depthStencil); + DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples); + + ~DepthStencilbuffer(); + + virtual IDirect3DSurface9 *getDepthStencil(); + + protected: + IDirect3DSurface9 *mDepthStencil; + + private: + DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer); +}; + +class Depthbuffer : public DepthStencilbuffer +{ + public: + explicit Depthbuffer(IDirect3DSurface9 *depthStencil); + Depthbuffer(GLsizei width, GLsizei height, GLsizei samples); + + virtual ~Depthbuffer(); + + private: + DISALLOW_COPY_AND_ASSIGN(Depthbuffer); +}; + +class Stencilbuffer : public DepthStencilbuffer +{ + public: + explicit Stencilbuffer(IDirect3DSurface9 *depthStencil); + Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples); + + virtual ~Stencilbuffer(); + + private: + DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); +}; +} + +#endif // LIBGLESV2_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp new file mode 100644 index 0000000000..4b97e9c113 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp @@ -0,0 +1,320 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ResourceManager.cpp: Implements the gl::ResourceManager class, which tracks and +// retrieves objects which may be shared by multiple Contexts. + +#include "libGLESv2/ResourceManager.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/Texture.h" + +namespace gl +{ +ResourceManager::ResourceManager() +{ + mRefCount = 1; +} + +ResourceManager::~ResourceManager() +{ + while (!mBufferMap.empty()) + { + deleteBuffer(mBufferMap.begin()->first); + } + + while (!mProgramMap.empty()) + { + deleteProgram(mProgramMap.begin()->first); + } + + while (!mShaderMap.empty()) + { + deleteShader(mShaderMap.begin()->first); + } + + while (!mRenderbufferMap.empty()) + { + deleteRenderbuffer(mRenderbufferMap.begin()->first); + } + + while (!mTextureMap.empty()) + { + deleteTexture(mTextureMap.begin()->first); + } +} + +void ResourceManager::addRef() +{ + mRefCount++; +} + +void ResourceManager::release() +{ + if (--mRefCount == 0) + { + delete this; + } +} + +// Returns an unused buffer name +GLuint ResourceManager::createBuffer() +{ + GLuint handle = mBufferHandleAllocator.allocate(); + + mBufferMap[handle] = NULL; + + return handle; +} + +// Returns an unused shader/program name +GLuint ResourceManager::createShader(GLenum type) +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + if (type == GL_VERTEX_SHADER) + { + mShaderMap[handle] = new VertexShader(this, handle); + } + else if (type == GL_FRAGMENT_SHADER) + { + mShaderMap[handle] = new FragmentShader(this, handle); + } + else UNREACHABLE(); + + return handle; +} + +// Returns an unused program/shader name +GLuint ResourceManager::createProgram() +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + mProgramMap[handle] = new Program(this, handle); + + return handle; +} + +// Returns an unused texture name +GLuint ResourceManager::createTexture() +{ + GLuint handle = mTextureHandleAllocator.allocate(); + + mTextureMap[handle] = NULL; + + return handle; +} + +// Returns an unused renderbuffer name +GLuint ResourceManager::createRenderbuffer() +{ + GLuint handle = mRenderbufferHandleAllocator.allocate(); + + mRenderbufferMap[handle] = NULL; + + return handle; +} + +void ResourceManager::deleteBuffer(GLuint buffer) +{ + BufferMap::iterator bufferObject = mBufferMap.find(buffer); + + if (bufferObject != mBufferMap.end()) + { + mBufferHandleAllocator.release(bufferObject->first); + if (bufferObject->second) bufferObject->second->release(); + mBufferMap.erase(bufferObject); + } +} + +void ResourceManager::deleteShader(GLuint shader) +{ + ShaderMap::iterator shaderObject = mShaderMap.find(shader); + + if (shaderObject != mShaderMap.end()) + { + if (shaderObject->second->getRefCount() == 0) + { + mProgramShaderHandleAllocator.release(shaderObject->first); + delete shaderObject->second; + mShaderMap.erase(shaderObject); + } + else + { + shaderObject->second->flagForDeletion(); + } + } +} + +void ResourceManager::deleteProgram(GLuint program) +{ + ProgramMap::iterator programObject = mProgramMap.find(program); + + if (programObject != mProgramMap.end()) + { + if (programObject->second->getRefCount() == 0) + { + mProgramShaderHandleAllocator.release(programObject->first); + delete programObject->second; + mProgramMap.erase(programObject); + } + else + { + programObject->second->flagForDeletion(); + } + } +} + +void ResourceManager::deleteTexture(GLuint texture) +{ + TextureMap::iterator textureObject = mTextureMap.find(texture); + + if (textureObject != mTextureMap.end()) + { + mTextureHandleAllocator.release(textureObject->first); + if (textureObject->second) textureObject->second->release(); + mTextureMap.erase(textureObject); + } +} + +void ResourceManager::deleteRenderbuffer(GLuint renderbuffer) +{ + RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer); + + if (renderbufferObject != mRenderbufferMap.end()) + { + mRenderbufferHandleAllocator.release(renderbufferObject->first); + if (renderbufferObject->second) renderbufferObject->second->release(); + mRenderbufferMap.erase(renderbufferObject); + } +} + +Buffer *ResourceManager::getBuffer(unsigned int handle) +{ + BufferMap::iterator buffer = mBufferMap.find(handle); + + if (buffer == mBufferMap.end()) + { + return NULL; + } + else + { + return buffer->second; + } +} + +Shader *ResourceManager::getShader(unsigned int handle) +{ + ShaderMap::iterator shader = mShaderMap.find(handle); + + if (shader == mShaderMap.end()) + { + return NULL; + } + else + { + return shader->second; + } +} + +Texture *ResourceManager::getTexture(unsigned int handle) +{ + if (handle == 0) return NULL; + + TextureMap::iterator texture = mTextureMap.find(handle); + + if (texture == mTextureMap.end()) + { + return NULL; + } + else + { + return texture->second; + } +} + +Program *ResourceManager::getProgram(unsigned int handle) +{ + ProgramMap::iterator program = mProgramMap.find(handle); + + if (program == mProgramMap.end()) + { + return NULL; + } + else + { + return program->second; + } +} + +Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle) +{ + RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle); + + if (renderbuffer == mRenderbufferMap.end()) + { + return NULL; + } + else + { + return renderbuffer->second; + } +} + +void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) +{ + mRenderbufferMap[handle] = buffer; +} + +void ResourceManager::checkBufferAllocation(unsigned int buffer) +{ + if (buffer != 0 && !getBuffer(buffer)) + { + Buffer *bufferObject = new Buffer(buffer); + mBufferMap[buffer] = bufferObject; + bufferObject->addRef(); + } +} + +void ResourceManager::checkTextureAllocation(GLuint texture, TextureType type) +{ + if (!getTexture(texture) && texture != 0) + { + Texture *textureObject; + + if (type == TEXTURE_2D) + { + textureObject = new Texture2D(texture); + } + else if (type == TEXTURE_CUBE) + { + textureObject = new TextureCubeMap(texture); + } + else + { + UNREACHABLE(); + return; + } + + mTextureMap[texture] = textureObject; + textureObject->addRef(); + } +} + +void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer) +{ + if (renderbuffer != 0 && !getRenderbuffer(renderbuffer)) + { + Renderbuffer *renderbufferObject = new Renderbuffer(renderbuffer, new Colorbuffer(0, 0, GL_RGBA4, 0)); + mRenderbufferMap[renderbuffer] = renderbufferObject; + renderbufferObject->addRef(); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h new file mode 100644 index 0000000000..ae4f1b04a5 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h @@ -0,0 +1,116 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ResourceManager.h : Defines the ResourceManager class, which tracks objects +// shared by multiple GL contexts. + +#ifndef LIBGLESV2_RESOURCEMANAGER_H_ +#define LIBGLESV2_RESOURCEMANAGER_H_ + +#define GL_APICALL +#include + +#ifdef _MSC_VER +#include +#else +#include +#endif + +#include "common/angleutils.h" +#include "libGLESv2/HandleAllocator.h" + +namespace gl +{ +class Buffer; +class Shader; +class Program; +class Texture; +class Renderbuffer; + +enum TextureType +{ + TEXTURE_2D, + TEXTURE_CUBE, + + TEXTURE_TYPE_COUNT, + TEXTURE_UNKNOWN +}; + +enum SamplerType +{ + SAMPLER_PIXEL, + SAMPLER_VERTEX +}; + +class ResourceManager +{ + public: + ResourceManager(); + ~ResourceManager(); + + void addRef(); + void release(); + + GLuint createBuffer(); + GLuint createShader(GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createRenderbuffer(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + + Buffer *getBuffer(GLuint handle); + Shader *getShader(GLuint handle); + Program *getProgram(GLuint handle); + Texture *getTexture(GLuint handle); + Renderbuffer *getRenderbuffer(GLuint handle); + + void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); + + void checkBufferAllocation(unsigned int buffer); + void checkTextureAllocation(GLuint texture, TextureType type); + void checkRenderbufferAllocation(GLuint renderbuffer); + + private: + DISALLOW_COPY_AND_ASSIGN(ResourceManager); + + std::size_t mRefCount; + +#ifndef HASH_MAP +# ifdef _MSC_VER +# define HASH_MAP stdext::hash_map +# else +# define HASH_MAP std::unordered_map +# endif +#endif + + typedef HASH_MAP BufferMap; + BufferMap mBufferMap; + HandleAllocator mBufferHandleAllocator; + + typedef HASH_MAP ShaderMap; + ShaderMap mShaderMap; + + typedef HASH_MAP ProgramMap; + ProgramMap mProgramMap; + HandleAllocator mProgramShaderHandleAllocator; + + typedef HASH_MAP TextureMap; + TextureMap mTextureMap; + HandleAllocator mTextureHandleAllocator; + + typedef HASH_MAP RenderbufferMap; + RenderbufferMap mRenderbufferMap; + HandleAllocator mRenderbufferHandleAllocator; +}; + +} + +#endif // LIBGLESV2_RESOURCEMANAGER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp new file mode 100644 index 0000000000..1087f11b4a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp @@ -0,0 +1,584 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Shader.cpp: Implements the gl::Shader class and its derived classes +// VertexShader and FragmentShader. Implements GL shader objects and related +// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. + +#include "libGLESv2/Shader.h" + +#include + +#include "GLSLANG/ShaderLang.h" +#include "libGLESv2/main.h" +#include "libGLESv2/utilities.h" + +namespace gl +{ +void *Shader::mFragmentCompiler = NULL; +void *Shader::mVertexCompiler = NULL; + +Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager) +{ + mSource = NULL; + mHlsl = NULL; + mInfoLog = NULL; + + uncompile(); + initializeCompiler(); + + mRefCount = 0; + mDeleteStatus = false; +} + +Shader::~Shader() +{ + delete[] mSource; + delete[] mHlsl; + delete[] mInfoLog; +} + +GLuint Shader::getHandle() const +{ + return mHandle; +} + +void Shader::setSource(GLsizei count, const char **string, const GLint *length) +{ + delete[] mSource; + int totalLength = 0; + + for (int i = 0; i < count; i++) + { + if (length && length[i] >= 0) + { + totalLength += length[i]; + } + else + { + totalLength += (int)strlen(string[i]); + } + } + + mSource = new char[totalLength + 1]; + char *code = mSource; + + for (int i = 0; i < count; i++) + { + int stringLength; + + if (length && length[i] >= 0) + { + stringLength = length[i]; + } + else + { + stringLength = (int)strlen(string[i]); + } + + strncpy(code, string[i], stringLength); + code += stringLength; + } + + mSource[totalLength] = '\0'; +} + +int Shader::getInfoLogLength() const +{ + if (!mInfoLog) + { + return 0; + } + else + { + return strlen(mInfoLog) + 1; + } +} + +void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) +{ + int index = 0; + + if (bufSize > 0) + { + if (mInfoLog) + { + index = std::min(bufSize - 1, (int)strlen(mInfoLog)); + memcpy(infoLog, mInfoLog, index); + } + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +int Shader::getSourceLength() const +{ + if (!mSource) + { + return 0; + } + else + { + return strlen(mSource) + 1; + } +} + +int Shader::getTranslatedSourceLength() const +{ + if (!mHlsl) + { + return 0; + } + else + { + return strlen(mHlsl) + 1; + } +} + +void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer) +{ + int index = 0; + + if (bufSize > 0) + { + if (source) + { + index = std::min(bufSize - 1, (int)strlen(source)); + memcpy(buffer, source, index); + } + + buffer[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) +{ + getSourceImpl(mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) +{ + getSourceImpl(mHlsl, bufSize, length, buffer); +} + +bool Shader::isCompiled() +{ + return mHlsl != NULL; +} + +const char *Shader::getHLSL() +{ + return mHlsl; +} + +void Shader::addRef() +{ + mRefCount++; +} + +void Shader::release() +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteShader(mHandle); + } +} + +unsigned int Shader::getRefCount() const +{ + return mRefCount; +} + +bool Shader::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +void Shader::flagForDeletion() +{ + mDeleteStatus = true; +} + +// Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) +void Shader::initializeCompiler() +{ + if (!mFragmentCompiler) + { + int result = ShInitialize(); + + if (result) + { + ShBuiltInResources resources; + ShInitBuiltInResources(&resources); + Context *context = getContext(); + + resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS; + resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS; + resources.MaxVaryingVectors = context->getMaximumVaryingVectors(); + resources.MaxVertexTextureImageUnits = context->getMaximumVertexTextureImageUnits(); + resources.MaxCombinedTextureImageUnits = context->getMaximumCombinedTextureImageUnits(); + resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; + resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors(); + resources.MaxDrawBuffers = MAX_DRAW_BUFFERS; + resources.OES_standard_derivatives = 1; + // resources.OES_EGL_image_external = getDisplay()->isD3d9ExDevice() ? 1 : 0; // TODO: commented out until the extension is actually supported. + + mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources); + mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources); + } + } +} + +void Shader::releaseCompiler() +{ + ShDestruct(mFragmentCompiler); + ShDestruct(mVertexCompiler); + + mFragmentCompiler = NULL; + mVertexCompiler = NULL; + + ShFinalize(); +} + +void Shader::parseVaryings() +{ + if (mHlsl) + { + const char *input = strstr(mHlsl, "// Varyings") + 12; + + while(true) + { + char varyingType[256]; + char varyingName[256]; + + int matches = sscanf(input, "static %255s %255s", varyingType, varyingName); + + if (matches != 2) + { + break; + } + + char *array = strstr(varyingName, "["); + int size = 1; + + if (array) + { + size = atoi(array + 1); + *array = '\0'; + } + + mVaryings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL)); + + input = strstr(input, ";") + 2; + } + + mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL; + mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL; + mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL; + mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL; + } +} + +// initialize/clean up previous state +void Shader::uncompile() +{ + // set by compileToHLSL + delete[] mHlsl; + mHlsl = NULL; + delete[] mInfoLog; + mInfoLog = NULL; + + // set by parseVaryings + mVaryings.clear(); + + mUsesFragCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesPointCoord = false; +} + +void Shader::compileToHLSL(void *compiler) +{ + // ensure we don't pass a NULL source to the compiler + char *source = "\0"; + if (mSource) + { + source = mSource; + } + + // ensure the compiler is loaded + initializeCompiler(); + + int compileOptions = SH_OBJECT_CODE; + std::string sourcePath; + if (perfActive()) + { + sourcePath = getTempPath(); + writeFile(sourcePath.c_str(), source, strlen(source)); + compileOptions |= SH_LINE_DIRECTIVES; + } + + int result; + if (sourcePath.empty()) + { + result = ShCompile(compiler, &source, 1, compileOptions); + } + else + { + const char* sourceStrings[2] = + { + sourcePath.c_str(), + source + }; + + result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH); + } + + if (result) + { + int objCodeLen = 0; + ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen); + mHlsl = new char[objCodeLen]; + ShGetObjectCode(compiler, mHlsl); + } + else + { + int infoLogLen = 0; + ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen); + mInfoLog = new char[infoLogLen]; + ShGetInfoLog(compiler, mInfoLog); + + TRACE("\n%s", mInfoLog); + } +} + +GLenum Shader::parseType(const std::string &type) +{ + if (type == "float") + { + return GL_FLOAT; + } + else if (type == "float2") + { + return GL_FLOAT_VEC2; + } + else if (type == "float3") + { + return GL_FLOAT_VEC3; + } + else if (type == "float4") + { + return GL_FLOAT_VEC4; + } + else if (type == "float2x2") + { + return GL_FLOAT_MAT2; + } + else if (type == "float3x3") + { + return GL_FLOAT_MAT3; + } + else if (type == "float4x4") + { + return GL_FLOAT_MAT4; + } + else UNREACHABLE(); + + return GL_NONE; +} + +// true if varying x has a higher priority in packing than y +bool Shader::compareVarying(const Varying &x, const Varying &y) +{ + if(x.type == y.type) + { + return x.size > y.size; + } + + switch (x.type) + { + case GL_FLOAT_MAT4: return true; + case GL_FLOAT_MAT2: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return true; + case GL_FLOAT_VEC4: return true; + case GL_FLOAT_MAT3: return true; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_VEC4: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return true; + case GL_FLOAT_MAT3: return true; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_MAT3: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return false; + case GL_FLOAT_MAT3: return true; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_VEC3: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return false; + case GL_FLOAT_MAT3: return false; + case GL_FLOAT_VEC3: return true; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT_VEC2: + switch(y.type) + { + case GL_FLOAT_MAT4: return false; + case GL_FLOAT_MAT2: return false; + case GL_FLOAT_VEC4: return false; + case GL_FLOAT_MAT3: return false; + case GL_FLOAT_VEC3: return false; + case GL_FLOAT_VEC2: return true; + case GL_FLOAT: return true; + default: UNREACHABLE(); + } + break; + case GL_FLOAT: return false; + default: UNREACHABLE(); + } + + return false; +} + +VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) +{ +} + +VertexShader::~VertexShader() +{ +} + +GLenum VertexShader::getType() +{ + return GL_VERTEX_SHADER; +} + +void VertexShader::uncompile() +{ + Shader::uncompile(); + + // set by ParseAttributes + mAttributes.clear(); +}; + +void VertexShader::compile() +{ + uncompile(); + + compileToHLSL(mVertexCompiler); + parseAttributes(); + parseVaryings(); +} + +int VertexShader::getSemanticIndex(const std::string &attributeName) +{ + if (!attributeName.empty()) + { + int semanticIndex = 0; + for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++) + { + if (attribute->name == attributeName) + { + return semanticIndex; + } + + semanticIndex += VariableRowCount(attribute->type); + } + } + + return -1; +} + +void VertexShader::parseAttributes() +{ + const char *hlsl = getHLSL(); + if (hlsl) + { + const char *input = strstr(hlsl, "// Attributes") + 14; + + while(true) + { + char attributeType[256]; + char attributeName[256]; + + int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName); + + if (matches != 2) + { + break; + } + + mAttributes.push_back(Attribute(parseType(attributeType), attributeName)); + + input = strstr(input, ";") + 2; + } + } +} + +FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) +{ +} + +FragmentShader::~FragmentShader() +{ +} + +GLenum FragmentShader::getType() +{ + return GL_FRAGMENT_SHADER; +} + +void FragmentShader::compile() +{ + uncompile(); + + compileToHLSL(mFragmentCompiler); + parseVaryings(); + mVaryings.sort(compareVarying); +} +} diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.h b/src/3rdparty/angle/src/libGLESv2/Shader.h new file mode 100644 index 0000000000..b73fc288a1 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Shader.h @@ -0,0 +1,166 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Shader.h: Defines the abstract gl::Shader class and its concrete derived +// classes VertexShader and FragmentShader. Implements GL shader objects and +// related functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section +// 3.8 page 84. + +#ifndef LIBGLESV2_SHADER_H_ +#define LIBGLESV2_SHADER_H_ + +#define GL_APICALL +#include +#include +#include +#include + +#include "libGLESv2/ResourceManager.h" + +namespace gl +{ +struct Varying +{ + Varying(GLenum type, const std::string &name, int size, bool array) + : type(type), name(name), size(size), array(array), reg(-1), col(-1) + { + } + + GLenum type; + std::string name; + int size; // Number of 'type' elements + bool array; + + int reg; // First varying register, assigned during link + int col; // First register element, assigned during link +}; + +typedef std::list VaryingList; + +class Shader +{ + friend class ProgramBinary; + + public: + Shader(ResourceManager *manager, GLuint handle); + + virtual ~Shader(); + + virtual GLenum getType() = 0; + GLuint getHandle() const; + + void deleteSource(); + void setSource(GLsizei count, const char **string, const GLint *length); + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); + int getSourceLength() const; + void getSource(GLsizei bufSize, GLsizei *length, char *buffer); + int getTranslatedSourceLength() const; + void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer); + + virtual void compile() = 0; + virtual void uncompile(); + bool isCompiled(); + const char *getHLSL(); + + void addRef(); + void release(); + unsigned int getRefCount() const; + bool isFlaggedForDeletion() const; + void flagForDeletion(); + + static void releaseCompiler(); + + protected: + void parseVaryings(); + + void compileToHLSL(void *compiler); + + void getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer); + + static GLenum parseType(const std::string &type); + static bool compareVarying(const Varying &x, const Varying &y); + + VaryingList mVaryings; + + bool mUsesFragCoord; + bool mUsesFrontFacing; + bool mUsesPointSize; + bool mUsesPointCoord; + + static void *mFragmentCompiler; + static void *mVertexCompiler; + + private: + DISALLOW_COPY_AND_ASSIGN(Shader); + + void initializeCompiler(); + + const GLuint mHandle; + unsigned int mRefCount; // Number of program objects this shader is attached to + bool mDeleteStatus; // Flag to indicate that the shader can be deleted when no longer in use + + char *mSource; + char *mHlsl; + char *mInfoLog; + + ResourceManager *mResourceManager; +}; + +struct Attribute +{ + Attribute() : type(GL_NONE), name("") + { + } + + Attribute(GLenum type, const std::string &name) : type(type), name(name) + { + } + + GLenum type; + std::string name; +}; + +typedef std::vector AttributeArray; + +class VertexShader : public Shader +{ + friend class ProgramBinary; + + public: + VertexShader(ResourceManager *manager, GLuint handle); + + ~VertexShader(); + + virtual GLenum getType(); + virtual void compile(); + virtual void uncompile(); + int getSemanticIndex(const std::string &attributeName); + + private: + DISALLOW_COPY_AND_ASSIGN(VertexShader); + + void parseAttributes(); + + AttributeArray mAttributes; +}; + +class FragmentShader : public Shader +{ + public: + FragmentShader(ResourceManager *manager, GLuint handle); + + ~FragmentShader(); + + virtual GLenum getType(); + virtual void compile(); + + private: + DISALLOW_COPY_AND_ASSIGN(FragmentShader); +}; +} + +#endif // LIBGLESV2_SHADER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.cpp b/src/3rdparty/angle/src/libGLESv2/Texture.cpp new file mode 100644 index 0000000000..af430bf145 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Texture.cpp @@ -0,0 +1,3118 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Texture.cpp: Implements the gl::Texture class and its derived classes +// Texture2D and TextureCubeMap. Implements GL texture objects and related +// functionality. [OpenGL ES 2.0.24] section 3.7 page 63. + +#include "libGLESv2/Texture.h" + +#include + +#include "common/debug.h" + +#include "libEGL/Display.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/utilities.h" +#include "libGLESv2/Blit.h" +#include "libGLESv2/Framebuffer.h" + +namespace gl +{ +unsigned int TextureStorage::mCurrentTextureSerial = 1; + +static D3DFORMAT ConvertTextureInternalFormat(GLint internalformat) +{ + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + return D3DFMT_INTZ; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return D3DFMT_DXT1; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + return D3DFMT_DXT3; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return D3DFMT_DXT5; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + return D3DFMT_A32B32G32R32F; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + return D3DFMT_A16B16G16R16F; + case GL_LUMINANCE8_EXT: + if (getContext()->supportsLuminanceTextures()) + { + return D3DFMT_L8; + } + break; + case GL_LUMINANCE8_ALPHA8_EXT: + if (getContext()->supportsLuminanceAlphaTextures()) + { + return D3DFMT_A8L8; + } + break; + case GL_RGB8_OES: + case GL_RGB565: + return D3DFMT_X8R8G8B8; + } + + return D3DFMT_A8R8G8B8; +} + +static bool IsTextureFormatRenderable(D3DFORMAT format) +{ + if (format == D3DFMT_INTZ) + { + return true; + } + switch(format) + { + case D3DFMT_L8: + case D3DFMT_A8L8: + case D3DFMT_DXT1: + case D3DFMT_DXT3: + case D3DFMT_DXT5: + return false; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + return true; + default: + UNREACHABLE(); + } + + return false; +} + +static inline DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable) +{ + DWORD d3dusage = 0; + + if (d3dfmt == D3DFMT_INTZ) + { + d3dusage |= D3DUSAGE_DEPTHSTENCIL; + } + else if(forceRenderable || (IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE))) + { + d3dusage |= D3DUSAGE_RENDERTARGET; + } + return d3dusage; +} + +static void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + int upsampleCount = 0; + + if (isCompressed) + { + // Don't expand the size of full textures that are at least 4x4 + // already. + if (isImage || *requestWidth < 4 || *requestHeight < 4) + { + while (*requestWidth % 4 != 0 || *requestHeight % 4 != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + } + *levelOffset = upsampleCount; +} + +static void CopyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) +{ + D3DLOCKED_RECT sourceLock = {0}; + D3DLOCKED_RECT destLock = {0}; + + source->LockRect(&sourceLock, NULL, 0); + dest->LockRect(&destLock, NULL, 0); + + if (sourceLock.pBits && destLock.pBits) + { + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + int rows = dx::IsCompressedFormat(desc.Format) ? desc.Height / 4 : desc.Height; + int bytes = dx::ComputeRowSize(desc.Format, desc.Width); + ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch); + + for(int i = 0; i < rows; i++) + { + memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + } + else UNREACHABLE(); +} + +Image::Image() +{ + mWidth = 0; + mHeight = 0; + mInternalFormat = GL_NONE; + + mSurface = NULL; + + mDirty = false; + + mD3DPool = D3DPOOL_SYSTEMMEM; + mD3DFormat = D3DFMT_UNKNOWN; +} + +Image::~Image() +{ + if (mSurface) + { + mSurface->Release(); + } +} + +bool Image::redefine(GLint internalformat, GLsizei width, GLsizei height, bool forceRelease) +{ + if (mWidth != width || + mHeight != height || + mInternalFormat != internalformat || + forceRelease) + { + mWidth = width; + mHeight = height; + mInternalFormat = internalformat; + // compute the d3d format that will be used + mD3DFormat = ConvertTextureInternalFormat(internalformat); + + if (mSurface) + { + mSurface->Release(); + mSurface = NULL; + } + + return true; + } + + return false; +} + +void Image::createSurface() +{ + if(mSurface) + { + return; + } + + IDirect3DTexture9 *newTexture = NULL; + IDirect3DSurface9 *newSurface = NULL; + const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; + const D3DFORMAT d3dFormat = getD3DFormat(); + ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures + + if (mWidth != 0 && mHeight != 0) + { + int levelToFetch = 0; + GLsizei requestWidth = mWidth; + GLsizei requestHeight = mHeight; + MakeValidSize(true, IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch); + + HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, d3dFormat, + poolToUse, &newTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + ERR("Creating image surface failed."); + return error(GL_OUT_OF_MEMORY); + } + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + newTexture->Release(); + } + + mSurface = newSurface; + mDirty = false; + mD3DPool = poolToUse; +} + +HRESULT Image::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) +{ + createSurface(); + + HRESULT result = D3DERR_INVALIDCALL; + + if (mSurface) + { + result = mSurface->LockRect(lockedRect, rect, 0); + ASSERT(SUCCEEDED(result)); + + mDirty = true; + } + + return result; +} + +void Image::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + } +} + +bool Image::isRenderableFormat() const +{ + return IsTextureFormatRenderable(getD3DFormat()); +} + +D3DFORMAT Image::getD3DFormat() const +{ + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mD3DFormat != D3DFMT_UNKNOWN); + + return mD3DFormat; +} + +IDirect3DSurface9 *Image::getSurface() +{ + createSurface(); + + return mSurface; +} + +void Image::setManagedSurface(IDirect3DSurface9 *surface) +{ + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + ASSERT(desc.Pool == D3DPOOL_MANAGED); + + if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight) + { + if (mSurface) + { + CopyLockableSurfaces(surface, mSurface); + mSurface->Release(); + } + + mSurface = surface; + mD3DPool = desc.Pool; + } +} + +void Image::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + IDirect3DSurface9 *sourceSurface = getSurface(); + + if (sourceSurface && sourceSurface != destSurface) + { + RECT rect; + rect.left = xoffset; + rect.top = yoffset; + rect.right = xoffset + width; + rect.bottom = yoffset + height; + + POINT point = {rect.left, rect.top}; + + if (mD3DPool == D3DPOOL_MANAGED) + { + D3DSURFACE_DESC desc; + sourceSurface->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + HRESULT result = getDevice()->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + + if (SUCCEEDED(result)) + { + CopyLockableSurfaces(surf, sourceSurface); + result = getDevice()->UpdateSurface(surf, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + surf->Release(); + } + } + else + { + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + HRESULT result = getDevice()->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + } + } +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +void Image::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint unpackAlignment, const void *input) +{ + RECT lockRect = + { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + + GLsizei inputPitch = ComputePitch(width, mInternalFormat, unpackAlignment); + + switch (mInternalFormat) + { + case GL_ALPHA8_EXT: + if (supportsSSE2()) + { + loadAlphaDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + else + { + loadAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + break; + case GL_LUMINANCE8_EXT: + loadLuminanceData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8); + break; + case GL_ALPHA32F_EXT: + loadAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE32F_EXT: + loadLuminanceFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_ALPHA16F_EXT: + loadAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE16F_EXT: + loadLuminanceHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE8_ALPHA8_EXT: + loadLuminanceAlphaData(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8); + break; + case GL_LUMINANCE_ALPHA32F_EXT: + loadLuminanceAlphaFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_LUMINANCE_ALPHA16F_EXT: + loadLuminanceAlphaHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB8_OES: + loadRGBUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB565: + loadRGB565Data(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGBA8_OES: + if (supportsSSE2()) + { + loadRGBAUByteDataSSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + else + { + loadRGBAUByteData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + } + break; + case GL_RGBA4: + loadRGBA4444Data(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB5_A1: + loadRGBA5551Data(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_BGRA8_EXT: + loadBGRAData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D + case GL_RGB32F_EXT: + loadRGBFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGB16F_EXT: + loadRGBHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGBA32F_EXT: + loadRGBAFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + case GL_RGBA16F_EXT: + loadRGBAHalfFloatData(width, height, inputPitch, input, locked.Pitch, locked.pBits); + break; + default: UNREACHABLE(); + } + + unlock(); +} + +void Image::loadAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast(input) + y * inputPitch; + dest = static_cast(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } +} + +void Image::loadAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } +} + +void Image::loadAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = 0; + dest[4 * x + 1] = 0; + dest[4 * x + 2] = 0; + dest[4 * x + 3] = source[x]; + } + } +} + +void Image::loadLuminanceData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast(input) + y * inputPitch; + dest = static_cast(output) + y * outputPitch; + + if (!native) // BGRA8 destination format + { + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + else // L8 destination format + { + memcpy(dest, source, width); + } + } +} + +void Image::loadLuminanceFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 1.0f; + } + } +} + +void Image::loadLuminanceHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x]; + dest[4 * x + 1] = source[x]; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 + } + } +} + +void Image::loadLuminanceAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast(input) + y * inputPitch; + dest = static_cast(output) + y * outputPitch; + + if (!native) // BGRA8 destination format + { + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2*x+0]; + dest[4 * x + 1] = source[2*x+0]; + dest[4 * x + 2] = source[2*x+0]; + dest[4 * x + 3] = source[2*x+1]; + } + } + else + { + memcpy(dest, source, width * 2); + } + } +} + +void Image::loadLuminanceAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2*x+0]; + dest[4 * x + 1] = source[2*x+0]; + dest[4 * x + 2] = source[2*x+0]; + dest[4 * x + 3] = source[2*x+1]; + } + } +} + +void Image::loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[2*x+0]; + dest[4 * x + 1] = source[2*x+0]; + dest[4 * x + 2] = source[2*x+0]; + dest[4 * x + 3] = source[2*x+1]; + } + } +} + +void Image::loadRGBUByteData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast(input) + y * inputPitch; + dest = static_cast(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 2]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 0]; + dest[4 * x + 3] = 0xFF; + } + } +} + +void Image::loadRGB565Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = static_cast(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + unsigned short rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2); + dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 3] = 0xFF; + } + } +} + +void Image::loadRGBFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 0]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 2]; + dest[4 * x + 3] = 1.0f; + } + } +} + +void Image::loadRGBHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned short *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + for (int x = 0; x < width; x++) + { + dest[4 * x + 0] = source[x * 3 + 0]; + dest[4 * x + 1] = source[x * 3 + 1]; + dest[4 * x + 2] = source[x * 3 + 2]; + dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 + } + } +} + +void Image::loadRGBAUByteData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned int *source = NULL; + unsigned int *dest = NULL; + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + + for (int x = 0; x < width; x++) + { + unsigned int rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } +} + +void Image::loadRGBA4444Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = static_cast(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + unsigned short rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + } + } +} + +void Image::loadRGBA5551Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned short *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = static_cast(output) + y * outputPitch; + for (int x = 0; x < width; x++) + { + unsigned short rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } +} + +void Image::loadRGBAFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const float *source = NULL; + float *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + memcpy(dest, source, width * 16); + } +} + +void Image::loadRGBAHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast(input) + y * inputPitch; + dest = static_cast(output) + y * outputPitch; + memcpy(dest, source, width * 8); + } +} + +void Image::loadBGRAData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned char *dest = NULL; + + for (int y = 0; y < height; y++) + { + source = static_cast(input) + y * inputPitch; + dest = static_cast(output) + y * outputPitch; + memcpy(dest, source, width*4); + } +} + +void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + const void *input) { + ASSERT(xoffset % 4 == 0); + ASSERT(yoffset % 4 == 0); + + RECT lockRect = { + xoffset, yoffset, + xoffset + width, yoffset + height + }; + + D3DLOCKED_RECT locked; + HRESULT result = lock(&locked, &lockRect); + if (FAILED(result)) + { + return; + } + + GLsizei inputSize = ComputeCompressedSize(width, height, mInternalFormat); + GLsizei inputPitch = ComputeCompressedPitch(width, mInternalFormat); + int rows = inputSize / inputPitch; + for (int i = 0; i < rows; ++i) + { + memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch); + } + + unlock(); +} + +// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures +void Image::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget) +{ + IDirect3DDevice9 *device = getDevice(); + IDirect3DSurface9 *renderTargetData = NULL; + D3DSURFACE_DESC description; + renderTarget->GetDesc(&description); + + HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); + + if (FAILED(result)) + { + ERR("Could not create matching destination surface."); + return error(GL_OUT_OF_MEMORY); + } + + result = device->GetRenderTargetData(renderTarget, renderTargetData); + + if (FAILED(result)) + { + ERR("GetRenderTargetData unexpectedly failed."); + renderTargetData->Release(); + return error(GL_OUT_OF_MEMORY); + } + + RECT sourceRect = {x, y, x + width, y + height}; + RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; + + D3DLOCKED_RECT sourceLock = {0}; + result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); + + if (FAILED(result)) + { + ERR("Failed to lock the source surface (rectangle might be invalid)."); + renderTargetData->Release(); + return error(GL_OUT_OF_MEMORY); + } + + D3DLOCKED_RECT destLock = {0}; + result = lock(&destLock, &destRect); + + if (FAILED(result)) + { + ERR("Failed to lock the destination surface (rectangle might be invalid)."); + renderTargetData->UnlockRect(); + renderTargetData->Release(); + return error(GL_OUT_OF_MEMORY); + } + + if (destLock.pBits && sourceLock.pBits) + { + unsigned char *source = (unsigned char*)sourceLock.pBits; + unsigned char *dest = (unsigned char*)destLock.pBits; + + switch (description.Format) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + switch(getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + for(int y = 0; y < height; y++) + { + memcpy(dest, source, 4 * width); + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + dest[x] = source[x * 4 + 2]; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + dest[x * 2 + 0] = source[x * 4 + 2]; + dest[x * 2 + 1] = source[x * 4 + 3]; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_R5G6B5: + switch(getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned short rgb = ((unsigned short*)source)[x]; + unsigned char red = (rgb & 0xF800) >> 8; + unsigned char green = (rgb & 0x07E0) >> 3; + unsigned char blue = (rgb & 0x001F) << 3; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 6); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = 0xFF; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0xF8; + dest[x] = red | (red >> 5); + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_A1R5G5B5: + switch(getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)source)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 5); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = 0xFF; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8R8G8B8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)source)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + unsigned char alpha = (signed short)argb >> 15; + dest[x + 0] = blue | (blue >> 5); + dest[x + 1] = green | (green >> 5); + dest[x + 2] = red | (red >> 5); + dest[x + 3] = alpha; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0x7C; + dest[x] = (red << 1) | (red >> 4); + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for(int y = 0; y < height; y++) + { + for(int x = 0; x < width; x++) + { + unsigned char red = source[x * 2 + 1] & 0x7C; + dest[x * 2 + 0] = (red << 1) | (red >> 4); + dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; + } + + source += sourceLock.Pitch; + dest += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + } + + unlock(); + renderTargetData->UnlockRect(); + + renderTargetData->Release(); + + mDirty = true; +} + +namespace +{ +struct L8 +{ + unsigned char L; + + static void average(L8 *dst, const L8 *src1, const L8 *src2) + { + dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L); + } +}; + +struct A8L8 +{ + unsigned char L; + unsigned char A; + + static void average(A8L8 *dst, const A8L8 *src1, const A8L8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct A8R8G8B8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char A; + + static void average(A8R8G8B8 *dst, const A8R8G8B8 *src1, const A8R8G8B8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct A16B16G16R16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) + { + dst->R = float32ToFloat16((float16ToFloat32(src1->R) + float16ToFloat32(src2->R)) * 0.5f); + dst->G = float32ToFloat16((float16ToFloat32(src1->G) + float16ToFloat32(src2->G)) * 0.5f); + dst->B = float32ToFloat16((float16ToFloat32(src1->B) + float16ToFloat32(src2->B)) * 0.5f); + dst->A = float32ToFloat16((float16ToFloat32(src1->A) + float16ToFloat32(src2->A)) * 0.5f); + } +}; + +struct A32B32G32R32F +{ + float R; + float G; + float B; + float A; + + static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2) + { + dst->R = (src1->R + src2->R) * 0.5f; + dst->G = (src1->G + src2->G) * 0.5f; + dst->B = (src1->B + src2->B) * 0.5f; + dst->A = (src1->A + src2->A) * 0.5f; + } +}; + +template +void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight, + const unsigned char *sourceData, int sourcePitch, + unsigned char *destData, int destPitch) +{ + unsigned int mipWidth = std::max(1U, sourceWidth >> 1); + unsigned int mipHeight = std::max(1U, sourceHeight >> 1); + + if (sourceHeight == 1) + { + ASSERT(sourceWidth != 1); + + const T *src = (const T*)sourceData; + T *dst = (T*)destData; + + for (unsigned int x = 0; x < mipWidth; x++) + { + T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]); + } + } + else if (sourceWidth == 1) + { + ASSERT(sourceHeight != 1); + + for (unsigned int y = 0; y < mipHeight; y++) + { + const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch); + const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch); + T *dst = (T*)(destData + y * destPitch); + + T::average(dst, src0, src1); + } + } + else + { + for (unsigned int y = 0; y < mipHeight; y++) + { + const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch); + const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch); + T *dst = (T*)(destData + y * destPitch); + + for (unsigned int x = 0; x < mipWidth; x++) + { + T tmp0; + T tmp1; + + T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]); + T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]); + T::average(&dst[x], &tmp0, &tmp1); + } + } + } +} + +void GenerateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) +{ + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + + ASSERT(sourceDesc.Format == destDesc.Format); + ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); + ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, NULL, 0); + ASSERT(SUCCEEDED(result)); + + const unsigned char *sourceData = reinterpret_cast(sourceLocked.pBits); + unsigned char *destData = reinterpret_cast(destLocked.pBits); + + if (sourceData && destData) + { + switch (sourceDesc.Format) + { + case D3DFMT_L8: + GenerateMip(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A8L8: + GenerateMip(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + GenerateMip(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A16B16G16R16F: + GenerateMip(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + case D3DFMT_A32B32G32R32F: + GenerateMip(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch); + break; + default: + UNREACHABLE(); + break; + } + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + } +} +} + +TextureStorage::TextureStorage(DWORD usage) + : mD3DUsage(usage), + mD3DPool(getDisplay()->getTexturePool(usage)), + mTextureSerial(issueTextureSerial()), + mLodOffset(0) +{ +} + +TextureStorage::~TextureStorage() +{ +} + +bool TextureStorage::isRenderTarget() const +{ + return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; +} + +bool TextureStorage::isManaged() const +{ + return (mD3DPool == D3DPOOL_MANAGED); +} + +D3DPOOL TextureStorage::getPool() const +{ + return mD3DPool; +} + +DWORD TextureStorage::getUsage() const +{ + return mD3DUsage; +} + +unsigned int TextureStorage::getTextureSerial() const +{ + return mTextureSerial; +} + +unsigned int TextureStorage::issueTextureSerial() +{ + return mCurrentTextureSerial++; +} + +int TextureStorage::getLodOffset() const +{ + return mLodOffset; +} + +Texture::Texture(GLuint id) : RefCountObject(id) +{ + mMinFilter = GL_NEAREST_MIPMAP_LINEAR; + mMagFilter = GL_LINEAR; + mWrapS = GL_REPEAT; + mWrapT = GL_REPEAT; + mDirtyParameters = true; + mUsage = GL_NONE; + mMaxAnisotropy = 1.0f; + + mDirtyImages = true; + + mImmutable = false; +} + +Texture::~Texture() +{ +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMinFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + { + if (mMinFilter != filter) + { + mMinFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMagFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + { + if (mMagFilter != filter) + { + mMagFilter = filter; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapS(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + { + if (mWrapS != wrap) + { + mWrapS = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapT(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + { + if (mWrapT != wrap) + { + mWrapT = wrap; + mDirtyParameters = true; + } + return true; + } + default: + return false; + } +} + +// Returns true on successful max anisotropy update (valid anisotropy value) +bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy) +{ + textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy); + if (textureMaxAnisotropy < 1.0f) + { + return false; + } + if (mMaxAnisotropy != textureMaxAnisotropy) + { + mMaxAnisotropy = textureMaxAnisotropy; + mDirtyParameters = true; + } + return true; +} + +// Returns true on successful usage state update (valid enum parameter) +bool Texture::setUsage(GLenum usage) +{ + switch (usage) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + mUsage = usage; + return true; + default: + return false; + } +} + +GLenum Texture::getMinFilter() const +{ + return mMinFilter; +} + +GLenum Texture::getMagFilter() const +{ + return mMagFilter; +} + +GLenum Texture::getWrapS() const +{ + return mWrapS; +} + +GLenum Texture::getWrapT() const +{ + return mWrapT; +} + +float Texture::getMaxAnisotropy() const +{ + return mMaxAnisotropy; +} + +GLenum Texture::getUsage() const +{ + return mUsage; +} + +void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels); + mDirtyImages = true; + } +} + +void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels); + mDirtyImages = true; + } +} + +bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels); + mDirtyImages = true; + } + + return true; +} + +bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image) +{ + if (pixels != NULL) + { + image->loadCompressedData(xoffset, yoffset, width, height, pixels); + mDirtyImages = true; + } + + return true; +} + +IDirect3DBaseTexture9 *Texture::getTexture() +{ + if (!isSamplerComplete()) + { + return NULL; + } + + // ensure the underlying texture is created + if (getStorage(false) == NULL) + { + return NULL; + } + + updateTexture(); + + return getBaseTexture(); +} + +bool Texture::hasDirtyParameters() const +{ + return mDirtyParameters; +} + +bool Texture::hasDirtyImages() const +{ + return mDirtyImages; +} + +void Texture::resetDirty() +{ + mDirtyParameters = false; + mDirtyImages = false; +} + +unsigned int Texture::getTextureSerial() +{ + TextureStorage *texture = getStorage(false); + return texture ? texture->getTextureSerial() : 0; +} + +unsigned int Texture::getRenderTargetSerial(GLenum target) +{ + TextureStorage *texture = getStorage(true); + return texture ? texture->getRenderTargetSerial(target) : 0; +} + +bool Texture::isImmutable() const +{ + return mImmutable; +} + +int Texture::getLodOffset() +{ + TextureStorage *texture = getStorage(false); + return texture ? texture->getLodOffset() : 0; +} + +GLint Texture::creationLevels(GLsizei width, GLsizei height) const +{ + if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture()) + { + return 0; // Maximum number of levels + } + else + { + // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. + return 1; + } +} + +GLint Texture::creationLevels(GLsizei size) const +{ + return creationLevels(size, size); +} + +int Texture::levelCount() +{ + return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0; +} + +Blit *Texture::getBlitter() +{ + Context *context = getContext(); + return context->getBlitter(); +} + +bool Texture::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + if (source && dest) + { + HRESULT result = D3DERR_OUTOFVIDEOMEMORY; + + if (fromManaged) + { + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + result = getDevice()->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + + if (SUCCEEDED(result)) + { + CopyLockableSurfaces(surf, source); + result = getDevice()->UpdateSurface(surf, NULL, dest, NULL); + surf->Release(); + } + } + else + { + egl::Display *display = getDisplay(); + IDirect3DDevice9 *device = display->getDevice(); + + display->endScene(); + result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return false; + } + } + + return true; +} + +TextureStorage2D::TextureStorage2D(IDirect3DTexture9 *surfaceTexture) : TextureStorage(D3DUSAGE_RENDERTARGET), mRenderTargetSerial(RenderbufferStorage::issueSerial()) +{ + mTexture = surfaceTexture; +} + +TextureStorage2D::TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height) + : TextureStorage(usage), mRenderTargetSerial(RenderbufferStorage::issueSerial()) +{ + mTexture = NULL; + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (width > 0 && height > 0) + { + IDirect3DDevice9 *device = getDevice(); + MakeValidSize(false, dx::IsCompressedFormat(format), &width, &height, &mLodOffset); + HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(), format, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } + } +} + +TextureStorage2D::~TextureStorage2D() +{ + if (mTexture) + { + mTexture->Release(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureStorage2D::getSurfaceLevel(int level, bool dirty) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface); + ASSERT(SUCCEEDED(result)); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + mTexture->AddDirtyRect(NULL); + } + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorage2D::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorage2D::getRenderTargetSerial(GLenum target) const +{ + return mRenderTargetSerial; +} + +Texture2D::Texture2D(GLuint id) : Texture(id) +{ + mTexStorage = NULL; + mSurface = NULL; + mColorbufferProxy = NULL; + mProxyRefs = 0; +} + +Texture2D::~Texture2D() +{ + mColorbufferProxy = NULL; + + delete mTexStorage; + mTexStorage = NULL; + + if (mSurface) + { + mSurface->setBoundTexture(NULL); + mSurface = NULL; + } +} + +// We need to maintain a count of references to renderbuffers acting as +// proxies for this texture, so that we do not attempt to use a pointer +// to a renderbuffer proxy which has been deleted. +void Texture2D::addProxyRef(const Renderbuffer *proxy) +{ + mProxyRefs++; +} + +void Texture2D::releaseProxy(const Renderbuffer *proxy) +{ + if (mProxyRefs > 0) + mProxyRefs--; + + if (mProxyRefs == 0) + mColorbufferProxy = NULL; +} + +GLenum Texture2D::getTarget() const +{ + return GL_TEXTURE_2D; +} + +GLsizei Texture2D::getWidth(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getWidth(); + else + return 0; +} + +GLsizei Texture2D::getHeight(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getHeight(); + else + return 0; +} + +GLenum Texture2D::getInternalFormat(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getInternalFormat(); + else + return GL_NONE; +} + +D3DFORMAT Texture2D::getD3DFormat(GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level].getD3DFormat(); + else + return D3DFMT_UNKNOWN; +} + +void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height) +{ + releaseTexImage(); + + bool redefined = mImageArray[level].redefine(internalformat, width, height, false); + + if (mTexStorage && redefined) + { + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i].markDirty(); + } + + delete mTexStorage; + mTexStorage = NULL; + mDirtyImages = true; + } +} + +void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + GLint internalformat = ConvertSizedInternalFormat(format, type); + redefineImage(level, internalformat, width, height); + + Texture::setImage(unpackAlignment, pixels, &mImageArray[level]); +} + +void Texture2D::bindTexImage(egl::Surface *surface) +{ + releaseTexImage(); + + GLint internalformat; + + switch(surface->getFormat()) + { + case D3DFMT_A8R8G8B8: + internalformat = GL_RGBA8_OES; + break; + case D3DFMT_X8R8G8B8: + internalformat = GL_RGB8_OES; + break; + default: + UNIMPLEMENTED(); + return; + } + + mImageArray[0].redefine(internalformat, surface->getWidth(), surface->getHeight(), true); + + delete mTexStorage; + mTexStorage = new TextureStorage2D(surface->getOffscreenTexture()); + + mDirtyImages = true; + mSurface = surface; + mSurface->setBoundTexture(this); +} + +void Texture2D::releaseTexImage() +{ + if (mSurface) + { + mSurface->setBoundTexture(NULL); + mSurface = NULL; + + if (mTexStorage) + { + delete mTexStorage; + mTexStorage = NULL; + } + + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i].redefine(GL_RGBA8_OES, 0, 0, true); + } + } +} + +void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +{ + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, format, width, height); + + Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]); +} + +void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(mImageArray[level].getSurface() != NULL); + + if (level < levelCount()) + { + IDirect3DSurface9 *destLevel = mTexStorage->getSurfaceLevel(level, true); + + if (destLevel) + { + Image *image = &mImageArray[level]; + image->updateSurface(destLevel, xoffset, yoffset, width, height); + + destLevel->Release(); + image->markClean(); + } + } +} + +void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level])) + { + commitRect(level, xoffset, yoffset, width, height); + } +} + +void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +{ + if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level])) + { + commitRect(level, xoffset, yoffset, width, height); + } +} + +void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); + redefineImage(level, internalformat, width, height); + + if (!mImageArray[level].isRenderableFormat()) + { + mImageArray[level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + mImageArray[level].markClean(); + + if (width != 0 && height != 0 && level < levelCount()) + { + RECT sourceRect; + sourceRect.left = x; + sourceRect.right = x + width; + sourceRect.top = y; + sourceRect.bottom = y + height; + + IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + if (xoffset + width > mImageArray[level].getWidth() || yoffset + height > mImageArray[level].getHeight()) + { + return error(GL_INVALID_VALUE); + } + + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + if (!mImageArray[level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) + { + mImageArray[level].copy(xoffset, yoffset, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + updateTexture(); + + if (level < levelCount()) + { + RECT sourceRect; + sourceRect.left = x; + sourceRect.right = x + width; + sourceRect.top = y; + sourceRect.bottom = y + height; + + IDirect3DSurface9 *dest = mTexStorage->getSurfaceLevel(level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, + gl::ExtractFormat(mImageArray[0].getInternalFormat()), + xoffset, yoffset, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height); + mImmutable = true; + + for (int level = 0; level < levels; level++) + { + mImageArray[level].redefine(internalformat, width, height, true); + width = std::max(1, width >> 1); + height = std::max(1, height >> 1); + } + + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level].redefine(GL_NONE, 0, 0, true); + } + + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false); + mImageArray[level].setManagedSurface(surface); + } + } +} + +// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. +bool Texture2D::isSamplerComplete() const +{ + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + bool mipmapping = false; + + switch (mMinFilter) + { + case GL_NEAREST: + case GL_LINEAR: + mipmapping = false; + break; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + mipmapping = true; + break; + default: UNREACHABLE(); + } + + if ((IsFloat32Format(getInternalFormat(0)) && !getContext()->supportsFloat32LinearFilter()) || + (IsFloat16Format(getInternalFormat(0)) && !getContext()->supportsFloat16LinearFilter())) + { + if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + bool npotSupport = getContext()->supportsNonPower2Texture(); + + if (!npotSupport) + { + if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) || + (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height))) + { + return false; + } + } + + if (mipmapping) + { + if (!npotSupport) + { + if (!isPow2(width) || !isPow2(height)) + { + return false; + } + } + + if (!isMipmapComplete()) + { + return false; + } + } + + return true; +} + +// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool Texture2D::isMipmapComplete() const +{ + if (isImmutable()) + { + return true; + } + + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + int q = log2(std::max(width, height)); + + for (int level = 1; level <= q; level++) + { + if (mImageArray[level].getInternalFormat() != mImageArray[0].getInternalFormat()) + { + return false; + } + + if (mImageArray[level].getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (mImageArray[level].getHeight() != std::max(1, height >> level)) + { + return false; + } + } + + return true; +} + +bool Texture2D::isCompressed(GLint level) const +{ + return IsCompressed(getInternalFormat(level)); +} + +bool Texture2D::isDepth(GLint level) const +{ + return IsDepthTexture(getInternalFormat(level)); +} + +IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const +{ + return mTexStorage ? mTexStorage->getBaseTexture() : NULL; +} + +// Constructs a Direct3D 9 texture resource from the texture images +void Texture2D::createTexture() +{ + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + + if (!(width > 0 && height > 0)) + return; // do not attempt to create d3d textures for nonexistant data + + GLint levels = creationLevels(width, height); + D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height); + + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getSurfaceLevel(level, false); + mImageArray[level].setManagedSurface(surface); + } + } + + mDirtyImages = true; +} + +void Texture2D::updateTexture() +{ + int levels = levelCount(); + + for (int level = 0; level < levels; level++) + { + Image *image = &mImageArray[level]; + + if (image->isDirty()) + { + commitRect(level, 0, 0, mImageArray[level].getWidth(), mImageArray[level].getHeight()); + } + } +} + +void Texture2D::convertToRenderTarget() +{ + TextureStorage2D *newTexStorage = NULL; + + if (mImageArray[0].getWidth() != 0 && mImageArray[0].getHeight() != 0) + { + GLsizei width = mImageArray[0].getWidth(); + GLsizei height = mImageArray[0].getHeight(); + GLint levels = creationLevels(width, height); + D3DFORMAT d3dfmt = mImageArray[0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true); + + newTexStorage = new TextureStorage2D(levels, d3dfmt, d3dusage, width, height); + + if (mTexStorage != NULL) + { + int levels = levelCount(); + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *source = mTexStorage->getSurfaceLevel(i, false); + IDirect3DSurface9 *dest = newTexStorage->getSurfaceLevel(i, true); + + if (!copyToRenderTarget(dest, source, mTexStorage->isManaged())) + { + delete newTexStorage; + if (source) source->Release(); + if (dest) dest->Release(); + return error(GL_OUT_OF_MEMORY); + } + + if (source) source->Release(); + if (dest) dest->Release(); + } + } + } + + delete mTexStorage; + mTexStorage = newTexStorage; + + mDirtyImages = true; +} + +void Texture2D::generateMipmaps() +{ + if (!getContext()->supportsNonPower2Texture()) + { + if (!isPow2(mImageArray[0].getWidth()) || !isPow2(mImageArray[0].getHeight())) + { + return error(GL_INVALID_OPERATION); + } + } + + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + unsigned int q = log2(std::max(mImageArray[0].getWidth(), mImageArray[0].getHeight())); + for (unsigned int i = 1; i <= q; i++) + { + redefineImage(i, mImageArray[0].getInternalFormat(), + std::max(mImageArray[0].getWidth() >> i, 1), + std::max(mImageArray[0].getHeight() >> i, 1)); + } + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (unsigned int i = 1; i <= q; i++) + { + IDirect3DSurface9 *upper = mTexStorage->getSurfaceLevel(i - 1, false); + IDirect3DSurface9 *lower = mTexStorage->getSurfaceLevel(i, true); + + if (upper != NULL && lower != NULL) + { + getBlitter()->boxFilter(upper, lower); + } + + if (upper != NULL) upper->Release(); + if (lower != NULL) lower->Release(); + + mImageArray[i].markClean(); + } + } + else + { + for (unsigned int i = 1; i <= q; i++) + { + if (mImageArray[i].getSurface() == NULL) + { + return error(GL_OUT_OF_MEMORY); + } + + GenerateMip(mImageArray[i].getSurface(), mImageArray[i - 1].getSurface()); + + mImageArray[i].markDirty(); + } + } +} + +Renderbuffer *Texture2D::getRenderbuffer(GLenum target) +{ + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); + } + + if (mColorbufferProxy == NULL) + { + mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture2D(this, target)); + } + + return mColorbufferProxy; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target) +{ + ASSERT(target == GL_TEXTURE_2D); + + // ensure the underlying texture is created + if (getStorage(true) == NULL) + { + return NULL; + } + + updateTexture(); + + // ensure this is NOT a depth texture + if (isDepth(0)) + { + return NULL; + } + return mTexStorage->getSurfaceLevel(0, false); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *Texture2D::getDepthStencil(GLenum target) +{ + ASSERT(target == GL_TEXTURE_2D); + + // ensure the underlying texture is created + if (getStorage(true) == NULL) + { + return NULL; + } + + updateTexture(); + + // ensure this is actually a depth texture + if (!isDepth(0)) + { + return NULL; + } + return mTexStorage->getSurfaceLevel(0, false); +} + +TextureStorage *Texture2D::getStorage(bool renderTarget) +{ + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) + { + if (renderTarget) + { + convertToRenderTarget(); + } + else + { + createTexture(); + } + } + + return mTexStorage; +} + +TextureStorageCubeMap::TextureStorageCubeMap(int levels, D3DFORMAT format, DWORD usage, int size) + : TextureStorage(usage), mFirstRenderTargetSerial(RenderbufferStorage::issueCubeSerials()) +{ + mTexture = NULL; + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (size > 0) + { + IDirect3DDevice9 *device = getDevice(); + int height = size; + MakeValidSize(false, dx::IsCompressedFormat(format), &size, &height, &mLodOffset); + HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(), format, getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + error(GL_OUT_OF_MEMORY); + } + } +} + +TextureStorageCubeMap::~TextureStorageCubeMap() +{ + if (mTexture) + { + mTexture->Release(); + } +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureStorageCubeMap::getCubeMapSurface(GLenum faceTarget, int level, bool dirty) +{ + IDirect3DSurface9 *surface = NULL; + + if (mTexture) + { + D3DCUBEMAP_FACES face = es2dx::ConvertCubeFace(faceTarget); + HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface); + ASSERT(SUCCEEDED(result)); + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + mTexture->AddDirtyRect(face, NULL); + } + } + + return surface; +} + +IDirect3DBaseTexture9 *TextureStorageCubeMap::getBaseTexture() const +{ + return mTexture; +} + +unsigned int TextureStorageCubeMap::getRenderTargetSerial(GLenum target) const +{ + return mFirstRenderTargetSerial + TextureCubeMap::faceIndex(target); +} + +TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id) +{ + mTexStorage = NULL; + for (int i = 0; i < 6; i++) + { + mFaceProxies[i] = NULL; + mFaceProxyRefs[i] = 0; + } +} + +TextureCubeMap::~TextureCubeMap() +{ + for (int i = 0; i < 6; i++) + { + mFaceProxies[i] = NULL; + } + + delete mTexStorage; + mTexStorage = NULL; +} + +// We need to maintain a count of references to renderbuffers acting as +// proxies for this texture, so that the texture is not deleted while +// proxy references still exist. If the reference count drops to zero, +// we set our proxy pointer NULL, so that a new attempt at referencing +// will cause recreation. +void TextureCubeMap::addProxyRef(const Renderbuffer *proxy) +{ + for (int i = 0; i < 6; i++) + { + if (mFaceProxies[i] == proxy) + mFaceProxyRefs[i]++; + } +} + +void TextureCubeMap::releaseProxy(const Renderbuffer *proxy) +{ + for (int i = 0; i < 6; i++) + { + if (mFaceProxies[i] == proxy) + { + if (mFaceProxyRefs[i] > 0) + mFaceProxyRefs[i]--; + + if (mFaceProxyRefs[i] == 0) + mFaceProxies[i] = NULL; + } + } +} + +GLenum TextureCubeMap::getTarget() const +{ + return GL_TEXTURE_CUBE_MAP; +} + +GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getWidth(); + else + return 0; +} + +GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getHeight(); + else + return 0; +} + +GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getInternalFormat(); + else + return GL_NONE; +} + +D3DFORMAT TextureCubeMap::getD3DFormat(GLenum target, GLint level) const +{ + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[faceIndex(target)][level].getD3DFormat(); + else + return D3DFMT_UNKNOWN; +} + +void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(0, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(1, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(2, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(3, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(4, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + setImage(5, level, width, height, format, type, unpackAlignment, pixels); +} + +void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +{ + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(faceIndex(face), level, format, width, height); + + Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]); +} + +void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(mImageArray[face][level].getSurface() != NULL); + + if (level < levelCount()) + { + IDirect3DSurface9 *destLevel = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true); + ASSERT(destLevel != NULL); + + if (destLevel != NULL) + { + Image *image = &mImageArray[face][level]; + image->updateSurface(destLevel, xoffset, yoffset, width, height); + + destLevel->Release(); + image->markClean(); + } + } +} + +void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level])) + { + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); + } +} + +void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +{ + if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level])) + { + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); + } +} + +// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. +bool TextureCubeMap::isSamplerComplete() const +{ + int size = mImageArray[0][0].getWidth(); + + bool mipmapping; + + switch (mMinFilter) + { + case GL_NEAREST: + case GL_LINEAR: + mipmapping = false; + break; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + mipmapping = true; + break; + default: + UNREACHABLE(); + return false; + } + + if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !getContext()->supportsFloat32LinearFilter()) || + (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !getContext()->supportsFloat16LinearFilter())) + { + if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST)) + { + return false; + } + } + + if (!isPow2(size) && !getContext()->supportsNonPower2Texture()) + { + if (getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE || mipmapping) + { + return false; + } + } + + if (!mipmapping) + { + if (!isCubeComplete()) + { + return false; + } + } + else + { + if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() + { + return false; + } + } + + return true; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureCubeMap::isCubeComplete() const +{ + if (mImageArray[0][0].getWidth() <= 0 || mImageArray[0][0].getHeight() != mImageArray[0][0].getWidth()) + { + return false; + } + + for (unsigned int face = 1; face < 6; face++) + { + if (mImageArray[face][0].getWidth() != mImageArray[0][0].getWidth() || + mImageArray[face][0].getWidth() != mImageArray[0][0].getHeight() || + mImageArray[face][0].getInternalFormat() != mImageArray[0][0].getInternalFormat()) + { + return false; + } + } + + return true; +} + +bool TextureCubeMap::isMipmapCubeComplete() const +{ + if (isImmutable()) + { + return true; + } + + if (!isCubeComplete()) + { + return false; + } + + GLsizei size = mImageArray[0][0].getWidth(); + + int q = log2(size); + + for (int face = 0; face < 6; face++) + { + for (int level = 1; level <= q; level++) + { + if (mImageArray[face][level].getInternalFormat() != mImageArray[0][0].getInternalFormat()) + { + return false; + } + + if (mImageArray[face][level].getWidth() != std::max(1, size >> level)) + { + return false; + } + } + } + + return true; +} + +bool TextureCubeMap::isCompressed(GLenum target, GLint level) const +{ + return IsCompressed(getInternalFormat(target, level)); +} + +IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const +{ + return mTexStorage ? mTexStorage->getBaseTexture() : NULL; +} + +// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one +void TextureCubeMap::createTexture() +{ + GLsizei size = mImageArray[0][0].getWidth(); + + if (!(size > 0)) + return; // do not attempt to create d3d textures for nonexistant data + + GLint levels = creationLevels(size); + D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size); + + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false); + mImageArray[face][level].setManagedSurface(surface); + } + } + } + + mDirtyImages = true; +} + +void TextureCubeMap::updateTexture() +{ + for (int face = 0; face < 6; face++) + { + int levels = levelCount(); + for (int level = 0; level < levels; level++) + { + Image *image = &mImageArray[face][level]; + + if (image->isDirty()) + { + commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); + } + } + } +} + +void TextureCubeMap::convertToRenderTarget() +{ + TextureStorageCubeMap *newTexStorage = NULL; + + if (mImageArray[0][0].getWidth() != 0) + { + GLsizei size = mImageArray[0][0].getWidth(); + GLint levels = creationLevels(size); + D3DFORMAT d3dfmt = mImageArray[0][0].getD3DFormat(); + DWORD d3dusage = GetTextureUsage(d3dfmt, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true); + + newTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size); + + if (mTexStorage != NULL) + { + int levels = levelCount(); + for (int f = 0; f < 6; f++) + { + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *source = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false); + IDirect3DSurface9 *dest = newTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true); + + if (!copyToRenderTarget(dest, source, mTexStorage->isManaged())) + { + delete newTexStorage; + if (source) source->Release(); + if (dest) dest->Release(); + return error(GL_OUT_OF_MEMORY); + } + + if (source) source->Release(); + if (dest) dest->Release(); + } + } + } + } + + delete mTexStorage; + mTexStorage = newTexStorage; + + mDirtyImages = true; +} + +void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) +{ + GLint internalformat = ConvertSizedInternalFormat(format, type); + redefineImage(faceIndex, level, internalformat, width, height); + + Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]); +} + +unsigned int TextureCubeMap::faceIndex(GLenum face) +{ + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); + + return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; +} + +void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height) +{ + bool redefined = mImageArray[face][level].redefine(internalformat, width, height, false); + + if (mTexStorage && redefined) + { + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + for (int f = 0; f < 6; f++) + { + mImageArray[f][i].markDirty(); + } + } + + delete mTexStorage; + mTexStorage = NULL; + + mDirtyImages = true; + } +} + +void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + unsigned int faceindex = faceIndex(target); + GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); + redefineImage(faceindex, level, internalformat, width, height); + + if (!mImageArray[faceindex][level].isRenderableFormat()) + { + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + mImageArray[faceindex][level].markClean(); + + ASSERT(width == height); + + if (width > 0 && level < levelCount()) + { + RECT sourceRect; + sourceRect.left = x; + sourceRect.right = x + width; + sourceRect.top = y; + sourceRect.bottom = y + height; + + IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, format, 0, 0, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +{ + GLsizei size = mImageArray[faceIndex(target)][level].getWidth(); + + if (xoffset + width > size || yoffset + height > size) + { + return error(GL_INVALID_VALUE); + } + + IDirect3DSurface9 *renderTarget = source->getRenderTarget(); + + if (!renderTarget) + { + ERR("Failed to retrieve the render target."); + return error(GL_OUT_OF_MEMORY); + } + + unsigned int faceindex = faceIndex(target); + + if (!mImageArray[faceindex][level].isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) + { + mImageArray[faceindex][level].copy(0, 0, x, y, width, height, renderTarget); + mDirtyImages = true; + } + else + { + if (!mTexStorage || !mTexStorage->isRenderTarget()) + { + convertToRenderTarget(); + } + + updateTexture(); + + if (level < levelCount()) + { + RECT sourceRect; + sourceRect.left = x; + sourceRect.right = x + width; + sourceRect.top = y; + sourceRect.bottom = y + height; + + IDirect3DSurface9 *dest = mTexStorage->getCubeMapSurface(target, level, true); + + if (dest) + { + getBlitter()->copy(renderTarget, sourceRect, gl::ExtractFormat(mImageArray[0][0].getInternalFormat()), xoffset, yoffset, dest); + dest->Release(); + } + } + } + + renderTarget->Release(); +} + +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) +{ + D3DFORMAT d3dfmt = ConvertTextureInternalFormat(internalformat); + DWORD d3dusage = GetTextureUsage(d3dfmt, mUsage, false); + + delete mTexStorage; + mTexStorage = new TextureStorageCubeMap(levels, d3dfmt, d3dusage, size); + mImmutable = true; + + for (int level = 0; level < levels; level++) + { + for (int face = 0; face < 6; face++) + { + mImageArray[face][level].redefine(internalformat, size, size, true); + size = std::max(1, size >> 1); + } + } + + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int face = 0; face < 6; face++) + { + mImageArray[face][level].redefine(GL_NONE, 0, 0, true); + } + } + + if (mTexStorage->isManaged()) + { + int levels = levelCount(); + + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < levels; level++) + { + IDirect3DSurface9 *surface = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false); + mImageArray[face][level].setManagedSurface(surface); + } + } + } +} + +void TextureCubeMap::generateMipmaps() +{ + if (!isCubeComplete()) + { + return error(GL_INVALID_OPERATION); + } + + if (!getContext()->supportsNonPower2Texture()) + { + if (!isPow2(mImageArray[0][0].getWidth())) + { + return error(GL_INVALID_OPERATION); + } + } + + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + unsigned int q = log2(mImageArray[0][0].getWidth()); + for (unsigned int f = 0; f < 6; f++) + { + for (unsigned int i = 1; i <= q; i++) + { + redefineImage(f, i, mImageArray[f][0].getInternalFormat(), + std::max(mImageArray[f][0].getWidth() >> i, 1), + std::max(mImageArray[f][0].getWidth() >> i, 1)); + } + } + + if (mTexStorage && mTexStorage->isRenderTarget()) + { + for (unsigned int f = 0; f < 6; f++) + { + for (unsigned int i = 1; i <= q; i++) + { + IDirect3DSurface9 *upper = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i - 1, false); + IDirect3DSurface9 *lower = mTexStorage->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true); + + if (upper != NULL && lower != NULL) + { + getBlitter()->boxFilter(upper, lower); + } + + if (upper != NULL) upper->Release(); + if (lower != NULL) lower->Release(); + + mImageArray[f][i].markClean(); + } + } + } + else + { + for (unsigned int f = 0; f < 6; f++) + { + for (unsigned int i = 1; i <= q; i++) + { + if (mImageArray[f][i].getSurface() == NULL) + { + return error(GL_OUT_OF_MEMORY); + } + + GenerateMip(mImageArray[f][i].getSurface(), mImageArray[f][i - 1].getSurface()); + + mImageArray[f][i].markDirty(); + } + } + } +} + +Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) +{ + if (!IsCubemapTextureTarget(target)) + { + return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); + } + + unsigned int face = faceIndex(target); + + if (mFaceProxies[face] == NULL) + { + mFaceProxies[face] = new Renderbuffer(id(), new RenderbufferTextureCubeMap(this, target)); + } + + return mFaceProxies[face]; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target) +{ + ASSERT(IsCubemapTextureTarget(target)); + + // ensure the underlying texture is created + if (getStorage(true) == NULL) + { + return NULL; + } + + updateTexture(); + + return mTexStorage->getCubeMapSurface(target, 0, false); +} + +TextureStorage *TextureCubeMap::getStorage(bool renderTarget) +{ + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) + { + if (renderTarget) + { + convertToRenderTarget(); + } + else + { + createTexture(); + } + } + + return mTexStorage; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.h b/src/3rdparty/angle/src/libGLESv2/Texture.h new file mode 100644 index 0000000000..7d7378f88b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Texture.h @@ -0,0 +1,433 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Texture.h: Defines the abstract gl::Texture class and its concrete derived +// classes Texture2D and TextureCubeMap. Implements GL texture objects and +// related functionality. [OpenGL ES 2.0.24] section 3.7 page 63. + +#ifndef LIBGLESV2_TEXTURE_H_ +#define LIBGLESV2_TEXTURE_H_ + +#include + +#define GL_APICALL +#include +#include + +#include "common/debug.h" +#include "common/RefCountObject.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/utilities.h" + +namespace egl +{ +class Surface; +} + +namespace gl +{ +class Blit; +class Framebuffer; + +enum +{ + // These are the maximums the implementation can support + // The actual GL caps are limited by the device caps + // and should be queried from the Context + IMPLEMENTATION_MAX_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, + + IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE +}; + +class Image +{ + public: + Image(); + ~Image(); + + bool redefine(GLint internalformat, GLsizei width, GLsizei height, bool forceRelease); + void markDirty() {mDirty = true;} + void markClean() {mDirty = false;} + + bool isRenderableFormat() const; + D3DFORMAT getD3DFormat() const; + + GLsizei getWidth() const {return mWidth;} + GLsizei getHeight() const {return mHeight;} + GLenum getInternalFormat() const {return mInternalFormat;} + bool isDirty() const {return mSurface && mDirty;} + IDirect3DSurface9 *getSurface(); + + void setManagedSurface(IDirect3DSurface9 *surface); + void updateSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint unpackAlignment, const void *input); + + void loadAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const; + void loadLuminanceAlphaFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadLuminanceAlphaHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBUByteData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGB565Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAUByteData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA4444Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBA5551Data(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadRGBAHalfFloatData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadBGRAData(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const; + void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + const void *input); + + void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget); + + private: + DISALLOW_COPY_AND_ASSIGN(Image); + + void createSurface(); + + HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); + void unlock(); + + GLsizei mWidth; + GLsizei mHeight; + GLint mInternalFormat; + + bool mDirty; + + D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. + D3DFORMAT mD3DFormat; + + IDirect3DSurface9 *mSurface; +}; + +class TextureStorage +{ + public: + explicit TextureStorage(DWORD usage); + + virtual ~TextureStorage(); + + bool isRenderTarget() const; + bool isManaged() const; + D3DPOOL getPool() const; + DWORD getUsage() const; + unsigned int getTextureSerial() const; + virtual unsigned int getRenderTargetSerial(GLenum target) const = 0; + int getLodOffset() const; + + protected: + int mLodOffset; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage); + + const DWORD mD3DUsage; + const D3DPOOL mD3DPool; + + const unsigned int mTextureSerial; + static unsigned int issueTextureSerial(); + + static unsigned int mCurrentTextureSerial; +}; + +class Texture : public RefCountObject +{ + public: + explicit Texture(GLuint id); + + virtual ~Texture(); + + virtual void addProxyRef(const Renderbuffer *proxy) = 0; + virtual void releaseProxy(const Renderbuffer *proxy) = 0; + + virtual GLenum getTarget() const = 0; + + bool setMinFilter(GLenum filter); + bool setMagFilter(GLenum filter); + bool setWrapS(GLenum wrap); + bool setWrapT(GLenum wrap); + bool setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy); + bool setUsage(GLenum usage); + + GLenum getMinFilter() const; + GLenum getMagFilter() const; + GLenum getWrapS() const; + GLenum getWrapT() const; + float getMaxAnisotropy() const; + GLenum getUsage() const; + + virtual bool isSamplerComplete() const = 0; + + IDirect3DBaseTexture9 *getTexture(); + virtual Renderbuffer *getRenderbuffer(GLenum target) = 0; + + virtual void generateMipmaps() = 0; + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0; + + bool hasDirtyParameters() const; + bool hasDirtyImages() const; + void resetDirty(); + unsigned int getTextureSerial(); + unsigned int getRenderTargetSerial(GLenum target); + + bool isImmutable() const; + int getLodOffset(); + + static const GLuint INCOMPLETE_TEXTURE_ID = static_cast(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager. + + protected: + void setImage(GLint unpackAlignment, const void *pixels, Image *image); + bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image); + void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image); + bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image); + + GLint creationLevels(GLsizei width, GLsizei height) const; + GLint creationLevels(GLsizei size) const; + + virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; + virtual void createTexture() = 0; + virtual void updateTexture() = 0; + virtual void convertToRenderTarget() = 0; + virtual IDirect3DSurface9 *getRenderTarget(GLenum target) = 0; + + int levelCount(); + + static Blit *getBlitter(); + static bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + + GLenum mMinFilter; + GLenum mMagFilter; + GLenum mWrapS; + GLenum mWrapT; + float mMaxAnisotropy; + bool mDirtyParameters; + GLenum mUsage; + + bool mDirtyImages; + + bool mImmutable; + + private: + DISALLOW_COPY_AND_ASSIGN(Texture); + + virtual TextureStorage *getStorage(bool renderTarget) = 0; +}; + +class TextureStorage2D : public TextureStorage +{ + public: + explicit TextureStorage2D(IDirect3DTexture9 *surfaceTexture); + TextureStorage2D(int levels, D3DFORMAT format, DWORD usage, int width, int height); + + virtual ~TextureStorage2D(); + + IDirect3DSurface9 *getSurfaceLevel(int level, bool dirty); + IDirect3DBaseTexture9 *getBaseTexture() const; + + virtual unsigned int getRenderTargetSerial(GLenum target) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorage2D); + + IDirect3DTexture9 *mTexture; + const unsigned int mRenderTargetSerial; +}; + +class Texture2D : public Texture +{ + public: + explicit Texture2D(GLuint id); + + ~Texture2D(); + + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + virtual GLenum getTarget() const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLenum getInternalFormat(GLint level) const; + D3DFORMAT getD3DFormat(GLint level) const; + bool isCompressed(GLint level) const; + bool isDepth(GLint level) const; + + void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); + void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); + void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); + + virtual bool isSamplerComplete() const; + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual void generateMipmaps(); + + virtual Renderbuffer *getRenderbuffer(GLenum target); + + protected: + friend class RenderbufferTexture2D; + virtual IDirect3DSurface9 *getRenderTarget(GLenum target); + virtual IDirect3DSurface9 *getDepthStencil(GLenum target); + + private: + DISALLOW_COPY_AND_ASSIGN(Texture2D); + + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void createTexture(); + virtual void updateTexture(); + virtual void convertToRenderTarget(); + virtual TextureStorage *getStorage(bool renderTarget); + + bool isMipmapComplete() const; + + void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height); + void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + Image mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + TextureStorage2D *mTexStorage; + egl::Surface *mSurface; + + // A specific internal reference count is kept for colorbuffer proxy references, + // because, as the renderbuffer acting as proxy will maintain a binding pointer + // back to this texture, there would be a circular reference if we used a binding + // pointer here. This reference count will cause the pointer to be set to NULL if + // the count drops to zero, but will not cause deletion of the Renderbuffer. + Renderbuffer *mColorbufferProxy; + unsigned int mProxyRefs; +}; + +class TextureStorageCubeMap : public TextureStorage +{ + public: + TextureStorageCubeMap(int levels, D3DFORMAT format, DWORD usage, int size); + + virtual ~TextureStorageCubeMap(); + + IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level, bool dirty); + IDirect3DBaseTexture9 *getBaseTexture() const; + + virtual unsigned int getRenderTargetSerial(GLenum target) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureStorageCubeMap); + + IDirect3DCubeTexture9 *mTexture; + const unsigned int mFirstRenderTargetSerial; +}; + +class TextureCubeMap : public Texture +{ + public: + explicit TextureCubeMap(GLuint id); + + ~TextureCubeMap(); + + void addProxyRef(const Renderbuffer *proxy); + void releaseProxy(const Renderbuffer *proxy); + + virtual GLenum getTarget() const; + + GLsizei getWidth(GLenum target, GLint level) const; + GLsizei getHeight(GLenum target, GLint level) const; + GLenum getInternalFormat(GLenum target, GLint level) const; + D3DFORMAT getD3DFormat(GLenum target, GLint level) const; + bool isCompressed(GLenum target, GLint level) const; + + void setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + + void setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); + + void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); + void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + void storage(GLsizei levels, GLenum internalformat, GLsizei size); + + virtual bool isSamplerComplete() const; + + virtual void generateMipmaps(); + + virtual Renderbuffer *getRenderbuffer(GLenum target); + + static unsigned int faceIndex(GLenum face); + + protected: + friend class RenderbufferTextureCubeMap; + virtual IDirect3DSurface9 *getRenderTarget(GLenum target); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); + + virtual IDirect3DBaseTexture9 *getBaseTexture() const; + virtual void createTexture(); + virtual void updateTexture(); + virtual void convertToRenderTarget(); + virtual TextureStorage *getStorage(bool renderTarget); + + bool isCubeComplete() const; + bool isMipmapCubeComplete() const; + + void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); + void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + void redefineImage(int faceIndex, GLint level, GLint internalformat, GLsizei width, GLsizei height); + + Image mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + TextureStorageCubeMap *mTexStorage; + + // A specific internal reference count is kept for colorbuffer proxy references, + // because, as the renderbuffer acting as proxy will maintain a binding pointer + // back to this texture, there would be a circular reference if we used a binding + // pointer here. This reference count will cause the pointer to be set to NULL if + // the count drops to zero, but will not cause deletion of the Renderbuffer. + Renderbuffer *mFaceProxies[6]; + unsigned int *mFaceProxyRefs[6]; +}; +} + +#endif // LIBGLESV2_TEXTURE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp b/src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp new file mode 100644 index 0000000000..48ea6643bc --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/TextureSSE2.cpp @@ -0,0 +1,100 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureSSE2.cpp: Implements SSE2-based functions of gl::Image class. It's +// in a separated file for GCC, which can enable SSE usage only per-file, +// not for code blocks that use SSE2 explicitly. + +#include "libGLESv2/Texture.h" + +#include + +namespace gl +{ + +void Image::loadRGBAUByteDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned int *source = NULL; + unsigned int *dest = NULL; + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + for (int y = 0; y < height; y++) + { + source = reinterpret_cast(static_cast(input) + y * inputPitch); + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + int x = 0; + + // Make output writes aligned + for (x = 0; ((reinterpret_cast(&dest[x]) & 15) != 0) && x < width; x++) + { + unsigned int rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + + for (; x + 3 < width; x += 4) + { + __m128i sourceData = _mm_loadu_si128(reinterpret_cast(&source[x])); + // Mask out g and a, which don't change + __m128i gaComponents = _mm_andnot_si128(brMask, sourceData); + // Mask out b and r + __m128i brComponents = _mm_and_si128(sourceData, brMask); + // Swap b and r + __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1)); + __m128i result = _mm_or_si128(gaComponents, brSwapped); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result); + } + + // Perform leftover writes + for (; x < width; x++) + { + unsigned int rgba = source[x]; + dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } +} + +void Image::loadAlphaDataSSE2(GLsizei width, GLsizei height, + int inputPitch, const void *input, size_t outputPitch, void *output) const +{ + const unsigned char *source = NULL; + unsigned int *dest = NULL; + __m128i zeroWide = _mm_setzero_si128(); + + for (int y = 0; y < height; y++) + { + source = static_cast(input) + y * inputPitch; + dest = reinterpret_cast(static_cast(output) + y * outputPitch); + + int x; + // Make output writes aligned + for (x = 0; ((reinterpret_cast(&dest[x]) & 0xF) != 0 && x < width); x++) + { + dest[x] = static_cast(source[x]) << 24; + } + + for (; x + 7 < width; x += 8) + { + __m128i sourceData = _mm_loadl_epi64(reinterpret_cast(&source[x])); + // Interleave each byte to 16bit, make the lower byte to zero + sourceData = _mm_unpacklo_epi8(zeroWide, sourceData); + // Interleave each 16bit to 32bit, make the lower 16bit to zero + __m128i lo = _mm_unpacklo_epi16(zeroWide, sourceData); + __m128i hi = _mm_unpackhi_epi16(zeroWide, sourceData); + + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), lo); + _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x + 4]), hi); + } + + // Handle the remainder + for (; x < width; x++) + { + dest[x] = static_cast(source[x]) << 24; + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp new file mode 100644 index 0000000000..32c40182d3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/VertexDataManager.cpp @@ -0,0 +1,783 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDataManager.h: Defines the VertexDataManager, a class that +// runs the Buffer translation process. + +#include "libGLESv2/VertexDataManager.h" + +#include "common/debug.h" + +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/main.h" + +#include "libGLESv2/vertexconversion.h" +#include "libGLESv2/IndexDataManager.h" + +namespace +{ + enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 }; + // This has to be at least 4k or else it fails on ATI cards. + enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; +} + +namespace gl +{ +unsigned int VertexBuffer::mCurrentSerial = 1; + +int elementsInBuffer(const VertexAttribute &attribute, int size) +{ + int stride = attribute.stride(); + return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride; +} + +VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device) +{ + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + mDirtyCurrentValue[i] = true; + mCurrentValueBuffer[i] = NULL; + mCurrentValueOffsets[i] = 0; + } + + const D3DCAPS9 &caps = context->getDeviceCaps(); + checkVertexCaps(caps.DeclTypes); + + mStreamingBuffer = new StreamingVertexBuffer(mDevice, INITIAL_STREAM_BUFFER_SIZE); + + if (!mStreamingBuffer) + { + ERR("Failed to allocate the streaming vertex buffer."); + } +} + +VertexDataManager::~VertexDataManager() +{ + delete mStreamingBuffer; + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + delete mCurrentValueBuffer[i]; + } +} + +std::size_t VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances) +{ + Buffer *buffer = attribute.mBoundBuffer.get(); + + int inputStride = attribute.stride(); + int elementSize = attribute.typeSize(); + const FormatConverter &converter = formatConverter(attribute); + std::size_t streamOffset = 0; + + void *output = NULL; + + if (vertexBuffer) + { + output = vertexBuffer->map(attribute, spaceRequired(attribute, count, instances), &streamOffset); + } + + if (output == NULL) + { + ERR("Failed to map vertex buffer."); + return -1; + } + + const char *input = NULL; + + if (buffer) + { + int offset = attribute.mOffset; + + input = static_cast(buffer->data()) + offset; + } + else + { + input = static_cast(attribute.mPointer); + } + + if (instances == 0 || attribute.mDivisor == 0) + { + input += inputStride * start; + } + + if (converter.identity && inputStride == elementSize) + { + memcpy(output, input, count * inputStride); + } + else + { + converter.convertArray(input, inputStride, count, output); + } + + vertexBuffer->unmap(); + + return streamOffset; +} + +GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) +{ + if (!mStreamingBuffer) + { + return GL_OUT_OF_MEMORY; + } + + const VertexAttributeArray &attribs = mContext->getVertexAttributes(); + ProgramBinary *programBinary = mContext->getCurrentProgramBinary(); + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); + } + + // Determine the required storage size per used buffer, and invalidate static buffers that don't contain matching attributes + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + + if (staticBuffer) + { + if (staticBuffer->size() == 0) + { + int totalCount = elementsInBuffer(attribs[i], buffer->size()); + staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount, 0)); + } + else if (staticBuffer->lookupAttribute(attribs[i]) == -1) + { + // This static buffer doesn't have matching attributes, so fall back to using the streaming buffer + // Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer + for (int previous = 0; previous < i; previous++) + { + if (translated[previous].active && attribs[previous].mArrayEnabled) + { + Buffer *previousBuffer = attribs[previous].mBoundBuffer.get(); + StaticVertexBuffer *previousStaticBuffer = previousBuffer ? previousBuffer->getStaticVertexBuffer() : NULL; + + if (staticBuffer == previousStaticBuffer) + { + mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[previous], count, instances)); + } + } + } + + mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances)); + + buffer->invalidateStaticData(); + } + } + else + { + mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count, instances)); + } + } + } + + // Reserve the required space per used buffer + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + ArrayVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer; + + if (vertexBuffer) + { + vertexBuffer->reserveRequiredSpace(); + } + } + } + + // Perform the vertex data translations + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active) + { + if (attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + + if (!buffer && attribs[i].mPointer == NULL) + { + // This is an application error that would normally result in a crash, but we catch it and return an error + ERR("An enabled vertex array has no buffer and no pointer."); + return GL_INVALID_OPERATION; + } + + const FormatConverter &converter = formatConverter(attribs[i]); + + StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL; + ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); + + std::size_t streamOffset = -1; + + if (staticBuffer) + { + streamOffset = staticBuffer->lookupAttribute(attribs[i]); + + if (streamOffset == -1) + { + // Convert the entire buffer + int totalCount = elementsInBuffer(attribs[i], buffer->size()); + int startIndex = attribs[i].mOffset / attribs[i].stride(); + + streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i], 0); + } + + if (streamOffset != -1) + { + streamOffset += (attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize; + + if (instances == 0 || attribs[i].mDivisor == 0) + { + streamOffset += start * converter.outputElementSize; + } + } + } + else + { + streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i], instances); + } + + if (streamOffset == -1) + { + return GL_OUT_OF_MEMORY; + } + + translated[i].vertexBuffer = vertexBuffer->getBuffer(); + translated[i].serial = vertexBuffer->getSerial(); + translated[i].divisor = attribs[i].mDivisor; + + translated[i].type = converter.d3dDeclType; + translated[i].stride = converter.outputElementSize; + translated[i].offset = streamOffset; + } + else + { + if (!mCurrentValueBuffer[i]) + { + mCurrentValueBuffer[i] = new StreamingVertexBuffer(mDevice, CONSTANT_VERTEX_BUFFER_SIZE); + } + + StreamingVertexBuffer *buffer = mCurrentValueBuffer[i]; + + if (mDirtyCurrentValue[i]) + { + const int requiredSpace = 4 * sizeof(float); + buffer->addRequiredSpace(requiredSpace); + buffer->reserveRequiredSpace(); + float *data = static_cast(buffer->map(VertexAttribute(), requiredSpace, &mCurrentValueOffsets[i])); + if (data) + { + data[0] = attribs[i].mCurrentValue[0]; + data[1] = attribs[i].mCurrentValue[1]; + data[2] = attribs[i].mCurrentValue[2]; + data[3] = attribs[i].mCurrentValue[3]; + buffer->unmap(); + mDirtyCurrentValue[i] = false; + } + } + + translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer(); + translated[i].serial = mCurrentValueBuffer[i]->getSerial(); + translated[i].divisor = 0; + + translated[i].type = D3DDECLTYPE_FLOAT4; + translated[i].stride = 0; + translated[i].offset = mCurrentValueOffsets[i]; + } + } + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && attribs[i].mArrayEnabled) + { + Buffer *buffer = attribs[i].mBoundBuffer.get(); + + if (buffer) + { + buffer->promoteStaticUsage(count * attribs[i].typeSize()); + } + } + } + + return GL_NO_ERROR; +} + +std::size_t VertexDataManager::spaceRequired(const VertexAttribute &attrib, std::size_t count, GLsizei instances) const +{ + size_t elementSize = formatConverter(attrib).outputElementSize; + + if (instances == 0 || attrib.mDivisor == 0) + { + return elementSize * count; + } + else + { + return elementSize * ((instances + attrib.mDivisor - 1) / attrib.mDivisor); + } +} + +// Mapping from OpenGL-ES vertex attrib type to D3D decl type: +// +// BYTE SHORT (Cast) +// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm) +// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast) +// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize) +// SHORT SHORT (Identity) +// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize) +// UNSIGNED_SHORT FLOAT (Cast) +// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize) +// FIXED (not in WebGL) FLOAT (FixedToFloat) +// FLOAT FLOAT (Identity) + +// GLToCType maps from GL type (as GLenum) to the C typedef. +template struct GLToCType { }; + +template <> struct GLToCType { typedef GLbyte type; }; +template <> struct GLToCType { typedef GLubyte type; }; +template <> struct GLToCType { typedef GLshort type; }; +template <> struct GLToCType { typedef GLushort type; }; +template <> struct GLToCType { typedef GLuint type; }; +template <> struct GLToCType { typedef GLfloat type; }; + +// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.) +enum D3DVertexType +{ + D3DVT_FLOAT, + D3DVT_SHORT, + D3DVT_SHORT_NORM, + D3DVT_UBYTE, + D3DVT_UBYTE_NORM, + D3DVT_USHORT_NORM +}; + +// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type. +template struct D3DToCType { }; + +template <> struct D3DToCType { typedef float type; }; +template <> struct D3DToCType { typedef short type; }; +template <> struct D3DToCType { typedef short type; }; +template <> struct D3DToCType { typedef unsigned char type; }; +template <> struct D3DToCType { typedef unsigned char type; }; +template <> struct D3DToCType { typedef unsigned short type; }; + +// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size. +template +struct WidenRule +{ +}; + +template struct WidenRule : gl::NoWiden { }; +template struct WidenRule : gl::WidenToEven { }; +template struct WidenRule : gl::WidenToEven { }; +template struct WidenRule : gl::WidenToFour { }; +template struct WidenRule : gl::WidenToFour { }; +template struct WidenRule : gl::WidenToEven { }; + +// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination. +template +struct VertexTypeFlags +{ +}; + +template +struct VertexTypeFlagsHelper +{ + enum { capflag = _capflag }; + enum { declflag = _declflag }; +}; + +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; +template <> struct VertexTypeFlags : VertexTypeFlagsHelper { }; + + +// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums). +template +struct VertexTypeMapping +{ +}; + +template +struct VertexTypeMappingBase +{ + enum { preferred = Preferred }; + enum { fallback = Fallback }; +}; + +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Normalize +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity, Cast +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity, Normalize +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast, Normalize +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast +template <> struct VertexTypeMapping : VertexTypeMappingBase { }; // Cast, Normalize +template struct VertexTypeMapping : VertexTypeMappingBase { }; // FixedToFloat +template struct VertexTypeMapping : VertexTypeMappingBase { }; // Identity + + +// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat). +// The conversion rules themselves are defined in vertexconversion.h. + +// Almost all cases are covered by Cast (including those that are actually Identity since Cast knows it's an identity mapping). +template +struct ConversionRule : gl::Cast::type, typename D3DToCType::type> +{ +}; + +// All conversions from normalized types to float use the Normalize operator. +template struct ConversionRule : gl::Normalize::type> { }; + +// Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules. +template <> struct ConversionRule : gl::FixedToFloat { }; +template <> struct ConversionRule : gl::FixedToFloat { }; + +// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1) +// whether it is normalized or not. +template +struct DefaultVertexValuesStage2 +{ +}; + +template struct DefaultVertexValuesStage2 : gl::NormalizedDefaultValues { }; +template struct DefaultVertexValuesStage2 : gl::SimpleDefaultValues { }; + +// Work out the default value rule for a D3D type (expressed as the C type) and +template +struct DefaultVertexValues : DefaultVertexValuesStage2 +{ +}; + +template struct DefaultVertexValues : gl::SimpleDefaultValues { }; + +// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion. +// The fallback conversion produces an output that all D3D9 devices must support. +template struct UsePreferred { enum { type = T::preferred }; }; +template struct UseFallback { enum { type = T::fallback }; }; + +// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion, +// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag +// and the D3DDECLTYPE member needed for the vertex declaration in declflag. +template class PreferenceRule> +struct Converter + : gl::VertexDataConverter::type, + WidenRule >::type, size>, + ConversionRule >::type>, + DefaultVertexValues >::type>::type, normalized > > +{ +private: + enum { d3dtype = PreferenceRule< VertexTypeMapping >::type }; + enum { d3dsize = WidenRule::finalWidth }; + +public: + enum { capflag = VertexTypeFlags::capflag }; + enum { declflag = VertexTypeFlags::declflag }; +}; + +// Initialise a TranslationInfo +#define TRANSLATION(type, norm, size, preferred) \ + { \ + Converter::identity, \ + Converter::finalSize, \ + Converter::convertArray, \ + static_cast(Converter::declflag) \ + } + +#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \ + { \ + Converter::capflag, \ + TRANSLATION(type, norm, size, UsePreferred), \ + TRANSLATION(type, norm, size, UseFallback) \ + } + +#define TRANSLATIONS_FOR_TYPE(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \ + } + +#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \ + { \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \ + } + +const VertexDataManager::TranslationDescription VertexDataManager::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1] +{ + TRANSLATIONS_FOR_TYPE(GL_BYTE), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE), + TRANSLATIONS_FOR_TYPE(GL_SHORT), + TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), + TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT) +}; + +void VertexDataManager::checkVertexCaps(DWORD declTypes) +{ + for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++) + { + for (unsigned int j = 0; j < 2; j++) + { + for (unsigned int k = 0; k < 4; k++) + { + if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0) + { + mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion; + } + else + { + mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion; + } + } + } + } +} + +// This is used to index mAttributeTypes and mPossibleTranslations. +unsigned int VertexDataManager::typeIndex(GLenum type) const +{ + switch (type) + { + case GL_BYTE: return 0; + case GL_UNSIGNED_BYTE: return 1; + case GL_SHORT: return 2; + case GL_UNSIGNED_SHORT: return 3; + case GL_FIXED: return 4; + case GL_FLOAT: return 5; + + default: UNREACHABLE(); return 5; + } +} + +VertexBuffer::VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : mDevice(device), mVertexBuffer(NULL) +{ + if (size > 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(usageFlags); + HRESULT result = device->CreateVertexBuffer(size, usageFlags, 0, pool, &mVertexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", size); + } + } +} + +VertexBuffer::~VertexBuffer() +{ + if (mVertexBuffer) + { + mVertexBuffer->Release(); + } +} + +void VertexBuffer::unmap() +{ + if (mVertexBuffer) + { + mVertexBuffer->Unlock(); + } +} + +IDirect3DVertexBuffer9 *VertexBuffer::getBuffer() const +{ + return mVertexBuffer; +} + +unsigned int VertexBuffer::getSerial() const +{ + return mSerial; +} + +unsigned int VertexBuffer::issueSerial() +{ + return mCurrentSerial++; +} + +ArrayVertexBuffer::ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : VertexBuffer(device, size, usageFlags) +{ + mBufferSize = size; + mWritePosition = 0; + mRequiredSpace = 0; +} + +ArrayVertexBuffer::~ArrayVertexBuffer() +{ +} + +void ArrayVertexBuffer::addRequiredSpace(UINT requiredSpace) +{ + mRequiredSpace += requiredSpace; +} + +StreamingVertexBuffer::StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize) : ArrayVertexBuffer(device, initialSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY) +{ +} + +StreamingVertexBuffer::~StreamingVertexBuffer() +{ +} + +void *StreamingVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *offset) +{ + void *mapPtr = NULL; + + if (mVertexBuffer) + { + HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE); + + if (FAILED(result)) + { + ERR("Lock failed with error 0x%08x", result); + return NULL; + } + + *offset = mWritePosition; + mWritePosition += requiredSpace; + } + + return mapPtr; +} + +void StreamingVertexBuffer::reserveRequiredSpace() +{ + if (mRequiredSpace > mBufferSize) + { + if (mVertexBuffer) + { + mVertexBuffer->Release(); + mVertexBuffer = NULL; + } + + mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations. + + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateVertexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize); + } + + mWritePosition = 0; + } + else if (mWritePosition + mRequiredSpace > mBufferSize) // Recycle + { + if (mVertexBuffer) + { + void *dummy; + mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + mVertexBuffer->Unlock(); + } + + mWritePosition = 0; + } + + mRequiredSpace = 0; +} + +StaticVertexBuffer::StaticVertexBuffer(IDirect3DDevice9 *device) : ArrayVertexBuffer(device, 0, D3DUSAGE_WRITEONLY) +{ +} + +StaticVertexBuffer::~StaticVertexBuffer() +{ +} + +void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset) +{ + void *mapPtr = NULL; + + if (mVertexBuffer) + { + HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0); + + if (FAILED(result)) + { + ERR("Lock failed with error 0x%08x", result); + return NULL; + } + + int attributeOffset = attribute.mOffset % attribute.stride(); + VertexElement element = {attribute.mType, attribute.mSize, attribute.stride(), attribute.mNormalized, attributeOffset, mWritePosition}; + mCache.push_back(element); + + *streamOffset = mWritePosition; + mWritePosition += requiredSpace; + } + + return mapPtr; +} + +void StaticVertexBuffer::reserveRequiredSpace() +{ + if (!mVertexBuffer && mBufferSize == 0) + { + D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY); + HRESULT result = mDevice->CreateVertexBuffer(mRequiredSpace, D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL); + mSerial = issueSerial(); + + if (FAILED(result)) + { + ERR("Out of memory allocating a vertex buffer of size %lu.", mRequiredSpace); + } + + mBufferSize = mRequiredSpace; + } + else if (mVertexBuffer && mBufferSize >= mRequiredSpace) + { + // Already allocated + } + else UNREACHABLE(); // Static vertex buffers can't be resized + + mRequiredSpace = 0; +} + +std::size_t StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute) +{ + for (unsigned int element = 0; element < mCache.size(); element++) + { + if (mCache[element].type == attribute.mType && + mCache[element].size == attribute.mSize && + mCache[element].stride == attribute.stride() && + mCache[element].normalized == attribute.mNormalized) + { + if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride()) + { + return mCache[element].streamOffset; + } + } + } + + return -1; +} + +const VertexDataManager::FormatConverter &VertexDataManager::formatConverter(const VertexAttribute &attribute) const +{ + return mAttributeTypes[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1]; +} +} diff --git a/src/3rdparty/angle/src/libGLESv2/VertexDataManager.h b/src/3rdparty/angle/src/libGLESv2/VertexDataManager.h new file mode 100644 index 0000000000..857591ac29 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/VertexDataManager.h @@ -0,0 +1,169 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// VertexDataManager.h: Defines the VertexDataManager, a class that +// runs the Buffer translation process. + +#ifndef LIBGLESV2_VERTEXDATAMANAGER_H_ +#define LIBGLESV2_VERTEXDATAMANAGER_H_ + +#include +#include + +#define GL_APICALL +#include + +#include "libGLESv2/Context.h" + +namespace gl +{ + +struct TranslatedAttribute +{ + bool active; + + D3DDECLTYPE type; + UINT offset; + UINT stride; // 0 means not to advance the read pointer at all + + IDirect3DVertexBuffer9 *vertexBuffer; + unsigned int serial; + unsigned int divisor; +}; + +class VertexBuffer +{ + public: + VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags); + virtual ~VertexBuffer(); + + void unmap(); + + IDirect3DVertexBuffer9 *getBuffer() const; + unsigned int getSerial() const; + + protected: + IDirect3DDevice9 *const mDevice; + IDirect3DVertexBuffer9 *mVertexBuffer; + + unsigned int mSerial; + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; + + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer); +}; + +class ArrayVertexBuffer : public VertexBuffer +{ + public: + ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags); + ~ArrayVertexBuffer(); + + std::size_t size() const { return mBufferSize; } + virtual void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset) = 0; + virtual void reserveRequiredSpace() = 0; + void addRequiredSpace(UINT requiredSpace); + + protected: + std::size_t mBufferSize; + std::size_t mWritePosition; + std::size_t mRequiredSpace; +}; + +class StreamingVertexBuffer : public ArrayVertexBuffer +{ + public: + StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize); + ~StreamingVertexBuffer(); + + void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset); + void reserveRequiredSpace(); +}; + +class StaticVertexBuffer : public ArrayVertexBuffer +{ + public: + explicit StaticVertexBuffer(IDirect3DDevice9 *device); + ~StaticVertexBuffer(); + + void *map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *streamOffset); + void reserveRequiredSpace(); + + std::size_t lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found + + private: + struct VertexElement + { + GLenum type; + GLint size; + GLsizei stride; + bool normalized; + int attributeOffset; + + std::size_t streamOffset; + }; + + std::vector mCache; +}; + +class VertexDataManager +{ + public: + VertexDataManager(Context *context, IDirect3DDevice9 *backend); + virtual ~VertexDataManager(); + + void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; } + + GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances); + + private: + DISALLOW_COPY_AND_ASSIGN(VertexDataManager); + + std::size_t spaceRequired(const VertexAttribute &attrib, std::size_t count, GLsizei instances) const; + std::size_t writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute, GLsizei instances); + + Context *const mContext; + IDirect3DDevice9 *const mDevice; + + StreamingVertexBuffer *mStreamingBuffer; + + bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS]; + StreamingVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS]; + std::size_t mCurrentValueOffsets[MAX_VERTEX_ATTRIBS]; + + // Attribute format conversion + struct FormatConverter + { + bool identity; + std::size_t outputElementSize; + void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out); + D3DDECLTYPE d3dDeclType; + }; + + enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; + + FormatConverter mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1] + + struct TranslationDescription + { + DWORD capsFlag; + FormatConverter preferredConversion; + FormatConverter fallbackConversion; + }; + + // This table is used to generate mAttributeTypes. + static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1] + + void checkVertexCaps(DWORD declTypes); + + unsigned int typeIndex(GLenum type) const; + const FormatConverter &formatConverter(const VertexAttribute &attribute) const; +}; + +} + +#endif // LIBGLESV2_VERTEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp new file mode 100644 index 0000000000..16d9c1775d --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp @@ -0,0 +1,7002 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions. + +#define GL_APICALL +#include +#include + +#include +#include + +#include "common/debug.h" +#include "common/version.h" + +#include "libGLESv2/main.h" +#include "libGLESv2/mathutil.h" +#include "libGLESv2/utilities.h" +#include "libGLESv2/Buffer.h" +#include "libGLESv2/Context.h" +#include "libGLESv2/Fence.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/Program.h" +#include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Renderbuffer.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/Texture.h" +#include "libGLESv2/Query.h" + +bool validImageSize(GLint level, GLsizei width, GLsizei height) +{ + if (level < 0 || width < 0 || height < 0) + { + return false; + } + + if (gl::getContext() && gl::getContext()->supportsNonPower2Texture()) + { + return true; + } + + if (level == 0) + { + return true; + } + + if (gl::isPow2(width) && gl::isPow2(height)) + { + return true; + } + + return false; +} + +// Verify that format/type are one of the combinations from table 3.4. +bool checkTextureFormatType(GLenum format, GLenum type) +{ + // validate by itself (used as secondary key below) + switch (format) + { + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + break; + default: + return error(GL_INVALID_ENUM, false); + } + + // invalid -> sets INVALID_ENUM + // invalid + combination -> sets INVALID_OPERATION + switch (type) + { + case GL_UNSIGNED_BYTE: + switch (format) + { + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + switch (format) + { + case GL_RGBA: + case GL_RGB: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + switch (format) + { + case GL_RGBA: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_SHORT_5_6_5: + switch (format) + { + case GL_RGB: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + switch (format) + { + case GL_DEPTH_COMPONENT: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + case GL_UNSIGNED_INT_24_8_OES: + switch (format) + { + case GL_DEPTH_STENCIL_OES: + return true; + default: + return error(GL_INVALID_OPERATION, false); + } + + default: + return error(GL_INVALID_ENUM, false); + } +} + +bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height, + GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type, + gl::Texture2D *texture) +{ + if (!texture) + { + return error(GL_INVALID_OPERATION, false); + } + + if (compressed != texture->isCompressed(level)) + { + return error(GL_INVALID_OPERATION, false); + } + + if (format != GL_NONE) + { + GLenum internalformat = gl::ConvertSizedInternalFormat(format, type); + if (internalformat != texture->getInternalFormat(level)) + { + return error(GL_INVALID_OPERATION, false); + } + } + + if (compressed) + { + if ((width % 4 != 0 && width != texture->getWidth(0)) || + (height % 4 != 0 && height != texture->getHeight(0))) + { + return error(GL_INVALID_OPERATION, false); + } + } + + if (xoffset + width > texture->getWidth(level) || + yoffset + height > texture->getHeight(level)) + { + return error(GL_INVALID_VALUE, false); + } + + return true; +} + +bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height, + GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type, + gl::TextureCubeMap *texture) +{ + if (!texture) + { + return error(GL_INVALID_OPERATION, false); + } + + if (compressed != texture->isCompressed(target, level)) + { + return error(GL_INVALID_OPERATION, false); + } + + if (format != GL_NONE) + { + GLenum internalformat = gl::ConvertSizedInternalFormat(format, type); + if (internalformat != texture->getInternalFormat(target, level)) + { + return error(GL_INVALID_OPERATION, false); + } + } + + if (compressed) + { + if ((width % 4 != 0 && width != texture->getWidth(target, 0)) || + (height % 4 != 0 && height != texture->getHeight(target, 0))) + { + return error(GL_INVALID_OPERATION, false); + } + } + + if (xoffset + width > texture->getWidth(target, level) || + yoffset + height > texture->getHeight(target, level)) + { + return error(GL_INVALID_VALUE, false); + } + + return true; +} + +// check for combinations of format and type that are valid for ReadPixels +bool validReadFormatType(GLenum format, GLenum type) +{ + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + break; + default: + return false; + } + break; + default: + return false; + } + return true; +} + +extern "C" +{ + +void __stdcall glActiveTexture(GLenum texture) +{ + EVENT("(GLenum texture = 0x%X)", texture); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1) + { + return error(GL_INVALID_ENUM); + } + + context->setActiveSampler(texture - GL_TEXTURE0); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glAttachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (!programObject->attachShader(shaderObject)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBeginQueryEXT(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint %d)", target, id); + + try + { + switch (target) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (id == 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->beginQuery(target, id); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) +{ + EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (strncmp(name, "gl_", 3) == 0) + { + return error(GL_INVALID_OPERATION); + } + + programObject->bindAttributeLocation(index, name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindBuffer(GLenum target, GLuint buffer) +{ + EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (target) + { + case GL_ARRAY_BUFFER: + context->bindArrayBuffer(buffer); + return; + case GL_ELEMENT_ARRAY_BUFFER: + context->bindElementArrayBuffer(buffer); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); + + try + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) + { + context->bindReadFramebuffer(framebuffer); + } + + if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) + { + context->bindDrawFramebuffer(framebuffer); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); + + try + { + if (target != GL_RENDERBUFFER) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->bindRenderbuffer(renderbuffer); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindTexture(GLenum target, GLuint texture) +{ + EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *textureObject = context->getTexture(texture); + + if (textureObject && textureObject->getTarget() != target && texture != 0) + { + return error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TEXTURE_2D: + context->bindTexture2D(texture); + return; + case GL_TEXTURE_CUBE_MAP: + context->bindTextureCubeMap(texture); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", + red, green, blue, alpha); + + try + { + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha)); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendEquation(GLenum mode) +{ + glBlendEquationSeparate(mode, mode); +} + +void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); + + try + { + switch (modeRGB) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (modeAlpha) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setBlendEquation(modeRGB, modeAlpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendFunc(GLenum sfactor, GLenum dfactor) +{ + glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); +} + +void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)", + srcRGB, dstRGB, srcAlpha, dstAlpha); + + try + { + switch (srcRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (dstRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (srcAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (dstAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; + default: + return error(GL_INVALID_ENUM); + } + + bool constantColorUsed = (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR || + dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR); + + bool constantAlphaUsed = (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA || + dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA); + + if (constantColorUsed && constantAlphaUsed) + { + ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL"); + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)", + target, size, data, usage); + + try + { + if (size < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (usage) + { + case GL_STREAM_DRAW: + case GL_STATIC_DRAW: + case GL_DYNAMIC_DRAW: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Buffer *buffer; + + switch (target) + { + case GL_ARRAY_BUFFER: + buffer = context->getArrayBuffer(); + break; + case GL_ELEMENT_ARRAY_BUFFER: + buffer = context->getElementArrayBuffer(); + break; + default: + return error(GL_INVALID_ENUM); + } + + if (!buffer) + { + return error(GL_INVALID_OPERATION); + } + + buffer->bufferData(data, size, usage); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)", + target, offset, size, data); + + try + { + if (size < 0 || offset < 0) + { + return error(GL_INVALID_VALUE); + } + + if (data == NULL) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Buffer *buffer; + + switch (target) + { + case GL_ARRAY_BUFFER: + buffer = context->getArrayBuffer(); + break; + case GL_ELEMENT_ARRAY_BUFFER: + buffer = context->getElementArrayBuffer(); + break; + default: + return error(GL_INVALID_ENUM); + } + + if (!buffer) + { + return error(GL_INVALID_OPERATION); + } + + if ((size_t)size + offset > buffer->size()) + { + return error(GL_INVALID_VALUE); + } + + buffer->bufferSubData(data, size, offset); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glCheckFramebufferStatus(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + try + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM, 0); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Framebuffer *framebuffer = NULL; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + framebuffer = context->getReadFramebuffer(); + } + else + { + framebuffer = context->getDrawFramebuffer(); + } + + return framebuffer->completeness(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +void __stdcall glClear(GLbitfield mask) +{ + EVENT("(GLbitfield mask = %X)", mask); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->clear(mask); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", + red, green, blue, alpha); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setClearColor(red, green, blue, alpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearDepthf(GLclampf depth) +{ + EVENT("(GLclampf depth = %f)", depth); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setClearDepth(depth); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearStencil(GLint s) +{ + EVENT("(GLint s = %d)", s); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setClearStencil(s); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + EVENT("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)", + red, green, blue, alpha); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompileShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + shaderObject->compile(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, + GLint border, GLsizei imageSize, const GLvoid* data) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " + "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", + target, level, internalformat, width, height, border, imageSize, data); + + try + { + if (!validImageSize(level, width, height) || border != 0 || imageSize < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (border != 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TEXTURE_2D: + if (width > (context->getMaximumTextureDimension() >> level) || + height > (context->getMaximumTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (width != height) + { + return error(GL_INVALID_VALUE); + } + + if (width > (context->getMaximumCubeTextureDimension() >> level) || + height > (context->getMaximumCubeTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (internalformat) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->supportsDXT1Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->supportsDXT3Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->supportsDXT5Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + default: UNREACHABLE(); + } + + if (imageSize != gl::ComputeCompressedSize(width, height, internalformat)) + { + return error(GL_INVALID_VALUE); + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->setCompressedImage(level, internalformat, width, height, imageSize, data); + } + else + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data); + break; + default: UNREACHABLE(); + } + } + } + + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const GLvoid* data) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, " + "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, imageSize, data); + + try + { + if (!gl::IsInternalTextureTarget(target)) + { + return error(GL_INVALID_ENUM); + } + + if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (format) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (width == 0 || height == 0 || data == NULL) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + switch (format) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->supportsDXT1Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->supportsDXT3Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->supportsDXT5Textures()) + { + return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed + } + break; + default: UNREACHABLE(); + } + + if (imageSize != gl::ComputeCompressedSize(width, height, format)) + { + return error(GL_INVALID_VALUE); + } + + if (xoffset % 4 != 0 || yoffset % 4 != 0) + { + return error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction + // does not exist unless DXT textures are supported. + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + if (validateSubImageParams2D(true, width, height, xoffset, yoffset, level, format, GL_NONE, texture)) + { + texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); + } + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + if (validateSubImageParamsCube(true, width, height, xoffset, yoffset, target, level, format, GL_NONE, texture)) + { + texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); + } + } + else + { + UNREACHABLE(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " + "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)", + target, level, internalformat, x, y, width, height, border); + + try + { + if (!validImageSize(level, width, height)) + { + return error(GL_INVALID_VALUE); + } + + if (border != 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TEXTURE_2D: + if (width > (context->getMaximumTextureDimension() >> level) || + height > (context->getMaximumTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (width != height) + { + return error(GL_INVALID_VALUE); + } + + if (width > (context->getMaximumCubeTextureDimension() >> level) || + height > (context->getMaximumCubeTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Framebuffer *framebuffer = context->getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Renderbuffer *source = framebuffer->getColorbuffer(); + GLenum colorbufferFormat = source->getInternalFormat(); + + // [OpenGL ES 2.0.24] table 3.9 + switch (internalformat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE: + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->supportsDXT1Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->supportsDXT3Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->supportsDXT5Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH_STENCIL_OES: + case GL_DEPTH24_STENCIL8_OES: + if (context->supportsDepthTextures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + default: + return error(GL_INVALID_ENUM); + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->copyImage(level, internalformat, x, y, width, height, framebuffer); + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); + } + else UNREACHABLE(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, level, xoffset, yoffset, x, y, width, height); + + try + { + if (!gl::IsInternalTextureTarget(target)) + { + return error(GL_INVALID_ENUM); + } + + if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + if (std::numeric_limits::max() - xoffset < width || std::numeric_limits::max() - yoffset < height) + { + return error(GL_INVALID_VALUE); + } + + if (width == 0 || height == 0) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + gl::Framebuffer *framebuffer = context->getReadFramebuffer(); + + if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Renderbuffer *source = framebuffer->getColorbuffer(); + GLenum colorbufferFormat = source->getInternalFormat(); + gl::Texture *texture = NULL; + GLenum textureFormat = GL_RGBA; + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *tex2d = context->getTexture2D(); + + if (!validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d)) + { + return; // error already registered by validateSubImageParams + } + textureFormat = gl::ExtractFormat(tex2d->getInternalFormat(level)); + texture = tex2d; + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texcube = context->getTextureCubeMap(); + + if (!validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube)) + { + return; // error already registered by validateSubImageParams + } + textureFormat = gl::ExtractFormat(texcube->getInternalFormat(target, level)); + texture = texcube; + } + else UNREACHABLE(); + + // [OpenGL ES 2.0.24] table 3.9 + switch (textureFormat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE: + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return error(GL_INVALID_OPERATION); + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + return error(GL_INVALID_OPERATION); + default: + return error(GL_INVALID_OPERATION); + } + + texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer); + } + } + + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLuint __stdcall glCreateProgram(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + return context->createProgram(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +GLuint __stdcall glCreateShader(GLenum type) +{ + EVENT("(GLenum type = 0x%X)", type); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (type) + { + case GL_FRAGMENT_SHADER: + case GL_VERTEX_SHADER: + return context->createShader(type); + default: + return error(GL_INVALID_ENUM, 0); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +void __stdcall glCullFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + try + { + switch (mode) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setCullMode(mode); + } + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteBuffer(buffers[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) +{ + EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteFence(fences[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ + EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + if (framebuffers[i] != 0) + { + context->deleteFramebuffer(framebuffers[i]); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + if (program == 0) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!context->getProgram(program)) + { + if(context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + context->deleteProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteQueriesEXT(GLsizei n, const GLuint *ids) +{ + EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteQuery(ids[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ + EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteRenderbuffer(renderbuffers[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + try + { + if (shader == 0) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!context->getShader(shader)) + { + if(context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + context->deleteShader(shader); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) +{ + EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + if (textures[i] != 0) + { + context->deleteTexture(textures[i]); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthFunc(GLenum func) +{ + EVENT("(GLenum func = 0x%X)", func); + + try + { + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GREATER: + case GL_GEQUAL: + case GL_NOTEQUAL: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setDepthFunc(func); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthMask(GLboolean flag) +{ + EVENT("(GLboolean flag = %d)", flag); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setDepthMask(flag != GL_FALSE); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) +{ + EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setDepthRange(zNear, zFar); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDetachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); + + if (!programObject) + { + gl::Shader *shaderByProgramHandle; + shaderByProgramHandle = context->getShader(program); + if (!shaderByProgramHandle) + { + return error(GL_INVALID_VALUE); + } + else + { + return error(GL_INVALID_OPERATION); + } + } + + if (!shaderObject) + { + gl::Program *programByShaderHandle = context->getProgram(shader); + if (!programByShaderHandle) + { + return error(GL_INVALID_VALUE); + } + else + { + return error(GL_INVALID_OPERATION); + } + } + + if (!programObject->detachShader(shaderObject)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDisable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: context->setCullFace(false); break; + case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(false); break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(false); break; + case GL_SAMPLE_COVERAGE: context->setSampleCoverage(false); break; + case GL_SCISSOR_TEST: context->setScissorTest(false); break; + case GL_STENCIL_TEST: context->setStencilTest(false); break; + case GL_DEPTH_TEST: context->setDepthTest(false); break; + case GL_BLEND: context->setBlend(false); break; + case GL_DITHER: context->setDither(false); break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDisableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %d)", index); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setEnableVertexAttribArray(index, false); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); + + try + { + if (count < 0 || first < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->drawArrays(mode, first, count, 0); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)", mode, first, count, primcount); + + try + { + if (count < 0 || first < 0 || primcount < 0) + { + return error(GL_INVALID_VALUE); + } + + if (primcount > 0) + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->drawArrays(mode, first, count, primcount); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +{ + EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)", + mode, count, type, indices); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (!context->supports32bitIndices()) + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + context->drawElements(mode, count, type, indices, 0); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount) +{ + EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei primcount = %d)", + mode, count, type, indices, primcount); + + try + { + if (count < 0 || primcount < 0) + { + return error(GL_INVALID_VALUE); + } + + if (primcount > 0) + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (!context->supports32bitIndices()) + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + context->drawElements(mode, count, type, indices, primcount); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glEnable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: context->setCullFace(true); break; + case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(true); break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(true); break; + case GL_SAMPLE_COVERAGE: context->setSampleCoverage(true); break; + case GL_SCISSOR_TEST: context->setScissorTest(true); break; + case GL_STENCIL_TEST: context->setStencilTest(true); break; + case GL_DEPTH_TEST: context->setDepthTest(true); break; + case GL_BLEND: context->setBlend(true); break; + case GL_DITHER: context->setDither(true); break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glEnableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %d)", index); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setEnableVertexAttribArray(index, true); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glEndQueryEXT(GLenum target) +{ + EVENT("GLenum target = 0x%X)", target); + + try + { + switch (target) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->endQuery(target); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFinishFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence* fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION); + } + + fenceObject->finishFence(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFinish(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->sync(true); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFlush(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->sync(false); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, " + "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer); + + try + { + if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Framebuffer *framebuffer = NULL; + GLuint framebufferHandle = 0; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + framebuffer = context->getReadFramebuffer(); + framebufferHandle = context->getReadFramebufferHandle(); + } + else + { + framebuffer = context->getDrawFramebuffer(); + framebufferHandle = context->getDrawFramebufferHandle(); + } + + if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) + { + return error(GL_INVALID_OPERATION); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + framebuffer->setColorbuffer(GL_RENDERBUFFER, renderbuffer); + break; + case GL_DEPTH_ATTACHMENT: + framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer); + break; + case GL_STENCIL_ATTACHMENT: + framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, " + "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level); + + try + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (texture == 0) + { + textarget = GL_NONE; + } + else + { + gl::Texture *tex = context->getTexture(texture); + + if (tex == NULL) + { + return error(GL_INVALID_OPERATION); + } + + switch (textarget) + { + case GL_TEXTURE_2D: + { + if (tex->getTarget() != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + gl::Texture2D *tex2d = static_cast(tex); + if (tex2d->isCompressed(0)) + { + return error(GL_INVALID_OPERATION); + } + break; + } + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + { + if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + { + return error(GL_INVALID_OPERATION); + } + gl::TextureCubeMap *texcube = static_cast(tex); + if (texcube->isCompressed(textarget, level)) + { + return error(GL_INVALID_OPERATION); + } + break; + } + + default: + return error(GL_INVALID_ENUM); + } + + if (level != 0) + { + return error(GL_INVALID_VALUE); + } + } + + gl::Framebuffer *framebuffer = NULL; + GLuint framebufferHandle = 0; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + framebuffer = context->getReadFramebuffer(); + framebufferHandle = context->getReadFramebufferHandle(); + } + else + { + framebuffer = context->getDrawFramebuffer(); + framebufferHandle = context->getDrawFramebufferHandle(); + } + + if (framebufferHandle == 0 || !framebuffer) + { + return error(GL_INVALID_OPERATION); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: framebuffer->setColorbuffer(textarget, texture); break; + case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture); break; + case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFrontFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + try + { + switch (mode) + { + case GL_CW: + case GL_CCW: + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setFrontFace(mode); + } + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) +{ + EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + buffers[i] = context->createBuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenerateMipmap(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (target) + { + case GL_TEXTURE_2D: + { + gl::Texture2D *tex2d = context->getTexture2D(); + + if (tex2d->isCompressed(0)) + { + return error(GL_INVALID_OPERATION); + } + if (tex2d->isDepth(0)) + { + return error(GL_INVALID_OPERATION); + } + + tex2d->generateMipmaps(); + break; + } + + case GL_TEXTURE_CUBE_MAP: + { + gl::TextureCubeMap *texcube = context->getTextureCubeMap(); + + if (texcube->isCompressed(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) + { + return error(GL_INVALID_OPERATION); + } + + texcube->generateMipmaps(); + break; + } + + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) +{ + EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + fences[i] = context->createFence(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) +{ + EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + framebuffers[i] = context->createFramebuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenQueriesEXT(GLsizei n, GLuint* ids) +{ + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + ids[i] = context->createQuery(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ + EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + renderbuffers[i] = context->createRenderbuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenTextures(GLsizei n, GLuint* textures) +{ + EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + textures[i] = context->createTexture(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, " + "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)", + program, index, bufsize, length, size, type, name); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (index >= (GLuint)programObject->getActiveAttributeCount()) + { + return error(GL_INVALID_VALUE); + } + + programObject->getActiveAttribute(index, bufsize, length, size, type, name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, " + "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", + program, index, bufsize, length, size, type, name); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (index >= (GLuint)programObject->getActiveUniformCount()) + { + return error(GL_INVALID_VALUE); + } + + programObject->getActiveUniform(index, bufsize, length, size, type, name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)", + program, maxcount, count, shaders); + + try + { + if (maxcount < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + return programObject->getAttachedShaders(maxcount, count, shaders); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +int __stdcall glGetAttribLocation(GLuint program, const GLchar* name) +{ + EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION, -1); + } + else + { + return error(GL_INVALID_VALUE, -1); + } + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programObject->isLinked() || !programBinary) + { + return error(GL_INVALID_OPERATION, -1); + } + + return programBinary->getAttributeLocation(name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, -1); + } + + return -1; +} + +void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) +{ + EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!(context->getBooleanv(pname, params))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) + return error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that the pname is valid, but there are no parameters to return + + if (nativeType == GL_FLOAT) + { + GLfloat *floatParams = NULL; + floatParams = new GLfloat[numParams]; + + context->getFloatv(pname, floatParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (floatParams[i] == 0.0f) + params[i] = GL_FALSE; + else + params[i] = GL_TRUE; + } + + delete [] floatParams; + } + else if (nativeType == GL_INT) + { + GLint *intParams = NULL; + intParams = new GLint[numParams]; + + context->getIntegerv(pname, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (intParams[i] == 0) + params[i] = GL_FALSE; + else + params[i] = GL_TRUE; + } + + delete [] intParams; + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Buffer *buffer; + + switch (target) + { + case GL_ARRAY_BUFFER: + buffer = context->getArrayBuffer(); + break; + case GL_ELEMENT_ARRAY_BUFFER: + buffer = context->getElementArrayBuffer(); + break; + default: return error(GL_INVALID_ENUM); + } + + if (!buffer) + { + // A null buffer means that "0" is bound to the requested buffer target + return error(GL_INVALID_OPERATION); + } + + switch (pname) + { + case GL_BUFFER_USAGE: + *params = buffer->usage(); + break; + case GL_BUFFER_SIZE: + *params = buffer->size(); + break; + default: return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glGetError(void) +{ + EVENT("()"); + + gl::Context *context = gl::getContext(); + + if (context) + { + return context->getError(); + } + + return GL_NO_ERROR; +} + +void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) +{ + EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); + + try + { + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION); + } + + fenceObject->getFenceiv(pname, params); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetFloatv(GLenum pname, GLfloat* params) +{ + EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!(context->getFloatv(pname, params))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) + return error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that the pname is valid, but that there are no parameters to return. + + if (nativeType == GL_BOOL) + { + GLboolean *boolParams = NULL; + boolParams = new GLboolean[numParams]; + + context->getBooleanv(pname, boolParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (boolParams[i] == GL_FALSE) + params[i] = 0.0f; + else + params[i] = 1.0f; + } + + delete [] boolParams; + } + else if (nativeType == GL_INT) + { + GLint *intParams = NULL; + intParams = new GLint[numParams]; + + context->getIntegerv(pname, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + params[i] = (GLfloat)intParams[i]; + } + + delete [] intParams; + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + target, attachment, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + gl::Framebuffer *framebuffer = NULL; + if (target == GL_READ_FRAMEBUFFER_ANGLE) + { + if(context->getReadFramebufferHandle() == 0) + { + return error(GL_INVALID_OPERATION); + } + + framebuffer = context->getReadFramebuffer(); + } + else + { + if (context->getDrawFramebufferHandle() == 0) + { + return error(GL_INVALID_OPERATION); + } + + framebuffer = context->getDrawFramebuffer(); + } + + GLenum attachmentType; + GLuint attachmentHandle; + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + attachmentType = framebuffer->getColorbufferType(); + attachmentHandle = framebuffer->getColorbufferHandle(); + break; + case GL_DEPTH_ATTACHMENT: + attachmentType = framebuffer->getDepthbufferType(); + attachmentHandle = framebuffer->getDepthbufferHandle(); + break; + case GL_STENCIL_ATTACHMENT: + attachmentType = framebuffer->getStencilbufferType(); + attachmentHandle = framebuffer->getStencilbufferHandle(); + break; + default: return error(GL_INVALID_ENUM); + } + + GLenum attachmentObjectType; // Type category + if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER) + { + attachmentObjectType = attachmentType; + } + else if (gl::IsInternalTextureTarget(attachmentType)) + { + attachmentObjectType = GL_TEXTURE; + } + else + { + UNREACHABLE(); + return; + } + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = attachmentObjectType; + break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE) + { + *params = attachmentHandle; + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + if (attachmentObjectType == GL_TEXTURE) + { + *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0 + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + if (attachmentObjectType == GL_TEXTURE) + { + if (gl::IsCubemapTextureTarget(attachmentType)) + { + *params = attachmentType; + } + else + { + *params = 0; + } + } + else + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glGetGraphicsResetStatusEXT(void) +{ + EVENT("()"); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + return context->getResetStatus(); + } + + return GL_NO_ERROR; + } + catch(std::bad_alloc&) + { + return GL_OUT_OF_MEMORY; + } +} + +void __stdcall glGetIntegerv(GLenum pname, GLint* params) +{ + EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (!(context->getIntegerv(pname, params))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getQueryParameterInfo(pname, &nativeType, &numParams)) + return error(GL_INVALID_ENUM); + + if (numParams == 0) + return; // it is known that pname is valid, but there are no parameters to return + + if (nativeType == GL_BOOL) + { + GLboolean *boolParams = NULL; + boolParams = new GLboolean[numParams]; + + context->getBooleanv(pname, boolParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (boolParams[i] == GL_FALSE) + params[i] = 0; + else + params[i] = 1; + } + + delete [] boolParams; + } + else if (nativeType == GL_FLOAT) + { + GLfloat *floatParams = NULL; + floatParams = new GLfloat[numParams]; + + context->getFloatv(pname, floatParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR) + { + params[i] = (GLint)(((GLfloat)(0xFFFFFFFF) * floatParams[i] - 1.0f) / 2.0f); + } + else + params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5)); + } + + delete [] floatParams; + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_DELETE_STATUS: + *params = programObject->isFlaggedForDeletion(); + return; + case GL_LINK_STATUS: + *params = programObject->isLinked(); + return; + case GL_VALIDATE_STATUS: + *params = programObject->isValidated(); + return; + case GL_INFO_LOG_LENGTH: + *params = programObject->getInfoLogLength(); + return; + case GL_ATTACHED_SHADERS: + *params = programObject->getAttachedShadersCount(); + return; + case GL_ACTIVE_ATTRIBUTES: + *params = programObject->getActiveAttributeCount(); + return; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = programObject->getActiveAttributeMaxLength(); + return; + case GL_ACTIVE_UNIFORMS: + *params = programObject->getActiveUniformCount(); + return; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = programObject->getActiveUniformMaxLength(); + return; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = programObject->getProgramBinaryLength(); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", + program, bufsize, length, infolog); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE); + } + + programObject->getInfoLog(bufsize, length, infolog); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) +{ + EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params); + + try + { + switch (pname) + { + case GL_CURRENT_QUERY_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + params[0] = context->getActiveQuery(target); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) +{ + EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params); + + try + { + switch (pname) + { + case GL_QUERY_RESULT_EXT: + case GL_QUERY_RESULT_AVAILABLE_EXT: + break; + default: + return error(GL_INVALID_ENUM); + } + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + return error(GL_INVALID_OPERATION); + } + + if (context->getActiveQuery(queryObject->getType()) == id) + { + return error(GL_INVALID_OPERATION); + } + + switch(pname) + { + case GL_QUERY_RESULT_EXT: + params[0] = queryObject->getResult(); + break; + case GL_QUERY_RESULT_AVAILABLE_EXT: + params[0] = queryObject->isResultAvailable(); + break; + default: + ASSERT(false); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (target != GL_RENDERBUFFER) + { + return error(GL_INVALID_ENUM); + } + + if (context->getRenderbufferHandle() == 0) + { + return error(GL_INVALID_OPERATION); + } + + gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferHandle()); + + switch (pname) + { + case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break; + case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break; + case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break; + case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break; + case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break; + case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break; + case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break; + case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break; + case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break; + case GL_RENDERBUFFER_SAMPLES_ANGLE: + if (context->getMaxSupportedSamples() != 0) + { + *params = renderbuffer->getSamples(); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_SHADER_TYPE: + *params = shaderObject->getType(); + return; + case GL_DELETE_STATUS: + *params = shaderObject->isFlaggedForDeletion(); + return; + case GL_COMPILE_STATUS: + *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE; + return; + case GL_INFO_LOG_LENGTH: + *params = shaderObject->getInfoLogLength(); + return; + case GL_SHADER_SOURCE_LENGTH: + *params = shaderObject->getSourceLength(); + return; + case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: + *params = shaderObject->getTranslatedSourceLength(); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", + shader, bufsize, length, infolog); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_VALUE); + } + + shaderObject->getInfoLog(bufsize, length, infolog); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)", + shadertype, precisiontype, range, precision); + + try + { + switch (shadertype) + { + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (precisiontype) + { + case GL_LOW_FLOAT: + case GL_MEDIUM_FLOAT: + case GL_HIGH_FLOAT: + // Assume IEEE 754 precision + range[0] = 127; + range[1] = 127; + *precision = 23; + break; + case GL_LOW_INT: + case GL_MEDIUM_INT: + case GL_HIGH_INT: + // Some (most) hardware only supports single-precision floating-point numbers, + // which can accurately represent integers up to +/-16777216 + range[0] = 24; + range[1] = 24; + *precision = 0; + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +{ + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", + shader, bufsize, length, source); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_OPERATION); + } + + shaderObject->getSource(bufsize, length, source); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +{ + EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", + shader, bufsize, length, source); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_OPERATION); + } + + shaderObject->getTranslatedSource(bufsize, length, source); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +const GLubyte* __stdcall glGetString(GLenum name) +{ + EVENT("(GLenum name = 0x%X)", name); + + try + { + gl::Context *context = gl::getNonLostContext(); + + switch (name) + { + case GL_VENDOR: + return (GLubyte*)"Google Inc."; + case GL_RENDERER: + return (GLubyte*)((context != NULL) ? context->getRendererString() : "ANGLE"); + case GL_VERSION: + return (GLubyte*)"OpenGL ES 2.0 (ANGLE " VERSION_STRING ")"; + case GL_SHADING_LANGUAGE_VERSION: + return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " VERSION_STRING ")"; + case GL_EXTENSIONS: + return (GLubyte*)((context != NULL) ? context->getExtensionString() : ""); + default: + return error(GL_INVALID_ENUM, (GLubyte*)NULL); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, (GLubyte*)NULL); + } +} + +void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = (GLfloat)texture->getMagFilter(); + break; + case GL_TEXTURE_MIN_FILTER: + *params = (GLfloat)texture->getMinFilter(); + break; + case GL_TEXTURE_WRAP_S: + *params = (GLfloat)texture->getWrapS(); + break; + case GL_TEXTURE_WRAP_T: + *params = (GLfloat)texture->getWrapT(); + break; + case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: + *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = (GLfloat)texture->getUsage(); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + *params = (GLfloat)texture->getMaxAnisotropy(); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = texture->getMagFilter(); + break; + case GL_TEXTURE_MIN_FILTER: + *params = texture->getMinFilter(); + break; + case GL_TEXTURE_WRAP_S: + *params = texture->getWrapS(); + break; + case GL_TEXTURE_WRAP_T: + *params = texture->getWrapT(); + break; + case GL_TEXTURE_IMMUTABLE_FORMAT_EXT: + *params = texture->isImmutable() ? GL_TRUE : GL_FALSE; + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = texture->getUsage(); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + *params = (GLint)texture->getMaxAnisotropy(); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)", + program, location, bufSize, params); + + try + { + if (bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->getUniformfv(location, &bufSize, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->getUniformfv(location, NULL, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", + program, location, bufSize, params); + + try + { + if (bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->getUniformiv(location, &bufSize, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (program == 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->getUniformiv(location, NULL, params)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +int __stdcall glGetUniformLocation(GLuint program, const GLchar* name) +{ + EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (strstr(name, "gl_") == name) + { + return -1; + } + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION, -1); + } + else + { + return error(GL_INVALID_VALUE, -1); + } + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + if (!programObject->isLinked() || !programBinary) + { + return error(GL_INVALID_OPERATION, -1); + } + + return programBinary->getUniformLocation(name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, -1); + } + + return -1; +} + +void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + const gl::VertexAttribute &attribState = context->getVertexAttribState(index); + + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + *params = (GLfloat)attribState.mSize; + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + *params = (GLfloat)attribState.mStride; + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + *params = (GLfloat)attribState.mType; + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + *params = (GLfloat)attribState.mBoundBuffer.id(); + break; + case GL_CURRENT_VERTEX_ATTRIB: + for (int i = 0; i < 4; ++i) + { + params[i] = attribState.mCurrentValue[i]; + } + break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: + *params = (GLfloat)attribState.mDivisor; + break; + default: return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + const gl::VertexAttribute &attribState = context->getVertexAttribState(index); + + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + *params = attribState.mSize; + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + *params = attribState.mStride; + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + *params = attribState.mType; + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE); + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + *params = attribState.mBoundBuffer.id(); + break; + case GL_CURRENT_VERTEX_ATTRIB: + for (int i = 0; i < 4; ++i) + { + float currentValue = attribState.mCurrentValue[i]; + params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f)); + } + break; + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: + *params = (GLint)attribState.mDivisor; + break; + default: return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) + { + return error(GL_INVALID_ENUM); + } + + *pointer = const_cast(context->getVertexAttribPointer(index)); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glHint(GLenum target, GLenum mode) +{ + EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); + + try + { + switch (mode) + { + case GL_FASTEST: + case GL_NICEST: + case GL_DONT_CARE: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + switch (target) + { + case GL_GENERATE_MIPMAP_HINT: + if (context) context->setGenerateMipmapHint(mode); + break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + if (context) context->setFragmentShaderDerivativeHint(mode); + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLboolean __stdcall glIsBuffer(GLuint buffer) +{ + EVENT("(GLuint buffer = %d)", buffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && buffer) + { + gl::Buffer *bufferObject = context->getBuffer(buffer); + + if (bufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsEnabled(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: return context->isCullFaceEnabled(); + case GL_POLYGON_OFFSET_FILL: return context->isPolygonOffsetFillEnabled(); + case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled(); + case GL_SAMPLE_COVERAGE: return context->isSampleCoverageEnabled(); + case GL_SCISSOR_TEST: return context->isScissorTestEnabled(); + case GL_STENCIL_TEST: return context->isStencilTestEnabled(); + case GL_DEPTH_TEST: return context->isDepthTestEnabled(); + case GL_BLEND: return context->isBlendEnabled(); + case GL_DITHER: return context->isDitherEnabled(); + default: + return error(GL_INVALID_ENUM, false); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, false); + } + + return false; +} + +GLboolean __stdcall glIsFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return GL_FALSE; + } + + return fenceObject->isFence(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) +{ + EVENT("(GLuint framebuffer = %d)", framebuffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && framebuffer) + { + gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); + + if (framebufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && program) + { + gl::Program *programObject = context->getProgram(program); + + if (programObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsQueryEXT(GLuint id) +{ + EVENT("(GLuint id = %d)", id); + + try + { + if (id == 0) + { + return GL_FALSE; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (queryObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) +{ + EVENT("(GLuint renderbuffer = %d)", renderbuffer); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && renderbuffer) + { + gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); + + if (renderbufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && shader) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (shaderObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsTexture(GLuint texture) +{ + EVENT("(GLuint texture = %d)", texture); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context && texture) + { + gl::Texture *textureObject = context->getTexture(texture); + + if (textureObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +void __stdcall glLineWidth(GLfloat width) +{ + EVENT("(GLfloat width = %f)", width); + + try + { + if (width <= 0.0f) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setLineWidth(width); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glLinkProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + context->linkProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glPixelStorei(GLenum pname, GLint param) +{ + EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + return error(GL_INVALID_VALUE); + } + + context->setUnpackAlignment(param); + break; + + case GL_PACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + return error(GL_INVALID_VALUE); + } + + context->setPackAlignment(param); + break; + + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + context->setPackReverseRowOrder(param != 0); + break; + + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) +{ + EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setPolygonOffsetParams(factor, units); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei bufSize, + GLvoid *data) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)", + x, y, width, height, format, type, bufSize, data); + + try + { + if (width < 0 || height < 0 || bufSize < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLenum currentFormat, currentType; + + // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound, + // and attempting to read back if that's the case is an error. The error will be registered + // by getCurrentReadFormat. + if (!context->getCurrentReadFormatType(¤tFormat, ¤tType)) + return; + + if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type)) + { + return error(GL_INVALID_OPERATION); + } + + context->readPixels(x, y, width, height, format, type, &bufSize, data); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)", + x, y, width, height, format, type, pixels); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLenum currentFormat, currentType; + + // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound, + // and attempting to read back if that's the case is an error. The error will be registered + // by getCurrentReadFormat. + if (!context->getCurrentReadFormatType(¤tFormat, ¤tType)) + return; + + if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type)) + { + return error(GL_INVALID_OPERATION); + } + + context->readPixels(x, y, width, height, format, type, NULL, pixels); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReleaseShaderCompiler(void) +{ + EVENT("()"); + + try + { + gl::Shader::releaseCompiler(); + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, samples, internalformat, width, height); + + try + { + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (!gl::IsColorRenderable(internalformat) && !gl::IsDepthRenderable(internalformat) && !gl::IsStencilRenderable(internalformat)) + { + return error(GL_INVALID_ENUM); + } + + if (width < 0 || height < 0 || samples < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (width > context->getMaximumRenderbufferDimension() || + height > context->getMaximumRenderbufferDimension() || + samples > context->getMaxSupportedSamples()) + { + return error(GL_INVALID_VALUE); + } + + GLuint handle = context->getRenderbufferHandle(); + if (handle == 0) + { + return error(GL_INVALID_OPERATION); + } + + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + context->setRenderbufferStorage(new gl::Depthbuffer(width, height, samples)); + break; + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + context->setRenderbufferStorage(new gl::Colorbuffer(width, height, internalformat, samples)); + break; + case GL_STENCIL_INDEX8: + context->setRenderbufferStorage(new gl::Stencilbuffer(width, height, samples)); + break; + case GL_DEPTH24_STENCIL8_OES: + context->setRenderbufferStorage(new gl::DepthStencilbuffer(width, height, samples)); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height); +} + +void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) +{ + EVENT("(GLclampf value = %f, GLboolean invert = %d)", value, invert); + + try + { + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glSetFenceNV(GLuint fence, GLenum condition) +{ + EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); + + try + { + if (condition != GL_ALL_COMPLETED_NV) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION); + } + + fenceObject->setFence(condition); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context* context = gl::getNonLostContext(); + + if (context) + { + context->setScissorParams(x, y, width, height); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +{ + EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, " + "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", + n, shaders, binaryformat, binary, length); + + try + { + // No binary shader formats are supported. + return error(GL_INVALID_ENUM); + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +{ + EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", + shader, count, string, length); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + shaderObject->setSource(count, string, length); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); +} + +void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->setStencilParams(func, ref, mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->setStencilBackParams(func, ref, mask); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilMask(GLuint mask) +{ + glStencilMaskSeparate(GL_FRONT_AND_BACK, mask); +} + +void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->setStencilWritemask(mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->setStencilBackWritemask(mask); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", + face, fail, zfail, zpass); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (fail) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (zfail) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (zpass) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->setStencilOperations(fail, zfail, zpass); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->setStencilBackOperations(fail, zfail, zpass); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLboolean __stdcall glTestFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Fence *fenceObject = context->getFence(fence); + + if (fenceObject == NULL) + { + return error(GL_INVALID_OPERATION, GL_TRUE); + } + + return fenceObject->testFence(); + } + } + catch(std::bad_alloc&) + { + error(GL_OUT_OF_MEMORY); + } + + return GL_TRUE; +} + +void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, " + "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", + target, level, internalformat, width, height, border, format, type, pixels); + + try + { + if (!validImageSize(level, width, height)) + { + return error(GL_INVALID_VALUE); + } + + if (internalformat != GLint(format)) + { + return error(GL_INVALID_OPERATION); + } + + // validate by itself (used as secondary key below) + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_24_8_OES: + case GL_HALF_FLOAT_OES: + case GL_FLOAT: + break; + default: + return error(GL_INVALID_ENUM); + } + + // validate + combinations + // - invalid -> sets INVALID_ENUM + // - invalid + combination -> sets INVALID_OPERATION + switch (format) + { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + break; + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + if (border != 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TEXTURE_2D: + if (width > (context->getMaximumTextureDimension() >> level) || + height > (context->getMaximumTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (width != height) + { + return error(GL_INVALID_VALUE); + } + + if (width > (context->getMaximumCubeTextureDimension() >> level) || + height > (context->getMaximumCubeTextureDimension() >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (format) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->supportsDXT1Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->supportsDXT3Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->supportsDXT5Textures()) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_ENUM); + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + if (!context->supportsDepthTextures()) + { + return error(GL_INVALID_VALUE); + } + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + // OES_depth_texture supports loading depth data and multiple levels, + // but ANGLE_depth_texture does not + if (pixels != NULL || level != 0) + { + return error(GL_INVALID_OPERATION); + } + break; + default: + break; + } + + if (type == GL_FLOAT) + { + if (!context->supportsFloat32Textures()) + { + return error(GL_INVALID_ENUM); + } + } + else if (type == GL_HALF_FLOAT_OES) + { + if (!context->supportsFloat16Textures()) + { + return error(GL_INVALID_ENUM); + } + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels); + } + else + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + texture->setImagePosX(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + texture->setImageNegX(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + texture->setImagePosY(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + texture->setImageNegY(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + texture->setImagePosZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + texture->setImageNegZ(level, width, height, format, type, context->getUnpackAlignment(), pixels); + break; + default: UNREACHABLE(); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + if (!texture->setWrapS((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_WRAP_T: + if (!texture->setWrapT((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MIN_FILTER: + if (!texture->setMinFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAG_FILTER: + if (!texture->setMagFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_USAGE_ANGLE: + if (!texture->setUsage((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy())) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +{ + glTexParameterf(target, pname, (GLfloat)*params); +} + +void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + if (!texture->setWrapS((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_WRAP_T: + if (!texture->setWrapT((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MIN_FILTER: + if (!texture->setMinFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAG_FILTER: + if (!texture->setMagFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_USAGE_ANGLE: + if (!texture->setUsage((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->supportsTextureFilterAnisotropy()) + { + return error(GL_INVALID_ENUM); + } + if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy())) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +{ + glTexParameteri(target, pname, *params); +} + +void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, levels, internalformat, width, height); + + try + { + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + { + return error(GL_INVALID_ENUM); + } + + if (width < 1 || height < 1 || levels < 1) + { + return error(GL_INVALID_VALUE); + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + return error(GL_INVALID_VALUE); + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + return error(GL_INVALID_OPERATION); + } + + GLenum format = gl::ExtractFormat(internalformat); + GLenum type = gl::ExtractType(internalformat); + + if (format == GL_NONE || type == GL_NONE) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + switch (target) + { + case GL_TEXTURE_2D: + if (width > context->getMaximumTextureDimension() || + height > context->getMaximumTextureDimension()) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP: + if (width > context->getMaximumCubeTextureDimension() || + height > context->getMaximumCubeTextureDimension()) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + if (levels != 1 && !context->supportsNonPower2Texture()) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + return error(GL_INVALID_OPERATION); + } + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->supportsDXT1Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->supportsDXT3Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->supportsDXT5Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + if (!context->supportsFloat32Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + if (!context->supportsFloat16Textures()) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + if (!context->supportsDepthTextures()) + { + return error(GL_INVALID_ENUM); + } + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + // ANGLE_depth_texture only supports 1-level textures + if (levels != 1) + { + return error(GL_INVALID_OPERATION); + } + break; + default: + break; + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture || texture->id() == 0) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->storage(levels, internalformat, width, height); + } + else if (target == GL_TEXTURE_CUBE_MAP) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture || texture->id() == 0) + { + return error(GL_INVALID_OPERATION); + } + + if (texture->isImmutable()) + { + return error(GL_INVALID_OPERATION); + } + + texture->storage(levels, internalformat, width); + } + else UNREACHABLE(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, " + "const GLvoid* pixels = 0x%0.8p)", + target, level, xoffset, yoffset, width, height, format, type, pixels); + + try + { + if (!gl::IsInternalTextureTarget(target)) + { + return error(GL_INVALID_ENUM); + } + + if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + if (std::numeric_limits::max() - xoffset < width || std::numeric_limits::max() - yoffset < height) + { + return error(GL_INVALID_VALUE); + } + + if (!checkTextureFormatType(format, type)) + { + return; // error is set by helper function + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (level > context->getMaximumTextureLevel()) + { + return error(GL_INVALID_VALUE); + } + + if (format == GL_FLOAT) + { + if (!context->supportsFloat32Textures()) + { + return error(GL_INVALID_ENUM); + } + } + else if (format == GL_HALF_FLOAT_OES) + { + if (!context->supportsFloat16Textures()) + { + return error(GL_INVALID_ENUM); + } + } + else if (gl::IsDepthTexture(format)) + { + if (!context->supportsDepthTextures()) + { + return error(GL_INVALID_ENUM); + } + if (target != GL_TEXTURE_2D) + { + return error(GL_INVALID_OPERATION); + } + // OES_depth_texture supports loading depth data, but ANGLE_depth_texture does not + return error(GL_INVALID_OPERATION); + } + + if (width == 0 || height == 0 || pixels == NULL) + { + return; + } + + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + if (validateSubImageParams2D(false, width, height, xoffset, yoffset, level, format, type, texture)) + { + texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + } + } + else if (gl::IsCubemapTextureTarget(target)) + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + if (validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, format, type, texture)) + { + texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); + } + } + else + { + UNREACHABLE(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform1f(GLint location, GLfloat x) +{ + glUniform1fv(location, 1, &x); +} + +void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform1fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform1i(GLint location, GLint x) +{ + glUniform1iv(location, 1, &x); +} + +void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform1iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLfloat xy[2] = {x, y}; + + glUniform2fv(location, 1, (GLfloat*)&xy); +} + +void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform2fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform2i(GLint location, GLint x, GLint y) +{ + GLint xy[4] = {x, y}; + + glUniform2iv(location, 1, (GLint*)&xy); +} + +void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform2iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat xyz[3] = {x, y, z}; + + glUniform3fv(location, 1, (GLfloat*)&xyz); +} + +void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform3fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLint xyz[3] = {x, y, z}; + + glUniform3iv(location, 1, (GLint*)&xyz); +} + +void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform3iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat xyzw[4] = {x, y, z, w}; + + glUniform4fv(location, 1, (GLfloat*)&xyzw); +} + +void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform4fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLint xyzw[4] = {x, y, z, w}; + + glUniform4iv(location, 1, (GLint*)&xyzw); +} + +void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniform4iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniformMatrix2fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniformMatrix3fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::ProgramBinary *programBinary = context->getCurrentProgramBinary(); + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->setUniformMatrix4fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUseProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject && program != 0) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + if (program != 0 && !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + context->useProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glValidateProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + return error(GL_INVALID_OPERATION); + } + else + { + return error(GL_INVALID_VALUE); + } + } + + programObject->validate(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) +{ + EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, 0, 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], 0, 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], values[1], 0, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, z, 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { values[0], values[1], values[2], 1 }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + GLfloat vals[4] = { x, y, z, w }; + context->setVertexAttrib(index, vals); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setVertexAttrib(index, values); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) +{ + EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setVertexAttribDivisor(index, divisor); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +{ + EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, " + "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", + index, size, type, normalized, stride, ptr); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + if (size < 1 || size > 4) + { + return error(GL_INVALID_VALUE); + } + + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (stride < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + context->setViewportParams(x, y, width, height); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " + "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, " + "GLbitfield mask = 0x%X, GLenum filter = 0x%X)", + srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter); + + try + { + switch (filter) + { + case GL_NEAREST: + break; + default: + return error(GL_INVALID_ENUM); + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + { + return error(GL_INVALID_VALUE); + } + + if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0) + { + ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation"); + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle()) + { + ERR("Blits with the same source and destination framebuffer are not supported by this implementation."); + return error(GL_INVALID_OPERATION); + } + + context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " + "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, " + "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, format, type, pixels); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, + GLenum *binaryFormat, void *binary) +{ + EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)", + program, bufSize, length, binaryFormat, binary); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + + if (!programBinary) + { + return error(GL_INVALID_OPERATION); + } + + if (!programBinary->save(binary, bufSize, length)) + { + return error(GL_INVALID_OPERATION); + } + + *binaryFormat = GL_PROGRAM_BINARY_ANGLE; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat, + const void *binary, GLint length) +{ + EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)", + program, binaryFormat, binary, length); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + if (binaryFormat != GL_PROGRAM_BINARY_ANGLE) + { + return error(GL_INVALID_ENUM); + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_OPERATION); + } + + context->setProgramBinary(program, binary, length); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname) +{ + struct Extension + { + const char *name; + __eglMustCastToProperFunctionPointerType address; + }; + + static const Extension glExtensions[] = + { + {"glTexImage3DOES", (__eglMustCastToProperFunctionPointerType)glTexImage3DOES}, + {"glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)glBlitFramebufferANGLE}, + {"glRenderbufferStorageMultisampleANGLE", (__eglMustCastToProperFunctionPointerType)glRenderbufferStorageMultisampleANGLE}, + {"glDeleteFencesNV", (__eglMustCastToProperFunctionPointerType)glDeleteFencesNV}, + {"glGenFencesNV", (__eglMustCastToProperFunctionPointerType)glGenFencesNV}, + {"glIsFenceNV", (__eglMustCastToProperFunctionPointerType)glIsFenceNV}, + {"glTestFenceNV", (__eglMustCastToProperFunctionPointerType)glTestFenceNV}, + {"glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)glGetFenceivNV}, + {"glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)glFinishFenceNV}, + {"glSetFenceNV", (__eglMustCastToProperFunctionPointerType)glSetFenceNV}, + {"glGetTranslatedShaderSourceANGLE", (__eglMustCastToProperFunctionPointerType)glGetTranslatedShaderSourceANGLE}, + {"glTexStorage2DEXT", (__eglMustCastToProperFunctionPointerType)glTexStorage2DEXT}, + {"glGetGraphicsResetStatusEXT", (__eglMustCastToProperFunctionPointerType)glGetGraphicsResetStatusEXT}, + {"glReadnPixelsEXT", (__eglMustCastToProperFunctionPointerType)glReadnPixelsEXT}, + {"glGetnUniformfvEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformfvEXT}, + {"glGetnUniformivEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformivEXT}, + {"glGenQueriesEXT", (__eglMustCastToProperFunctionPointerType)glGenQueriesEXT}, + {"glDeleteQueriesEXT", (__eglMustCastToProperFunctionPointerType)glDeleteQueriesEXT}, + {"glIsQueryEXT", (__eglMustCastToProperFunctionPointerType)glIsQueryEXT}, + {"glBeginQueryEXT", (__eglMustCastToProperFunctionPointerType)glBeginQueryEXT}, + {"glEndQueryEXT", (__eglMustCastToProperFunctionPointerType)glEndQueryEXT}, + {"glGetQueryivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryivEXT}, + {"glGetQueryObjectuivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryObjectuivEXT}, + {"glVertexAttribDivisorANGLE", (__eglMustCastToProperFunctionPointerType)glVertexAttribDivisorANGLE}, + {"glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawArraysInstancedANGLE}, + {"glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawElementsInstancedANGLE}, + {"glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glGetProgramBinaryOES}, + {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES}, }; + + for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++) + { + if (strcmp(procname, glExtensions[ext].name) == 0) + { + return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address; + } + } + + return NULL; +} + +// Non-public functions used by EGL + +bool __stdcall glBindTexImage(egl::Surface *surface) +{ + EVENT("(egl::Surface* surface = 0x%0.8p)", + surface); + + try + { + gl::Context *context = gl::getNonLostContext(); + + if (context) + { + gl::Texture2D *textureObject = context->getTexture2D(); + + if (textureObject->isImmutable()) + { + return false; + } + + if (textureObject) + { + textureObject->bindTexImage(surface); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, false); + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def new file mode 100644 index 0000000000..5f935c3733 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def @@ -0,0 +1,182 @@ +LIBRARY libGLESv2 +EXPORTS + glActiveTexture @1 + glAttachShader @2 + glBindAttribLocation @3 + glBindBuffer @4 + glBindFramebuffer @5 + glBindRenderbuffer @6 + glBindTexture @7 + glBlendColor @8 + glBlendEquation @9 + glBlendEquationSeparate @10 + glBlendFunc @11 + glBlendFuncSeparate @12 + glBufferData @13 + glBufferSubData @14 + glCheckFramebufferStatus @15 + glClear @16 + glClearColor @17 + glClearDepthf @18 + glClearStencil @19 + glColorMask @20 + glCompileShader @21 + glCompressedTexImage2D @22 + glCompressedTexSubImage2D @23 + glCopyTexImage2D @24 + glCopyTexSubImage2D @25 + glCreateProgram @26 + glCreateShader @27 + glCullFace @28 + glDeleteBuffers @29 + glDeleteFramebuffers @30 + glDeleteProgram @32 + glDeleteRenderbuffers @33 + glDeleteShader @34 + glDeleteTextures @31 + glDepthFunc @36 + glDepthMask @37 + glDepthRangef @38 + glDetachShader @35 + glDisable @39 + glDisableVertexAttribArray @40 + glDrawArrays @41 + glDrawElements @42 + glEnable @43 + glEnableVertexAttribArray @44 + glFinish @45 + glFlush @46 + glFramebufferRenderbuffer @47 + glFramebufferTexture2D @48 + glFrontFace @49 + glGenBuffers @50 + glGenFramebuffers @52 + glGenRenderbuffers @53 + glGenTextures @54 + glGenerateMipmap @51 + glGetActiveAttrib @55 + glGetActiveUniform @56 + glGetAttachedShaders @57 + glGetAttribLocation @58 + glGetBooleanv @59 + glGetBufferParameteriv @60 + glGetError @61 + glGetFloatv @62 + glGetFramebufferAttachmentParameteriv @63 + glGetIntegerv @64 + glGetProgramInfoLog @66 + glGetProgramiv @65 + glGetRenderbufferParameteriv @67 + glGetShaderInfoLog @69 + glGetShaderPrecisionFormat @70 + glGetShaderSource @71 + glGetShaderiv @68 + glGetString @72 + glGetTexParameterfv @73 + glGetTexParameteriv @74 + glGetUniformLocation @77 + glGetUniformfv @75 + glGetUniformiv @76 + glGetVertexAttribPointerv @80 + glGetVertexAttribfv @78 + glGetVertexAttribiv @79 + glHint @81 + glIsBuffer @82 + glIsEnabled @83 + glIsFramebuffer @84 + glIsProgram @85 + glIsRenderbuffer @86 + glIsShader @87 + glIsTexture @88 + glLineWidth @89 + glLinkProgram @90 + glPixelStorei @91 + glPolygonOffset @92 + glReadPixels @93 + glReleaseShaderCompiler @94 + glRenderbufferStorage @95 + glSampleCoverage @96 + glScissor @97 + glShaderBinary @98 + glShaderSource @99 + glStencilFunc @100 + glStencilFuncSeparate @101 + glStencilMask @102 + glStencilMaskSeparate @103 + glStencilOp @104 + glStencilOpSeparate @105 + glTexImage2D @106 + glTexParameterf @107 + glTexParameterfv @108 + glTexParameteri @109 + glTexParameteriv @110 + glTexSubImage2D @111 + glUniform1f @112 + glUniform1fv @113 + glUniform1i @114 + glUniform1iv @115 + glUniform2f @116 + glUniform2fv @117 + glUniform2i @118 + glUniform2iv @119 + glUniform3f @120 + glUniform3fv @121 + glUniform3i @122 + glUniform3iv @123 + glUniform4f @124 + glUniform4fv @125 + glUniform4i @126 + glUniform4iv @127 + glUniformMatrix2fv @128 + glUniformMatrix3fv @129 + glUniformMatrix4fv @130 + glUseProgram @131 + glValidateProgram @132 + glVertexAttrib1f @133 + glVertexAttrib1fv @134 + glVertexAttrib2f @135 + glVertexAttrib2fv @136 + glVertexAttrib3f @137 + glVertexAttrib3fv @138 + glVertexAttrib4f @139 + glVertexAttrib4fv @140 + glVertexAttribPointer @141 + glViewport @142 + + ; Extensions + glTexImage3DOES @143 + glBlitFramebufferANGLE @149 + glRenderbufferStorageMultisampleANGLE @150 + glDeleteFencesNV @151 + glFinishFenceNV @152 + glGenFencesNV @153 + glGetFenceivNV @154 + glIsFenceNV @155 + glSetFenceNV @156 + glTestFenceNV @157 + glGetTranslatedShaderSourceANGLE @159 + glTexStorage2DEXT @160 + glGetGraphicsResetStatusEXT @161 + glReadnPixelsEXT @162 + glGetnUniformfvEXT @163 + glGetnUniformivEXT @164 + glGenQueriesEXT @165 + glDeleteQueriesEXT @166 + glIsQueryEXT @167 + glBeginQueryEXT @168 + glEndQueryEXT @169 + glGetQueryivEXT @170 + glGetQueryObjectuivEXT @171 + glVertexAttribDivisorANGLE @172 + glDrawArraysInstancedANGLE @173 + glDrawElementsInstancedANGLE @174 + glProgramBinaryOES @175 + glGetProgramBinaryOES @176 + + ; EGL dependencies + glCreateContext @144 NONAME + glDestroyContext @145 NONAME + glMakeCurrent @146 NONAME + glGetCurrentContext @147 NONAME + glGetProcAddress @148 NONAME + glBindTexImage @158 NONAME diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc b/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc new file mode 100644 index 0000000000..0ad21e440e --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include +#include "../common/version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""../common/version.h""\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "ANGLE libGLESv2 Dynamic Link Library" + VALUE "FileVersion", VERSION_STRING + VALUE "InternalName", "libGLESv2" + VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc." + VALUE "OriginalFilename", "libGLESv2.dll" + VALUE "PrivateBuild", VERSION_STRING + VALUE "ProductName", "ANGLE libGLESv2 Dynamic Link Library" + VALUE "ProductVersion", VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp new file mode 100644 index 0000000000..6e678c2616 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/main.cpp @@ -0,0 +1,176 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// main.cpp: DLL entry point and management of thread-local data. + +#include "libGLESv2/main.h" +#include "libGLESv2/utilities.h" + +#include "common/debug.h" +#include "libEGL/Surface.h" + +#include "libGLESv2/Framebuffer.h" + +static DWORD currentTLS = TLS_OUT_OF_INDEXES; + +extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + { + currentTLS = TlsAlloc(); + + if (currentTLS == TLS_OUT_OF_INDEXES) + { + return FALSE; + } + } + // Fall throught to initialize index + case DLL_THREAD_ATTACH: + { + gl::Current *current = (gl::Current*)LocalAlloc(LPTR, sizeof(gl::Current)); + + if (current) + { + TlsSetValue(currentTLS, current); + + current->context = NULL; + current->display = NULL; + } + } + break; + case DLL_THREAD_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + } + break; + case DLL_PROCESS_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + + TlsFree(currentTLS); + } + break; + default: + break; + } + + return TRUE; +} + +namespace gl +{ +void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->context = context; + current->display = display; + + if (context && display && surface) + { + context->makeCurrent(display, surface); + } +} + +Context *getContext() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->context; +} + +Context *getNonLostContext() +{ + Context *context = getContext(); + + if (context) + { + if (context->isContextLost()) + { + error(GL_OUT_OF_MEMORY); + return NULL; + } + else + { + return context; + } + } + return NULL; +} + +egl::Display *getDisplay() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->display; +} + +IDirect3DDevice9 *getDevice() +{ + egl::Display *display = getDisplay(); + + return display->getDevice(); +} + +bool checkDeviceLost(HRESULT errorCode) +{ + egl::Display *display = NULL; + + if (isDeviceLostError(errorCode)) + { + display = gl::getDisplay(); + display->notifyDeviceLost(); + return true; + } + return false; +} +} + +// Records an error code +void error(GLenum errorCode) +{ + gl::Context *context = glGetCurrentContext(); + + if (context) + { + switch (errorCode) + { + case GL_INVALID_ENUM: + context->recordInvalidEnum(); + TRACE("\t! Error generated: invalid enum\n"); + break; + case GL_INVALID_VALUE: + context->recordInvalidValue(); + TRACE("\t! Error generated: invalid value\n"); + break; + case GL_INVALID_OPERATION: + context->recordInvalidOperation(); + TRACE("\t! Error generated: invalid operation\n"); + break; + case GL_OUT_OF_MEMORY: + context->recordOutOfMemory(); + TRACE("\t! Error generated: out of memory\n"); + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + context->recordInvalidFramebufferOperation(); + TRACE("\t! Error generated: invalid framebuffer operation\n"); + break; + default: UNREACHABLE(); + } + } +} diff --git a/src/3rdparty/angle/src/libGLESv2/main.h b/src/3rdparty/angle/src/libGLESv2/main.h new file mode 100644 index 0000000000..504848aa65 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/main.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// main.h: Management of thread-local data. + +#ifndef LIBGLESV2_MAIN_H_ +#define LIBGLESV2_MAIN_H_ + +#define GL_APICALL +#include +#include + +#include "common/debug.h" +#include "libEGL/Display.h" + +#include "libGLESv2/Context.h" + +namespace gl +{ +struct Current +{ + Context *context; + egl::Display *display; +}; + +void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface); + +Context *getContext(); +Context *getNonLostContext(); +egl::Display *getDisplay(); + +IDirect3DDevice9 *getDevice(); + +bool checkDeviceLost(HRESULT errorCode); +} + +void error(GLenum errorCode); + +template +const T &error(GLenum errorCode, const T &returnValue) +{ + error(errorCode); + + return returnValue; +} + +#endif // LIBGLESV2_MAIN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/mathutil.h b/src/3rdparty/angle/src/libGLESv2/mathutil.h new file mode 100644 index 0000000000..790ecd89fa --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/mathutil.h @@ -0,0 +1,145 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// mathutil.h: Math and bit manipulation functions. + +#ifndef LIBGLESV2_MATHUTIL_H_ +#define LIBGLESV2_MATHUTIL_H_ + +#include +#include +#include + +namespace gl +{ +struct Vector4 +{ + Vector4() {} + Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} + + float x; + float y; + float z; + float w; +}; + +inline bool isPow2(int x) +{ + return (x & (x - 1)) == 0 && (x != 0); +} + +inline int log2(int x) +{ + int r = 0; + while ((x >> r) > 1) r++; + return r; +} + +inline unsigned int ceilPow2(unsigned int x) +{ + if (x != 0) x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + + return x; +} + +template +inline T clamp(T x, MIN min, MAX max) +{ + return x < min ? min : (x > max ? max : x); +} + +inline float clamp01(float x) +{ + return clamp(x, 0.0f, 1.0f); +} + +template +inline unsigned int unorm(float x) +{ + const unsigned int max = 0xFFFFFFFF >> (32 - n); + + if (x > 1) + { + return max; + } + else if (x < 0) + { + return 0; + } + else + { + return (unsigned int)(max * x + 0.5f); + } +} + +inline bool supportsSSE2() +{ + static bool checked = false; + static bool supports = false; + + if (checked) + { + return supports; + } + + int info[4]; + __cpuid(info, 0); + + if (info[0] >= 1) + { + __cpuid(info, 1); + + supports = (info[3] >> 26) & 1; + } + + checked = true; + + return supports; +} + +inline unsigned short float32ToFloat16(float fp32) +{ + unsigned int fp32i = (unsigned int&)fp32; + unsigned int sign = (fp32i & 0x80000000) >> 16; + unsigned int abs = fp32i & 0x7FFFFFFF; + + if(abs > 0x47FFEFFF) // Infinity + { + return sign | 0x7FFF; + } + else if(abs < 0x38800000) // Denormal + { + unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000; + int e = 113 - (abs >> 23); + + if(e < 24) + { + abs = mantissa >> e; + } + else + { + abs = 0; + } + + return sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13; + } + else + { + return sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13; + } +} + +float float16ToFloat32(unsigned short h); + +} + +#endif // LIBGLESV2_MATHUTIL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/resource.h b/src/3rdparty/angle/src/libGLESv2/resource.h new file mode 100644 index 0000000000..39adaad0dd --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by libGLESv2.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps new file mode 100644 index 0000000000..dcb3bd0e76 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.ps @@ -0,0 +1,39 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +sampler2D tex : s0; + +uniform float4 mode : c0; + +// Passthrough Pixel Shader +// Outputs texture 0 sampled at texcoord 0. +float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy); +}; + +// Luminance Conversion Pixel Shader +// Outputs sample(tex0, tc0).rrra. +// For LA output (pass A) set C0.X = 1, C0.Y = 0. +// For L output (A = 1) set C0.X = 0, C0.Y = 1. +float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 tmp = tex2D(tex, texcoord.xy); + tmp.w = tmp.w * mode.x + mode.y; + return tmp.xxxw; +}; + +// RGB/A Component Mask Pixel Shader +// Outputs sample(tex0, tc0) with options to force RGB = 0 and/or A = 1. +// To force RGB = 0, set C0.X = 0, otherwise C0.X = 1. +// To force A = 1, set C0.Z = 0, C0.W = 1, otherwise C0.Z = 1, C0.W = 0. +float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR +{ + float4 tmp = tex2D(tex, texcoord.xy); + tmp.xyz = tmp.xyz * mode.x; + tmp.w = tmp.w * mode.z + mode.w; + return tmp; +}; diff --git a/src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs new file mode 100644 index 0000000000..3a36980b93 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/shaders/Blit.vs @@ -0,0 +1,43 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +struct VS_OUTPUT +{ + float4 position : POSITION; + float4 texcoord : TEXCOORD0; +}; + +uniform float4 halfPixelSize : c0; + +// Standard Vertex Shader +// Input 0 is the homogenous position. +// Outputs the homogenous position as-is. +// Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right. +// C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0. +VS_OUTPUT standardvs(in float4 position : POSITION) +{ + VS_OUTPUT Out; + + Out.position = position + halfPixelSize; + Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); + + return Out; +}; + +// Flip Y Vertex Shader +// Input 0 is the homogenous position. +// Outputs the homogenous position as-is. +// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right. +// C0.XY must be the half-pixel width and height. C0.ZW must be 0. +VS_OUTPUT flipyvs(in float4 position : POSITION) +{ + VS_OUTPUT Out; + + Out.position = position + halfPixelSize; + Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0); + + return Out; +}; diff --git a/src/3rdparty/angle/src/libGLESv2/utilities.cpp b/src/3rdparty/angle/src/libGLESv2/utilities.cpp new file mode 100644 index 0000000000..a3eb27d392 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/utilities.cpp @@ -0,0 +1,1218 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// utilities.cpp: Conversion functions and other utility routines. + +#include "libGLESv2/utilities.h" + +#include +#include +#include + +#include "common/debug.h" + +#include "libGLESv2/mathutil.h" +#include "libGLESv2/Context.h" + +namespace gl +{ + +// This is how much data the application expects for a uniform +int UniformExternalComponentCount(GLenum type) +{ + switch (type) + { + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return 1; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + return 2; + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_FLOAT_MAT2: + return 4; + case GL_FLOAT_MAT3: + return 9; + case GL_FLOAT_MAT4: + return 16; + default: + UNREACHABLE(); + } + + return 0; +} + +// This is how much data we actually store for a uniform +int UniformInternalComponentCount(GLenum type) +{ + switch (type) + { + case GL_BOOL: + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + return 1; + case GL_BOOL_VEC2: + case GL_INT_VEC2: + return 2; + case GL_INT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + return 4; + case GL_FLOAT_MAT2: + return 8; + case GL_FLOAT_MAT3: + return 12; + case GL_FLOAT_MAT4: + return 16; + default: + UNREACHABLE(); + } + + return 0; +} + +GLenum UniformComponentType(GLenum type) +{ + switch(type) + { + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return GL_BOOL; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + return GL_FLOAT; + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + return GL_INT; + default: + UNREACHABLE(); + } + + return GL_NONE; +} + +size_t UniformComponentSize(GLenum type) +{ + switch(type) + { + case GL_BOOL: return sizeof(GLint); + case GL_FLOAT: return sizeof(GLfloat); + case GL_INT: return sizeof(GLint); + default: UNREACHABLE(); + } + + return 0; +} + +size_t UniformInternalSize(GLenum type) +{ + return UniformComponentSize(UniformComponentType(type)) * UniformInternalComponentCount(type); +} + +size_t UniformExternalSize(GLenum type) +{ + return UniformComponentSize(UniformComponentType(type)) * UniformExternalComponentCount(type); +} + +int VariableRowCount(GLenum type) +{ + switch (type) + { + case GL_NONE: + return 0; + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + return 1; + case GL_FLOAT_MAT2: + return 2; + case GL_FLOAT_MAT3: + return 3; + case GL_FLOAT_MAT4: + return 4; + default: + UNREACHABLE(); + } + + return 0; +} + +int VariableColumnCount(GLenum type) +{ + switch (type) + { + case GL_NONE: + return 0; + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + return 1; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_FLOAT_MAT2: + return 2; + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC3: + case GL_FLOAT_MAT3: + return 3; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_FLOAT_MAT4: + return 4; + default: + UNREACHABLE(); + } + + return 0; +} + +int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize) +{ + ASSERT(allocationSize <= bitsSize); + + unsigned int mask = std::numeric_limits::max() >> (std::numeric_limits::digits - allocationSize); + + for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++) + { + if ((*bits & mask) == 0) + { + *bits |= mask; + return i; + } + + mask <<= 1; + } + + return -1; +} + +GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment) +{ + ASSERT(alignment > 0 && isPow2(alignment)); + + GLsizei rawPitch = ComputePixelSize(internalformat) * width; + return (rawPitch + alignment - 1) & ~(alignment - 1); +} + +GLsizei ComputeCompressedPitch(GLsizei width, GLenum internalformat) +{ + return ComputeCompressedSize(width, 1, internalformat); +} + +GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum internalformat) +{ + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return 8 * ((width + 3) / 4) * ((height + 3) / 4); + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return 16 * ((width + 3) / 4) * ((height + 3) / 4); + default: + return 0; + } +} + +bool IsCompressed(GLenum format) +{ + if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || + format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || + format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE || + format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE) + { + return true; + } + else + { + return false; + } +} + +bool IsDepthTexture(GLenum format) +{ + if (format == GL_DEPTH_COMPONENT || + format == GL_DEPTH_STENCIL_OES || + format == GL_DEPTH_COMPONENT16 || + format == GL_DEPTH_COMPONENT32_OES || + format == GL_DEPTH24_STENCIL8_OES) + { + return true; + } + + return false; +} + +bool IsStencilTexture(GLenum format) +{ + if (format == GL_DEPTH_STENCIL_OES || + format == GL_DEPTH24_STENCIL8_OES) + { + return true; + } + + return false; +} + +// Returns the size, in bytes, of a single texel in an Image +int ComputePixelSize(GLint internalformat) +{ + switch (internalformat) + { + case GL_ALPHA8_EXT: return sizeof(unsigned char); + case GL_LUMINANCE8_EXT: return sizeof(unsigned char); + case GL_ALPHA32F_EXT: return sizeof(float); + case GL_LUMINANCE32F_EXT: return sizeof(float); + case GL_ALPHA16F_EXT: return sizeof(unsigned short); + case GL_LUMINANCE16F_EXT: return sizeof(unsigned short); + case GL_LUMINANCE8_ALPHA8_EXT: return sizeof(unsigned char) * 2; + case GL_LUMINANCE_ALPHA32F_EXT: return sizeof(float) * 2; + case GL_LUMINANCE_ALPHA16F_EXT: return sizeof(unsigned short) * 2; + case GL_RGB8_OES: return sizeof(unsigned char) * 3; + case GL_RGB565: return sizeof(unsigned short); + case GL_RGB32F_EXT: return sizeof(float) * 3; + case GL_RGB16F_EXT: return sizeof(unsigned short) * 3; + case GL_RGBA8_OES: return sizeof(unsigned char) * 4; + case GL_RGBA4: return sizeof(unsigned short); + case GL_RGB5_A1: return sizeof(unsigned short); + case GL_RGBA32F_EXT: return sizeof(float) * 4; + case GL_RGBA16F_EXT: return sizeof(unsigned short) * 4; + case GL_BGRA8_EXT: return sizeof(unsigned char) * 4; + case GL_BGRA4_ANGLEX: return sizeof(unsigned short); + case GL_BGR5_A1_ANGLEX: return sizeof(unsigned short); + default: UNREACHABLE(); + } + + return 0; +} + +bool IsCubemapTextureTarget(GLenum target) +{ + return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); +} + +bool IsInternalTextureTarget(GLenum target) +{ + return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target); +} + +GLint ConvertSizedInternalFormat(GLenum format, GLenum type) +{ + switch (format) + { + case GL_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_ALPHA8_EXT; + case GL_FLOAT: return GL_ALPHA32F_EXT; + case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_LUMINANCE: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_EXT; + case GL_FLOAT: return GL_LUMINANCE32F_EXT; + case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_ALPHA8_EXT; + case GL_FLOAT: return GL_LUMINANCE_ALPHA32F_EXT; + case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_RGB8_OES; + case GL_UNSIGNED_SHORT_5_6_5: return GL_RGB565; + case GL_FLOAT: return GL_RGB32F_EXT; + case GL_HALF_FLOAT_OES: return GL_RGB16F_EXT; + default: UNIMPLEMENTED(); + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_RGBA8_OES; + case GL_UNSIGNED_SHORT_4_4_4_4: return GL_RGBA4; + case GL_UNSIGNED_SHORT_5_5_5_1: return GL_RGB5_A1; + case GL_FLOAT: return GL_RGBA32F_EXT; + case GL_HALF_FLOAT_OES: return GL_RGBA16F_EXT; + break; + default: UNIMPLEMENTED(); + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: return GL_BGRA8_EXT; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return GL_BGRA4_ANGLEX; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return GL_BGR5_A1_ANGLEX; + default: UNIMPLEMENTED(); + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + return format; + case GL_DEPTH_COMPONENT: + switch (type) + { + case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16; + case GL_UNSIGNED_INT: return GL_DEPTH_COMPONENT32_OES; + default: UNIMPLEMENTED(); + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: return GL_DEPTH24_STENCIL8_OES; + default: UNIMPLEMENTED(); + } + break; + default: + UNIMPLEMENTED(); + } + + return GL_NONE; +} + +GLenum ExtractFormat(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGB565: return GL_RGB; + case GL_RGBA4: return GL_RGBA; + case GL_RGB5_A1: return GL_RGBA; + case GL_RGB8_OES: return GL_RGB; + case GL_RGBA8_OES: return GL_RGBA; + case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA; + case GL_LUMINANCE8_EXT: return GL_LUMINANCE; + case GL_ALPHA8_EXT: return GL_ALPHA; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + case GL_RGBA32F_EXT: return GL_RGBA; + case GL_RGB32F_EXT: return GL_RGB; + case GL_ALPHA32F_EXT: return GL_ALPHA; + case GL_LUMINANCE32F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA32F_EXT: return GL_LUMINANCE_ALPHA; + case GL_RGBA16F_EXT: return GL_RGBA; + case GL_RGB16F_EXT: return GL_RGB; + case GL_ALPHA16F_EXT: return GL_ALPHA; + case GL_LUMINANCE16F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA16F_EXT: return GL_LUMINANCE_ALPHA; + case GL_BGRA8_EXT: return GL_BGRA_EXT; + case GL_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT; + case GL_DEPTH24_STENCIL8_OES: return GL_DEPTH_STENCIL_OES; + default: return GL_NONE; // Unsupported + } +} + +GLenum ExtractType(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGB565: return GL_UNSIGNED_SHORT_5_6_5; + case GL_RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4; + case GL_RGB5_A1: return GL_UNSIGNED_SHORT_5_5_5_1; + case GL_RGB8_OES: return GL_UNSIGNED_BYTE; + case GL_RGBA8_OES: return GL_UNSIGNED_BYTE; + case GL_LUMINANCE8_ALPHA8_EXT: return GL_UNSIGNED_BYTE; + case GL_LUMINANCE8_EXT: return GL_UNSIGNED_BYTE; + case GL_ALPHA8_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_UNSIGNED_BYTE; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_UNSIGNED_BYTE; + case GL_RGBA32F_EXT: return GL_FLOAT; + case GL_RGB32F_EXT: return GL_FLOAT; + case GL_ALPHA32F_EXT: return GL_FLOAT; + case GL_LUMINANCE32F_EXT: return GL_FLOAT; + case GL_LUMINANCE_ALPHA32F_EXT: return GL_FLOAT; + case GL_RGBA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_RGB16F_EXT: return GL_HALF_FLOAT_OES; + case GL_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_LUMINANCE16F_EXT: return GL_HALF_FLOAT_OES; + case GL_LUMINANCE_ALPHA16F_EXT: return GL_HALF_FLOAT_OES; + case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE; + case GL_DEPTH_COMPONENT16: return GL_UNSIGNED_SHORT; + case GL_DEPTH_COMPONENT32_OES: return GL_UNSIGNED_INT; + case GL_DEPTH24_STENCIL8_OES: return GL_UNSIGNED_INT_24_8_OES; + default: return GL_NONE; // Unsupported + } +} + +bool IsColorRenderable(GLenum internalformat) +{ + switch (internalformat) + { + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + return true; + case GL_DEPTH_COMPONENT16: + case GL_STENCIL_INDEX8: + case GL_DEPTH24_STENCIL8_OES: + return false; + default: + UNIMPLEMENTED(); + } + + return false; +} + +bool IsDepthRenderable(GLenum internalformat) +{ + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + case GL_DEPTH24_STENCIL8_OES: + return true; + case GL_STENCIL_INDEX8: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + return false; + default: + UNIMPLEMENTED(); + } + + return false; +} + +bool IsStencilRenderable(GLenum internalformat) +{ + switch (internalformat) + { + case GL_STENCIL_INDEX8: + case GL_DEPTH24_STENCIL8_OES: + return true; + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_RGB8_OES: + case GL_RGBA8_OES: + case GL_DEPTH_COMPONENT16: + return false; + default: + UNIMPLEMENTED(); + } + + return false; +} + +bool IsFloat32Format(GLint internalformat) +{ + switch (internalformat) + { + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + return true; + default: + return false; + } +} + +bool IsFloat16Format(GLint internalformat) +{ + switch (internalformat) + { + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + return true; + default: + return false; + } +} + +} + +namespace es2dx +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison) +{ + D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; + switch (comparison) + { + case GL_NEVER: d3dComp = D3DCMP_NEVER; break; + case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break; + case GL_LESS: d3dComp = D3DCMP_LESS; break; + case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break; + case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break; + case GL_GREATER: d3dComp = D3DCMP_GREATER; break; + case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break; + case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3DCOLOR ConvertColor(gl::Color color) +{ + return D3DCOLOR_RGBA(gl::unorm<8>(color.red), + gl::unorm<8>(color.green), + gl::unorm<8>(color.blue), + gl::unorm<8>(color.alpha)); +} + +D3DBLEND ConvertBlendFunc(GLenum blend) +{ + D3DBLEND d3dBlend = D3DBLEND_ZERO; + + switch (blend) + { + case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break; + case GL_ONE: d3dBlend = D3DBLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break; + case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break; + case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3DBLENDOP ConvertBlendOp(GLenum blendOp) +{ + D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; + + switch (blendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) +{ + D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break; + case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break; + case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) +{ + D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; + + switch (wrap) + { + case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break; + case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break; + case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break; + default: UNREACHABLE(); + } + + return d3dWrap; +} + +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) +{ + D3DCULL cull = D3DCULL_CCW; + switch (cullFace) + { + case GL_FRONT: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case GL_BACK: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case GL_FRONT_AND_BACK: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: UNREACHABLE(); + } + + return cull; +} + +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace) +{ + D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; + + switch (cubeFace) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + face = D3DCUBEMAP_FACE_POSITIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + face = D3DCUBEMAP_FACE_NEGATIVE_X; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + face = D3DCUBEMAP_FACE_POSITIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + face = D3DCUBEMAP_FACE_NEGATIVE_Y; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + face = D3DCUBEMAP_FACE_POSITIVE_Z; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = D3DCUBEMAP_FACE_NEGATIVE_Z; + break; + default: UNREACHABLE(); + } + + return face; +} + +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + return (red ? D3DCOLORWRITEENABLE_RED : 0) | + (green ? D3DCOLORWRITEENABLE_GREEN : 0) | + (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | + (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); +} + +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) +{ + if (maxAnisotropy > 1.0f) + { + return D3DTEXF_ANISOTROPIC; + } + + D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; + switch (magFilter) + { + case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break; + case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break; + default: UNREACHABLE(); + } + + return d3dMagFilter; +} + +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy) +{ + switch (minFilter) + { + case GL_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + default: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + UNREACHABLE(); + } + + if (maxAnisotropy > 1.0f) + { + *d3dMinFilter = D3DTEXF_ANISOTROPIC; + } +} + +bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, + D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount) +{ + switch (primitiveType) + { + case GL_POINTS: + *d3dPrimitiveType = D3DPT_POINTLIST; + *d3dPrimitiveCount = elementCount; + break; + case GL_LINES: + *d3dPrimitiveType = D3DPT_LINELIST; + *d3dPrimitiveCount = elementCount / 2; + break; + case GL_LINE_LOOP: + *d3dPrimitiveType = D3DPT_LINESTRIP; + *d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately + break; + case GL_LINE_STRIP: + *d3dPrimitiveType = D3DPT_LINESTRIP; + *d3dPrimitiveCount = elementCount - 1; + break; + case GL_TRIANGLES: + *d3dPrimitiveType = D3DPT_TRIANGLELIST; + *d3dPrimitiveCount = elementCount / 3; + break; + case GL_TRIANGLE_STRIP: + *d3dPrimitiveType = D3DPT_TRIANGLESTRIP; + *d3dPrimitiveCount = elementCount - 2; + break; + case GL_TRIANGLE_FAN: + *d3dPrimitiveType = D3DPT_TRIANGLEFAN; + *d3dPrimitiveCount = elementCount - 2; + break; + default: + return false; + } + + return true; +} + +D3DFORMAT ConvertRenderbufferFormat(GLenum format) +{ + switch (format) + { + case GL_NONE: return D3DFMT_NULL; + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8_OES: return D3DFMT_A8R8G8B8; + case GL_RGB565: return D3DFMT_R5G6B5; + case GL_RGB8_OES: return D3DFMT_X8R8G8B8; + case GL_DEPTH_COMPONENT16: + case GL_STENCIL_INDEX8: + case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8; + default: UNREACHABLE(); return D3DFMT_A8R8G8B8; + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples) +{ + if (samples <= 1) + return D3DMULTISAMPLE_NONE; + else + return (D3DMULTISAMPLE_TYPE)samples; +} + +} + +namespace dx2es +{ + +unsigned int GetStencilSize(D3DFORMAT stencilFormat) +{ + if (stencilFormat == D3DFMT_INTZ) + { + return 8; + } + switch(stencilFormat) + { + case D3DFMT_D24FS8: + case D3DFMT_D24S8: + return 8; + case D3DFMT_D24X4S4: + return 4; + case D3DFMT_D15S1: + return 1; + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D32: + case D3DFMT_D24X8: + case D3DFMT_D32F_LOCKABLE: + case D3DFMT_D16: + return 0; + //case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only + //case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only + default: + return 0; + } +} + +unsigned int GetAlphaSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 2; + case D3DFMT_A8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + return 1; + case D3DFMT_X8R8G8B8: + case D3DFMT_R5G6B5: + return 0; + default: + return 0; + } +} + +unsigned int GetRedSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + return 5; + default: + return 0; + } +} + +unsigned int GetGreenSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + return 5; + case D3DFMT_R5G6B5: + return 6; + default: + return 0; + } +} + +unsigned int GetBlueSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A16B16G16R16F: + return 16; + case D3DFMT_A32B32G32R32F: + return 32; + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + return 5; + default: + return 0; + } +} + +unsigned int GetDepthSize(D3DFORMAT depthFormat) +{ + if (depthFormat == D3DFMT_INTZ) + { + return 24; + } + switch (depthFormat) + { + case D3DFMT_D16_LOCKABLE: return 16; + case D3DFMT_D32: return 32; + case D3DFMT_D15S1: return 15; + case D3DFMT_D24S8: return 24; + case D3DFMT_D24X8: return 24; + case D3DFMT_D24X4S4: return 24; + case D3DFMT_D16: return 16; + case D3DFMT_D32F_LOCKABLE: return 32; + case D3DFMT_D24FS8: return 24; + //case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only + //case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only + default: return 0; + } +} + +GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type) +{ + if (type == D3DMULTISAMPLE_NONMASKABLE) + return 0; + else + return type; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + switch (d3dformat) + { + case D3DFMT_L8: + return (format == GL_LUMINANCE); + case D3DFMT_A8L8: + return (format == GL_LUMINANCE_ALPHA); + case D3DFMT_DXT1: + return (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + case D3DFMT_DXT3: + return (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + case D3DFMT_DXT5: + return (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + case D3DFMT_A8R8G8B8: + case D3DFMT_A16B16G16R16F: + case D3DFMT_A32B32G32R32F: + return (format == GL_RGBA || format == GL_BGRA_EXT); + case D3DFMT_X8R8G8B8: + return (format == GL_RGB); + default: + if (d3dformat == D3DFMT_INTZ && gl::IsDepthTexture(format)) + return true; + return false; + } +} + +bool ConvertReadBufferFormat(D3DFORMAT d3dformat, GLenum *format, GLenum *type) +{ + switch (d3dformat) + { + case D3DFMT_A8R8G8B8: + *type = GL_UNSIGNED_BYTE; + *format = GL_BGRA_EXT; + break; + case D3DFMT_X8R8G8B8: + *type = GL_UNSIGNED_BYTE; + *format = GL_RGB; + break; + case D3DFMT_R5G6B5: + *type = GL_UNSIGNED_SHORT_5_6_5; + *format = GL_RGB; + break; + case D3DFMT_A16B16G16R16F: + *type = GL_HALF_FLOAT_OES; + *format = GL_RGBA; + break; + case D3DFMT_A32B32G32R32F: + *type = GL_FLOAT; + *format = GL_RGBA; + break; + case D3DFMT_A4R4G4B4: + *type = GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT; + *format = GL_BGRA_EXT; + break; + case D3DFMT_A1R5G5B5: + *type = GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT; + *format = GL_BGRA_EXT; + break; + default: + *type = GL_NONE; + *format = GL_NONE; + return false; + } + return true; +} + +GLenum ConvertBackBufferFormat(D3DFORMAT format) +{ + switch (format) + { + case D3DFMT_A4R4G4B4: return GL_RGBA4; + case D3DFMT_A8R8G8B8: return GL_RGBA8_OES; + case D3DFMT_A1R5G5B5: return GL_RGB5_A1; + case D3DFMT_R5G6B5: return GL_RGB565; + case D3DFMT_X8R8G8B8: return GL_RGB8_OES; + default: + UNREACHABLE(); + } + + return GL_RGBA4; +} + +GLenum ConvertDepthStencilFormat(D3DFORMAT format) +{ + if (format == D3DFMT_INTZ) + { + return GL_DEPTH24_STENCIL8_OES; + } + switch (format) + { + case D3DFMT_D16: + case D3DFMT_D24X8: + return GL_DEPTH_COMPONENT16; + case D3DFMT_D24S8: + return GL_DEPTH24_STENCIL8_OES; + default: + UNREACHABLE(); + } + + return GL_DEPTH24_STENCIL8_OES; +} + +} + +namespace dx +{ + +bool IsCompressedFormat(D3DFORMAT surfaceFormat) +{ + switch(surfaceFormat) + { + case D3DFMT_DXT1: + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + return true; + default: + return false; + } +} + +size_t ComputeRowSize(D3DFORMAT format, unsigned int width) +{ + if (format == D3DFMT_INTZ) + { + return 4 * width; + } + switch (format) + { + case D3DFMT_L8: + return 1 * width; + case D3DFMT_A8L8: + return 2 * width; + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + return 4 * width; + case D3DFMT_A16B16G16R16F: + return 8 * width; + case D3DFMT_A32B32G32R32F: + return 16 * width; + case D3DFMT_DXT1: + return 8 * ((width + 3) / 4); + case D3DFMT_DXT3: + case D3DFMT_DXT5: + return 16 * ((width + 3) / 4); + default: + UNREACHABLE(); + return 0; + } +} + +} + +std::string getTempPath() +{ + char path[MAX_PATH]; + DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path); + if (pathLen == 0) + { + UNREACHABLE(); + return std::string(); + } + + UINT unique = GetTempFileNameA(path, "sh", 0, path); + if (unique == 0) + { + UNREACHABLE(); + return std::string(); + } + + return path; +} + +void writeFile(const char* path, const void* content, size_t size) +{ + FILE* file = fopen(path, "w"); + if (!file) + { + UNREACHABLE(); + return; + } + + fwrite(content, sizeof(char), size, file); + fclose(file); +} diff --git a/src/3rdparty/angle/src/libGLESv2/utilities.h b/src/3rdparty/angle/src/libGLESv2/utilities.h new file mode 100644 index 0000000000..29ad207313 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/utilities.h @@ -0,0 +1,121 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// utilities.h: Conversion functions and other utility routines. + +#ifndef LIBGLESV2_UTILITIES_H +#define LIBGLESV2_UTILITIES_H + +#define GL_APICALL +#include +#include +#include + +#include + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))); + +namespace gl +{ + +struct Color; + +int UniformExternalComponentCount(GLenum type); +int UniformInternalComponentCount(GLenum type); +GLenum UniformComponentType(GLenum type); +size_t UniformInternalSize(GLenum type); +size_t UniformExternalSize(GLenum type); +int VariableRowCount(GLenum type); +int VariableColumnCount(GLenum type); + +int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize); + +int ComputePixelSize(GLint internalformat); +GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment); +GLsizei ComputeCompressedPitch(GLsizei width, GLenum format); +GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format); +bool IsCompressed(GLenum format); +bool IsDepthTexture(GLenum format); +bool IsStencilTexture(GLenum format); +bool IsCubemapTextureTarget(GLenum target); +bool IsInternalTextureTarget(GLenum target); +GLint ConvertSizedInternalFormat(GLenum format, GLenum type); +GLenum ExtractFormat(GLenum internalformat); +GLenum ExtractType(GLenum internalformat); + +bool IsColorRenderable(GLenum internalformat); +bool IsDepthRenderable(GLenum internalformat); +bool IsStencilRenderable(GLenum internalformat); + +bool IsFloat32Format(GLint internalformat); +bool IsFloat16Format(GLint internalformat); +} + +namespace es2dx +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison); +D3DCOLOR ConvertColor(gl::Color color); +D3DBLEND ConvertBlendFunc(GLenum blend); +D3DBLENDOP ConvertBlendOp(GLenum blendOp); +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp); +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap); +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace); +D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace); +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha); +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy); +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy); +bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount, + D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount); +D3DFORMAT ConvertRenderbufferFormat(GLenum format); +D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples); + +} + +namespace dx2es +{ + +GLuint GetAlphaSize(D3DFORMAT colorFormat); +GLuint GetRedSize(D3DFORMAT colorFormat); +GLuint GetGreenSize(D3DFORMAT colorFormat); +GLuint GetBlueSize(D3DFORMAT colorFormat); +GLuint GetDepthSize(D3DFORMAT depthFormat); +GLuint GetStencilSize(D3DFORMAT stencilFormat); + +GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type); + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); +bool ConvertReadBufferFormat(D3DFORMAT d3dformat, GLenum *format, GLenum *type); +GLenum ConvertBackBufferFormat(D3DFORMAT format); +GLenum ConvertDepthStencilFormat(D3DFORMAT format); + +} + +namespace dx +{ +bool IsCompressedFormat(D3DFORMAT format); +size_t ComputeRowSize(D3DFORMAT format, unsigned int width); +} + +std::string getTempPath(); +void writeFile(const char* path, const void* data, size_t size); + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case D3DERR_DRIVERINTERNALERROR: + case D3DERR_DEVICELOST: + case D3DERR_DEVICEHUNG: + case D3DERR_DEVICEREMOVED: + return true; + default: + return false; + } +}; + +#endif // LIBGLESV2_UTILITIES_H diff --git a/src/3rdparty/angle/src/libGLESv2/vertexconversion.h b/src/3rdparty/angle/src/libGLESv2/vertexconversion.h new file mode 100644 index 0000000000..5bb8b8995e --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/vertexconversion.h @@ -0,0 +1,208 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// vertexconversion.h: A library of vertex conversion classes that can be used to build +// the FormatConverter objects used by the buffer conversion system. + +#ifndef LIBGLESV2_VERTEXCONVERSION_H_ +#define LIBGLESV2_VERTEXCONVERSION_H_ + +#include +#include + +#include "libGLESv2/Context.h" // Defines Index + +namespace gl +{ + +// Conversion types: +// static const bool identity: true if this is an identity transform, false otherwise +// static U convert(T): convert a single element from the input type to the output type +// typedef ... OutputType: the type produced by this conversion + +template +struct Identity +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) + { + return x; + } +}; + +template +struct Cast +{ + static const bool identity = false; + + typedef ToT OutputType; + + static ToT convert(FromT x) + { + return static_cast(x); + } +}; + +template +struct Cast +{ + static const bool identity = true; + + typedef T OutputType; + + static T convert(T x) + { + return static_cast(x); + } +}; + +template +struct Normalize +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(T x) + { + typedef std::numeric_limits NL; + float f = static_cast(x); + + if (NL::is_signed) + { + // const float => VC2008 computes it at compile time + // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that. + const float divisor = 1.0f/(2*static_cast(NL::max())+1); + return (2*f+1)*divisor; + } + else + { + return f/NL::max(); + } + } +}; + +template +struct FixedToFloat +{ + static const bool identity = false; + + typedef float OutputType; + + static float convert(FromType x) + { + const float divisor = 1.0f / static_cast(static_cast(1) << ScaleBits); + return static_cast(x) * divisor; + } +}; + +// Widen types: +// static const unsigned int initialWidth: number of components before conversion +// static const unsigned int finalWidth: number of components after conversion + +// Float is supported at any size. +template +struct NoWiden +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N; +}; + +// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components +template +struct WidenToEven +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = N+(N&1); +}; + +template +struct WidenToFour +{ + static const std::size_t initialWidth = N; + static const std::size_t finalWidth = 4; +}; + +// Most types have 0 and 1 that are just that. +template +struct SimpleDefaultValues +{ + static T zero() { return static_cast(0); } + static T one() { return static_cast(1); } +}; + +// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value. +template +struct NormalizedDefaultValues +{ + static T zero() { return static_cast(0); } + static T one() { return std::numeric_limits::max(); } +}; + +// Converter: +// static const bool identity: true if this is an identity transform (with no widening) +// static const std::size_t finalSize: number of bytes per output vertex +// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided. + +template > +struct VertexDataConverter +{ + typedef typename Converter::OutputType OutputType; + typedef InT InputType; + + static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity; + static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType); + + static void convertArray(const InputType *in, std::size_t stride, std::size_t n, OutputType *out) + { + for (std::size_t i = 0; i < n; i++) + { + const InputType *ein = pointerAddBytes(in, i * stride); + + copyComponent(out, ein, 0, static_cast(DefaultValueRule::zero())); + copyComponent(out, ein, 1, static_cast(DefaultValueRule::zero())); + copyComponent(out, ein, 2, static_cast(DefaultValueRule::zero())); + copyComponent(out, ein, 3, static_cast(DefaultValueRule::one())); + + out += WidenRule::finalWidth; + } + } + + static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out) + { + return convertArray(static_cast(in), stride, n, static_cast(out)); + } + + private: + // Advance the given pointer by a number of bytes (not pointed-to elements). + template + static T *pointerAddBytes(T *basePtr, std::size_t numBytes) + { + return reinterpret_cast(reinterpret_cast(basePtr) + numBytes); + } + + static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue) + { + if (WidenRule::finalWidth > elementindex) + { + if (WidenRule::initialWidth > elementindex) + { + out[elementindex] = Converter::convert(in[elementindex]); + } + else + { + out[elementindex] = defaultvalue; + } + } + } +}; + +} + +#endif // LIBGLESV2_VERTEXCONVERSION_H_ diff --git a/src/angle/README.qt b/src/angle/README.qt new file mode 100644 index 0000000000..61023efcd1 --- /dev/null +++ b/src/angle/README.qt @@ -0,0 +1,29 @@ +This is the ANGLE project from: + +http://code.google.com/p/angleproject/ + +The upstream version used here can be found in: + +src/common/version.h + +This copy of the library has been modified with several patches +that can be found in the 'patches' subdirectory. + +Updating ANGLE +------------------------------------------------------------- +To update to a newer version of ANGLE, extract the archive +directly into the 'src/3rdparty/angle' directory. ANGLE contains +a .gitignore file that will overwrite the one in Qt, but this is +not desirable so the ANGLE one should be discarded and the one in +Qt should be kept. If there are new source/header files in ANGLE +(git status -u) then they should be added to the relevant .pro +file before committing. + + +Using a custom ANGLE +------------------------------------------------------------- +Qt supports building a version of ANGLE other than the one that +is contained in the source tree. To get Qt to build a different +copy of ANGLE, you can set the ANGLE_DIR environment variable +to point to the location of the custom ANGLE before building Qt. + diff --git a/src/angle/angle.pro b/src/angle/angle.pro new file mode 100644 index 0000000000..00e0501d60 --- /dev/null +++ b/src/angle/angle.pro @@ -0,0 +1,19 @@ +TEMPLATE = subdirs +SUBDIRS += src + +# We need to call syncqt manually instead of using "load(qt_module_headers)" for several reasons: +# 1) qt_module_headers assumes the TARGET is the same as the include directory (eg: libGLESv2 != GLES2) +# 2) If we made a 'QtANGLE' module, the include directory would be flattened which won't work since +# we need to support "#include " +!build_pass { + qtPrepareTool(QMAKE_SYNCQT, syncqt) + QTDIR = $$[QT_HOST_PREFIX] + exists($$QTDIR/.qmake.cache): \ + mod_component_base = $$QTDIR + else: \ + mod_component_base = $$dirname(_QMAKE_CACHE_) + QMAKE_SYNCQT += -minimal -module KHR -module EGL -module GLES2 \ + -mkspecsdir $$[QT_HOST_DATA/get]/mkspecs -outdir $$mod_component_base $$dirname(_QMAKE_CONF_) + !silent:message($$QMAKE_SYNCQT) + system($$QMAKE_SYNCQT)|error("Failed to run: $$QMAKE_SYNCQT") +} diff --git a/src/angle/patches/0003-Fix-Float16ToFloat32.py.patch b/src/angle/patches/0003-Fix-Float16ToFloat32.py.patch new file mode 100644 index 0000000000..c37ab43fb9 --- /dev/null +++ b/src/angle/patches/0003-Fix-Float16ToFloat32.py.patch @@ -0,0 +1,54 @@ +From e4f894847ebefe54f9a9f9911c38dc3efe77c260 Mon Sep 17 00:00:00 2001 +From: Jason Barron +Date: Tue, 16 Oct 2012 10:34:32 +0200 +Subject: [PATCH 3/3] Fix Float16ToFloat32.py. + +To ensure generation of compilable code, the script should +be using the alternate form of the hex string formatter to +be sure it gets prefixed by '0x'. + +Also remove an extra '=' character. + +This issue has been reported upstream to the ANGLE team: + + http://code.google.com/p/angleproject/issues/detail?id=376 + +Change-Id: I8ccf017afcfbd2c2f52ed291b89f29ba597c9c41 +--- + src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py +index ae646ff..fb2964e 100644 +--- a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py ++++ b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py +@@ -56,22 +56,22 @@ namespace gl + + print "const static unsigned g_mantissa[2048] = {" + for i in range(0, 2048): +- print " %08x," % convertMantissa(i) ++ print " %#10x," % convertMantissa(i) + print "};\n" + + print "const static unsigned g_exponent[64] = {" + for i in range(0, 64): +- print " %08x," % convertExponent(i) ++ print " %#10x," % convertExponent(i) + print "};\n" + + print "const static unsigned g_offset[64] = {" + for i in range(0, 64): +- print " %08x," % convertOffset(i) ++ print " %#10x," % convertOffset(i) + print "};\n" + + print """float float16ToFloat32(unsigned short h) + { +- unsigned i32 = =g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; ++ unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return *(float*) &i32; + } + } +-- +1.7.11.msysgit.1 + diff --git a/src/angle/src/common/common.pri b/src/angle/src/common/common.pri new file mode 100644 index 0000000000..e99080d19f --- /dev/null +++ b/src/angle/src/common/common.pri @@ -0,0 +1,53 @@ +include (../config.pri) + +INCLUDEPATH += \ + $$ANGLE_DIR/src \ + $$ANGLE_DIR/include + +LIBS = $$QMAKE_LIBS_CORE $$QMAKE_LIBS_GUI + +# DirectX is included in the Windows 8 Kit, but everything else requires the DX SDK. +win32-msvc2012 { + FXC = fxc.exe +} else { + DX_DIR = $$(DXSDK_DIR) + isEmpty(DX_DIR) { + error("Cannot determine DirectX SDK location. Please set DXSDK_DIR environment variable.") + } + + DXINC_DIR = $$quote($${DX_DIR}Include) + contains(QT_ARCH, x86_64) { + DXLIB_DIR = $$quote($${DX_DIR}Lib\\x64) + } else { + DXLIB_DIR = $$quote($${DX_DIR}Lib\\x86) + } + + FXC = "\"$${DX_DIR}Utilities\\bin\\x86\\fxc.exe\"" + + msvc { + # Unfortunately MinGW cannot use the DirectX headers from the DX SDK because d3d11shader.h uses + # buffer annotation macros (eg: __out, __in) which are not defined in the MinGW copy of + # specstrings_strict.h + INCLUDEPATH += $$DXINC_DIR + + # Similarly we want the MinGW linker to use the import libraries shipped with the compiler + # instead of those from the SDK which cause a crash on startup. + LIBS += -L$$DXLIB_DIR + } +} + +# Use the DEF files in release mode +msvc:CONFIG(release, debug|release) { + QMAKE_LFLAGS += /DEF:$$ANGLE_DIR/src/$${TARGET}/$${TARGET}.def +} + +HEADERS += \ + $$ANGLE_DIR/src/common/angleutils.h \ + $$ANGLE_DIR/src/common/debug.h \ + $$ANGLE_DIR/src/common/RefCountObject.h \ + $$ANGLE_DIR/src/common/version.h + +SOURCES += \ + $$ANGLE_DIR/src/common/debug.cpp \ + $$ANGLE_DIR/src/common/RefCountObject.cpp + diff --git a/src/angle/src/compiler/compiler.pro b/src/angle/src/compiler/compiler.pro new file mode 100644 index 0000000000..26b03bfc86 --- /dev/null +++ b/src/angle/src/compiler/compiler.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = preprocessor translator_common.pro translator_hlsl.pro diff --git a/src/angle/src/compiler/preprocessor/preprocessor.pro b/src/angle/src/compiler/preprocessor/preprocessor.pro new file mode 100644 index 0000000000..12f83d5281 --- /dev/null +++ b/src/angle/src/compiler/preprocessor/preprocessor.pro @@ -0,0 +1,58 @@ +TEMPLATE = lib +CONFIG += static +TARGET = preprocessor + +include(../../config.pri) + +INCLUDEPATH = $$ANGLE_DIR/src/compiler/preprocessor/new + +DEFINES += _SECURE_SCL=0 + + +FLEX_SOURCES = \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Tokenizer.l + +BISON_SOURCES = \ + $$ANGLE_DIR/src/compiler/preprocessor/new/ExpressionParser.y + +HEADERS += \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Diagnostics.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/DirectiveHandler.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/DirectiveParser.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/ExpressionParser.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Input.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Lexer.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Macro.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/MacroExpander.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/numeric_lex.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/pp_utils.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Preprocessor.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/SourceLocation.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Token.h \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Tokenizer.h + +SOURCES += \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Diagnostics.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/DirectiveHandler.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/DirectiveParser.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Input.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Lexer.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Macro.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/MacroExpander.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Preprocessor.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/new/Token.cpp + +# NOTE: 'win_flex' and 'bison' can be found in qt5/gnuwin32/bin +flex.commands = $$addGnuPath(win_flex) --noline --nounistd --outfile=${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_NAME} +flex.output = ${QMAKE_FILE_BASE}.cpp +flex.input = FLEX_SOURCES +flex.dependency_type = TYPE_C +flex.variable_out = GENERATED_SOURCES +QMAKE_EXTRA_COMPILERS += flex + +bison.commands = $$addGnuPath(bison) --no-lines --skeleton=yacc.c --output=${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_NAME} +bison.output = ${QMAKE_FILE_BASE}.cpp +bison.input = BISON_SOURCES +bison.dependency_type = TYPE_C +bison.variable_out = GENERATED_SOURCES +QMAKE_EXTRA_COMPILERS += bison diff --git a/src/angle/src/compiler/translator_common.pro b/src/angle/src/compiler/translator_common.pro new file mode 100644 index 0000000000..f7f5a8cb6e --- /dev/null +++ b/src/angle/src/compiler/translator_common.pro @@ -0,0 +1,137 @@ +TEMPLATE = lib +CONFIG += static +TARGET = translator_common + +include(../config.pri) + +INCLUDEPATH += \ + $$ANGLE_DIR/src \ + $$ANGLE_DIR/include + +DEFINES += _SECURE_SCL=0 _LIB COMPILER_IMPLEMENTATION + +FLEX_SOURCES = $$ANGLE_DIR/src/compiler/glslang.l +BISON_SOURCES = $$ANGLE_DIR/src/compiler/glslang.y + +HEADERS += \ + $$ANGLE_DIR/src/compiler/BaseTypes.h \ + $$ANGLE_DIR/src/compiler/BuiltInFunctionEmulator.h \ + $$ANGLE_DIR/src/compiler/Common.h \ + $$ANGLE_DIR/src/compiler/ConstantUnion.h \ + $$ANGLE_DIR/src/compiler/debug.h \ + $$ANGLE_DIR/src/compiler/DetectRecursion.h \ + $$ANGLE_DIR/src/compiler/Diagnostics.h \ + $$ANGLE_DIR/src/compiler/DirectiveHandler.h \ + $$ANGLE_DIR/src/compiler/ForLoopUnroll.h \ + $$ANGLE_DIR/src/compiler/InfoSink.h \ + $$ANGLE_DIR/src/compiler/Initialize.h \ + $$ANGLE_DIR/src/compiler/InitializeDll.h \ + $$ANGLE_DIR/src/compiler/InitializeGlobals.h \ + $$ANGLE_DIR/src/compiler/InitializeParseContext.h \ + $$ANGLE_DIR/src/compiler/intermediate.h \ + $$ANGLE_DIR/src/compiler/localintermediate.h \ + $$ANGLE_DIR/src/compiler/MapLongVariableNames.h \ + $$ANGLE_DIR/src/compiler/MMap.h \ + $$ANGLE_DIR/src/compiler/osinclude.h \ + $$ANGLE_DIR/src/compiler/ParseHelper.h \ + $$ANGLE_DIR/src/compiler/PoolAlloc.h \ + $$ANGLE_DIR/src/compiler/QualifierAlive.h \ + $$ANGLE_DIR/src/compiler/RemoveTree.h \ + $$ANGLE_DIR/src/compiler/RenameFunction.h \ + $$ANGLE_DIR/include/GLSLANG/ResourceLimits.h \ + $$ANGLE_DIR/include/GLSLANG/ShaderLang.h \ + $$ANGLE_DIR/src/compiler/ShHandle.h \ + $$ANGLE_DIR/src/compiler/SymbolTable.h \ + $$ANGLE_DIR/src/compiler/Types.h \ + $$ANGLE_DIR/src/compiler/UnfoldShortCircuit.h \ + $$ANGLE_DIR/src/compiler/util.h \ + $$ANGLE_DIR/src/compiler/ValidateLimitations.h \ + $$ANGLE_DIR/src/compiler/VariableInfo.h \ + $$ANGLE_DIR/src/compiler/VariablePacker.h \ + $$ANGLE_DIR/src/compiler/preprocessor/atom.h \ + $$ANGLE_DIR/src/compiler/preprocessor/compile.h \ + $$ANGLE_DIR/src/compiler/preprocessor/cpp.h \ + $$ANGLE_DIR/src/compiler/preprocessor/length_limits.h \ + $$ANGLE_DIR/src/compiler/preprocessor/memory.h \ + $$ANGLE_DIR/src/compiler/preprocessor/parser.h \ + $$ANGLE_DIR/src/compiler/preprocessor/preprocess.h \ + $$ANGLE_DIR/src/compiler/preprocessor/scanner.h \ + $$ANGLE_DIR/src/compiler/preprocessor/slglobals.h \ + $$ANGLE_DIR/src/compiler/preprocessor/symbols.h \ + $$ANGLE_DIR/src/compiler/preprocessor/tokens.h \ + $$ANGLE_DIR/src/compiler/timing/RestrictFragmentShaderTiming.h \ + $$ANGLE_DIR/src/compiler/timing/RestrictVertexShaderTiming.h \ + $$ANGLE_DIR/src/compiler/depgraph/DependencyGraph.h \ + $$ANGLE_DIR/src/compiler/depgraph/DependencyGraphBuilder.h \ + $$ANGLE_DIR/src/compiler/depgraph/DependencyGraphOutput.h + +SOURCES += \ + $$ANGLE_DIR/src/compiler/BuiltInFunctionEmulator.cpp \ + $$ANGLE_DIR/src/compiler/Compiler.cpp \ + $$ANGLE_DIR/src/compiler/debug.cpp \ + $$ANGLE_DIR/src/compiler/DetectRecursion.cpp \ + $$ANGLE_DIR/src/compiler/Diagnostics.cpp \ + $$ANGLE_DIR/src/compiler/DirectiveHandler.cpp \ + $$ANGLE_DIR/src/compiler/ForLoopUnroll.cpp \ + $$ANGLE_DIR/src/compiler/InfoSink.cpp \ + $$ANGLE_DIR/src/compiler/Initialize.cpp \ + $$ANGLE_DIR/src/compiler/InitializeDll.cpp \ + $$ANGLE_DIR/src/compiler/InitializeParseContext.cpp \ + $$ANGLE_DIR/src/compiler/Intermediate.cpp \ + $$ANGLE_DIR/src/compiler/intermOut.cpp \ + $$ANGLE_DIR/src/compiler/IntermTraverse.cpp \ + $$ANGLE_DIR/src/compiler/MapLongVariableNames.cpp \ + $$ANGLE_DIR/src/compiler/ossource_win.cpp \ + $$ANGLE_DIR/src/compiler/parseConst.cpp \ + $$ANGLE_DIR/src/compiler/ParseHelper.cpp \ + $$ANGLE_DIR/src/compiler/PoolAlloc.cpp \ + $$ANGLE_DIR/src/compiler/QualifierAlive.cpp \ + $$ANGLE_DIR/src/compiler/RemoveTree.cpp \ + $$ANGLE_DIR/src/compiler/ShaderLang.cpp \ + $$ANGLE_DIR/src/compiler/SymbolTable.cpp \ + $$ANGLE_DIR/src/compiler/util.cpp \ + $$ANGLE_DIR/src/compiler/ValidateLimitations.cpp \ + $$ANGLE_DIR/src/compiler/VariableInfo.cpp \ + $$ANGLE_DIR/src/compiler/VariablePacker.cpp \ + $$ANGLE_DIR/src/compiler/preprocessor/atom.c \ + $$ANGLE_DIR/src/compiler/preprocessor/cpp.c \ + $$ANGLE_DIR/src/compiler/preprocessor/cppstruct.c \ + $$ANGLE_DIR/src/compiler/preprocessor/memory.c \ + $$ANGLE_DIR/src/compiler/preprocessor/scanner.c \ + $$ANGLE_DIR/src/compiler/preprocessor/symbols.c \ + $$ANGLE_DIR/src/compiler/preprocessor/tokens.c \ + $$ANGLE_DIR/src/compiler/depgraph/DependencyGraph.cpp \ + $$ANGLE_DIR/src/compiler/depgraph/DependencyGraphBuilder.cpp \ + $$ANGLE_DIR/src/compiler/depgraph/DependencyGraphOutput.cpp \ + $$ANGLE_DIR/src/compiler/depgraph/DependencyGraphTraverse.cpp \ + $$ANGLE_DIR/src/compiler/timing/RestrictFragmentShaderTiming.cpp \ + $$ANGLE_DIR/src/compiler/timing/RestrictVertexShaderTiming.cpp + +# NOTE: 'win_flex' and 'bison' can be found in qt5/gnuwin32/bin +flex.commands = $$addGnuPath(win_flex) --noline --nounistd --outfile=${QMAKE_FILE_BASE}_lex.cpp ${QMAKE_FILE_NAME} +flex.output = ${QMAKE_FILE_BASE}_lex.cpp +flex.input = FLEX_SOURCES +flex.dependency_type = TYPE_C +flex.variable_out = GENERATED_SOURCES +QMAKE_EXTRA_COMPILERS += flex + +bison.commands = $$addGnuPath(bison) --no-lines --skeleton=yacc.c --defines=${QMAKE_FILE_BASE}_tab.h \ + --output=${QMAKE_FILE_BASE}_tab.cpp ${QMAKE_FILE_NAME} +bison.output = ${QMAKE_FILE_BASE}_tab.h +bison.input = BISON_SOURCES +bison.dependency_type = TYPE_C +bison.variable_out = GENERATED_SOURCES +QMAKE_EXTRA_COMPILERS += bison + +# This is a dummy compiler to work around the fact that an extra compiler can only +# have one output file even if the command generates two. +MAKEFILE_NOOP_COMMAND = @echo -n +msvc: MAKEFILE_NOOP_COMMAND = @echo >NUL +bison_impl.output = ${QMAKE_FILE_BASE}_tab.cpp +bison_impl.input = BISON_SOURCES +bison_impl.commands = $$MAKEFILE_NOOP_COMMAND +bison_impl.depends = ${QMAKE_FILE_BASE}_tab.h +bison_impl.output = ${QMAKE_FILE_BASE}_tab.cpp +bison_impl.variable_out = GENERATED_SOURCES +QMAKE_EXTRA_COMPILERS += bison_impl + diff --git a/src/angle/src/compiler/translator_hlsl.pro b/src/angle/src/compiler/translator_hlsl.pro new file mode 100644 index 0000000000..e4afaec5c5 --- /dev/null +++ b/src/angle/src/compiler/translator_hlsl.pro @@ -0,0 +1,25 @@ +TEMPLATE = lib +CONFIG += static +TARGET = translator_hlsl + +include(../config.pri) + +INCLUDEPATH += $$ANGLE_DIR/src \ + $$ANGLE_DIR/include + +DEFINES += COMPILER_IMPLEMENTATION + +HEADERS += \ + $$ANGLE_DIR/src/compiler/DetectDiscontinuity.h \ + $$ANGLE_DIR/src/compiler/OutputHLSL.h \ + $$ANGLE_DIR/src/compiler/SearchSymbol.h \ + $$ANGLE_DIR/src/compiler/TranslatorHLSL.h \ + $$ANGLE_DIR/src/compiler/UnfoldShortCircuit.h + +SOURCES += \ + $$ANGLE_DIR/src/compiler/CodeGenHLSL.cpp \ + $$ANGLE_DIR/src/compiler/DetectDiscontinuity.cpp \ + $$ANGLE_DIR/src/compiler/OutputHLSL.cpp \ + $$ANGLE_DIR/src/compiler/SearchSymbol.cpp \ + $$ANGLE_DIR/src/compiler/TranslatorHLSL.cpp \ + $$ANGLE_DIR/src/compiler/UnfoldShortCircuit.cpp diff --git a/src/angle/src/config.pri b/src/angle/src/config.pri new file mode 100644 index 0000000000..3770d6ef09 --- /dev/null +++ b/src/angle/src/config.pri @@ -0,0 +1,103 @@ +# This file contains build options that are relevant for both the compilers +# and the khronos implementation libraries. + +ANGLE_DIR = $$(ANGLE_DIR) +isEmpty(ANGLE_DIR) { + ANGLE_DIR = $$PWD/../../3rdparty/angle +} else { + !build_pass:message("Using external ANGLE from $$ANGLE_DIR") +} + +!exists($$ANGLE_DIR/src) { + error("$$ANGLE_DIR does not contain ANGLE") +} + +win32 { + GNUTOOLS_DIR=$$[QT_HOST_DATA]/../gnuwin32/bin + exists($$GNUTOOLS_DIR/gperf.exe) { + GNUTOOLS = "(set $$escape_expand(\\\")PATH=$$replace(GNUTOOLS_DIR, [/\\\\], $${QMAKE_DIR_SEP});%PATH%$$escape_expand(\\\"))" + } +} + +defineReplace(addGnuPath) { + unset(gnuPath) + gnuPath = $$1 + !isEmpty(gnuPath):!isEmpty(GNUTOOLS) { + eval(gnuPath = $${GNUTOOLS} && $$gnuPath) + silent: eval(gnuPath = @echo generating sources from ${QMAKE_FILE_IN} && $$val_escape($$gnuPath)) + } + return($$gnuPath) +} + +# Defines for modifying Win32 headers +DEFINES += _WINDOWS \ + _UNICODE \ + _CRT_SECURE_NO_DEPRECATE \ + _HAS_EXCEPTIONS=0 \ + NOMINMAX \ + WIN32_LEAN_AND_MEAN=1 + +# Defines specifying the API version (0x0600 = Vista) +DEFINES += _WIN32_WINNT=0x0600 WINVER=0x0600 + +# ANGLE specific defines +DEFINES += ANGLE_DISABLE_TRACE \ + ANGLE_DISABLE_PERF \ + ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0 \ + ANGLE_USE_NEW_PREPROCESSOR=1 + +# Force release builds for now. Debug builds of ANGLE will generate libraries with +# the 'd' library suffix, but this means that the library name no longer matches that +# listed in the DEF file which causes errors at runtime. Using the DEF is mandatory +# to generate the import library because the symbols are not marked with __declspec +# and therefore not exported by default. With the import library, the debug build is +# useless, so just disable until we can find another solution. +CONFIG -= debug +CONFIG += release + +TARGET = $$qtLibraryTarget($$TARGET) + +CONFIG(debug, debug|release) { + DEFINES += _DEBUG +} else { + DEFINES += NDEBUG +} + +# c++11 is needed by MinGW to get support for unordered_map. +CONFIG -= qt +CONFIG += stl rtti_off exceptions c++11 + +INCLUDEPATH += . .. $$PWD/../include + +DESTDIR = $$QT_BUILD_TREE/lib +DLLDESTDIR = $$QT_BUILD_TREE/bin + +msvc { + # Disabled Warnings: + # 4100: 'identifier' : unreferenced formal parameter + # 4127: conditional expression is constant + # 4189: 'identifier' : local variable is initialized but not referenced + # 4239: nonstandard extension used : 'token' : conversion from 'type' to 'type' + # 4244: 'argument' : conversion from 'type1' to 'type2', possible loss of data + # 4245: 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch + # 4512: 'class' : assignment operator could not be generated + # 4702: unreachable code + QMAKE_CFLAGS_WARN_ON = -W4 -wd"4100" -wd"4127" -wd"4189" -wd"4239" -wd"4244" -wd"4245" -wd"4512" -wd"4702" + QMAKE_CFLAGS_RELEASE = -O2 -Oy- -MT -Gy -GS -Gm- + QMAKE_CFLAGS_DEBUG = -Od -Oy- -MTd -Gy -GS -Gm- -RTC1 + QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = -Zi $$QMAKE_CFLAGS_RELEASE + + QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON +} + +gcc { + QMAKE_CFLAGS_WARN_ON = -Wall -Wno-unknown-pragmas -Wno-comment -Wno-missing-field-initializers \ + -Wno-switch -Wno-unused-parameter -Wno-write-strings -Wno-sign-compare -Wno-missing-braces \ + -Wno-unused-but-set-variable -Wno-unused-variable -Wno-narrowing -Wno-maybe-uninitialized \ + -Wno-strict-aliasing -Wno-type-limits + + QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON -Wno-reorder -Wno-conversion-null -Wno-delete-non-virtual-dtor +} + +QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE diff --git a/src/angle/src/libEGL/libEGL.pro b/src/angle/src/libEGL/libEGL.pro new file mode 100644 index 0000000000..b7182b7fee --- /dev/null +++ b/src/angle/src/libEGL/libEGL.pro @@ -0,0 +1,31 @@ +TEMPLATE = lib +TARGET = libEGL + +include(../common/common.pri) + +LIBS += -ld3d9 -ldxguid -ldwmapi \ + -L$$[QT_INSTALL_LIBS] -llibGLESv2 + +HEADERS += \ + $$ANGLE_DIR/src/libEGL/Config.h \ + $$ANGLE_DIR/src/libEGL/Display.h \ + $$ANGLE_DIR/src/libEGL/main.h \ + $$ANGLE_DIR/src/libEGL/resource.h \ + $$ANGLE_DIR/src/libEGL/ShaderCache.h \ + $$ANGLE_DIR/src/libEGL/Surface.h + +SOURCES += \ + $$ANGLE_DIR/src/libEGL/Config.cpp \ + $$ANGLE_DIR/src/libEGL/Display.cpp \ + $$ANGLE_DIR/src/libEGL/libEGL.cpp \ + $$ANGLE_DIR/src/libEGL/main.cpp \ + $$ANGLE_DIR/src/libEGL/Surface.cpp + +load(qt_installs) + +egl_headers.files = \ + $$ANGLE_DIR/include/EGL/egl.h \ + $$ANGLE_DIR/include/EGL/eglext.h \ + $$ANGLE_DIR/include/EGL/eglplatform.h +egl_headers.path = $$[QT_INSTALL_HEADERS]/EGL +INSTALLS += egl_headers diff --git a/src/angle/src/libGLESv2/libGLESv2.pro b/src/angle/src/libGLESv2/libGLESv2.pro new file mode 100644 index 0000000000..a4e83ea10d --- /dev/null +++ b/src/angle/src/libGLESv2/libGLESv2.pro @@ -0,0 +1,107 @@ +TEMPLATE = lib +TARGET = libGLESv2 +DEPENDPATH += . shaders + +include(../common/common.pri) + +INCLUDEPATH += $$OUT_PWD/.. + +LIBS += -ld3d9 -ld3dcompiler +STATICLIBS = translator_common translator_hlsl preprocessor + +for(libname, STATICLIBS) { + # Appends 'd' to the library for debug builds and builds up the fully + # qualified path to pass to the linker. + staticlib = $$QT_BUILD_TREE/lib/$${QMAKE_PREFIX_STATICLIB}$$qtLibraryTarget($$libname).$${QMAKE_EXTENSION_STATICLIB} + LIBS += $$staticlib + PRE_TARGETDEPS += $$staticlib +} + +HEADERS += \ + $$ANGLE_DIR/src/libGLESv2/BinaryStream.h \ + $$ANGLE_DIR/src/libGLESv2/Blit.h \ + $$ANGLE_DIR/src/libGLESv2/Buffer.h \ + $$ANGLE_DIR/src/libGLESv2/Context.h \ + $$ANGLE_DIR/src/libGLESv2/D3DConstantTable.h \ + $$ANGLE_DIR/src/libGLESv2/Fence.h \ + $$ANGLE_DIR/src/libGLESv2/Framebuffer.h \ + $$ANGLE_DIR/src/libGLESv2/HandleAllocator.h \ + $$ANGLE_DIR/src/libGLESv2/IndexDataManager.h \ + $$ANGLE_DIR/src/libGLESv2/main.h \ + $$ANGLE_DIR/src/libGLESv2/mathutil.h \ + $$ANGLE_DIR/src/libGLESv2/Program.h \ + $$ANGLE_DIR/src/libGLESv2/ProgramBinary.h \ + $$ANGLE_DIR/src/libGLESv2/Query.h \ + $$ANGLE_DIR/src/libGLESv2/Renderbuffer.h \ + $$ANGLE_DIR/src/libGLESv2/resource.h \ + $$ANGLE_DIR/src/libGLESv2/ResourceManager.h \ + $$ANGLE_DIR/src/libGLESv2/Shader.h \ + $$ANGLE_DIR/src/libGLESv2/Texture.h \ + $$ANGLE_DIR/src/libGLESv2/utilities.h \ + $$ANGLE_DIR/src/libGLESv2/vertexconversion.h \ + $$ANGLE_DIR/src/libGLESv2/VertexDataManager.h + +SOURCES += \ + $$ANGLE_DIR/src/libGLESv2/Blit.cpp \ + $$ANGLE_DIR/src/libGLESv2/Buffer.cpp \ + $$ANGLE_DIR/src/libGLESv2/Context.cpp \ + $$ANGLE_DIR/src/libGLESv2/D3DConstantTable.cpp \ + $$ANGLE_DIR/src/libGLESv2/Fence.cpp \ + $$ANGLE_DIR/src/libGLESv2/Framebuffer.cpp \ + $$ANGLE_DIR/src/libGLESv2/Float16ToFloat32.cpp \ + $$ANGLE_DIR/src/libGLESv2/HandleAllocator.cpp \ + $$ANGLE_DIR/src/libGLESv2/IndexDataManager.cpp \ + $$ANGLE_DIR/src/libGLESv2/libGLESv2.cpp \ + $$ANGLE_DIR/src/libGLESv2/main.cpp \ + $$ANGLE_DIR/src/libGLESv2/Program.cpp \ + $$ANGLE_DIR/src/libGLESv2/ProgramBinary.cpp \ + $$ANGLE_DIR/src/libGLESv2/Query.cpp \ + $$ANGLE_DIR/src/libGLESv2/Renderbuffer.cpp \ + $$ANGLE_DIR/src/libGLESv2/ResourceManager.cpp \ + $$ANGLE_DIR/src/libGLESv2/Shader.cpp \ + $$ANGLE_DIR/src/libGLESv2/Texture.cpp \ + $$ANGLE_DIR/src/libGLESv2/TextureSSE2.cpp \ + $$ANGLE_DIR/src/libGLESv2/utilities.cpp \ + $$ANGLE_DIR/src/libGLESv2/VertexDataManager.cpp + +float_converter.target = float_converter +float_converter.commands = python $$ANGLE_DIR/src/libGLESv2/Float16ToFloat32.py \ + > $$ANGLE_DIR/src/libGLESv2/Float16ToFloat32.cpp +QMAKE_EXTRA_TARGETS += float_converter + +# Generate the shader header files. +PS_INPUT = $$ANGLE_DIR/src/libGLESv2/shaders/Blit.ps +VS_INPUT = $$ANGLE_DIR/src/libGLESv2/shaders/Blit.vs +PIXEL_SHADERS = passthroughps luminanceps componentmaskps +VERTEX_SHADERS = standardvs flipyvs +SHADER_DIR = $$OUT_PWD/shaders + +for (ps, PIXEL_SHADERS) { + fxc_$${ps}.commands = $$FXC /nologo /E $$ps /T ps_2_0 /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} + fxc_$${ps}.output = $$SHADER_DIR/$${ps}.h + fxc_$${ps}.input = PS_INPUT + fxc_$${ps}.dependency_type = TYPE_C + fxc_$${ps}.variable_out = HEADERS + QMAKE_EXTRA_COMPILERS += fxc_$${ps} +} +for (vs, VERTEX_SHADERS) { + fxc_$${vs}.commands = $$FXC /nologo /E $$vs /T vs_2_0 /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} + fxc_$${vs}.output = $$SHADER_DIR/$${vs}.h + fxc_$${vs}.input = VS_INPUT + fxc_$${vs}.dependency_type = TYPE_C + fxc_$${vs}.variable_out = HEADERS + QMAKE_EXTRA_COMPILERS += fxc_$${vs} +} + +load(qt_installs) + +khr_headers.files = $$ANGLE_DIR/include/KHR/khrplatform.h +khr_headers.path = $$[QT_INSTALL_HEADERS]/KHR +gles2_headers.files = \ + $$ANGLE_DIR/include/GLES2/gl2.h \ + $$ANGLE_DIR/include/GLES2/gl2ext.h \ + $$ANGLE_DIR/include/GLES2/gl2platform.h +gles2_headers.path = $$[QT_INSTALL_HEADERS]/GLES2 +INSTALLS += khr_headers gles2_headers + + diff --git a/src/angle/src/src.pro b/src/angle/src/src.pro new file mode 100644 index 0000000000..d1f5f57591 --- /dev/null +++ b/src/angle/src/src.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS += compiler libGLESv2 libEGL +CONFIG += ordered diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 6680a9dc2b..0ad07fe5cf 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -115,7 +115,7 @@ QWindowsEGLStaticContext::~QWindowsEGLStaticContext() When building for 64bit, de-activate the "WarnAsError" option in every project file (as otherwise integer conversion warnings will break the build). - \o Run configure.exe with the options "-opengl es2 -angle ". + \o Run configure.exe with the options "-opengl es2". \o Build qtbase and test some examples. \endlist diff --git a/src/src.pro b/src/src.pro index fe892aa7ad..1ce31eed47 100644 --- a/src/src.pro +++ b/src/src.pro @@ -35,6 +35,9 @@ src_testlib.subdir = $$PWD/testlib src_testlib.target = sub-testlib src_testlib.depends = src_corelib # src_gui & src_widgets are not build-depends +src_angle.subdir = $$PWD/angle +src_angle.target = src_angle + src_gui.subdir = $$PWD/gui src_gui.target = sub-gui src_gui.depends = src_corelib @@ -69,6 +72,10 @@ contains(QT_CONFIG, dbus) { } contains(QT_CONFIG, concurrent):SUBDIRS += src_concurrent !contains(QT_CONFIG, no-gui) { + win32:contains(QT_CONFIG, angle) { + SUBDIRS += src_angle + src_gui.depends += src_angle + } SUBDIRS += src_gui src_platformsupport src_plugins.depends += src_gui src_platformsupport !contains(QT_CONFIG, no-widgets) { -- cgit v1.2.3 From 8e002f1c0e0e0605d6cdfb90cdf909035eb643c8 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 23 Oct 2012 19:17:25 +0100 Subject: Update QDataStream format docs for gui/math3d classes Change-Id: I158d1bc5414f273320f0561000e69c3e06f6ac5a Reviewed-by: Mitch Curtis Reviewed-by: Jerome Pasion --- src/corelib/doc/src/datastreamformat.qdoc | 58 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/corelib/doc/src/datastreamformat.qdoc b/src/corelib/doc/src/datastreamformat.qdoc index e9f0139a8b..8c3b592276 100644 --- a/src/corelib/doc/src/datastreamformat.qdoc +++ b/src/corelib/doc/src/datastreamformat.qdoc @@ -213,22 +213,22 @@ \endlist \row \li QMatrix4x4 \li \list - \li m11 (double) - \li m12 (double) - \li m13 (double) - \li m14 (double) - \li m21 (double) - \li m22 (double) - \li m23 (double) - \li m24 (double) - \li m31 (double) - \li m32 (double) - \li m33 (double) - \li m34 (double) - \li m41 (double) - \li m42 (double) - \li m43 (double) - \li m44 (double) + \li m11 (float) + \li m12 (float) + \li m13 (float) + \li m14 (float) + \li m21 (float) + \li m22 (float) + \li m23 (float) + \li m24 (float) + \li m31 (float) + \li m32 (float) + \li m33 (float) + \li m34 (float) + \li m41 (float) + \li m42 (float) + \li m43 (float) + \li m44 (float) \endlist \row \li QPair \li \list @@ -278,10 +278,10 @@ \endlist \row \li QQuaternion \li \list - \li The scalar component (double) - \li The x coordinate (double) - \li The y coordinate (double) - \li The z coordinate (double) + \li The scalar component (float) + \li The x coordinate (float) + \li The y coordinate (float) + \li The z coordinate (float) \endlist \row \li QRect \li \list @@ -347,21 +347,21 @@ \endlist \row \li QVector2D \li \list - \li the x coordinate (double) - \li the y coordinate (double) + \li the x coordinate (float) + \li the y coordinate (float) \endlist \row \li QVector3D \li \list - \li the x coordinate (double) - \li the y coordinate (double) - \li the z coordinate (double) + \li the x coordinate (float) + \li the y coordinate (float) + \li the z coordinate (float) \endlist \row \li QVector4D \li \list - \li the x coordinate (double) - \li the y coordinate (double) - \li the z coordinate (double) - \li the w coordinate (double) + \li the x coordinate (float) + \li the y coordinate (float) + \li the z coordinate (float) + \li the w coordinate (float) \endlist \row \li QVector \li \list -- cgit v1.2.3 From 9fc7fcb4c90f9fdc5bb3581609a1d5b01cfb7076 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 22 Oct 2012 14:43:38 +0300 Subject: Add ContextMenu event to QWindowSystemInterface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context menu key wasn't working, as QPA had no handling for it. Added ContextMenu event to QWindowSystemInterface and proper handling to QGuiApplication and QWidgetWindow. Also provide Windows implementation. Task-number: QTBUG-27648 Change-Id: I7ce71ec4b5cdcc7be758e67f9faf6d863f7b19be Reviewed-by: Friedemann Kleint Reviewed-by: Samuel Rødal --- src/gui/kernel/qguiapplication.cpp | 19 ++++++++++++ src/gui/kernel/qguiapplication_p.h | 3 ++ src/gui/kernel/qwindowsysteminterface.cpp | 12 ++++++++ src/gui/kernel/qwindowsysteminterface.h | 5 ++++ src/gui/kernel/qwindowsysteminterface_p.h | 18 +++++++++++- src/plugins/platforms/windows/qtwindowsglobal.h | 5 ++++ src/plugins/platforms/windows/qwindowscontext.cpp | 23 +++++++++++++++ src/plugins/platforms/windows/qwindowscontext.h | 3 ++ src/widgets/kernel/qwidgetwindow.cpp | 35 ++++++++++++++++++++++- src/widgets/kernel/qwidgetwindow_qpa_p.h | 3 ++ 10 files changed, 124 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index a67917ca3b..64d2f8001f 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1211,6 +1211,12 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv QGuiApplicationPrivate::processFileOpenEvent( static_cast(e)); break; +#ifndef QT_NO_CONTEXTMENU + case QWindowSystemInterfacePrivate::ContextMenu: + QGuiApplicationPrivate::processContextMenuEvent( + static_cast(e)); + break; +#endif default: qWarning() << "Unknown user input event type:" << e->type; break; @@ -1639,6 +1645,19 @@ void QGuiApplicationPrivate::processPlatformPanelEvent(QWindowSystemInterfacePri QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev); } +#ifndef QT_NO_CONTEXTMENU +void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e) +{ + // Widgets do not care about mouse triggered context menu events. Also, do not forward event + // to a window blocked by a modal window. + if (!e->window || e->mouseTriggered || e->window->d_func()->blockedByModalWindow) + return; + + QContextMenuEvent ev(QContextMenuEvent::Keyboard, e->pos, e->globalPos, e->modifiers); + QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev); +} +#endif + Q_GUI_EXPORT uint qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k) { return qHash(k.device) + k.touchPointId; diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 0c81d78f86..44a9275688 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -138,6 +138,9 @@ public: static void processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e); static void processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e); +#ifndef QT_NO_CONTEXTMENU + static void processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e); +#endif #ifndef QT_NO_DRAGANDDROP static QPlatformDragQtResponse processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions); diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 82e0e44ac7..6fb10b6c75 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -630,6 +630,18 @@ void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w) QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } +#ifndef QT_NO_CONTEXTMENU +void QWindowSystemInterface::handleContextMenuEvent(QWindow *w, bool mouseTriggered, + const QPoint &pos, const QPoint &globalPos, + Qt::KeyboardModifiers modifiers) +{ + QWindowSystemInterfacePrivate::ContextMenuEvent *e = + new QWindowSystemInterfacePrivate::ContextMenuEvent(w, mouseTriggered, pos, + globalPos, modifiers); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); +} +#endif + Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier) { QWindowSystemInterface::handleMouseEvent(w, local, global, b, mods); } diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 74b5a136f4..b4b2e845fc 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -175,6 +175,11 @@ public: static void handleTabletLeaveProximityEvent(int device, int pointerType, qint64 uid); static void handlePlatformPanelEvent(QWindow *w); +#ifndef QT_NO_CONTEXTMENU + static void handleContextMenuEvent(QWindow *w, bool mouseTriggered, + const QPoint &pos, const QPoint &globalPos, + Qt::KeyboardModifiers modifiers); +#endif // For event dispatcher implementations static bool sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 4e907f3f51..1b5351db71 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -77,7 +77,8 @@ public: Tablet, TabletEnterProximity, TabletLeaveProximity, - PlatformPanel + PlatformPanel, + ContextMenu }; class WindowSystemEvent { @@ -333,6 +334,21 @@ public: QPointer window; }; +#ifndef QT_NO_CONTEXTMENU + class ContextMenuEvent : public WindowSystemEvent { + public: + explicit ContextMenuEvent(QWindow *w, bool mouseTriggered, const QPoint &pos, + const QPoint &globalPos, Qt::KeyboardModifiers modifiers) + : WindowSystemEvent(ContextMenu), window(w), mouseTriggered(mouseTriggered), pos(pos), + globalPos(globalPos), modifiers(modifiers) { } + QPointer window; + bool mouseTriggered; + QPoint pos; // Only valid if triggered by mouse + QPoint globalPos; // Only valid if triggered by mouse + Qt::KeyboardModifiers modifiers; + }; +#endif + class WindowSystemEventList { QList impl; mutable QMutex mutex; diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 73f963b6b8..7ff8edb588 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -105,6 +105,7 @@ enum WindowsEventType // Simplify event types ThemeChanged = ThemingEventFlag + 1, DisplayChangedEvent = 437, SettingChangedEvent = DisplayChangedEvent + 1, + ContextMenu = 123, UnknownEvent = 542 }; @@ -194,6 +195,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return QtWindows::DisplayChangedEvent; case WM_THEMECHANGED: return QtWindows::ThemeChanged; +#ifndef QT_NO_CONTEXTMENU + case WM_CONTEXTMENU: + return QtWindows::ContextMenu; +#endif default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 3d4871d7a2..42db58ae6c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -868,6 +868,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, if (const QWindow *modalWindow = QGuiApplication::modalWindow()) QWindowsWindow::baseWindowOf(modalWindow)->alertWindow(); break; +#endif +#ifndef QT_NO_CONTEXTMENU + case QtWindows::ContextMenu: + handleContextMenuEvent(platformWindow->window(), msg); + return true; #endif default: break; @@ -900,6 +905,24 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et, } } +#ifndef QT_NO_CONTEXTMENU +void QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) +{ + bool mouseTriggered = false; + QPoint globalPos; + QPoint pos; + if (msg.lParam != (int)0xffffffff) { + mouseTriggered = true; + globalPos.setX(msg.pt.x); + globalPos.setY(msg.pt.y); + pos = QWindowsGeometryHint::mapFromGlobal(msg.hwnd, globalPos); + } + + QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos, + QWindowsKeyMapper::queryKeyboardModifiers()); +} +#endif + /*! \brief Windows functions for actual windows. diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index dcc636bfc0..ef48a52e07 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -187,6 +187,9 @@ public: private: void handleFocusEvent(QtWindows::WindowsEventType et, QWindowsWindow *w); +#ifndef QT_NO_CONTEXTMENU + void handleContextMenuEvent(QWindow *window, const MSG &msg); +#endif void unregisterWindowClasses(); QScopedPointer d; diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 5f25e1274e..900818d5c6 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -200,7 +200,11 @@ bool QWidgetWindow::event(QEvent *event) handleTabletEvent(static_cast(event)); return true; #endif - +#ifndef QT_NO_CONTEXTMENU + case QEvent::ContextMenu: + handleContextMenuEvent(static_cast(event)); + return true; +#endif default: break; } @@ -618,6 +622,35 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event) } #endif // QT_NO_TABLETEVENT +#ifndef QT_NO_CONTEXTMENU +void QWidgetWindow::handleContextMenuEvent(QContextMenuEvent *e) +{ + // We are only interested in keyboard originating context menu events here, + // mouse originated context menu events for widgets are generated in mouse handling methods. + if (e->reason() != QContextMenuEvent::Keyboard) + return; + + QWidget *fw = QWidget::keyboardGrabber(); + if (!fw) { + if (QApplication::activePopupWidget()) { + fw = (QApplication::activePopupWidget()->focusWidget() + ? QApplication::activePopupWidget()->focusWidget() + : QApplication::activePopupWidget()); + } else if (QApplication::focusWidget()) { + fw = QApplication::focusWidget(); + } else { + fw = m_widget; + } + } + if (fw && fw->isEnabled()) { + QPoint pos = fw->inputMethodQuery(Qt::ImMicroFocus).toRect().center(); + QContextMenuEvent widgetEvent(QContextMenuEvent::Keyboard, pos, fw->mapToGlobal(pos), + e->modifiers()); + QGuiApplication::sendSpontaneousEvent(fw, &widgetEvent); + } +} +#endif // QT_NO_CONTEXTMENU + void QWidgetWindow::updateObjectName() { QString name = m_widget->objectName(); diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h index 80aa022ce2..e832249107 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa_p.h +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -92,6 +92,9 @@ protected: #ifndef QT_NO_TABLETEVENT void handleTabletEvent(QTabletEvent *); #endif +#ifndef QT_NO_CONTEXTMENU + void handleContextMenuEvent(QContextMenuEvent *); +#endif private slots: void updateObjectName(); -- cgit v1.2.3 From 935f223440bd125ccbda380ea880486653e8b42e Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Tue, 9 Oct 2012 13:00:07 +0100 Subject: Add DnD support for QNX. We only need DnD within the same application for now, so returning a QSimpleDrag is enough. Change-Id: I842d48f0252f8103fa8632dd3d149ae431658adb Reviewed-by: Thomas McGuire Reviewed-by: Kevin Krammer Reviewed-by: Nicolas Arnaud-Cormos --- src/plugins/platforms/qnx/qqnxintegration.cpp | 17 +++++++++++++++++ src/plugins/platforms/qnx/qqnxintegration.h | 11 ++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index a45c65db08..adb92741f9 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -89,6 +89,8 @@ #include #endif +#include + #include #include @@ -128,6 +130,9 @@ QQnxIntegration::QQnxIntegration() #if !defined(QT_NO_CLIPBOARD) , m_clipboard(0) #endif +#if !defined(QT_NO_DRAGANDDROP) + , m_drag(new QSimpleDrag()) +#endif { qIntegrationDebug() << Q_FUNC_INFO; // Open connection to QNX composition manager @@ -224,6 +229,11 @@ QQnxIntegration::~QQnxIntegration() qIntegrationDebug() << Q_FUNC_INFO << "platform plugin shutdown begin"; delete m_nativeInterface; +#if !defined(QT_NO_DRAGANDDROP) + // Destroy the drag object + delete m_drag; +#endif + #if defined(QQNX_PPS) // Destroy the hardware button notifier delete m_buttonsNotifier; @@ -364,6 +374,13 @@ QPlatformClipboard *QQnxIntegration::clipboard() const } #endif +#if !defined(QT_NO_DRAGANDDROP) +QPlatformDrag *QQnxIntegration::drag() const +{ + return m_drag; +} +#endif + QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { qIntegrationDebug() << Q_FUNC_INFO; diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index acedda51c6..441e2c9d68 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -62,6 +62,8 @@ class QQnxAbstractNavigator; class QQnxAbstractVirtualKeyboard; class QQnxServices; +class QSimpleDrag; + #if defined(QQNX_PPS) class QQnxInputContext; class QQnxNavigatorEventNotifier; @@ -105,7 +107,9 @@ public: #if !defined(QT_NO_CLIPBOARD) QPlatformClipboard *clipboard() const; #endif - +#if !defined(QT_NO_DRAGANDDROP) + QPlatformDrag *drag() const; +#endif QVariant styleHint(StyleHint hint) const; QPlatformServices *services() const; @@ -151,9 +155,10 @@ private: #if !defined(QT_NO_CLIPBOARD) mutable QQnxClipboard* m_clipboard; #endif - QQnxAbstractNavigator *m_navigator; - +#if !defined(QT_NO_DRAGANDDROP) + QSimpleDrag *m_drag; +#endif static QQnxWindowMapper ms_windowMapper; static QMutex ms_windowMapperMutex; -- cgit v1.2.3 From 82cb34b05f59b3e3f2d641304381ea9d359bc67b Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 23 Oct 2012 11:50:13 +0300 Subject: Fix widget borders when using global stylesheetstyle Recent fixes to stylesheetstyle caused not calling fixupBorder() when globalStyleSheetStyle is used. Task-number: QTBUG-27651 Change-Id: I73263c951e2db7d574e81da3f60a1b79f3852716 Reviewed-by: J-P Nurmi Reviewed-by: Thomas Hartmann --- src/widgets/styles/qstylesheetstyle.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 1c4cad7afe..17ed82c730 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -997,16 +997,12 @@ QRenderRule::QRenderRule(const QVector &declarations, const QObject } } - if (object) { + if (const QWidget *widget = qobject_cast(object)) { QStyleSheetStyle *style = const_cast(globalStyleSheetStyle); - if (!style) { - if (const QWidget *widget = qobject_cast(object)) { - style = qobject_cast(widget->style()); - if (style) - fixupBorder(style->nativeFrameWidth(widget)); - } - } - + if (!style) + style = qobject_cast(widget->style()); + if (style) + fixupBorder(style->nativeFrameWidth(widget)); } if (hasBorder() && border()->hasBorderImage()) defaultBackground = QBrush(); -- cgit v1.2.3 From 33214af3784feacb2d5188bbf07da92f45f582f9 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Mon, 22 Oct 2012 14:19:24 +1000 Subject: Fixed crash on destruction of animating QDockWidget in a QMainWindow It doesn't make sense to hold an unguarded pointer to a QPropertyAnimation while assigning ownership of that animation to the animated widget. Destruction of the widget while the animation is in progress causes the animation pointer to become dangling; then the widget is removed from the containing QMainWindowLayout, which attempts to abort the animation, dereferencing the invalid pointer. The crash can be reproduced sometimes with tst_QDockWidget::taskQTBUG_2940_resizeAfterUndocking (which is in Qt4 only). Change-Id: I758bf7193b2ea39cd4d8e87197d8ff957d3368eb Reviewed-by: Robin Burchell Reviewed-by: Andy Shaw --- src/widgets/widgets/qwidgetanimator.cpp | 4 +++- src/widgets/widgets/qwidgetanimator_p.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/widgets/widgets/qwidgetanimator.cpp b/src/widgets/widgets/qwidgetanimator.cpp index edd9d63081..aef967bd65 100644 --- a/src/widgets/widgets/qwidgetanimator.cpp +++ b/src/widgets/widgets/qwidgetanimator.cpp @@ -59,7 +59,9 @@ void QWidgetAnimator::abort(QWidget *w) return; QPropertyAnimation *anim = *it; m_animation_map.erase(it); - anim->stop(); + if (anim) { + anim->stop(); + } #ifndef QT_NO_MAINWINDOW m_mainWindowLayout->animationFinished(w); #endif diff --git a/src/widgets/widgets/qwidgetanimator_p.h b/src/widgets/widgets/qwidgetanimator_p.h index 5649488c13..98963ce0bc 100644 --- a/src/widgets/widgets/qwidgetanimator_p.h +++ b/src/widgets/widgets/qwidgetanimator_p.h @@ -55,6 +55,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -79,7 +80,7 @@ private Q_SLOTS: #endif private: - typedef QHash AnimationMap; + typedef QHash > AnimationMap; AnimationMap m_animation_map; QMainWindowLayout *m_mainWindowLayout; }; -- cgit v1.2.3 From a26c97859a2d67392af4e1748b14623072ebe555 Mon Sep 17 00:00:00 2001 From: Jason Barron Date: Wed, 24 Oct 2012 14:00:32 +0200 Subject: Fix incorrect library path in libEGL.pro. Should not use the QT_INSTALL* variables here since it won't work if we configure with a prefix. Change-Id: I03ac170cb11262c38928f2a0d95e6f243d6d665b Reviewed-by: Maurice Kalinowski Reviewed-by: Friedemann Kleint --- src/angle/src/libEGL/libEGL.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/angle/src/libEGL/libEGL.pro b/src/angle/src/libEGL/libEGL.pro index b7182b7fee..845b1af0e9 100644 --- a/src/angle/src/libEGL/libEGL.pro +++ b/src/angle/src/libEGL/libEGL.pro @@ -4,7 +4,7 @@ TARGET = libEGL include(../common/common.pri) LIBS += -ld3d9 -ldxguid -ldwmapi \ - -L$$[QT_INSTALL_LIBS] -llibGLESv2 + -L$$QT_BUILD_TREE/lib -llibGLESv2 HEADERS += \ $$ANGLE_DIR/src/libEGL/Config.h \ -- cgit v1.2.3 From ed19c0875e9a2485dcd2cbab3f603611ad0b19c9 Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Tue, 16 Oct 2012 18:25:01 +0200 Subject: QSslSocket: Allow disconnections within the connected() signal When doing happy eyeballs style network state lookup, we might have to close an SSL socket from its connected signal. This can cause the warning: QSslSocket::startClientEncryption: cannot start handshake when not connected The signal should be emitted after we called startClientEncryption to avoid this warning. In that case it will initialize the encryption and ramp it down right after. Change-Id: I0c8c79cad7f91f0088b87c5e4ee8aafbc688411c Reviewed-by: Shane Kearns --- src/network/ssl/qsslsocket.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 8260c1c563..e97cf0817a 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2153,11 +2153,13 @@ void QSslSocketPrivate::_q_connectedSlot() qDebug() << "\tlocal =" << QHostInfo::fromName(q->localAddress().toString()).hostName() << q->localAddress() << q->localPort(); #endif - emit q->connected(); - if (autoStartHandshake) { + if (autoStartHandshake) q->startClientEncryption(); - } else if (pendingClose) { + + emit q->connected(); + + if (pendingClose && !autoStartHandshake) { pendingClose = false; q->disconnectFromHost(); } -- cgit v1.2.3 From de58eb64bc564fcb8af61a45576783e432d2380c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 23 Oct 2012 13:14:27 +0200 Subject: Revert hacks in text rendering code path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a lot of hacks here and there in Qt trying to align the text in a correct way which caused regressions to appear once the default coordinate system changed. We need to remove these hacks to get a more consistent and maintainable base. This also fixes the regression introduced by changing the aliased coordinate system. Task-number: QTBUG-27667 Change-Id: I620db2ca23b7ff6c912f3a51e86e7e36bbef81f0 Reviewed-by: Samuel Rødal --- src/gui/opengl/qopenglpaintengine.cpp | 2 +- src/gui/painting/qpaintengine_raster.cpp | 5 +-- src/gui/painting/qpainter.cpp | 43 ++++++++-------------- src/gui/text/qtextengine.cpp | 15 ++++++-- src/gui/text/qtextengine_p.h | 2 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 2 +- 6 files changed, 33 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 8e967207d4..624eeaffd9 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -1638,7 +1638,7 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type continue; int x = qFloor(staticTextItem->glyphPositions[i].x) + c.baseLineX - margin; - int y = qFloor(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin; + int y = qRound(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin; vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h)); textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 1a63ced897..fec01afdee 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2787,7 +2787,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(), qFloor(positions[i].x) + offset.x(), - qFloor(positions[i].y) + offset.y(), + qRound(positions[i].y) + offset.y(), alphaMap->width(), alphaMap->height()); fontEngine->unlockAlphaMapForGlyph(); @@ -2818,7 +2818,6 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, rightShift = 3; // divide by 8 int margin = fontEngine->glyphMargin(glyphType); - const QFixed offs = s->flags.legacy_rounding ? QFixed::fromReal(aliasedCoordinateDelta) : QFixed(); const uchar *bits = image.bits(); for (int i=0; irenderHints() + & QPainter::Qt4CompatiblePainting; + + if (wasCompatiblePainting) + painter->setRenderHint(QPainter::Qt4CompatiblePainting, false); + const qreal underlineOffset = fe->underlinePosition().toReal(); // deliberately ceil the offset to avoid the underline coming too close to // the text above it. - const qreal underlinePos = pos.y() + qCeil(underlineOffset); + const qreal underlinePos = pos.y() + qCeil(underlineOffset) + 0.5; if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme(); @@ -6247,6 +6253,9 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const painter->setPen(oldPen); painter->setBrush(oldBrush); + + if (wasCompatiblePainting) + painter->setRenderHint(QPainter::Qt4CompatiblePainting); } Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, @@ -7500,36 +7509,16 @@ start_lengthVariant: qreal yoff = 0; qreal xoff = 0; - if (tf & Qt::AlignBottom) { + if (tf & Qt::AlignBottom) yoff = r.height() - height; - } else if (tf & Qt::AlignVCenter) { + else if (tf & Qt::AlignVCenter) yoff = (r.height() - height)/2; - if (painter) { - QTransform::TransformationType type = painter->transform().type(); - if (type <= QTransform::TxScale) { - // do the rounding manually to work around inconsistencies - // in the paint engines when drawing on floating point offsets - const qreal scale = painter->transform().m22(); - if (scale != 0) - yoff = -qRound(-yoff * scale) / scale; - } - } - } - if (tf & Qt::AlignRight) { + + if (tf & Qt::AlignRight) xoff = r.width() - width; - } else if (tf & Qt::AlignHCenter) { + else if (tf & Qt::AlignHCenter) xoff = (r.width() - width)/2; - if (painter) { - QTransform::TransformationType type = painter->transform().type(); - if (type <= QTransform::TxScale) { - // do the rounding manually to work around inconsistencies - // in the paint engines when drawing on floating point offsets - const qreal scale = painter->transform().m11(); - if (scale != 0) - xoff = qRound(xoff * scale) / scale; - } - } - } + QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height); if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) { diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 38fe2f8140..025d4289aa 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -3060,8 +3060,7 @@ void QTextEngine::drawItemDecorationList(QPainter *painter, const ItemDecoration foreach (const ItemDecoration &decoration, decorationList) { painter->setPen(decoration.pen); - QLineF line(decoration.x1, decoration.y, decoration.x2, decoration.y); - painter->drawLine(line); + painter->drawLine(QLineF(decoration.x1, decoration.y, decoration.x2, decoration.y)); } } @@ -3069,13 +3068,23 @@ void QTextEngine::drawDecorations(QPainter *painter) { QPen oldPen = painter->pen(); + bool wasCompatiblePainting = painter->renderHints() + & QPainter::Qt4CompatiblePainting; + + if (wasCompatiblePainting) + painter->setRenderHint(QPainter::Qt4CompatiblePainting, false); + adjustUnderlines(); drawItemDecorationList(painter, underlineList); drawItemDecorationList(painter, strikeOutList); drawItemDecorationList(painter, overlineList); - painter->setPen(oldPen); clearDecorations(); + + if (wasCompatiblePainting) + painter->setRenderHint(QPainter::Qt4CompatiblePainting); + + painter->setPen(oldPen); } void QTextEngine::clearDecorations() diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 82467229eb..aff5e1cb7f 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -390,7 +390,7 @@ struct Q_AUTOTEST_EXPORT QScriptLine mutable uint gridfitted : 1; uint hasTrailingSpaces : 1; uint leadingIncluded : 1; - QFixed height() const { return (ascent + descent).ceil() + QFixed height() const { return ascent + descent + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); } QFixed base() const { return ascent + (leadingIncluded ? qMax(QFixed(),leading) : QFixed()); } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index e542397663..7284efa53b 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1675,7 +1675,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp continue; int x = qFloor(staticTextItem->glyphPositions[i].x) + c.baseLineX - margin; - int y = qFloor(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin; + int y = qRound(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin; vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h)); textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); -- cgit v1.2.3 From 52ccbd8911f1b96b8bea6a4c9da4d4a762dee2a7 Mon Sep 17 00:00:00 2001 From: aavit Date: Tue, 23 Oct 2012 15:27:18 +0200 Subject: Fix: don't override the new non-cosmetic default pen in qwidget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As QWidget initializes any painter created in paintevent handler to have the pen color of the palette's foreground, setting it to 0 width, i.e. cosmetic, it negated the effect of the recent change to default 1-width non-cosmetic, ref. I04d910e9700baf7f13a8aac07a3633014bb9283e This caused scaled painting with default pen on QImage and QWidget to yield different results. Change-Id: I930b64bf7c0a8c84b9ea3edb49adc813370fed0e Reviewed-by: Samuel Rødal --- src/widgets/kernel/qwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index bb148a52ac..07dab9e784 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -11237,7 +11237,7 @@ void QWidget::ungrabGesture(Qt::GestureType gesture) void QWidget::initPainter(QPainter *painter) const { const QPalette &pal = palette(); - painter->d_func()->state->pen = QPen(pal.brush(foregroundRole()), 0); + painter->d_func()->state->pen = QPen(pal.brush(foregroundRole()), 1); painter->d_func()->state->bgBrush = pal.brush(backgroundRole()); QFont f(font(), const_cast(this)); painter->d_func()->state->deviceFont = f; -- cgit v1.2.3 From c4109fe10370b7b27b22ddc9db4286db34ea9c4e Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 23 Oct 2012 16:25:47 +0300 Subject: Fix crash when handling WM_PAINT during COM operations Synchronous expose corrupts painter state if it is done during existing paint operation, which can happen e.g. when requesting some value from dumpcpp generated wrapper inside a slot. Fixed by implementing support for setting asynchronous expose and doing expose according to the setting in handleWmPaint(). Task-number: QTBUG-27209 Change-Id: I89b5aa823fda947d26b1a4757f129e7c31ea408b Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowscontext.cpp | 13 ++++++++++++- src/plugins/platforms/windows/qwindowscontext.h | 2 ++ src/plugins/platforms/windows/qwindowsintegration.cpp | 13 +++++++++++++ src/plugins/platforms/windows/qwindowswindow.cpp | 6 ++++-- 4 files changed, 31 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 42db58ae6c..a0749388f9 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -259,6 +259,7 @@ struct QWindowsContextPrivate { const HRESULT m_oleInitializeResult; const QByteArray m_eventType; QWindow *m_lastActiveWindow; + bool m_asyncExpose; }; QWindowsContextPrivate::QWindowsContextPrivate() : @@ -267,7 +268,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() : m_defaultDPI(GetDeviceCaps(m_displayContext,LOGPIXELSY)), m_oleInitializeResult(OleInitialize(NULL)), m_eventType(QByteArrayLiteral("windows_generic_MSG")), - m_lastActiveWindow(0) + m_lastActiveWindow(0), m_asyncExpose(0) { #ifndef Q_OS_WINCE QWindowsContext::user32dll.init(); @@ -923,6 +924,16 @@ void QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) } #endif +bool QWindowsContext::asyncExpose() const +{ + return d->m_asyncExpose; +} + +void QWindowsContext::setAsyncExpose(bool value) +{ + d->m_asyncExpose = value; +} + /*! \brief Windows functions for actual windows. diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index ef48a52e07..21a846ef97 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -184,6 +184,8 @@ public: #endif static QByteArray comErrorString(HRESULT hr); + bool asyncExpose() const; + void setAsyncExpose(bool value); private: void handleFocusEvent(QtWindows::WindowsEventType et, QWindowsWindow *w); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index f95fbf4b34..b7309c3f7c 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -96,6 +96,7 @@ QT_BEGIN_NAMESPACE class QWindowsNativeInterface : public QPlatformNativeInterface { Q_OBJECT + Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) public: #ifndef QT_NO_OPENGL virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); @@ -106,6 +107,8 @@ public: Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, const QString &windowName, void *eventProc) const; + bool asyncExpose() const; + void setAsyncExpose(bool value); }; void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) @@ -183,6 +186,16 @@ void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTempl return hwnd; } +bool QWindowsNativeInterface::asyncExpose() const +{ + return QWindowsContext::instance()->asyncExpose(); +} + +void QWindowsNativeInterface::setAsyncExpose(bool value) +{ + QWindowsContext::instance()->setAsyncExpose(value); +} + /*! \class QWindowsIntegration \brief QPlatformIntegration implementation for Windows. diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 99b8922768..9aada91e73 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1158,7 +1158,8 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, InvalidateRect(hwnd, 0, false); BeginPaint(hwnd, &ps); QWindowSystemInterface::handleExposeEvent(window(), QRegion(qrectFromRECT(ps.rcPaint))); - QWindowSystemInterface::flushWindowSystemEvents(); + if (!QWindowsContext::instance()->asyncExpose()) + QWindowSystemInterface::flushWindowSystemEvents(); EndPaint(hwnd, &ps); } else { @@ -1169,7 +1170,8 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, qDebug() << __FUNCTION__ << this << window() << updateRect; QWindowSystemInterface::handleExposeEvent(window(), QRegion(updateRect)); - QWindowSystemInterface::flushWindowSystemEvents(); + if (!QWindowsContext::instance()->asyncExpose()) + QWindowSystemInterface::flushWindowSystemEvents(); EndPaint(hwnd, &ps); } return true; -- cgit v1.2.3 From 92c739cf50b18b8abdc1b30480b75cc6b27cf5bf Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 23 Oct 2012 14:03:05 +0200 Subject: Implement viewOptions logic in QTableViewPrivate. This is similar to the patch 05aa8c6c12509cce87d1a3811c5ea1dd83fa0898 which was applied to QListView. Task-number: QTBUG-26548 Change-Id: I38ff07230673a93a32b01a7f1951d0378d94185b Reviewed-by: Giuseppe D'Angelo Reviewed-by: Oliver Wolff Reviewed-by: Stephen Kelly --- src/widgets/itemviews/qtableview.cpp | 12 +++++++++--- src/widgets/itemviews/qtableview_p.h | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index b337f7f87f..80abb050ee 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -1290,14 +1290,20 @@ void QTableView::scrollContentsBy(int dx, int dy) } } +QStyleOptionViewItem QTableViewPrivate::viewOptions() const +{ + QStyleOptionViewItem option = QAbstractItemViewPrivate::viewOptions(); + option.showDecorationSelected = true; + return option; +} + /*! \reimp */ QStyleOptionViewItem QTableView::viewOptions() const { - QStyleOptionViewItem option = QAbstractItemView::viewOptions(); - option.showDecorationSelected = true; - return option; + Q_D(const QTableView); + return d->viewOptions(); } /*! diff --git a/src/widgets/itemviews/qtableview_p.h b/src/widgets/itemviews/qtableview_p.h index 792f507252..fbad4edf71 100644 --- a/src/widgets/itemviews/qtableview_p.h +++ b/src/widgets/itemviews/qtableview_p.h @@ -150,6 +150,8 @@ public: void init(); void trimHiddenSelections(QItemSelectionRange *range) const; + QStyleOptionViewItem viewOptions() const; + inline bool isHidden(int row, int col) const { return verticalHeader->isSectionHidden(row) || horizontalHeader->isSectionHidden(col); -- cgit v1.2.3 From 6e908f09dfc19be3cbbf38628c63c348c5172e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Mon, 22 Oct 2012 00:55:04 +0100 Subject: Don't crash if there's no m_image yet. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reproducible with: QBackingStore store( &window ); store.beginPaint(QRect(0,0,500,500)); All other methods already have null pointer checks. Change-Id: Ie278a263760900b58cf4a2ef286deb7f35d50cd0 Reviewed-by: Samuel Rødal --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 847fd67047..649469ab9d 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -262,11 +262,14 @@ QXcbBackingStore::~QXcbBackingStore() QPaintDevice *QXcbBackingStore::paintDevice() { - return m_image->image(); + return m_image ? m_image->image() : 0; } void QXcbBackingStore::beginPaint(const QRegion ®ion) { + if (!m_image) + return; + m_image->preparePaint(region); #if 0 -- cgit v1.2.3 From d58161e749348a9e11e063b1bbb3dbbc0aa46c5e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 22 Oct 2012 19:27:05 +0200 Subject: QMacStyle: make default button animations independent of QWidget Change-Id: I63c078050288e3151a9c6aad5d4ae28a58afd84f Reviewed-by: Gabriel de Dietrich --- src/widgets/styles/qmacstyle_mac.mm | 168 +++++++++++--------------------- src/widgets/styles/qmacstyle_mac_p.h | 8 +- src/widgets/widgets/qabstractbutton.cpp | 2 + src/widgets/widgets/qpushbutton.cpp | 2 +- 4 files changed, 65 insertions(+), 115 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 2b6f271a40..a227e06d77 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1683,46 +1683,6 @@ QMacStylePrivate::QMacStylePrivate() } -bool QMacStylePrivate::animatable(QMacStylePrivate::Animates as, const QObject *obj) const -{ - if (!obj) - return false; - - if (as == AquaPushButton) { - QPushButton *pb = const_cast(qobject_cast(obj)); - if (pb && pb->window()->isActiveWindow() && !mouseDown) { - if (pb != defaultButton) { - // Changed on its own, update the value. - const_cast(this)->stopAnimate(as, defaultButton); - const_cast(this)->startAnimate(as, pb); - } - return true; - } - } - return animation(obj); -} - -void QMacStylePrivate::stopAnimate(QMacStylePrivate::Animates as, QObject *obj) -{ - stopAnimation(obj); - if (as == AquaPushButton && defaultButton) { - stopAnimation(defaultButton); - QPushButton *tmp = defaultButton; - defaultButton = 0; - tmp->update(); - } else if (as == AquaScrollBar) { - scrollBarInfos.remove(qobject_cast(obj)); - } -} - -void QMacStylePrivate::startAnimate(QMacStylePrivate::Animates as, QObject *obj) -{ - if (!animation(obj)) - startAnimation(new QStyleAnimation(obj)); - if (as == AquaPushButton) - defaultButton = qobject_cast(obj); -} - bool QMacStylePrivate::addWidget(QWidget *w) { //already knew of it @@ -1730,17 +1690,9 @@ bool QMacStylePrivate::addWidget(QWidget *w) return false; Q_Q(QMacStyle); - if (QPushButton *btn = qobject_cast(w)) { - btn->installEventFilter(q); - if (btn->isDefault() || (btn->autoDefault() && btn->hasFocus())) - startAnimate(AquaPushButton, btn); + if (qobject_cast(w)) { + w->installEventFilter(q); return true; - } else { - bool isScrollBar = (qobject_cast(w)); - if (isScrollBar) { - w->installEventFilter(q); - return true; - } } if (w->isWindow()) { w->installEventFilter(q); @@ -1749,16 +1701,6 @@ bool QMacStylePrivate::addWidget(QWidget *w) return false; } -void QMacStylePrivate::removeWidget(QWidget *w) -{ - QPushButton *btn = qobject_cast(w); - if (btn && btn == defaultButton) { - stopAnimate(AquaPushButton, btn); - } else if (qobject_cast(w)) { - stopAnimate(AquaScrollBar, w); - } -} - ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags) { ThemeDrawState tds = kThemeStateActive; @@ -1839,49 +1781,6 @@ bool QMacStyle::eventFilter(QObject *o, QEvent *e) } } #endif - } else if (QPushButton *btn = qobject_cast(o)) { - switch (e->type()) { - default: - break; - case QEvent::FocusIn: - if (btn->autoDefault()) - d->startAnimate(QMacStylePrivate::AquaPushButton, btn); - break; - case QEvent::Destroy: - case QEvent::Hide: - if (btn == d->defaultButton) - d->stopAnimate(QMacStylePrivate::AquaPushButton, btn); - break; - case QEvent::MouseButtonPress: - // It is very confusing to keep the button pulsing, so just stop the animation. - if (static_cast(e)->button() == Qt::LeftButton) - d->mouseDown = true; - d->stopAnimate(QMacStylePrivate::AquaPushButton, btn); - break; - case QEvent::MouseButtonRelease: - if (static_cast(e)->button() == Qt::LeftButton) - d->mouseDown = false; - // fall through - case QEvent::FocusOut: - case QEvent::Show: - case QEvent::WindowActivate: { - QList list = btn->window()->findChildren(); - for (int i = 0; i < list.size(); ++i) { - QPushButton *pBtn = list.at(i); - if ((e->type() == QEvent::FocusOut - && (pBtn->isDefault() || (pBtn->autoDefault() && pBtn->hasFocus())) - && pBtn != btn) - || ((e->type() == QEvent::Show || e->type() == QEvent::MouseButtonRelease - || e->type() == QEvent::WindowActivate) - && pBtn->isDefault())) { - if (pBtn->window()->isActiveWindow()) { - d->startAnimate(QMacStylePrivate::AquaPushButton, pBtn); - } - break; - } - } - break; } - } } return false; } @@ -2172,7 +2071,6 @@ void QMacStyle::polish(QWidget* w) void QMacStyle::unpolish(QWidget* w) { Q_D(QMacStyle); - d->removeWidget(w); if ((qobject_cast(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) { QPalette pal = qApp->palette(w); w->setPalette(pal); @@ -2201,6 +2099,7 @@ void QMacStyle::unpolish(QWidget* w) if (qobject_cast(w)) { w->setAttribute(Qt::WA_OpaquePaintEvent, true); w->setMouseTracking(false); + d->scrollBarInfos.remove(w); } } @@ -3633,13 +3532,64 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter break; } + // a focused auto-default button within an active window + // takes precedence over a normal default button + if (btn->features & QStyleOptionButton::AutoDefaultButton + && opt->state & State_Active && opt->state & State_HasFocus) { + d->autoDefaultButton = opt->styleObject; + if (!d->animation(opt->styleObject)) + d->startAnimation(new QStyleAnimation(opt->styleObject)); + } else if (d->autoDefaultButton == opt->styleObject) { + if (QStyleAnimation *animation = d->animation(opt->styleObject)) { + animation->updateTarget(); + d->stopAnimation(opt->styleObject); + } + d->autoDefaultButton = 0; + } + + if (!d->autoDefaultButton) { + if (btn->features & QStyleOptionButton::DefaultButton && opt->state & State_Active) { + d->defaultButton = opt->styleObject; + if (!d->animation(opt->styleObject)) + d->startAnimation(new QStyleAnimation(opt->styleObject)); + } else if (d->defaultButton == opt->styleObject) { + if (QStyleAnimation *animation = d->animation(opt->styleObject)) { + animation->updateTarget(); + d->stopAnimation(opt->styleObject); + } + d->defaultButton = 0; + } + } + + // TODO: find out the pressed button in a qwidget independent way + extern QWidget *qt_button_down; // qwidgetwindow.cpp + if (opt->styleObject == qt_button_down) + d->pressedButton = opt->styleObject; + else if (d->pressedButton == opt->styleObject) + d->pressedButton = 0; + + // the default button animation is paused meanwhile any button + // is pressed or an auto-default button is animated instead + if (QStyleAnimation *defaultAnimation = d->animation(d->defaultButton)) { + if (d->pressedButton || d->autoDefaultButton) { + if (defaultAnimation->state() == QStyleAnimation::Running) { + defaultAnimation->pause(); + defaultAnimation->updateTarget(); + } + } else if (defaultAnimation->state() == QStyleAnimation::Paused) { + defaultAnimation->resume(); + } + } + HIThemeButtonDrawInfo bdi; d->initHIThemePushButton(btn, w, tds, &bdi); - if (btn->features & QStyleOptionButton::DefaultButton - && d->animatable(QMacStylePrivate::AquaPushButton, w)) { - bdi.adornment |= kThemeAdornmentDefault; - bdi.animation.time.start = d->defaultButtonStart; - bdi.animation.time.current = CFAbsoluteTimeGetCurrent(); + if (!d->pressedButton) { + QStyleAnimation* animation = d->animation(opt->styleObject); + if (animation && animation->state() == QStyleAnimation::Running) { + bdi.adornment |= kThemeAdornmentDefault; + bdi.animation.time.start = d->defaultButtonStart; + bdi.animation.time.current = CFAbsoluteTimeGetCurrent(); + } } // Unlike Carbon, we want the button to always be drawn inside its bounds. // Therefore, make the button a bit smaller, so that even if it got focus, diff --git a/src/widgets/styles/qmacstyle_mac_p.h b/src/widgets/styles/qmacstyle_mac_p.h index 66691c63f7..ec6f7c75b4 100644 --- a/src/widgets/styles/qmacstyle_mac_p.h +++ b/src/widgets/styles/qmacstyle_mac_p.h @@ -160,12 +160,8 @@ public: // Stuff from QAquaAnimate: bool addWidget(QWidget *); - void removeWidget(QWidget *); enum Animates { AquaPushButton, AquaProgressBar, AquaListViewItemOpen, AquaScrollBar }; - bool animatable(Animates, const QObject *) const; - void stopAnimate(Animates, QObject *); - void startAnimate(Animates, QObject *); static ThemeDrawState getDrawState(QStyle::State flags); QAquaWidgetSize aquaSizeConstrain(const QStyleOption *option, const QWidget *widg, QStyle::ContentsType ct = QStyle::CT_CustomBase, @@ -201,7 +197,9 @@ public: QPixmap generateBackgroundPattern() const; public: - QPointer defaultButton; //default push buttons + mutable QPointer pressedButton; + mutable QPointer defaultButton; + mutable QPointer autoDefaultButton; struct OverlayScrollBarInfo { OverlayScrollBarInfo() diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp index 5d879c8930..eba63045fe 100644 --- a/src/widgets/widgets/qabstractbutton.cpp +++ b/src/widgets/widgets/qabstractbutton.cpp @@ -1113,6 +1113,8 @@ void QAbstractButton::mouseReleaseEvent(QMouseEvent *e) } if (!d->down) { + // refresh is required by QMacStyle to resume the default button animation + d->refresh(); e->ignore(); return; } diff --git a/src/widgets/widgets/qpushbutton.cpp b/src/widgets/widgets/qpushbutton.cpp index 5e8d7d16bd..0aeec551d6 100644 --- a/src/widgets/widgets/qpushbutton.cpp +++ b/src/widgets/widgets/qpushbutton.cpp @@ -329,7 +329,7 @@ void QPushButton::initStyleOption(QStyleOptionButton *option) const if (d->menu) option->features |= QStyleOptionButton::HasMenu; #endif - if (autoDefault() || d->defaultButton) + if (autoDefault()) option->features |= QStyleOptionButton::AutoDefaultButton; if (d->defaultButton) option->features |= QStyleOptionButton::DefaultButton; -- cgit v1.2.3 From 50e7a5b7239f45c782f1814c185a1cdef31748d8 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 23 Oct 2012 14:36:59 +0200 Subject: QStyleAnimation: writable duration & delay properties These will be needed by upcoming QFadeStyleAnimation and QBlendStyleAnimation. Change-Id: Ibc5092d5dbd834cb9b16353d3e83b95b04d9484b Reviewed-by: Gabriel de Dietrich --- src/widgets/styles/qstyleanimation.cpp | 37 +++++++++++++++++++++++++--------- src/widgets/styles/qstyleanimation_p.h | 9 ++++++++- 2 files changed, 35 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qstyleanimation.cpp b/src/widgets/styles/qstyleanimation.cpp index 6b12ca9540..d81532f8a5 100644 --- a/src/widgets/styles/qstyleanimation.cpp +++ b/src/widgets/styles/qstyleanimation.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QStyleAnimation::QStyleAnimation(QObject *target) : QAbstractAnimation(), - _startTime(QTime::currentTime()) + _delay(0), _duration(-1), _startTime(QTime::currentTime()) { if (target) { moveToThread(target->thread()); @@ -61,14 +61,29 @@ QStyleAnimation::~QStyleAnimation() { } +QObject *QStyleAnimation::target() const +{ + return parent(); +} + int QStyleAnimation::duration() const { - return -1; + return _duration; } -QObject *QStyleAnimation::target() const +void QStyleAnimation::setDuration(int duration) { - return parent(); + _duration = duration; +} + +int QStyleAnimation::delay() const +{ + return _delay; +} + +void QStyleAnimation::setDelay(int delay) +{ + _delay = delay; } QTime QStyleAnimation::startTime() const @@ -89,7 +104,7 @@ void QStyleAnimation::updateTarget() bool QStyleAnimation::isUpdateNeeded() const { - return true; + return currentTime() > _delay; } void QStyleAnimation::updateCurrentTime(int) @@ -137,11 +152,13 @@ void QProgressStyleAnimation::setSpeed(int speed) bool QProgressStyleAnimation::isUpdateNeeded() const { - int current = animationStep(); - if (_step == -1 || _step != current) - { - _step = current; - return true; + if (QStyleAnimation::isUpdateNeeded()) { + int current = animationStep(); + if (_step == -1 || _step != current) + { + _step = current; + return true; + } } return false; } diff --git a/src/widgets/styles/qstyleanimation_p.h b/src/widgets/styles/qstyleanimation_p.h index 577b1d7dd4..3188eebebc 100644 --- a/src/widgets/styles/qstyleanimation_p.h +++ b/src/widgets/styles/qstyleanimation_p.h @@ -66,9 +66,14 @@ public: QStyleAnimation(QObject *target); virtual ~QStyleAnimation(); - int duration() const; QObject *target() const; + int duration() const; + void setDuration(int duration); + + int delay() const; + void setDelay(int delay); + QTime startTime() const; void setStartTime(const QTime &time); @@ -79,6 +84,8 @@ protected: virtual void updateCurrentTime(int time); private: + int _delay; + int _duration; QTime _startTime; }; -- cgit v1.2.3 From 611c0081ff265354405882b40b323d7cb20ca967 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 22 Oct 2012 16:39:35 +0200 Subject: Mac: Non-editable QComboBoxes shouldn't get focus by default On Mac, only line edits and list views always get tab focus. It's only when we enable full keyboard access that other controls can get tab focus. When it's not editable, a combobox looks like a button, and it behaves as such in this respect. Change-Id: Ia31b0ad01b48a47c1b81180364681d8614863106 Reviewed-by: Jens Bache-Wiig --- src/widgets/widgets/qcombobox.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 16de0da4ac..74b3dc77d3 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -919,7 +919,17 @@ QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent) void QComboBoxPrivate::init() { Q_Q(QComboBox); - q->setFocusPolicy(Qt::WheelFocus); +#ifdef Q_OS_MAC + // On Mac, only line edits and list views always get tab focus. It's only + // when we enable full keyboard access that other controls can get tab focus. + // When it's not editable, a combobox looks like a button, and it behaves as + // such in this respect. + if (!q->isEditable()) + q->setFocusPolicy(Qt::TabFocus); + else +#endif + q->setFocusPolicy(Qt::WheelFocus); + q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, QSizePolicy::ComboBox)); setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem); @@ -1655,6 +1665,10 @@ void QComboBox::setEditable(bool editable) } QLineEdit *le = new QLineEdit(this); setLineEdit(le); +#ifdef Q_OS_MAC + // See comment in QComboBoxPrivate::init() + setFocusPolicy(Qt::WheelFocus); +#endif } else { if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) { d->viewContainer()->updateScrollers(); @@ -1664,6 +1678,10 @@ void QComboBox::setEditable(bool editable) d->lineEdit->hide(); d->lineEdit->deleteLater(); d->lineEdit = 0; +#ifdef Q_OS_MAC + // See comment in QComboBoxPrivate::init() + setFocusPolicy(Qt::TabFocus); +#endif } d->viewContainer()->updateTopBottomMargin(); -- cgit v1.2.3 From dee57bc91080740201a0bf0b8c42eb374ee696f3 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 18 Oct 2012 14:29:06 +0200 Subject: Core/kernel: Make some signals private. There are more opportunities in QtCore and the rest of Qt to make signals private instead of public. This is a test-dart to see if there is any reason not to do this. It would be nice to make QObject::destroyed private, but as it has a default argument it would be source incompatible to anyone connecting to the SIGNAL(destroyed()) instead of SIGNAL(destroyed(QObject*)). Currently the function-pointer-based connect syntax does not accept a functor (or lambda) with a different number of arguments than the signal. Olivier says a fix for that might come in 5.1, but for now the qfiledialog2 test is changed to not use that anymore. Also, the function pointer for a private signal can not be assigned to a local variable, so the qmetamethod test is changed to not do so anymore. Change-Id: Iaf776b822f9ba364f2c184df0c6b23811da56e44 Reviewed-by: Olivier Goffart --- src/corelib/kernel/qcoreapplication.cpp | 2 +- src/corelib/kernel/qcoreapplication.h | 12 ++++++++++-- src/corelib/kernel/qeventdispatcher_unix.cpp | 2 +- src/corelib/kernel/qobject.cpp | 2 +- src/corelib/kernel/qobject.h | 6 +++++- src/corelib/kernel/qsocketnotifier.cpp | 2 +- src/corelib/kernel/qsocketnotifier.h | 6 +++++- src/corelib/kernel/qtimer.cpp | 2 +- src/corelib/kernel/qtimer.h | 6 +++++- src/corelib/kernel/qwineventnotifier.cpp | 2 +- src/corelib/kernel/qwineventnotifier.h | 6 +++++- 11 files changed, 36 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 55112af7ec..8ff4aa7c54 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1003,7 +1003,7 @@ int QCoreApplication::exec() if (self) { self->d_func()->in_exec = false; if (!self->d_func()->aboutToQuitEmitted) - emit self->aboutToQuit(); + emit self->aboutToQuit(QPrivateSignal()); self->d_func()->aboutToQuitEmitted = true; sendPostedEvents(0, QEvent::DeferredDelete); } diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 622139e6f8..46eab4e740 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -166,8 +166,16 @@ public Q_SLOTS: static void quit(); Q_SIGNALS: - void aboutToQuit(); - void unixSignal(int); + void aboutToQuit( +#if !defined(qdoc) + QPrivateSignal +#endif + ); + void unixSignal(int +#if !defined(qdoc) + , QPrivateSignal +#endif + ); protected: bool event(QEvent *); diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index ded1f27f4f..44715b0553 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -191,7 +191,7 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, for (int i = 0; i < NSIG; ++i) { if (signals_fired[i]) { signals_fired[i] = 0; - emit QCoreApplication::instance()->unixSignal(i); + emit QCoreApplication::instance()->unixSignal(i, QCoreApplication::QPrivateSignal()); } } } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 58e8fcb24d..268677ee1b 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1004,7 +1004,7 @@ void QObject::setObjectName(const QString &name) if (d->extraData->objectName != name) { d->extraData->objectName = name; - emit objectNameChanged(d->extraData->objectName); + emit objectNameChanged(d->extraData->objectName, QPrivateSignal()); } } diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 653cc6a42e..689946b6c4 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -348,7 +348,11 @@ public: Q_SIGNALS: void destroyed(QObject * = 0); - void objectNameChanged(const QString &objectName); + void objectNameChanged(const QString &objectName +#if !defined(qdoc) + , QPrivateSignal +#endif + ); public: inline QObject *parent() const { return d_ptr->parent; } diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp index cf65ea895c..f1b8741242 100644 --- a/src/corelib/kernel/qsocketnotifier.cpp +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -298,7 +298,7 @@ bool QSocketNotifier::event(QEvent *e) } QObject::event(e); // will activate filters if ((e->type() == QEvent::SockAct) || (e->type() == QEvent::SockClose)) { - emit activated(d->sockfd); + emit activated(d->sockfd, QPrivateSignal()); return true; } return false; diff --git a/src/corelib/kernel/qsocketnotifier.h b/src/corelib/kernel/qsocketnotifier.h index 177ce224bd..35e73b790b 100644 --- a/src/corelib/kernel/qsocketnotifier.h +++ b/src/corelib/kernel/qsocketnotifier.h @@ -69,7 +69,11 @@ public Q_SLOTS: void setEnabled(bool); Q_SIGNALS: - void activated(int socket); + void activated(int socket +#if !defined(qdoc) + , QPrivateSignal +#endif + ); protected: bool event(QEvent *); diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index a685973bd7..9dea666363 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -247,7 +247,7 @@ void QTimer::timerEvent(QTimerEvent *e) if (e->timerId() == id) { if (single) stop(); - emit timeout(); + emit timeout(QPrivateSignal()); } } diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index b934440275..a3cc1c7813 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -88,7 +88,11 @@ public Q_SLOTS: void stop(); Q_SIGNALS: - void timeout(); + void timeout( +#if !defined(qdoc) + QPrivateSignal +#endif + ); protected: void timerEvent(QTimerEvent *); diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp index 9a99b15202..44116c3333 100644 --- a/src/corelib/kernel/qwineventnotifier.cpp +++ b/src/corelib/kernel/qwineventnotifier.cpp @@ -234,7 +234,7 @@ bool QWinEventNotifier::event(QEvent * e) } QObject::event(e); // will activate filters if (e->type() == QEvent::WinEventAct) { - emit activated(d->handleToEvent); + emit activated(d->handleToEvent, QPrivateSignal()); return true; } return false; diff --git a/src/corelib/kernel/qwineventnotifier.h b/src/corelib/kernel/qwineventnotifier.h index add4059595..d5e4d0f7e3 100644 --- a/src/corelib/kernel/qwineventnotifier.h +++ b/src/corelib/kernel/qwineventnotifier.h @@ -74,7 +74,11 @@ public Q_SLOTS: void setEnabled(bool enable); Q_SIGNALS: - void activated(HANDLE hEvent); + void activated(HANDLE hEvent +#if !defined(qdoc) + , QPrivateSignal +#endif + ); protected: bool event(QEvent * e); -- cgit v1.2.3 From f42283669fca94ccb48cc589237379a7b6cefb49 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Thu, 11 Oct 2012 17:01:21 +0300 Subject: Remove stale QT_MODULE() usage cases As of Qt5, this macro is defined to be empty; simply get rid of these leftovers. Change-Id: I167ccb4c9e92ec9b5e4faeb02bf9c5ef5d982b50 Reviewed-by: Thiago Macieira --- src/corelib/io/qwinoverlappedionotifier_p.h | 2 -- src/corelib/kernel/qeventloop_p.h | 2 -- src/corelib/thread/qbasicatomic.h | 2 -- src/gui/kernel/qinputmethod.h | 2 -- src/gui/kernel/qplatformscreen_p.h | 2 -- src/gui/kernel/qplatformsharedgraphicscache.h | 2 -- src/gui/kernel/qplatformwindow_p.h | 2 -- src/gui/kernel/qscreen_p.h | 2 -- src/network/kernel/qdnslookup.h | 2 -- src/widgets/kernel/qwidgetsfunctions_wince.h | 1 - 10 files changed, 19 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qwinoverlappedionotifier_p.h b/src/corelib/io/qwinoverlappedionotifier_p.h index 326df584d7..331d915ccc 100644 --- a/src/corelib/io/qwinoverlappedionotifier_p.h +++ b/src/corelib/io/qwinoverlappedionotifier_p.h @@ -61,8 +61,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Core) - class Q_CORE_EXPORT QWinOverlappedIoNotifier : public QObject { Q_OBJECT diff --git a/src/corelib/kernel/qeventloop_p.h b/src/corelib/kernel/qeventloop_p.h index f0eec41137..9594789944 100644 --- a/src/corelib/kernel/qeventloop_p.h +++ b/src/corelib/kernel/qeventloop_p.h @@ -48,8 +48,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Core) - class QEventLoopPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QEventLoop) diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index 3e9c72b241..6072212350 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -105,8 +105,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Core) - #if 0 // silence syncqt warnings QT_END_NAMESPACE diff --git a/src/gui/kernel/qinputmethod.h b/src/gui/kernel/qinputmethod.h index 25b133ec0a..d038542dc3 100644 --- a/src/gui/kernel/qinputmethod.h +++ b/src/gui/kernel/qinputmethod.h @@ -48,8 +48,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - class QInputMethodPrivate; class QWindow; class QRectF; diff --git a/src/gui/kernel/qplatformscreen_p.h b/src/gui/kernel/qplatformscreen_p.h index 8aaa8192c8..a63f8298ec 100644 --- a/src/gui/kernel/qplatformscreen_p.h +++ b/src/gui/kernel/qplatformscreen_p.h @@ -57,8 +57,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - class QScreen; class QPlatformScreenPrivate diff --git a/src/gui/kernel/qplatformsharedgraphicscache.h b/src/gui/kernel/qplatformsharedgraphicscache.h index 9c07b0e03c..707e862fbc 100644 --- a/src/gui/kernel/qplatformsharedgraphicscache.h +++ b/src/gui/kernel/qplatformsharedgraphicscache.h @@ -58,8 +58,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - class Q_GUI_EXPORT QPlatformSharedGraphicsCache: public QObject { Q_OBJECT diff --git a/src/gui/kernel/qplatformwindow_p.h b/src/gui/kernel/qplatformwindow_p.h index f4bb8ed388..ac9abfa10b 100644 --- a/src/gui/kernel/qplatformwindow_p.h +++ b/src/gui/kernel/qplatformwindow_p.h @@ -59,8 +59,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - class QPlatformWindowPrivate { public: diff --git a/src/gui/kernel/qscreen_p.h b/src/gui/kernel/qscreen_p.h index 0bd63ca57b..f3b6082c15 100644 --- a/src/gui/kernel/qscreen_p.h +++ b/src/gui/kernel/qscreen_p.h @@ -51,8 +51,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Gui) - class QScreenPrivate : public QObjectPrivate { public: diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h index 84e5fcfb03..5218c2618a 100644 --- a/src/network/kernel/qdnslookup.h +++ b/src/network/kernel/qdnslookup.h @@ -52,8 +52,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Network) - class QHostAddress; class QDnsLookupPrivate; class QDnsDomainNameRecordPrivate; diff --git a/src/widgets/kernel/qwidgetsfunctions_wince.h b/src/widgets/kernel/qwidgetsfunctions_wince.h index e52fbea63a..39d29b83ad 100644 --- a/src/widgets/kernel/qwidgetsfunctions_wince.h +++ b/src/widgets/kernel/qwidgetsfunctions_wince.h @@ -46,7 +46,6 @@ #ifdef QT_BUILD_GUI_LIB QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -QT_MODULE(Gui) QT_END_NAMESPACE QT_END_HEADER #endif -- cgit v1.2.3 From 38630bc35af614ddebade70b9a44574c162ce4a9 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Mon, 22 Oct 2012 19:27:31 +0300 Subject: QTextEngine: Support SMP code points when case changing Semi-related to QTBUG-17337 Change-Id: I6b42c0f7e588bbeab27bf410fcdfa1a6f80e4ac2 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qtextengine.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 025d4289aa..82cff6a043 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1015,10 +1015,22 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const casedString.resize(entire_shaper_item.item.length); HB_UChar16 *uc = casedString.data(); for (uint i = 0; i < entire_shaper_item.item.length; ++i) { - if(si.analysis.flags == QScriptAnalysis::Lowercase) - uc[i] = QChar::toLower(entire_shaper_item.string[si.position + i]); - else - uc[i] = QChar::toUpper(entire_shaper_item.string[si.position + i]); + uint ucs4 = entire_shaper_item.string[si.position + i]; + if (QChar::isHighSurrogate(ucs4)) { + uc[i] = ucs4; // high part never changes in simple casing + if (i + 1 < entire_shaper_item.item.length) { + ushort low = entire_shaper_item.string[si.position + i + 1]; + if (QChar::isLowSurrogate(low)) { + ucs4 = QChar::surrogateToUcs4(ucs4, low); + ucs4 = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) + : QChar::toUpper(ucs4); + uc[++i] = QChar::lowSurrogate(ucs4); + } + } + } else { + uc[i] = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4) + : QChar::toUpper(ucs4); + } } entire_shaper_item.item.pos = 0; entire_shaper_item.string = uc; -- cgit v1.2.3 From 79a389c34618880fab7a0b4f397ed3b0f0c0c675 Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Tue, 23 Oct 2012 18:34:25 +0200 Subject: Remove widget dependencies on Vista style animations This patch will make it possible to get animations on desktop components without using the widget pointer. Change-Id: I2d2eca111dab0d96f276ff3627505c0652c4b4e5 Reviewed-by: J-P Nurmi --- src/widgets/styles/qwindowsvistastyle.cpp | 679 +++++++++++++++--------------- 1 file changed, 350 insertions(+), 329 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index d58e76e043..87c67dc84b 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -144,6 +144,20 @@ bool QWindowsVistaStylePrivate::useVista() (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))); } +/* \internal + Checks and returns the style object +*/ +inline QObject *styleObject(const QStyleOption *option) { + return option ? option->styleObject : 0; +} + +bool canAnimate(const QStyleOption *option) { + return option + && option->styleObject + && !option->styleObject->property("_q_no_animation").toBool(); +} + + /*! \class QWindowsVistaStyle \brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista. @@ -328,17 +342,17 @@ void QWindowsVistaPulse::paint(QPainter *painter, const QStyleOption *option) transition has completed. During this time, the result will be retrieved by the Animation::paint(...) function and not by the style itself. - + To determine if a transition should occur, the style needs to know the previous state of the widget as well as the current one. This is solved by updating dynamic properties on the widget every time the function is called. - + Transitions interrupting existing transitions should always be smooth, so whenever a hover-transition is started on a pulsating button, it uses the current frame of the pulse-animation as the starting image for the hover transition. - + */ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const @@ -353,135 +367,135 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt return; } - QRect oldRect; - QRect newRect; - - if (widget && d->transitionsEnabled()) - { - /* all widgets that supports state transitions : */ - if ( -#ifndef QT_NO_LINEEDIT - (qobject_cast(widget) && element == PE_FrameLineEdit) || -#endif // QT_NO_LINEEDIT - (qobject_cast(widget)&& element == PE_IndicatorRadioButton) || - (qobject_cast(widget) && element == PE_IndicatorCheckBox) || - (qobject_cast(widget)&& element == PE_IndicatorCheckBox) || - (qobject_cast(widget) && element == PE_PanelButtonBevel) - ) + if (d->transitionsEnabled() && canAnimate(option)) { { - // Retrieve and update the dynamic properties tracking - // the previous state of the widget: - QWidget *w = const_cast (widget); - int oldState = w->property("_q_stylestate").toInt(); - oldRect = w->property("_q_stylerect").toRect(); - newRect = w->rect(); - w->setProperty("_q_stylestate", (int)option->state); - w->setProperty("_q_stylerect", w->rect()); - - bool doTransition = oldState && - ((state & State_Sunken) != (oldState & State_Sunken) || - (state & State_On) != (oldState & State_On) || - (state & State_MouseOver) != (oldState & State_MouseOver)); - - if (oldRect != newRect || - (state & State_Enabled) != (oldState & State_Enabled) || - (state & State_Active) != (oldState & State_Active)) - d->stopAnimation(widget); + QRect oldRect; + QRect newRect; -#ifndef QT_NO_LINEEDIT - if (const QLineEdit *edit = qobject_cast(widget)) - if (edit->isReadOnly() && element == PE_FrameLineEdit) // Do not animate read only line edits + /* widgets that support state transitions : */ + if ( element == PE_FrameLineEdit + || element == PE_IndicatorRadioButton + || element == PE_IndicatorCheckBox) + { + // Retrieve and update the dynamic properties tracking + // the previous state of the widget: + QObject *styleObject = option->styleObject; + styleObject->setProperty("_q_no_animation", true); + + int oldState = styleObject->property("_q_stylestate").toInt(); + oldRect = styleObject->property("_q_stylerect").toRect(); + newRect = option->rect; + styleObject->setProperty("_q_stylestate", (int)option->state); + styleObject->setProperty("_q_stylerect", option->rect); + + bool doTransition = oldState && + ((state & State_Sunken) != (oldState & State_Sunken) || + (state & State_On) != (oldState & State_On) || + (state & State_MouseOver) != (oldState & State_MouseOver)); + + if (oldRect != newRect || + (state & State_Enabled) != (oldState & State_Enabled) || + (state & State_Active) != (oldState & State_Active)) + d->stopAnimation(styleObject); + + if (option->state & State_ReadOnly && element == PE_FrameLineEdit) // Do not animate read only line edits doTransition = false; -#endif // QT_NO_LINEEDIT - if (doTransition) { + if (doTransition) { + QStyleOption *styleOption = 0; + if (const QStyleOptionGroupBox *combo = qstyleoption_cast(option)) + styleOption = new QStyleOptionGroupBox(*combo); + else + styleOption = new QStyleOption(*option); - // We create separate images for the initial and final transition states and store them in the - // Transition object. - QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - QStyleOption opt = *option; + styleOption->state = (QStyle::State)oldState; + styleOption->rect = QRect(QPoint(0,0), newRect.size()); - opt.rect.setRect(0, 0, option->rect.width(), option->rect.height()); - opt.state = (QStyle::State)oldState; - startImage.fill(0); - QPainter startPainter(&startImage); + QWindowsVistaAnimation *anim = qobject_cast(d->animation(styleObject)); + QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject); - QWindowsVistaAnimation *anim = qobject_cast(d->animation(widget)); - QWindowsVistaTransition *t = new QWindowsVistaTransition(w); + // We create separate images for the initial and final transition states and store them in the + // Transition object. + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + startImage.fill(0); + QPainter startPainter(&startImage); - // If we have a running animation on the widget already, we will use that to paint the initial - // state of the new transition, this ensures a smooth transition from a current animation such as a - // pulsating default button into the intended target state. + QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + endImage.fill(0); + QPainter endPainter(&endImage); - if (!anim) - proxy()->drawPrimitive(element, &opt, &startPainter, 0); // Note that the widget pointer is intentionally 0 - else // this ensures that we do not recurse in the animation logic above - anim->paint(&startPainter, &opt); + // If we have a running animation on the widget already, we will use that to paint the initial + // state of the new transition, this ensures a smooth transition from a current animation such as a + // pulsating default button into the intended target state. + if (!anim) + proxy()->drawPrimitive(element, styleOption, &startPainter, widget); + else + anim->paint(&startPainter, styleOption); - d->startAnimation(t); - t->setStartImage(startImage); + t->setStartImage(startImage); - // The end state of the transition is simply the result we would have painted - // if the style was not animated. + // The end state of the transition is simply the result we would have painted + // if the style was not animated. + styleOption->state = option->state; + drawPrimitive(element, styleOption, &endPainter, widget); - QPainter endPainter(&endImage); - endImage.fill(0); - QStyleOption opt2 = opt; - opt2.state = option->state; - proxy()->drawPrimitive(element, &opt2, &endPainter, 0); // Note that the widget pointer is intentionally 0 - // this ensures that we do not recurse in the animation logic above - t->setEndImage(endImage); - HTHEME theme; - int partId; - int duration; - int fromState = 0; - int toState = 0; + t->setEndImage(endImage); - //translate state flags to UXTHEME states : - if (element == PE_FrameLineEdit) { - theme = pOpenThemeData(0, L"Edit"); - partId = EP_EDITBORDER_NOSCROLL; + HTHEME theme; + int partId; + int duration; + int fromState = 0; + int toState = 0; + + //translate state flags to UXTHEME states : + if (element == PE_FrameLineEdit) { + theme = pOpenThemeData(0, L"Edit"); + partId = EP_EDITBORDER_NOSCROLL; + + if (oldState & State_MouseOver) + fromState = ETS_HOT; + else if (oldState & State_HasFocus) + fromState = ETS_FOCUSED; + else + fromState = ETS_NORMAL; - if (oldState & State_MouseOver) - fromState = ETS_HOT; - else if (oldState & State_HasFocus) - fromState = ETS_FOCUSED; - else - fromState = ETS_NORMAL; + if (state & State_MouseOver) + toState = ETS_HOT; + else if (state & State_HasFocus) + toState = ETS_FOCUSED; + else + toState = ETS_NORMAL; - if (state & State_MouseOver) - toState = ETS_HOT; - else if (state & State_HasFocus) - toState = ETS_FOCUSED; - else - toState = ETS_NORMAL; + } else { + theme = pOpenThemeData(0, L"Button"); + if (element == PE_IndicatorRadioButton) + partId = BP_RADIOBUTTON; + else if (element == PE_IndicatorCheckBox) + partId = BP_CHECKBOX; + else + partId = BP_PUSHBUTTON; - } else { - theme = pOpenThemeData(0, L"Button"); - if (element == PE_IndicatorRadioButton) - partId = BP_RADIOBUTTON; - else if (element == PE_IndicatorCheckBox) - partId = BP_CHECKBOX; - else - partId = BP_PUSHBUTTON; + fromState = buttonStateId(oldState, partId); + toState = buttonStateId(option->state, partId); + } - fromState = buttonStateId(oldState, partId); - toState = buttonStateId(option->state, partId); - } + // Retrieve the transition time between the states from the system. + if (theme && pGetThemeTransitionDuration(theme, partId, fromState, toState, + TMT_TRANSITIONDURATIONS, &duration) == S_OK) + { + t->setDuration(duration); + } + t->setStartTime(QTime::currentTime()); - // Retrieve the transition time between the states from the system. - if (theme && pGetThemeTransitionDuration(theme, partId, fromState, toState, - TMT_TRANSITIONDURATIONS, &duration) == S_OK) - { - t->setDuration(duration); + delete styleOption; + d->startAnimation(t); } - t->setStartTime(QTime::currentTime()); + styleObject->setProperty("_q_no_animation", false); } - } - } // End of animation part + } // End of animation part + } QRect rect = option->rect; @@ -546,7 +560,8 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt case PE_IndicatorCheckBox: case PE_IndicatorRadioButton: { - if (QWindowsVistaAnimation *a = qobject_cast(d->animation(widget)) ){ + if (QWindowsVistaAnimation *a = + qobject_cast(d->animation(styleObject(option)))){ a->paint(painter, option); } else { QWindowsXPStyle::drawPrimitive(element, option, painter, widget); @@ -563,36 +578,32 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt d->drawBackground(theme); } break; - case PE_Frame: -#ifndef QT_NO_TEXTEDIT - if (const QTextEdit *edit = qobject_cast(widget)) { - painter->save(); - int stateId = ETS_NORMAL; - if (!(state & State_Enabled)) - stateId = ETS_DISABLED; - else if (edit->isReadOnly()) - stateId = ETS_READONLY; - else if (state & State_HasFocus) - stateId = ETS_SELECTED; - XPThemeData theme(widget, painter, - QWindowsXPStylePrivate::EditTheme, - EP_EDITBORDER_HVSCROLL, stateId, option->rect); - uint resolve_mask = option->palette.resolve(); - if (resolve_mask & (1 << QPalette::Base)) { - // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping - int borderSize = 1; - pGetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize); - QRegion clipRegion = option->rect; - QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize); - clipRegion ^= content; - painter->setClipRegion(clipRegion); - } - d->drawBackground(theme); - painter->restore(); - } else -#endif // QT_NO_TEXTEDIT - QWindowsXPStyle::drawPrimitive(element, option, painter, widget); - break; + case PE_Frame: { + painter->save(); + int stateId = ETS_NORMAL; + if (!(state & State_Enabled)) + stateId = ETS_DISABLED; + else if (state & State_ReadOnly) + stateId = ETS_READONLY; + else if (state & State_HasFocus) + stateId = ETS_SELECTED; + XPThemeData theme(widget, painter, + QWindowsXPStylePrivate::EditTheme, + EP_EDITBORDER_HVSCROLL, stateId, option->rect); + uint resolve_mask = option->palette.resolve(); + if (resolve_mask & (1 << QPalette::Base)) { + // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping + int borderSize = 1; + pGetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize); + QRegion clipRegion = option->rect; + QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize); + clipRegion ^= content; + painter->setClipRegion(clipRegion); + } + d->drawBackground(theme); + painter->restore(); + } + break; case PE_PanelLineEdit: if (const QStyleOptionFrame *panel = qstyleoption_cast(option)) { @@ -662,7 +673,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt break; case PE_FrameLineEdit: - if (QWindowsVistaAnimation *anim = qobject_cast(d->animation(widget))) { + if (QWindowsVistaAnimation *anim = qobject_cast(d->animation(styleObject(option)))) { anim->paint(painter, option); } else { QPainter *p = painter; @@ -928,145 +939,166 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption int partId = 0; int stateId = 0; - QRect oldRect; - QRect newRect; + if (d->transitionsEnabled() && canAnimate(option)) + { + if (element == CE_PushButtonBevel) { + QRect oldRect; + QRect newRect; + + QObject *styleObject = option->styleObject; + + int oldState = styleObject->property("_q_stylestate").toInt(); + oldRect = styleObject->property("_q_stylerect").toRect(); + newRect = option->rect; + styleObject->setProperty("_q_stylestate", (int)option->state); + styleObject->setProperty("_q_stylerect", option->rect); + + bool wasDefault = false; + bool isDefault = false; + if (const QStyleOptionButton *button = qstyleoption_cast(option)) { + wasDefault = styleObject->property("_q_isdefault").toBool(); + isDefault = button->features & QStyleOptionButton::DefaultButton; + styleObject->setProperty("_q_isdefault", isDefault); + } - if (d->transitionsEnabled() && widget) { - if (const QStyleOptionButton *button = qstyleoption_cast(option)) { - if ((qobject_cast(widget) && element == CE_PushButtonBevel)) - { - QWidget *w = const_cast (widget); - int oldState = w->property("_q_stylestate").toInt(); - oldRect = w->property("_q_stylerect").toRect(); - newRect = w->rect(); - w->setProperty("_q_stylestate", (int)option->state); - w->setProperty("_q_stylerect", w->rect()); - - bool wasDefault = w->property("_q_isdefault").toBool(); - bool isDefault = button->features & QStyleOptionButton::DefaultButton; - w->setProperty("_q_isdefault", isDefault); - - bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || - (state & State_On) != (oldState & State_On) || - (state & State_MouseOver) != (oldState & State_MouseOver)); - - if (oldRect != newRect || (wasDefault && !isDefault)) - { - doTransition = false; - d->stopAnimation(widget); - } + bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || + (state & State_On) != (oldState & State_On) || + (state & State_MouseOver) != (oldState & State_MouseOver)); - if (doTransition) { - QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - QWindowsVistaAnimation *anim = qobject_cast(d->animation(widget)); + if (oldRect != newRect || (wasDefault && !isDefault)) { + doTransition = false; + d->stopAnimation(styleObject); + } - QStyleOptionButton opt = *button; - opt.state = (QStyle::State)oldState; + if (doTransition) { + styleObject->setProperty("_q_no_animation", true); + + QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject); + QWindowsVistaAnimation *anim = qobject_cast(d->animation(styleObject)); + QStyleOption *styleOption = 0; + if (const QStyleOptionComboBox *combo = qstyleoption_cast(option)) + styleOption = new QStyleOptionComboBox(*combo); + else if (const QStyleOptionButton *button = qstyleoption_cast(option)) + styleOption = new QStyleOptionButton(*button); + else + styleOption = new QStyleOption(*option); - startImage.fill(0); - QWindowsVistaTransition *t = new QWindowsVistaTransition(w); - QPainter startPainter(&startImage); + styleOption->state = (QStyle::State)oldState; + styleOption->rect = QRect(QPoint(0,0), newRect.size()); - if (!anim) { - proxy()->drawControl(element, &opt, &startPainter, 0 /* Intentional */); - } else { - anim->paint(&startPainter, &opt); - d->stopAnimation(widget); - } + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + startImage.fill(0); + QPainter startPainter(&startImage); - t->setStartImage(startImage); - d->startAnimation(t); + // Use current state of existing animation if already one is running + if (!anim) { + proxy()->drawControl(element, styleOption, &startPainter, widget); + } else { + anim->paint(&startPainter, styleOption); + d->stopAnimation(styleObject); + } - endImage.fill(0); - QPainter endPainter(&endImage); - proxy()->drawControl(element, option, &endPainter, 0 /* Intentional */); - t->setEndImage(endImage); - int duration = 0; - HTHEME theme = pOpenThemeData(0, L"Button"); + t->setStartImage(startImage); + QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + endImage.fill(0); + QPainter endPainter(&endImage); + styleOption->state = option->state; + proxy()->drawControl(element, styleOption, &endPainter, widget); + t->setEndImage(endImage); - int fromState = buttonStateId(oldState, BP_PUSHBUTTON); - int toState = buttonStateId(option->state, BP_PUSHBUTTON); - if (pGetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK) - t->setDuration(duration); - else - t->setDuration(0); - t->setStartTime(QTime::currentTime()); - } + + int duration = 0; + HTHEME theme = pOpenThemeData(0, L"Button"); + + int fromState = buttonStateId(oldState, BP_PUSHBUTTON); + int toState = buttonStateId(option->state, BP_PUSHBUTTON); + if (pGetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK) + t->setDuration(duration); + else + t->setDuration(0); + t->setStartTime(QTime::currentTime()); + styleObject->setProperty("_q_no_animation", false); + + delete styleOption; + d->startAnimation(t); + } + + QWindowsVistaAnimation *anim = qobject_cast(d->animation(styleObject)); + if (anim) { + anim->paint(painter, option); + return; } + } } switch (element) { case CE_PushButtonBevel: if (const QStyleOptionButton *btn = qstyleoption_cast(option)) { - QWindowsVistaAnimation *anim = qobject_cast(d->animation(widget)); - if (anim && (btn->state & State_Enabled)) { - anim->paint(painter, option); - } else { - themeNumber = QWindowsXPStylePrivate::ButtonTheme; - partId = BP_PUSHBUTTON; - if (btn->features & QStyleOptionButton::CommandLinkButton) - partId = BP_COMMANDLINK; - bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken)); - if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat)) - stateId = PBS_DISABLED; - else if (justFlat) - ; - else if (flags & (State_Sunken | State_On)) - stateId = PBS_PRESSED; - else if (flags & State_MouseOver) - stateId = PBS_HOT; - else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active)) - stateId = PBS_DEFAULTED; - else - stateId = PBS_NORMAL; + themeNumber = QWindowsXPStylePrivate::ButtonTheme; + partId = BP_PUSHBUTTON; + if (btn->features & QStyleOptionButton::CommandLinkButton) + partId = BP_COMMANDLINK; + bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken)); + if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat)) + stateId = PBS_DISABLED; + else if (justFlat) + ; + else if (flags & (State_Sunken | State_On)) + stateId = PBS_PRESSED; + else if (flags & State_MouseOver) + stateId = PBS_HOT; + else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active)) + stateId = PBS_DEFAULTED; + else + stateId = PBS_NORMAL; - if (!justFlat) { + if (!justFlat) { - if (widget && d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) && + if (d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) && !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) && - (state & State_Enabled) && (state & State_Active)) - { - if (!anim && widget) { - QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - startImage.fill(0); - QImage alternateImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - alternateImage.fill(0); - - QWindowsVistaPulse *pulse = new QWindowsVistaPulse(const_cast(widget)); - - QPainter startPainter(&startImage); - stateId = PBS_DEFAULTED; - XPThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect); - d->drawBackground(theme); - - QPainter alternatePainter(&alternateImage); - theme.stateId = PBS_DEFAULTED_ANIMATING; - theme.painter = &alternatePainter; - d->drawBackground(theme); - pulse->setPrimaryImage(startImage); - pulse->setAlternateImage(alternateImage); - pulse->setStartTime(QTime::currentTime()); - pulse->setDuration(2000); - d->startAnimation(pulse); - anim = pulse; - } + (state & State_Enabled) && (state & State_Active)) + { + QWindowsVistaAnimation *anim = qobject_cast(d->animation(styleObject(option))); - if (anim) - anim->paint(painter, option); - else { - XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect); - d->drawBackground(theme); - } + if (!anim) { + QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + startImage.fill(0); + QImage alternateImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + alternateImage.fill(0); + + QWindowsVistaPulse *pulse = new QWindowsVistaPulse(styleObject(option)); + + QPainter startPainter(&startImage); + stateId = PBS_DEFAULTED; + XPThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect); + d->drawBackground(theme); + + QPainter alternatePainter(&alternateImage); + theme.stateId = PBS_DEFAULTED_ANIMATING; + theme.painter = &alternatePainter; + d->drawBackground(theme); + pulse->setPrimaryImage(startImage); + pulse->setAlternateImage(alternateImage); + pulse->setStartTime(QTime::currentTime()); + pulse->setDuration(2000); + d->startAnimation(pulse); + anim = pulse; } + + if (anim) + anim->paint(painter, option); else { - d->stopAnimation(widget); XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect); d->drawBackground(theme); } } + else { + XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect); + d->drawBackground(theme); + } } + if (btn->features & QStyleOptionButton::HasMenu) { int mbiw = 0, mbih = 0; XPThemeData theme(widget, 0, QWindowsXPStylePrivate::ToolBarTheme, @@ -1102,10 +1134,10 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) { - if (!d->animation(option->styleObject)) - d->startAnimation(new QProgressStyleAnimation(d->animationFps, option->styleObject)); + if (!d->animation(styleObject(option))) + d->startAnimation(new QProgressStyleAnimation(d->animationFps, styleObject(option))); } else { - d->stopAnimation(option->styleObject); + d->stopAnimation(styleObject(option)); } XPThemeData theme(widget, painter, @@ -1116,7 +1148,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption QTime current = QTime::currentTime(); if (isIndeterminate) { - if (QProgressStyleAnimation *a = qobject_cast(d->animation(option->styleObject))) { + if (QProgressStyleAnimation *a = qobject_cast(d->animation(styleObject(option)))) { int glowSize = 120; int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width()); int animOffset = a->startTime().msecsTo(current) / 4; @@ -1186,7 +1218,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } d->drawBackground(theme); - if (QProgressStyleAnimation *a = qobject_cast(d->animation(option->styleObject))) { + if (QProgressStyleAnimation *a = qobject_cast(d->animation(styleObject(option)))) { int glowSize = 140; int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width()); int animOffset = a->startTime().msecsTo(current) / 4; @@ -1195,7 +1227,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (bar->progress < bar->maximum) a->setStartTime(QTime::currentTime()); else - d->stopAnimation(option->styleObject); //we stop the glow motion only after it has + d->stopAnimation(styleObject(option)); //we stop the glow motion only after it has //moved out of view } painter->save(); @@ -1592,38 +1624,33 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow()) flags |= State_MouseOver; - if (d->transitionsEnabled() && widget) { - if ((qobject_cast(widget) && control == CC_ScrollBar) -#ifndef QT_NO_SPINBOX - || (qobject_cast(widget) && control == CC_SpinBox) -#endif // QT_NO_SPINBOX -#ifndef QT_NO_COMBOBOX - || (qobject_cast(widget) && control == CC_ComboBox) -#endif // QT_NO_COMBOBOX - ) - { - QWidget *w = const_cast (widget); + if (d->transitionsEnabled() && canAnimate(option)) + { + + if (control == CC_ScrollBar || control == CC_SpinBox ) { + + QObject *styleObject = option->styleObject; // Can be widget or qquickitem - int oldState = w->property("_q_stylestate").toInt(); - int oldActiveControls = w->property("_q_stylecontrols").toInt(); - QRect oldRect = w->property("_q_stylerect").toRect(); - w->setProperty("_q_stylestate", (int)option->state); - w->setProperty("_q_stylecontrols", (int)option->activeSubControls); - w->setProperty("_q_stylerect", w->rect()); + int oldState = styleObject->property("_q_stylestate").toInt(); + int oldActiveControls = styleObject->property("_q_stylecontrols").toInt(); + + QRect oldRect = styleObject->property("_q_stylerect").toRect(); + styleObject->setProperty("_q_stylestate", (int)option->state); + styleObject->setProperty("_q_stylecontrols", (int)option->activeSubControls); + styleObject->setProperty("_q_stylerect", option->rect); bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) || (state & State_On) != (oldState & State_On) || (state & State_MouseOver) != (oldState & State_MouseOver) || - oldActiveControls != option->activeSubControls); - + oldActiveControls != option->activeSubControls); if (qstyleoption_cast(option)) { - QRect oldSliderPos = w->property("_q_stylesliderpos").toRect(); + QRect oldSliderPos = styleObject->property("_q_stylesliderpos").toRect(); QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget); - w->setProperty("_q_stylesliderpos", currentPos); + styleObject->setProperty("_q_stylesliderpos", currentPos); if (oldSliderPos != currentPos) { doTransition = false; - d->stopAnimation(widget); + d->stopAnimation(styleObject); } } else if (control == CC_SpinBox) { //spinboxes have a transition when focus changes @@ -1633,58 +1660,51 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle if (oldRect != option->rect) { doTransition = false; - d->stopAnimation(widget); + d->stopAnimation(styleObject); } if (doTransition) { QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); + startImage.fill(0); + QPainter startPainter(&startImage); + QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - QWindowsVistaAnimation *anim = qobject_cast(d->animation(widget)); - QWindowsVistaTransition *t = new QWindowsVistaTransition(w); + endImage.fill(0); + QPainter endPainter(&endImage); + + QWindowsVistaAnimation *anim = qobject_cast(d->animation(styleObject)); + QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject); + + // Draw the image that ends the animation by using the current styleoption + QStyleOptionComplex *styleOption = 0; + if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) + styleOption = new QStyleOptionSlider(*slider); + else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast(option)) + styleOption = new QStyleOptionSpinBox(*spinbox); + else + styleOption = new QStyleOptionComplex(*option); + + styleOption->rect = QRect(QPoint(0,0), option->rect.size()); + + styleObject->setProperty("_q_no_animation", true); + + // Draw transition source if (!anim) { - if (const QStyleOptionComboBox *combo = qstyleoption_cast(option)) { - //Combo boxes are special cased to avoid cleartype issues - startImage.fill(0); - QPainter startPainter(&startImage); - QStyleOptionComboBox startCombo = *combo; - startCombo.state = (QStyle::State)oldState; - startCombo.activeSubControls = (QStyle::SubControl)oldActiveControls; - proxy()->drawComplexControl(control, &startCombo, &startPainter, 0 /* Intentional */); - t->setStartImage(startImage); - } else if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { - //This is a workaround for the direct3d engine as it currently has some issues with grabWindow - startImage.fill(0); - QPainter startPainter(&startImage); - QStyleOptionSlider startSlider = *slider; - startSlider.state = (QStyle::State)oldState; - startSlider.activeSubControls = (QStyle::SubControl)oldActiveControls; - proxy()->drawComplexControl(control, &startSlider, &startPainter, 0 /* Intentional */); - t->setStartImage(startImage); - } else { - QPoint offset(0, 0); - QWindow *window = widget->windowHandle(); - if (!window) { - if (const QWidget *nativeParent = widget->nativeParentWidget()) { - offset = widget->mapTo(nativeParent, offset); - window = nativeParent->windowHandle(); - } - } - if (window && window->handle()) { - const QPixmap pixmap = window->screen()->grabWindow(window->winId(), - offset.x(), offset.y(), option->rect.width(), option->rect.height()); - t->setStartImage(pixmap.toImage()); - } - } + styleOption->state = (QStyle::State)oldState; + styleOption->activeSubControls = (QStyle::SubControl)oldActiveControls; + proxy()->drawComplexControl(control, styleOption, &startPainter, widget); } else { - startImage.fill(0); - QPainter startPainter(&startImage); anim->paint(&startPainter, option); - t->setStartImage(startImage); } - d->startAnimation(t); - endImage.fill(0); - QPainter endPainter(&endImage); - proxy()->drawComplexControl(control, option, &endPainter, 0 /* Intentional */); + t->setStartImage(startImage); + + // Draw transition target + styleOption->state = option->state; + styleOption->activeSubControls = option->activeSubControls; + proxy()->drawComplexControl(control, styleOption, &endPainter, widget); + + styleObject->setProperty("_q_no_animation", false); + t->setEndImage(endImage); t->setStartTime(QTime::currentTime()); @@ -1692,13 +1712,14 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle t->setDuration(150); else t->setDuration(500); - } - if (QWindowsVistaAnimation *anim = qobject_cast(d->animation(widget))) { + delete styleOption; + d->startAnimation(t); + } + if (QWindowsVistaAnimation *anim = qobject_cast(d->animation(styleObject))) { anim->paint(painter, option); return; } - } } -- cgit v1.2.3 From 4b1e476da085fd2f7a44113c4e2c7e6ddaa208aa Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Mon, 15 Oct 2012 14:35:19 +0200 Subject: Happy Eyeballs: Make sure that we commit the address type for SSL connections _q_connected checks if pendingEncrypt is false before committing the address type. This could be used to delay the commit but nothing is done later in _q_encrypted, so the commit is avoided completely. This causes SSL connections on a network without IPV6 support to hang if the domain name record contains both IPV4 and IPV6 addresses. As SSL is handled a few layers above IP, there should be no reason to avoid/delay committing the address type if the TCP connection was established surccessfully. Thus this patch is removing the check completely. Change-Id: If56a3365f9f51712b4aae3f7902711711ace86fd Reviewed-by: Shane Kearns --- .../access/qhttpnetworkconnectionchannel.cpp | 42 +++++++++++----------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index a3e46d8cd2..51076c6c22 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -1025,31 +1025,29 @@ void QHttpNetworkConnectionChannel::_q_disconnected() void QHttpNetworkConnectionChannel::_q_connected() { // For the Happy Eyeballs we need to check if this is the first channel to connect. - if (!pendingEncrypt) { - if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::InProgress) { - if (connection->d_func()->delayedConnectionTimer.isActive()) - connection->d_func()->delayedConnectionTimer.stop(); - if (networkLayerPreference == QAbstractSocket::IPv4Protocol) + if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::InProgress) { + if (connection->d_func()->delayedConnectionTimer.isActive()) + connection->d_func()->delayedConnectionTimer.stop(); + if (networkLayerPreference == QAbstractSocket::IPv4Protocol) + connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4; + else if (networkLayerPreference == QAbstractSocket::IPv6Protocol) + connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6; + else { + if (socket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol) connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4; - else if (networkLayerPreference == QAbstractSocket::IPv6Protocol) + else connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6; - else { - if (socket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol) - connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4; - else - connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6; - } - connection->d_func()->networkLayerDetected(networkLayerPreference); - } else { - if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4) && (networkLayerPreference != QAbstractSocket::IPv4Protocol)) - || ((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv6) && (networkLayerPreference != QAbstractSocket::IPv6Protocol))) { - close(); - // This is the second connection so it has to be closed and we can schedule it for another request. - QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); - return; - } - //The connections networkLayerState had already been decided. } + connection->d_func()->networkLayerDetected(networkLayerPreference); + } else { + if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4) && (networkLayerPreference != QAbstractSocket::IPv4Protocol)) + || ((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv6) && (networkLayerPreference != QAbstractSocket::IPv6Protocol))) { + close(); + // This is the second connection so it has to be closed and we can schedule it for another request. + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); + return; + } + //The connections networkLayerState had already been decided. } // improve performance since we get the request sent by the kernel ASAP -- cgit v1.2.3 From c6151b75b09f1b5891ea50a80e78be8f37469cb9 Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Wed, 17 Oct 2012 16:11:58 +0200 Subject: Remove Windows as a dependency of mac style There is not need to have this dependency any more since mac is overriding anything we depend on in Windows style anyway. Change-Id: I8fe0e0cc949265170947b492e04e08fdd4cf5027 Reviewed-by: Jens Bache-Wiig Reviewed-by: Gabriel de Dietrich --- src/widgets/styles/qmacstyle_mac.h | 4 +- src/widgets/styles/qmacstyle_mac.mm | 141 ++++++++++++++++++++++++----------- src/widgets/styles/qmacstyle_mac_p.h | 4 +- 3 files changed, 103 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qmacstyle_mac.h b/src/widgets/styles/qmacstyle_mac.h index 50eff86ec0..60d5ec21eb 100644 --- a/src/widgets/styles/qmacstyle_mac.h +++ b/src/widgets/styles/qmacstyle_mac.h @@ -42,7 +42,7 @@ #ifndef QMACSTYLE_MAC_H #define QMACSTYLE_MAC_H -#include +#include QT_BEGIN_HEADER @@ -62,7 +62,7 @@ class QPalette; class QPushButton; class QStyleOptionButton; class QMacStylePrivate; -class Q_WIDGETS_EXPORT_STYLE_MAC QMacStyle : public QWindowsStyle +class Q_WIDGETS_EXPORT_STYLE_MAC QMacStyle : public QCommonStyle { Q_OBJECT public: diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index a227e06d77..f1d513bc23 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1891,7 +1891,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD } QMacStyle::QMacStyle() - : QWindowsStyle(*new QMacStylePrivate) + : QCommonStyle(*new QMacStylePrivate) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 Q_D(QMacStyle); @@ -2054,7 +2054,7 @@ void QMacStyle::polish(QWidget* w) } } - QWindowsStyle::polish(w); + QCommonStyle::polish(w); if (QRubberBand *rubber = qobject_cast(w)) { rubber->setWindowOpacity(0.25); @@ -2094,7 +2094,7 @@ void QMacStyle::unpolish(QWidget* w) if (QFocusFrame *frame = qobject_cast(w)) frame->setAttribute(Qt::WA_NoSystemBackground, true); - QWindowsStyle::unpolish(w); + QCommonStyle::unpolish(w); if (qobject_cast(w)) { w->setAttribute(Qt::WA_OpaquePaintEvent, true); @@ -2205,6 +2205,47 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW case PM_SliderLength: ret = 17; break; + // Returns the number of pixels to use for the business part of the + // slider (i.e., the non-tickmark portion). The remaining space is shared + // equally between the tickmark regions. + case PM_SliderControlThickness: + if (const QStyleOptionSlider *sl = qstyleoption_cast(opt)) { + int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width(); + int ticks = sl->tickPosition; + int n = 0; + if (ticks & QSlider::TicksAbove) + ++n; + if (ticks & QSlider::TicksBelow) + ++n; + if (!n) { + ret = space; + break; + } + + int thick = 6; // Magic constant to get 5 + 16 + 5 + if (ticks != QSlider::TicksBothSides && ticks != QSlider::NoTicks) + thick += proxy()->pixelMetric(PM_SliderLength, sl, widget) / 4; + + space -= thick; + if (space > 0) + thick += (space * 2) / (n + 2); + ret = thick; + } else { + ret = 0; + } + break; + case PM_SmallIconSize: + ret = int(QStyleHelper::dpiScaled(16.)); + break; + + case PM_LargeIconSize: + ret = int(QStyleHelper::dpiScaled(32.)); + break; + + case PM_IconViewIconSize: + ret = proxy()->pixelMetric(PM_LargeIconSize, opt, widget); + break; + case PM_ButtonDefaultIndicator: ret = 0; break; @@ -2452,7 +2493,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW switch (d->aquaSizeConstrain(opt, widget)) { case QAquaSizeLarge: case QAquaSizeUnknown: - ret = QWindowsStyle::pixelMetric(metric, opt, widget); + ret = QCommonStyle::pixelMetric(metric, opt, widget); break; case QAquaSizeSmall: ret = 20; @@ -2483,7 +2524,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW #endif break; default: - ret = QWindowsStyle::pixelMetric(metric, opt, widget); + ret = QCommonStyle::pixelMetric(metric, opt, widget); break; } return ret; @@ -2491,7 +2532,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW QPalette QMacStyle::standardPalette() const { - QPalette pal = QWindowsStyle::standardPalette(); + QPalette pal = QCommonStyle::standardPalette(); pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191)); pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191)); pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191)); @@ -2503,6 +2544,22 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w { SInt32 ret = 0; switch (sh) { + case SH_Slider_SnapToValue: + case SH_PrintDialog_RightAlignButtons: + case SH_FontDialog_SelectAssociatedText: + case SH_MenuBar_MouseTracking: + case SH_Menu_MouseTracking: + case SH_ComboBox_ListMouseTracking: + case SH_MainWindow_SpaceBelowMenuBar: + case SH_ItemView_ChangeHighlightOnFocus: + ret = 1; + break; + case SH_ToolBox_SelectedPageTitleBold: + ret = 0; + break; + case SH_DialogButtonBox_ButtonsHaveIcons: + ret = 0; + break; case SH_Menu_SelectionWrap: ret = false; break; @@ -2556,7 +2613,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w ret = Qt::AlignTop; break; case SH_ScrollView_FrameOnlyAroundContents: - ret = QWindowsStyle::styleHint(sh, opt, w, hret); + ret = QCommonStyle::styleHint(sh, opt, w, hret); break; case SH_Menu_FillScreenWithScroll: ret = false; @@ -2780,7 +2837,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w ret = false; break; default: - ret = QWindowsStyle::styleHint(sh, opt, w, hret); + ret = QCommonStyle::styleHint(sh, opt, w, hret); break; } return ret; @@ -2807,7 +2864,7 @@ QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixm default: ; } - return QWindowsStyle::generatedIconPixmap(iconMode, pixmap, opt); + return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt); } @@ -2822,7 +2879,7 @@ QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOpt static bool recursionGuard = false; if (recursionGuard) - return QWindowsStyle::standardPixmap(standardPixmap, opt, widget); + return QCommonStyle::standardPixmap(standardPixmap, opt, widget); recursionGuard = true; QIcon icon = standardIcon(standardPixmap, opt, widget); @@ -2964,7 +3021,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai if (const QStyleOptionFrame *groupBox = qstyleoption_cast(opt)) { const QStyleOptionFrameV2 *frame2 = qstyleoption_cast(opt); if (frame2 && frame2->features & QStyleOptionFrameV2::Flat) { - QWindowsStyle::drawPrimitive(pe, groupBox, p, w); + QCommonStyle::drawPrimitive(pe, groupBox, p, w); } else { HIThemeGroupBoxDrawInfo gdi; gdi.version = qt_mac_hitheme_version; @@ -3198,12 +3255,12 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal); } else { - QWindowsStyle::drawPrimitive(pe, opt, p, w); + QCommonStyle::drawPrimitive(pe, opt, p, w); } } break; case PE_PanelLineEdit: - QWindowsStyle::drawPrimitive(pe, opt, p, w); + QCommonStyle::drawPrimitive(pe, opt, p, w); // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit). // Focus frame is drawn outside the rectangle passed in the option-rect. if (const QStyleOptionFrame *panel = qstyleoption_cast(opt)) { @@ -3248,14 +3305,14 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai } break; case PE_PanelStatusBar: { if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4) { - QWindowsStyle::drawPrimitive(pe, opt, p, w); + QCommonStyle::drawPrimitive(pe, opt, p, w); break; } // Use the Leopard style only if the status bar is the status bar for a // QMainWindow with a unifed toolbar. if (w == 0 || w->parent() == 0 || qobject_cast(w->parent()) == 0 || qobject_cast(w->parent())->unifiedTitleAndToolBarOnMac() == false ) { - QWindowsStyle::drawPrimitive(pe, opt, p, w); + QCommonStyle::drawPrimitive(pe, opt, p, w); break; } @@ -3281,7 +3338,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai } default: - QWindowsStyle::drawPrimitive(pe, opt, p, w); + QCommonStyle::drawPrimitive(pe, opt, p, w); break; } } @@ -3512,10 +3569,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } } } else { - QWindowsStyle::drawControl(ce, &myTb, p, w); + QCommonStyle::drawControl(ce, &myTb, p, w); } } else { - QWindowsStyle::drawControl(ce, &myTb, p, w); + QCommonStyle::drawControl(ce, &myTb, p, w); } } break; @@ -3528,7 +3585,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter break; if (btn->features & QStyleOptionButton::CommandLinkButton) { - QWindowsStyle::drawControl(ce, opt, p, w); + QCommonStyle::drawControl(ce, opt, p, w); break; } @@ -3656,7 +3713,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } } if (themeId == kThemePushButtonFont) { - QWindowsStyle::drawControl(ce, btn, p, w); + QCommonStyle::drawControl(ce, btn, p, w); } else { p->save(); CGContextSetShouldAntialias(cg, true); @@ -3684,7 +3741,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } } else { if (hasIcon && !hasText) { - QWindowsStyle::drawControl(ce, btn, p, w); + QCommonStyle::drawControl(ce, btn, p, w); } else { QRect freeContentRect = btn->rect; QRect textRect = itemTextRect( @@ -3728,7 +3785,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter if (const QStyleOptionComboBox *cb = qstyleoption_cast(opt)) { QStyleOptionComboBox comboCopy = *cb; comboCopy.direction = Qt::LeftToRight; - QWindowsStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w); + QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w); } break; case CE_TabBarTabShape: @@ -4456,7 +4513,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } break; default: - QWindowsStyle::drawControl(ce, opt, p, w); + QCommonStyle::drawControl(ce, opt, p, w); break; } } @@ -4503,7 +4560,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, break; case SE_HeaderLabel: if (qstyleoption_cast(opt)) { - rect = QWindowsStyle::subElementRect(sr, opt, widget); + rect = QCommonStyle::subElementRect(sr, opt, widget); if (widget && widget->height() <= 22){ // We need to allow the text a bit more space when the header is // small, otherwise it gets clipped: @@ -4579,7 +4636,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, } break; case SE_TabWidgetTabContents: - rect = QWindowsStyle::subElementRect(sr, opt, widget); + rect = QCommonStyle::subElementRect(sr, opt, widget); if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast(opt)) { if (twf->lineWidth != 0) { @@ -4600,7 +4657,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, } break; case SE_LineEditContents: - rect = QWindowsStyle::subElementRect(sr, opt, widget); + rect = QCommonStyle::subElementRect(sr, opt, widget); if(widget->parentWidget() && qobject_cast(widget->parentWidget())) rect.adjust(-1, -2, 0, 0); else @@ -4855,7 +4912,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, } #endif default: - rect = QWindowsStyle::subElementRect(sr, opt, widget); + rect = QCommonStyle::subElementRect(sr, opt, widget); break; } return rect; @@ -5347,7 +5404,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel; didModifySubControls = true; } - QWindowsStyle::drawComplexControl(cc, &groupBox, p, widget); + QCommonStyle::drawComplexControl(cc, &groupBox, p, widget); if (didModifySubControls) { p->save(); CGContextSetShouldAntialias(cg, true); @@ -5500,7 +5557,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex QStyleHelper::drawDial(dial, p); break; default: - QWindowsStyle::drawComplexControl(cc, opt, p, widget); + QCommonStyle::drawComplexControl(cc, opt, p, widget); break; } } @@ -5514,7 +5571,7 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, switch (cc) { case CC_ComboBox: if (const QStyleOptionComboBox *cmb = qstyleoption_cast(opt)) { - sc = QWindowsStyle::hitTestComplexControl(cc, cmb, pt, widget); + sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt, widget); if (!cmb->editable && sc != QStyle::SC_None) sc = SC_ComboBoxArrow; // A bit of a lie, but what we want } @@ -5630,7 +5687,7 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, break; */ default: - sc = QWindowsStyle::hitTestComplexControl(cc, opt, pt, widget); + sc = QCommonStyle::hitTestComplexControl(cc, opt, pt, widget); break; } return sc; @@ -5852,7 +5909,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op case SC_GroupBoxContents: case SC_GroupBoxFrame: { if (flat) { - ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget); + ret = QCommonStyle::subControlRect(cc, groupBox, sc, widget); break; } QFontMetrics fm = groupBox->fontMetrics; @@ -5873,7 +5930,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op } break; default: - ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget); + ret = QCommonStyle::subControlRect(cc, groupBox, sc, widget); break; } } @@ -5966,19 +6023,19 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op ret = visualRect(spin->direction, spin->rect, ret); break; default: - ret = QWindowsStyle::subControlRect(cc, spin, sc, widget); + ret = QCommonStyle::subControlRect(cc, spin, sc, widget); break; } } break; case CC_ToolButton: - ret = QWindowsStyle::subControlRect(cc, opt, sc, widget); + ret = QCommonStyle::subControlRect(cc, opt, sc, widget); if (sc == SC_ToolButtonMenu && widget && !qobject_cast(widget->parentWidget())) { ret.adjust(-1, 0, 0, 0); } break; default: - ret = QWindowsStyle::subControlRect(cc, opt, sc, widget); + ret = QCommonStyle::subControlRect(cc, opt, sc, widget); break; } return ret; @@ -5999,7 +6056,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, case QStyle::CT_TabWidget: // the size between the pane and the "contentsRect" (+4,+4) // (the "contentsRect" is on the inside of the pane) - sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget); + sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); /** This is supposed to show the relationship between the tabBar and the stack widget of a QTabWidget. @@ -6197,7 +6254,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, break; } case CT_HeaderSection:{ const QStyleOptionHeader *header = qstyleoption_cast(opt); - sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget); + sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); if (header->text.contains(QLatin1Char('\n'))) useAquaGuideline = false; break; } @@ -6219,7 +6276,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, break; default: - sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget); + sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); } if (useAquaGuideline){ @@ -6261,7 +6318,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_PushButton: if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { if (btn->features & QStyleOptionButton::CommandLinkButton) { - return QWindowsStyle::sizeFromContents(ct, opt, sz, widget); + return QCommonStyle::sizeFromContents(ct, opt, sz, widget); } } @@ -6316,7 +6373,7 @@ void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPale { if(flags & Qt::TextShowMnemonic) flags |= Qt::TextHideMnemonic; - QWindowsStyle::drawItemText(p, r, flags, pal, enabled, text, textRole); + QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole); } bool QMacStyle::event(QEvent *e) @@ -6373,7 +6430,7 @@ QIcon QMacStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *o { switch (standardIcon) { default: - return QWindowsStyle::standardIcon(standardIcon, opt, widget); + return QCommonStyle::standardIcon(standardIcon, opt, widget); case SP_ToolBarHorizontalExtensionButton: case SP_ToolBarVerticalExtensionButton: { QPixmap pixmap(qt_mac_toolbar_ext); diff --git a/src/widgets/styles/qmacstyle_mac_p.h b/src/widgets/styles/qmacstyle_mac_p.h index ec6f7c75b4..af1c88d50d 100644 --- a/src/widgets/styles/qmacstyle_mac_p.h +++ b/src/widgets/styles/qmacstyle_mac_p.h @@ -47,7 +47,7 @@ #undef check #include "qmacstyle_mac.h" -#include "qwindowsstyle_p.h" +#include "qcommonstyle_p.h" #include #include #include @@ -139,7 +139,7 @@ enum QAquaWidgetSize { QAquaSizeLarge = 0, QAquaSizeSmall = 1, QAquaSizeMini = 2 bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option); -class QMacStylePrivate : public QWindowsStylePrivate +class QMacStylePrivate : public QCommonStylePrivate { Q_DECLARE_PUBLIC(QMacStyle) public: -- cgit v1.2.3